Pythonのバックテストには、元データから当時利用可能な情報、注文、約定、照合できる台帳への鎖が必要です。タイムスタンプだけでなく記録IDも保持します。速く描けた曲線では、未来の発表値、未完成足、利用できない約定価格を検知できません。

研究上の要件から環境を選ぶ

MT5のストラテジーテスターは複数商品を使うEAのテスト・最適化に対応します。一通貨しか使えないからPythonへ逃げる、という説明は不正確です。Pythonは独自のデータ処理・計算・研究を組む別の手段。実装差を調べるなら同じ凍結データ、契約仕様、規則、約定条件を使います。

データの意味と必要なスタックを保存

商品・提供者・価格側・タイムゾーン・標本間隔・取得期間を記録し、重複ID、順序、欠落を検査。市場休場は破損とは限らず、補間は存在しない観測を作り得ます。元ファイルと加工履歴を両方残します。

MetaTrader5のcopy_rates_rangeはtime/OHLC/tick_volume/spread/real_volume等を返しますが、完全な過去の手数料やスワップ料金表は含みません。返る足は端末履歴と設定に依存し、期間を要求しただけで全件取得は証明されません。時刻引数とデータはUTCを明示し、セッション表示へ後で変換します。

pandasとNumPyは計算、Backtraderはイベント駆動の構成、vectorbtはorders/signals/custom order-function等のモードを提供します。vectorbtも資金・資産の状態を更新し、配列入力だから全約定が互いに独立とは言えません。小さく必要な構成を選び、版、ライセンス、環境、データ利用権を記録。データや配備まで必ず無料というわけではありません。

indexを落とすと別の足へフラグが付く

完成済みの架空記録A=100、B=102、C=104と、C:1/A:0/B:0の順のフラグを使います。1はさらに検討する候補で、注文や約定価格ではありません。

横にスクロールすると図全体を確認できます。

IDによる選択と配列位置による選択価格A100/B102/C104と、別順序のフラグC1/A0/B0。Seriesのラベル整列はC104、IDを落とす位置計算は先頭A100を選ぶ。ID別の価格違う順序のフラグA 100C 1B 102A 0C 104B 0Series:ID C → 104IDなし:先頭 → 100同じデータでも選ぶ記録が変わる
価格A100/B102/C104と、別順序のフラグC1/A0/B0。Seriesのラベル整列はC104、IDを落とす位置計算は先頭A100を選ぶ。
prices * flags
# A: 0, B: 0, C: 104
prices.to_numpy() * flags.to_numpy()
# 100, 0, 0

SeriesはIDで整列しますが、二つを配列にすると位置で掛けます。それをA/B/Cに戻すとAが候補になります。長さだけでなくto_numpy()前にIDを照合します。正しい整列の後にも、フラグがいつ分かったかは別確認です。

いつ利用可能かを規則とコードにする

10:00開始のH1足は、その瞬間に完成OHLCが分かるわけではありません。リサンプルのclosedは区間の所属、labelは表示側を制御し、ラベル変更で利用可能時刻を早められません。

マクロ値は対象月だけでなく、当時の版の発表時刻で結合します。merge_asofは結合キーの昇順が必要。backwardは以前または同時、nearestは未来を選ぶこともあり、どちらも改定値の存在を自動判断しません。許容差と同時刻イベント順序を定めます。

架空の判断時刻10:04UTC、保存発表10:00の値50と10:05の値60なら、backward無制限は4分前の50、nearestは1分後の60。2分の後方許容では一致なしです。欠損を未来の近い値に置き換えると情報集合が変わります。

別の完成足モデルは最初の20足High=100〜119、各Open=High−0.5/Low=High−2/Close=High−1。足21はO120/H121/L118/C120.5、足22はO120.6/H122/L119/C121です。市場データでもFX取引でもない任意価格です。

previous_high = bars["high"].shift(1).rolling(20).max()
signal = bars["close"] > previous_high
next_bar_signal = signal.shift(1, fill_value=False)

足21の過去20足高値119に対し120.5>119で真。現在Highを含めると121となり偽です。最後の行は観測信号を足22へ置くだけで、約定価格・注文受理・出口は与えません。完成済み入力だけを使い、数量・注文型・イベント順序を別に定義します。

信号・約定・費用を分ける

Backtraderの公式標準モデルでは現在足処理後のMarket注文は次の利用可能な足Openを使います。設定や別執行モデルで挙動は変わります。同じ足内でSLとTPの両方へ到達していてもOHLCだけでは先後を判定できません。

独立した一取引台帳:10,000EURをEUR/USD Ask1.1002で買う(同時Bid1.1000)。後で全量を指定Bid1.1012で売る(Ask1.1014)。pip=.0001USD/EUR、約定差10pip=10USD。片道手数料各1USDなら純利益8USDです。追加滑り・金利0という仮定。別に入口スプレッド2pipを引いて6USDとすると、既に価格側へ含めた差を二重計上します。

実商品では金利、換算、契約単位、必要証拠金、拒否注文を定義。複数商品は共通資金・利用可能証拠金・同時要求の順序も必要です。独立曲線の合算では、共通口座が資金不足で受け付けられない注文を含め得ます。ランダム滑りなら分布、乱数seed、ライブラリ版を保存します。

台帳でしか検証できない性能の数字

同じ金額のRによる架空例:40勝各+2R、60敗各−1Rなら利益80R、損失60R、純20R、PF80/60≈1.33、平均0.2R。全100取引に費用0.1Rなら勝ち+1.9R/負け−1.1R、利益76R、損失66R、純10R、PF約1.15、平均0.1Rです。実バックテストの成績ではありません。

別の再エントリー反例は5足条件が真・真・真・偽・真。両方が足1で入り、足2の入口判定前にストップで閉じ、その後に出口なしとします。「フラットかつ真で入る」方式は足2で再入場。「一度偽で再武装が必要」方式は足4で準備し足5で入ります。両方2回でも入口は[1,2]対[1,5]。これは選んだ状態機械で、特定ライブラリの既定値の説明ではありません。

未決済を含む純資産と決済成績を両方残し、下落には初期資金も含めます。入出金と収益を分け、日付付き台帳と資産経路から再構成できないリターン、Sharpe、下落値を付け足しません。

選別履歴と未使用期間を分ける

候補選択前に時系列の学習・評価期間を固定します。採用・不採用の商品、パラメータ、フィルター、分割を全て記録。パラメータが二つでも試した仮説が二つとは限りません。Baileyらの研究は反復選択と過剰適合を扱いますが、本稿の架空例からPBOを推定していません。

別の100取引で75勝各+0.2R、25敗各−1Rなら利益15R、損失25R、純−10R、PF0.6。75%勝率だけでバグや過剰適合を診断できません。観測、依存性、執行、費用、パラメータ感度を調べます。未使用期間で三分の一低下等の固定割合だけでも原因は判定できません。

共通10,000円ではAとBの両方を受け付けられない

共通10,000円ではAとBの両方を受け付けられない独立架空の証拠金予約。A6000/B5000、相殺・部分受付・価格変動なし。仮定に基づく計算A→BA受付、B拒否B→AB受付、A拒否別々の口座を合算共有口座とは別モデル
共通10,000円ではAとBの両方を受け付けられない. 独立架空の証拠金予約。A6000/B5000、相殺・部分受付・価格変動なし。

同時刻でも処理順と拒否記録を保存。架空予約額は実商品の必要証拠金率ではありません。

小さな画面では横にスクロールするか、図を拡大できます。数値と要点は下のテキストにも記載しています。

A→B
A受付、B拒否 – 残り4000円ではB5000円を満たさない。
B→A
B受付、A拒否 – 残り5000円ではA6000円を満たさない。
別々の口座を合算
共有口座とは別モデル – 各々10000円なら元の資金制約を変えている。

明日行う最小のオフライン検証

  1. 隔離したプロジェクトに未加工データ、ID、UTC、価格側、版を保存。学習演習にライブ認証情報や注文は不要。
  2. 数件で信号の利用可能時点と次の実行イベント、欠損・改定処理を確認。
  3. 同じ真の連続で追加・反転・再入場・再武装のどれをするか定義し、入口IDを検査。
  4. 各約定と費用を照合し、凍結規則で別の執行仮定を比較。
  5. 試行履歴と評価期間、制限を保存。ウォークフォワードの利用可能情報へ進む。

このページのID整列、asof、閉じ足、再入場の小例はPython3.12.10/pandas3.0.5/NumPy2.5.3でオフライン確認しました。実相場の戦略テスト、Backtrader/vectorbtの実行、MT5端末への接続は行っていません。

円の独立例:同時要求の処理順を隠さない

架空共有資金10,000円、A要求の予約証拠金6,000円、Bは5,000円。費用、価格変動、相殺、部分受付なしで全量受付か拒否のみとします。A→BならA受付、残り4,000円でB拒否。B→AならB受付、残り5,000円でA拒否です。

両戦略を別の10,000円口座で計算して合算すれば両方入れてしまい、同じ共有口座の比較になりません。これは証拠金予約の状態演習で、実商品の規制率や業者の受付優先順ではありません。シンボル順序や時刻が同じでも、決めた処理順と拒否台帳を保存してください。