mcpField
V
vectorbt-expert

vectorbt-expert

github.com/marketcallsデータ・データベース2153.0k 回インストール15 週間前に更新
リポジトリ

vectorbt-expert について

vectorbt-expertは、VectorBTによるバックテストの開発と確認を支援するリファレンススキルです。クオンツ調査向けに、データ読み込み、インジケーター、コスト、リスク分析、可視化の規則と戦略テンプレートをまとめています。

主な機能

  1. 01データソースと読み込み規則を整理
  2. 02既定の指標ライブラリとしてOpenAlgo taを使用
  3. 03ポジションサイズ、コスト、損切り規則を網羅
  4. 04ベンチマーク比較と堅牢性分析に対応
  5. 05戦略テンプレートとチャート規則を提供

活用シーン

  1. 01市場ごとのデータ取得方法を計画
  2. 02指標の選択と売買シグナルの整理
  3. 03バックテストの手数料とポジション設定を確認
  4. 04ベンチマーク比較や堅牢性テストを実施

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/marketcalls/vectorbt-backtesting-skills --skill vectorbt-expert

インストール後、Claude Code で/vectorbt-expertを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

rules/
crypto-market-costs.md
csv-data-resampling.md
data-fetching.md
duckdb-data.md
futures-backtesting.md
indian-market-costs.md
indicators-signals.md
long-short-trading.md
openalgo-ta-helpers.md
openstatz-tearsheet.md
parameter-optimization.md
performance-analysis.md
pitfalls.md
plotting.md
position-sizing.md
robustness-testing.md
simulation-modes.md
stop-loss-take-profit.md
rules/assets/buy_hold/
backtest.py
rules/assets/donchian/
backtest.py
rules/assets/dual_momentum/
backtest.py
rules/assets/ema_crossover/
backtest.py
rules/assets/macd/
backtest.py
rules/assets/momentum/
backtest.py
rules/assets/realistic_costs/
template.py
rules/assets/rsi_accumulation/
backtest.py
rules/assets/rsi/
backtest.py
rules/assets/sda2/
backtest.py
rules/assets/supertrend/
backtest.py
rules/assets/walk_forward/
template.py

詳細

VectorBT バックテストエキスパートスキル

環境

  • vectorbt、pandas、numpy、plotly を使用する Python
  • データソース:OpenAlgo(インド市場)、DuckDB(データベースに直接接続)、yfinance(米国/グローバル)、CCXT(暗号資産)、カスタムプロバイダー
  • DuckDB のサポート:カスタム DuckDB と OpenAlgo Historify 形式の両方に対応
  • API キーは python-dotenv と find_dotenv() を使って単一のルート .env から読み込みます。キーをハードコードしないでください
  • テクニカル指標:OpenAlgo ta(デフォルト。from openalgo import ta。トレンド/モメンタム/ボラティリティ/出来高/オシレーター/統計/ハイブリッドを網羅する 100 以上の指標)。TA-Lib を使うのは、ユーザーが TA-Lib/talib を明示的に指定した場合のみです。どちらの場合も、VectorBT の組み込み指標は絶対に使わないでください
  • 特殊な指標(TA-Lib に相当するものがなく、常に openalgo.ta を使用):Supertrend、Donchian、Ichimoku、HMA、KAMA、ALMA、ZLEMA、VWMA
  • シグナルのクリーニング:openalgo.ta の exrem、crossover、crossunder、flip を使用します(指標ライブラリに関係なく常に使用)
  • 手数料モデル:インド市場標準(STT + 法定諸費用 + 1 注文あたり Rs 20)
  • ベンチマーク:デフォルトでは OpenAlgo 経由の NIFTY 50(NSE_INDEX)
  • チャート:template="plotly_dark" を指定した Plotly
  • 環境変数は、find_dotenv()(スクリプトのディレクトリから上位へ検索)を使ってプロジェクトルートの単一 .env から読み込みます
  • スクリプトは backtesting/{strategy_name}/ ディレクトリに配置します(事前に作成せず、必要に応じて作成)
  • コードやロガーの出力にアイコンや絵文字を使わないでください

重要なルール

  1. すべてのテクニカル指標(EMA、SMA、RSI、MACD、BBANDS、ATR、ADX、STDDEV、MOM など 90 種類以上)には、デフォルトで OpenAlgo ta(from openalgo import ta)を使用します。プロンプトでユーザーが「talib」/「TA-Lib」を明示的に指定した場合に限り、TA-Lib を使用してください。どちらのライブラリを使う場合も、vbt.MA.run()、vbt.RSI.run()、その他の VectorBT 組み込み指標は絶対に使わないでください。
  2. TA-Lib に存在しない指標には、常に OpenAlgo ta を使用します:Supertrend、Donchian、Ichimoku、HMA、KAMA、ALMA、ZLEMA、VWMA。これらには TA-Lib に相当するものがないため、TA-Lib を明示的に使用するスクリプトでも openalgo.ta を使います。
  3. シグナルユーティリティには OpenAlgo ta を使用します:ta.exrem()、ta.crossover()、ta.crossunder()、ta.flip()。openalgo.ta をインポートできない場合(単独の DuckDB 使用時)は、インラインの exrem() フォールバックを使用します。duckdb-data を参照してください。
  4. 生の買い/売りシグナルを生成した後は、必ず ta.exrem() でシグナルをクリーニングしてください。exrem の前に必ず .fillna(False) を適用してください。
  5. 市場ごとに手数料を設定します:インド(indian-market-costs)、米国(us-market-costs)、暗号資産(crypto-market-costs)。ユーザーの市場に基づいて自動選択してください。
  6. デフォルトのベンチマーク:インド=OpenAlgo 経由の NIFTY、米国=S&P 500(^GSPC)、暗号資産=Bitcoin(BTC-USD)。data-fetching の「市場選択ガイド」を参照してください。
  7. バックテストの後は必ず、戦略とベンチマークの比較表を作成してください。
  8. バックテストレポートについて、一般のトレーダーにもリスクと強みが伝わるよう、平易な言葉で必ず説明してください。
  9. Plotly のローソク足チャートでは、週末による間隔を避けるため、xaxis type="category" を必ず使用してください。
  10. 株式は整数株:株式には必ず min_size=1, size_granularity=1 を設定してください。
  11. DuckDB のデータ読み込み:ユーザーが DuckDB のパスを指定した場合は、duckdb.connect() に read_only=True を指定してデータを直接読み込みます。形式を自動検出してください:OpenAlgo Historify(テーブル market_data、エポックタイムスタンプ)またはカスタム形式(テーブル ohlcv、date 列と time 列)。duckdb-data を参照してください。

モジュール式ルールファイル

各トピックの詳細なリファレンスは rules/ にあります。

ルールファイルトピック
data-fetchingOpenAlgo(インド)、yfinance(米国)、CCXT(暗号資産)、カスタムプロバイダー、.env の設定
simulation-modesfrom_signals、from_orders、from_holding、方向の種類
position-sizing金額/価値/割合/目標割合によるサイズ設定
indicators-signalsOpenAlgo ta インジケーターのリファレンス(デフォルト)、TA-Lib のオプトイン、シグナル生成
openalgo-ta-helpersOpenAlgo ta の完全なカタログ(100 以上のインジケーター):exrem、crossover、Supertrend、Donchian、Ichimoku、MA
stop-loss-take-profit固定 SL、TP、トレーリングストップ
parameter-optimizationブロードキャストとループベースの最適化
performance-analysis統計、指標、ベンチマークとの比較、CAGR
plottingローソク足(カテゴリ軸)、VectorBT のプロット、カスタム Plotly
indian-market-costsセグメント別のインド市場手数料モデル
us-market-costs米国市場の手数料モデル(株式、オプション、先物)
crypto-market-costs暗号資産の手数料モデル(現物、USDT-M、COIN-M 先物)
futures-backtestingロットサイズ(SEBI が 2025 年 12 月に改定)、価値によるサイズ設定
long-short-tradingロング/ショートの同時取引、方向の比較
duckdb-dataDuckDB からの直接読み込み、Historify 形式、自動検出、リサンプリング、複数銘柄
csv-data-resamplingCSV の読み込み、インド市場に合わせたリサンプリング
walk-forwardウォークフォワード分析、WFE 比率
robustness-testingモンテカルロ、ノイズテスト、パラメーター感度、遅延テスト
pitfallsよくある間違いと実運用開始前のチェックリスト
strategy-catalogコードスニペット付きの戦略リファレンス
openstatz-tearsheetOpenStatz のインタラクティブなオフラインダッシュボード、指標、モンテカルロ(QuantStats に代わるもの)

戦略テンプレート(rules/assets/ 内)

現実的な手数料、NIFTY ベンチマーク、比較表、平易な言葉によるレポートを含む、本番環境向けのスクリプトです。

テンプレートパス説明
EMA クロスオーバーassets/ema_crossover/backtest.pyEMA 10/20 のクロスオーバー
RSIassets/rsi/backtest.pyRSI(14) の売られ過ぎ/買われ過ぎ
Donchianassets/donchian/backtest.pyDonchian チャネルブレイクアウト
Supertrendassets/supertrend/backtest.py日中セッション対応の Supertrend
MACDassets/macd/backtest.pyMACD シグナルローソク足のブレイクアウト
SDA2assets/sda2/backtest.pySDA2 トレンドフォロー
モメンタムassets/momentum/backtest.pyダブルモメンタム(MOM + MOM-of-MOM)
デュアルモメンタムassets/dual_momentum/backtest.py四半期ごとの ETF ローテーション
バイ・アンド・ホールドassets/buy_hold/backtest.py静的なマルチアセット配分
RSI 積み立てassets/rsi_accumulation/backtest.pyRSI の区分に応じた週次の積み立て
ウォークフォワードassets/walk_forward/template.pyウォークフォワード分析テンプレート
現実的なコストassets/realistic_costs/template.py取引コストの影響を比較

クイックテンプレート:標準的なバックテストスクリプト

import os
from datetime import datetime, timedelta
from pathlib import Path

import numpy as np
import pandas as pd
import vectorbt as vbt
from dotenv import find_dotenv, load_dotenv
from openalgo import api, ta

# --- Config ---
script_dir = Path(__file__).resolve().parent
load_dotenv(find_dotenv(), override=False)

SYMBOL = "SBIN"
EXCHANGE = "NSE"
INTERVAL = "D"
INIT_CASH = 1_000_000
FEES = 0.00111              # Indian delivery equity (STT + statutory)
FIXED_FEES = 20             # Rs 20 per order
ALLOCATION = 0.75
BENCHMARK_SYMBOL = "NIFTY"
BENCHMARK_EXCHANGE = "NSE_INDEX"

# --- Fetch Data ---
client = api(
    api_key=os.getenv("OPENALGO_API_KEY"),
    host=os.getenv("OPENALGO_HOST", "http://127.0.0.1:5000"),
)

end_date = datetime.now().date()
start_date = end_date - timedelta(days=365 * 3)

df = client.history(
    symbol=SYMBOL, exchange=EXCHANGE, interval=INTERVAL,
    start_date=start_date.strftime("%Y-%m-%d"),
    end_date=end_date.strftime("%Y-%m-%d"),
)
if "timestamp" in df.columns:
    df["timestamp"] = pd.to_datetime(df["timestamp"])
    df = df.set_index("timestamp")
else:
    df.index = pd.to_datetime(df.index)
df = df.sort_index()
if df.index.tz is not None:
    df.index = df.index.tz_convert(None)

close = df["close"]

# --- Strategy: EMA Crossover (OpenAlgo ta - default indicator library) ---
ema_fast = ta.ema(close, 10)
ema_slow = ta.ema(close, 20)

buy_raw = (ema_fast > ema_slow) & (ema_fast.shift(1) <= ema_slow.shift(1))
sell_raw = (ema_fast < ema_slow) & (ema_fast.shift(1) >= ema_slow.shift(1))

entries = ta.exrem(buy_raw.fillna(False), sell_raw.fillna(False))
exits = ta.exrem(sell_raw.fillna(False), buy_raw.fillna(False))

# --- Backtest ---
pf = vbt.Portfolio.from_signals(
    close, entries, exits,
    init_cash=INIT_CASH, size=ALLOCATION, size_type="percent",
    fees=FEES, fixed_fees=FIXED_FEES, direction="longonly",
    min_size=1, size_granularity=1, freq="1D",
)

# --- Benchmark ---
df_bench = client.history(
    symbol=BENCHMARK_SYMBOL, exchange=BENCHMARK_EXCHANGE, interval=INTERVAL,
    start_date=start_date.strftime("%Y-%m-%d"),
    end_date=end_date.strftime("%Y-%m-%d"),
)
if "timestamp" in df_bench.columns:
    df_bench["timestamp"] = pd.to_datetime(df_bench["timestamp"])
    df_bench = df_bench.set_index("timestamp")
else:
    df_bench.index = pd.to_datetime(df_bench.index)
df_bench = df_bench.sort_index()
if df_bench.index.tz is not None:
    df_bench.index = df_bench.index.tz_convert(None)
bench_close = df_bench["close"].reindex(close.index).ffill().bfill()
pf_bench = vbt.Portfolio.from_holding(bench_close, init_cash=INIT_CASH, fees=FEES, freq="1D")

# --- Results ---
print(pf.stats())

# --- Strategy vs Benchmark ---
comparison = pd.DataFrame({
    "Strategy": [
        f"{pf.total_return() * 100:.2f}%", f"{pf.sharpe_ratio():.2f}",
        f"{pf.sortino_ratio():.2f}", f"{pf.max_drawdown() * 100:.2f}%",
        f"{pf.trades.win_rate() * 100:.1f}%", f"{pf.trades.count()}",
        f"{pf.trades.profit_factor():.2f}",
    ],
    f"Benchmark ({BENCHMARK_SYMBOL})": [
        f"{pf_bench.total_return() * 100:.2f}%", f"{pf_bench.sharpe_ratio():.2f}",
        f"{pf_bench.sortino_ratio():.2f}", f"{pf_bench.max_drawdown() * 100:.2f}%",
        "-", "-", "-",
    ],
}, index=["Total Return", "Sharpe Ratio", "Sortino Ratio", "Max Drawdown",
          "Win Rate", "Total Trades", "Profit Factor"])
print(comparison.to_string())

# --- Explain ---
print(f"* Total Return: {pf.total_return() * 100:.2f}% vs NIFTY {pf_bench.total_return() * 100:.2f}%")
print(f"* Max Drawdown: {pf.max_drawdown() * 100:.2f}%")
print(f"  -> On Rs {INIT_CASH:,}, worst temporary loss = Rs {abs(pf.max_drawdown()) * INIT_CASH:,.0f}")

# --- Plot ---
fig = pf.plot(subplots=['value', 'underwater', 'cum_returns'], template="plotly_dark")
fig.show()

# --- Export ---
pf.positions.records_readable.to_csv(script_dir / f"{SYMBOL}_trades.csv", index=False)

クイックテンプレート:DuckDB バックテストスクリプト

import datetime as dt
from pathlib import Path

import duckdb
import numpy as np
import pandas as pd
import vectorbt as vbt

try:
    # Default: OpenAlgo ta for both indicators and signal cleaning
    from openalgo import ta
    exrem = ta.exrem
    ema = ta.ema
except ImportError:
    # Fallback ONLY when the openalgo package itself is not installed
    # (standalone DuckDB with no OpenAlgo). Use TA-Lib for indicators
    # and this inline exrem() replacement for signal cleaning.
    import talib as tl

    def ema(data, period):
        return pd.Series(tl.EMA(data.values, timeperiod=period), index=data.index)

    def exrem(signal1, signal2):
        result = signal1.copy()
        active = False
        for i in range(len(signal1)):
            if active:
                result.iloc[i] = False
            if signal1.iloc[i] and not active:
                active = True
            if signal2.iloc[i]:
                active = False
        return result

# --- Config ---
SYMBOL = "SBIN"
DB_PATH = r"path/to/market_data.duckdb"
INIT_CASH = 1_000_000
FEES = 0.000225              # Intraday equity
FIXED_FEES = 20

# --- Load from DuckDB ---
con = duckdb.connect(DB_PATH, read_only=True)
df = con.execute("""
    SELECT date, time, open, high, low, close, volume
    FROM ohlcv WHERE symbol = ? ORDER BY date, time
""", [SYMBOL]).fetchdf()
con.close()

df["datetime"] = pd.to_datetime(df["date"].astype(str) + " " + df["time"].astype(str))
df = df.set_index("datetime").sort_index()
df = df.drop(columns=["date", "time"])

# --- Resample to 5min ---
df_5m = df.resample("5min", origin="start_day", offset="9h15min",
                     label="right", closed="right").agg({
    "open": "first", "high": "max", "low": "min", "close": "last", "volume": "sum"
}).dropna()
close = df_5m["close"]

# --- Strategy + Backtest (same as OpenAlgo template, but use the ema()/exrem() resolved above) ---

ユーザーが TA-Lib を明示的に指定した場合は、上記の try/except を省略し、代わりに import talib as tl を直接実行してください。exrem のフォールバックは、openalgo 自体を利用できない場合に限ります。

コメント