MQL5バックテスト実務ノート|検証条件・最適化・リアル差分を記録する考え方

EAファンクラブ

MQL5でEAを検証する時、バックテストは重要な確認手段です。

しかし、バックテスト結果だけを見てEAの良し悪しを判断すると、誤解が起きやすくなります。検証期間、銘柄、時間足、スプレッド、tick model、初期証拠金、手数料、最適化条件、ログ粒度が変わるだけで、結果は大きく変わることがあります。

また、バックテストで良く見える設定が、リアル稼働でも同じように動くとは限りません。約定、スプレッド、スリッページ、外部通信、サーバー時刻、ティック配信、VPS環境、リアルタイムのインジケーター更新など、バックテストでは再現しきれない差分があります。

バックテスト実務で重要なのは、検証条件、最適化条件、ログ、リアル差分、再現性を記録することです。

この記事では、MQL5 EAのバックテストで確認すべき設計判断を、開発実務ノートとして整理します。完成EAソース全文、外部シート制御ロジック、認証ロジック、endpoint、token、URL実値、実運用set値、中核Entry条件は公開しません。

本記事は、投資判断や売買指示ではなく、EA検証の再現性と不具合調査を高めるための技術記事です。利益保証、勝率保証、推奨ロット、推奨銘柄、推奨設定を目的とした内容ではありません。

この記事で扱う実務課題

項目この記事で扱う内容扱わない内容
目的バックテスト条件・最適化・リアル差分を記録する考え方利益を狙う売買ロジック、具体的なEntry条件
主な対象検証期間、銘柄、時間足、スプレッド、tick model、最適化、ログ記録完成EAソース全文、実運用コード全文
設計観点再現性、過剰最適化防止、リアル差分確認、不具合調査認証ロジック、外部制御、実運用set値
コード例一般化した検証条件Snapshot、検証ログ、差分記録テンプレート実売買条件、独自優位性のある判定式
読者MQL5開発者、EA検証担当者、改修依頼前ユーザー、販売前チェック担当者勝てる設定や推奨パラメータを知りたい人

なぜバックテスト条件を記録する必要があるのか

バックテスト結果は、検証条件とセットで見ないと意味がありません。

同じEAでも、期間、銘柄、時間足、スプレッド、tick model、初期証拠金、ロット設定、手数料設定が変われば、結果が変わります。

条件影響すること記録しない場合の問題
検証期間相場局面、ボラティリティ、トレンド・レンジ比率どの相場で有効だったか分からない
銘柄スプレッド、tick value、contract size、取引時間別銘柄へ流用して誤解する
時間足シグナル頻度、判定タイミング、決済頻度別時間足で同じ結果になると誤解する
スプレッドEntry可否、損益、短期売買結果リアルとの差を説明できない
tick model約定タイミング、未確定足、インジ値再現性を確認しにくい
設定値Entry、risk、exit、filterの動作同じ結果を再現できない
EAバージョンロジック・ログ・仕様差分どの版の結果か分からない

バックテスト結果を比較するには、まず検証条件を固定し、後から同じ条件で再確認できるように記録する必要があります。

Backtest Condition Snapshotを残す

Backtest Condition Snapshotとは、バックテスト時の条件をまとめた記録です。

検証結果だけでなく、どの条件で検証したのかを保存しておくことで、後から再現や比較がしやすくなります。

記録項目目的
EA名・バージョンEA名、内部revisionどの版の検証か固定する
銘柄対象symbol銘柄仕様差を確認する
時間足M1、M5、M15など判定頻度と結果を比較する
検証期間開始日・終了日相場局面を把握する
tick model使用したモデリング条件再現性と精度を確認する
スプレッド条件固定・現在値・指定値リアル差分を見る
初期証拠金検証用の資金条件DD率やロット挙動を見る
設定ファイル検証に使ったset再検証できるようにする
ログモード詳細、summary、BT用ログ量と確認対象を整理する

Backtest Condition Snapshotがないと、「前回と同じ条件で再テストしたつもり」でも、実際には条件が変わっていることがあります。

最適化は検証ではなく候補探し

MT5の最適化は便利ですが、最適化結果をそのまま実運用候補と考えるのは危険です。

最適化は、あくまで候補を探す工程です。最適化で良い結果が出た設定は、別期間、別相場、別スプレッド、別銘柄、リアルタイム条件で再確認する必要があります。

工程目的注意点
単体バックテストEAが想定通り動くか確認するまずロジック・ログ・発注結果を見る
最適化設定候補を探す結果の良さだけで判断しない
別期間検証過剰最適化を疑う最適化期間外でも極端に崩れないか確認する
条件変更検証スプレッドや銘柄差を確認する少し条件を変えると崩れる設定に注意する
リアル確認実際の配信・約定・環境差を見るバックテストと完全一致を期待しない

最適化は、検証の終点ではありません。候補を見つけた後に、その候補がどの条件で安定しているのかを確認する必要があります。

過剰最適化に注意する

過剰最適化とは、特定の期間や条件にだけ過度に合った設定になっている状態です。

過剰最適化された設定は、バックテスト上では良く見えても、別期間やリアル稼働で崩れやすくなります。

兆候注意点
特定期間だけ極端に良い別期間で崩れる可能性がある
パラメータが細かすぎる実運用環境の誤差に弱い可能性がある
少し設定を変えると結果が大きく崩れる頑健性が低い可能性がある
取引回数が少なすぎる偶然の影響が大きい可能性がある
スプレッド変更に弱いリアルで差が出やすい可能性がある
DDの発生タイミングが偏っている特定相場への依存が強い可能性がある

過剰最適化を避けるには、最適化結果の上位だけを見るのではなく、周辺設定、別期間、悪化条件、リアル差分も確認する必要があります。

リアル差分を最初から想定する

バックテストとリアル稼働には差があります。

これはバックテストが無意味ということではありません。バックテストは検証の重要な入口ですが、リアル稼働で完全に同じ結果になるとは考えない方が安全です。

差分内容確認方法
スプレッド差リアルでは時間帯により変動するspreadログ、時間帯別検証
スリッページ差約定価格が想定とずれる場合があるOrderSend結果、約定価格ログ
tick差ティック配信や履歴データの条件が異なるtick modelとリアルログ比較
外部通信差バックテストでは外部通信を再現しにくい外部連携を別責務で検証
インジ更新差未確定足やリペイントの扱いが変わるshift、buffer、リアルタイム確認
サーバー時刻差ブローカーやサーバーで時刻条件が変わるserver timeログ
VPS環境差CPU、メモリ、回線、同時稼働数が影響する稼働環境メモ、長時間確認

リアル差分は、検証後に初めて気づくものではなく、設計段階から想定して記録しておくべき項目です。

バックテストログで見るべきポイント

バックテストでは、損益グラフだけでなく、EAがどの理由でEntryし、どの理由で見送り、どの理由で決済したかを確認する必要があります。

ログ区分確認できること
BT_CONDITION検証条件symbol、timeframe、period、spread
SIGNALEntry候補が出ているかSIGNAL_OK、NO_SIGNAL
GATE発注前条件で止まっているかSPREAD_BLOCK、TIME_BLOCK
RISKrisk条件で止まっているかLOT_INVALID、MAX_POSITION_BLOCK
ORDER注文結果ORDER_SEND_OK、ORDER_SEND_FAIL、retcode
EXIT決済理由TP、SL、TRAIL、SIGNAL_EXIT
SUMMARY検証全体の要約entry count、block count、error count

バックテストログでは、成功系をすべて出すよりも、見送り理由、失敗理由、summaryを整理すると確認しやすくなります。

実コード例1:Backtest Condition Snapshotを作る

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したBacktest Condition Snapshot例です。
// 実運用EAの完成ソースではありません。

struct BacktestConditionSnapshot
{
   string eaName;
   string version;
   string symbol;
   string timeframe;
   string testProfile;
   string spreadMode;
   datetime capturedAt;
};

BacktestConditionSnapshot BuildBacktestConditionSnapshot()
{
   BacktestConditionSnapshot snap;
   snap.eaName = "SampleEA";
   snap.version = "sample";
   snap.symbol = _Symbol;
   snap.timeframe = EnumToString((ENUM_TIMEFRAMES)Period());
   snap.testProfile = "BT_PROFILE_SAMPLE";
   snap.spreadMode = "RECORDED_IN_TESTER";
   snap.capturedAt = TimeCurrent();

   return snap;
}

void PrintBacktestConditionSnapshot(const BacktestConditionSnapshot &snap)
{
   Print("DIAG/BT_CONDITION: event=SNAPSHOT",
         " ea=", snap.eaName,
         " version=", snap.version,
         " symbol=", snap.symbol,
         " timeframe=", snap.timeframe,
         " profile=", snap.testProfile,
         " spread=", snap.spreadMode);
}

この例では、検証条件をSnapshotとしてまとめています。実際の検証では、検証期間、初期証拠金、tick model、setファイル名なども管理台帳や検証メモへ残します。

実コード例2:検証summaryを残す

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したバックテストsummary例です。
// 実運用EAの完成ソースではありません。

struct BacktestSummary
{
   int signalCount;
   int entryCount;
   int gateBlockCount;
   int orderFailCount;
   int exitCount;
};

BacktestSummary g_btSummary;

void CountSignal()
{
   g_btSummary.signalCount++;
}

void CountEntry()
{
   g_btSummary.entryCount++;
}

void CountGateBlock()
{
   g_btSummary.gateBlockCount++;
}

void CountOrderFail()
{
   g_btSummary.orderFailCount++;
}

void CountExit()
{
   g_btSummary.exitCount++;
}

void PrintBacktestSummary()
{
   Print("DIAG/BT_SUMMARY: event=RESULT",
         " signal=", g_btSummary.signalCount,
         " entry=", g_btSummary.entryCount,
         " gate_block=", g_btSummary.gateBlockCount,
         " order_fail=", g_btSummary.orderFailCount,
         " exit=", g_btSummary.exitCount);
}

バックテストでは、すべての成功ログを出すより、件数をsummaryとして残す方が確認しやすい場合があります。

特に、なぜEntryが少ないのか、どのGATEで止まっているのか、OrderSend失敗があるのかを件数で確認できると、検証効率が上がります。

実コード例3:リアル差分メモをログ化する

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したリアル差分ログ例です。
// 実運用EAの完成ソースではありません。

void PrintLiveDifferenceNote(string category,
                             string reason,
                             string detail)
{
   Print("DIAG/LIVE_DIFF: category=", category,
         " reason=", reason,
         " detail=", detail);
}

void TraceSpreadDifference(int backtestSpread,
                           int currentSpread)
{
   if(currentSpread > backtestSpread)
   {
      PrintLiveDifferenceNote("SPREAD",
                              "LIVE_SPREAD_WIDER",
                              "bt=" + IntegerToString(backtestSpread) +
                              " live=" + IntegerToString(currentSpread));
      return;
   }

   PrintLiveDifferenceNote("SPREAD",
                           "SPREAD_WITHIN_TEST_CONDITION",
                           "bt=" + IntegerToString(backtestSpread) +
                           " live=" + IntegerToString(currentSpread));
}

この例では、バックテスト条件とリアル条件の差分をログとして記録する考え方を示しています。

実際のEAでは、スプレッド、約定価格、サーバー時刻、外部通信、ポジション反映など、比較したい項目を仕様に合わせて整理します。

実コード例4:最適化候補をそのまま採用しない

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化した最適化候補レビュー例です。
// 実運用EAの完成ソースではありません。

struct OptimizationReview
{
   bool candidate;
   bool needsOutOfSampleTest;
   bool needsSpreadStressTest;
   string reason;
};

OptimizationReview ReviewOptimizationCandidate(double profitFactor,
                                               int tradeCount,
                                               double maxDrawdownPercent)
{
   OptimizationReview review;
   review.candidate = false;
   review.needsOutOfSampleTest = true;
   review.needsSpreadStressTest = true;
   review.reason = "INIT";

   if(tradeCount < 30)
   {
      review.reason = "TOO_FEW_TRADES";
      return review;
   }

   if(maxDrawdownPercent > 50.0)
   {
      review.reason = "DRAWDOWN_TOO_LARGE";
      return review;
   }

   if(profitFactor <= 1.0)
   {
      review.reason = "PF_NOT_ENOUGH";
      return review;
   }

   review.candidate = true;
   review.reason = "REVIEW_REQUIRED";

   return review;
}

この例は、最適化結果を即採用せず、追加検証が必要な候補として扱う考え方を示しています。

数値基準はEAや目的によって変わるため、この記事では推奨値として扱いません。重要なのは、最適化結果をそのまま採用せず、別期間・悪化条件・リアル差分を確認することです。

バックテストとリアルの比較で確認すること

バックテスト後にリアル確認へ進む場合、次のような項目を比較します。

比較項目確認内容
Entry時刻バックテストとリアルで候補発生タイミングが大きく違わないか
Entry理由SIGNAL、GATE、riskのreasonが一致しているか
スプレッドリアルでGATE_BLOCKが増えていないか
約定価格OrderSend時の想定価格と約定価格に差があるか
決済理由TP、SL、Trail、signal exitの発生理由が追えるか
インジケーター値CopyBuffer値、shift、bar timeが一致しているか
外部連携バックテストでは省略した処理がリアルで影響していないか

リアル確認では、損益だけでなく、Entry理由・見送り理由・決済理由がバックテストと比較できることが重要です。

バックテストで見落としやすい項目

バックテストでは確認しにくい項目があります。

項目理由補足確認
外部通信Strategy Testerでは実運用と同じ通信条件にならない場合がある外部連携は別責務で確認する
通知通知先やWebhookの状態を再現しにくいnotification層として個別確認する
VPS負荷ローカルBTとVPS稼働は環境が違う長時間放置確認を行う
リアルスプレッド時間帯や流動性で変動するspreadログを残す
サーバー時刻ブローカーやサーバー設定で異なるserver time基準をログに出す
手動操作BTでは手動介入を再現しにくい裁量補助EAは実地確認が必要

バックテストで確認できることと、リアルで確認すべきことを分けると、検証の抜け漏れを減らせます。

よくある失敗例

失敗1:検証条件を記録していない

期間、銘柄、時間足、スプレッド、tick model、設定値を記録していないと、後から同じ結果を再現できません。

失敗2:最適化結果をそのまま実運用候補にする

最適化は候補探しです。別期間、別条件、スプレッド悪化、リアル差分を確認せずに採用するのは危険です。

失敗3:損益グラフだけを見る

損益だけでは、EAがなぜEntryし、なぜ見送り、なぜ決済したか分かりません。ログでreasonを確認します。

失敗4:バックテストとリアルが完全一致すると考える

リアルではスプレッド、約定、tick、サーバー時刻、外部通信、VPS環境が異なります。完全一致ではなく、差分を記録して確認します。

失敗5:取引回数が少ない結果を過信する

取引回数が少ない場合、偶然の影響が大きくなります。別期間や条件変更で確認する必要があります。

失敗6:BTログが多すぎて読めない

毎tick詳細ログを出すと、検証速度が落ち、重要なエラーが埋もれます。summaryログ、失敗理由、block理由を中心にします。

失敗7:リアル差分を記録しない

リアルで違いが出た時、スプレッド差なのか、約定差なのか、signal差なのか、外部連携差なのかを追えなくなります。

導入前・開発依頼前に整理する情報

EAのバックテストや最適化を依頼する場合、次の情報を整理しておくと確認がスムーズになります。

  • EA名・バージョン
  • 検証する銘柄
  • 検証する時間足
  • 検証期間
  • tick model
  • スプレッド条件
  • 初期証拠金
  • 使用するsetファイル
  • 最適化する項目
  • 固定する項目
  • 最適化結果の評価基準
  • 別期間検証の有無
  • スプレッド悪化検証の有無
  • リアル確認で比較するログ項目
  • バックテスト時のログ粒度
  • 外部通信や通知をBTでどう扱うか

バックテストは、結果だけでなく、条件とログをセットで残すことが重要です。条件が残っていれば、後から再検証、比較、改修、不具合調査がしやすくなります。

関連する技術講座・確認ページ

ページ確認できること
技術講座ハブMQL5やMT5開発に関する講座一覧
MT5バックテストの基本ガイドストラテジーテスター、検証条件、バックテスト確認の基本
MQL5デバッグ・ログファースト開発完全ガイドログ確認、デバッグ、原因調査の基本
MQL5ロット・証拠金・銘柄仕様完全ガイドロット、証拠金、銘柄仕様の確認
MQL5長時間稼働・安定化完全ガイドバックテスト後の長時間稼働確認
MT5開発依頼前に用意する資料まとめ仕様書、setファイル、ログ、スクリーンショットの整理
不具合報告・調査依頼について不具合相談前に送る情報
免責事項・リスク説明投資判断、損益、利用上の注意に関する確認

FAQ

バックテスト結果が良ければリアルでも同じになりますか?

必ずしも同じにはなりません。リアルではスプレッド、約定、tick、サーバー時刻、外部通信、VPS環境などの差があります。バックテストは重要な確認手段ですが、リアル差分も記録して確認する必要があります。

最適化で一番良い結果の設定を使えばよいですか?

避けた方が安全です。最適化は候補探しです。上位結果だけでなく、別期間、スプレッド悪化、周辺設定、取引回数、DD、リアル差分を確認します。

バックテスト条件で最低限記録すべきものは何ですか?

EA名・バージョン、銘柄、時間足、検証期間、tick model、スプレッド、初期証拠金、setファイル、ログモードは最低限記録した方がよいです。

バックテストログはどのくらい出すべきですか?

目的によります。開発中は詳細ログが有効ですが、長期間BTではsummary化が必要です。SIGNAL、GATE、RISK、ORDER、EXITのreasonが追えることを優先します。

取引回数が少なくても利益が出ていればよいですか?

取引回数が少ない場合、偶然の影響が大きくなる可能性があります。別期間や条件変更で確認し、結果を過信しない方が安全です。

バックテストで外部通信や通知も検証できますか?

実運用と同じ条件で再現できない場合があります。外部通信、Webhook通知、認証、外部制御は、売買ロジックとは別責務として個別に確認する方が安全です。

バックテストとリアルでEntry位置が違う時は何を見ますか?

まず、signal理由、GATE理由、スプレッド、サーバー時刻、tick、インジケーター値、shift、OrderSend結果を確認します。損益だけでなく、Entry理由の差分を見ることが重要です。

実装コードがなくてもバックテスト設計の相談はできますか?

可能です。検証したい銘柄、時間足、期間、setファイル、評価基準、最適化対象、リアル確認項目が整理されていれば、検証設計の相談は進めやすくなります。

関連する開発実務ノート

バックテストや最適化の結果を正しく扱うには、ログ設計、長時間稼働、インジケーターEA化、商品化前チェックもあわせて整理しておく必要があります。

まとめ

MQL5 EAのバックテストでは、結果だけでなく、検証条件、最適化条件、ログ、リアル差分、再現性をセットで記録することが重要です。

特に、次の4点を分けると、検証結果の比較や不具合調査がしやすくなります。

  • Backtest Condition Snapshot:EA名、バージョン、銘柄、時間足、期間、tick model、スプレッド、set条件を記録する
  • Optimization Review:最適化結果を即採用せず、候補として扱う
  • Backtest Summary:signal、entry、gate block、order fail、exitの件数を要約する
  • Live Difference Note:スプレッド、約定、tick、外部通信、サーバー時刻などのリアル差分を記録する

バックテストはEA検証の重要な入口ですが、リアル稼働と完全一致するものではありません。最適化結果も、設定候補を探すための材料であり、別期間・別条件・リアル差分の確認が必要です。

完成EAの中核ロジックや実運用set値を公開しなくても、検証条件、ログ、最適化、リアル差分の記録方法を整理しておくことで、開発依頼、既存EA改修、検証、不具合調査、販売前チェックの品質を上げやすくなります。

ABOUT ME
記事URLをコピーしました