MQL5バックテスト実務ノート|検証条件・最適化・リアル差分を記録する考え方
MQL5でEAを検証する時、バックテストは重要な確認手段です。
しかし、バックテスト結果だけを見てEAの良し悪しを判断すると、誤解が起きやすくなります。検証期間、銘柄、時間足、スプレッド、tick model、初期証拠金、手数料、最適化条件、ログ粒度が変わるだけで、結果は大きく変わることがあります。
また、バックテストで良く見える設定が、リアル稼働でも同じように動くとは限りません。約定、スプレッド、スリッページ、外部通信、サーバー時刻、ティック配信、VPS環境、リアルタイムのインジケーター更新など、バックテストでは再現しきれない差分があります。
バックテスト実務で重要なのは、検証条件、最適化条件、ログ、リアル差分、再現性を記録することです。
この記事では、MQL5 EAのバックテストで確認すべき設計判断を、開発実務ノートとして整理します。完成EAソース全文、外部シート制御ロジック、認証ロジック、endpoint、token、URL実値、実運用set値、中核Entry条件は公開しません。
本記事は、投資判断や売買指示ではなく、EA検証の再現性と不具合調査を高めるための技術記事です。利益保証、勝率保証、推奨ロット、推奨銘柄、推奨設定を目的とした内容ではありません。
- この記事で扱う実務課題
- なぜバックテスト条件を記録する必要があるのか
- Backtest Condition Snapshotを残す
- 最適化は検証ではなく候補探し
- 過剰最適化に注意する
- リアル差分を最初から想定する
- バックテストログで見るべきポイント
- 実コード例1:Backtest Condition Snapshotを作る
- 実コード例2:検証summaryを残す
- 実コード例3:リアル差分メモをログ化する
- 実コード例4:最適化候補をそのまま採用しない
- バックテストとリアルの比較で確認すること
- バックテストで見落としやすい項目
- よくある失敗例
- 導入前・開発依頼前に整理する情報
- 関連する技術講座・確認ページ
- FAQ
- 関連する開発実務ノート
- まとめ
この記事で扱う実務課題
| 項目 | この記事で扱う内容 | 扱わない内容 |
|---|---|---|
| 目的 | バックテスト条件・最適化・リアル差分を記録する考え方 | 利益を狙う売買ロジック、具体的な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 |
| SIGNAL | Entry候補が出ているか | SIGNAL_OK、NO_SIGNAL |
| GATE | 発注前条件で止まっているか | SPREAD_BLOCK、TIME_BLOCK |
| RISK | risk条件で止まっているか | 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・インジの作り方
- MQL5長時間稼働EA実務ノート|フリーズ・重い・オブジェクト残存を防ぐ考え方
- MQL5インジケーターEA化実務ノート|サイン取得・確定足・リペイント確認の考え方
- MQL5商品化・配布前チェック実務ノート|Inputs・HELP・Snapshot・manual・UserLive化の基本
まとめ
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改修、検証、不具合調査、販売前チェックの品質を上げやすくなります。

