MT5 Strategy Testerの使い方と検証設計

目次

この記事の結論

MT5 Strategy Testerは、MQL5で作成したEAの売買ロジックを過去データ上で検証するための機能です。
バックテストでは、総損益だけでなく、最大ドローダウン、取引回数、損益比、連敗数、スプレッド条件を確認する必要があります。
ストラテジーテスターの結果は、将来の利益を保証するものではありません。
実運用前には、フォワードテストで約定差、スプレッド拡大、ブローカー条件の違いを確認する必要があります。
MQL5のEAでは、OnInit、OnTick、OnDeinitを分け、シグナル判定、リスク確認、注文前チェックを構造化すると検証しやすくなります。

1. MT5 Strategy Testerの役割

【結論】
MT5 Strategy Testerの役割は、EAの売買条件が過去データ上でどのように動いたかを確認することです。
検証対象は利益だけではなく、リスク、取引頻度、ドローダウン、パラメータ依存性です。

MT5 Strategy Testerは、MetaTrader 5上でEAを過去データに適用し、売買結果を確認するための検証環境です。
MQL5で作成したExpert Advisorは、ティック更新時にOnTickで処理されます。
そのため、バックテストでは、価格更新、スプレッド、約定条件、時間足、銘柄仕様が結果に影響します。

【定義】
バックテストとは、過去の価格データを使ってEAの売買ロジックを検証する作業です。
バックテスト結果は、ロジックの傾向を確認するための材料であり、将来の成績を保証するものではありません。

1.1 Strategy Testerで確認できること

Strategy Testerでは、次のような項目を確認できます。

  • EAが想定どおりにエントリーしているか
  • 決済条件が正しく動いているか
  • 最大ドローダウンが許容範囲に収まっているか
  • 取引回数が少なすぎないか
  • パラメータ変更に対して結果が極端に変わらないか
  • スプレッド条件の影響を受けすぎていないか

MT5 Strategy Testerは、EAの完成度を測る最終判定ではありません。
EAの弱点を見つけ、フォワードテストへ進めるかを判断するための検証工程です。

MT5 Strategy Tester interface showing EA backtest validation with equity curve, drawdown, trade count, and checklist for risk management before live trading

2. 基本的な考え方

【結論】
Strategy Testerを使うときは、売買ロジック、フィルター、リスク管理、注文処理を分けて検証します。
すべてを一度に最適化すると、過剰最適化が起きやすくなります。

EAの検証では、次の流れで分解すると問題点を見つけやすくなります。

相場認識
↓
フィルター判定
↓
シグナル判定
↓
リスク確認
↓
注文前チェック
↓
注文送信
↓
約定後管理
↓
決済・停止判定

MQL5のEAでは、OnInitで初期化処理を行い、OnTickで売買判断を行い、OnDeinitで後処理を行います。
インジケータ値を使う場合は、OnInitでハンドルを作成し、OnTickでCopyBufferを使って値を取得します。
この構造にすると、テスト中にどの処理で問題が起きているかを切り分けやすくなります。

2.1 総損益だけで判断しない

総損益が良く見えても、最大ドローダウンが大きいEAは実運用で継続しにくくなります。
取引回数が少ないEAは、数回の偶然で結果が良く見える場合があります。
勝率が高くても、損失1回が大きいロジックでは資金曲線が崩れやすくなります。

MT5 Strategy Testerでは、総損益、最大ドローダウン、勝率、損益比、取引回数をまとめて見る必要があります。
単独の指標だけでEAの優劣を判断すると、実運用でのリスクを見落としやすくなります。

3. 代表的な検証パターン

【結論】
MT5 Strategy Testerでは、単一条件テスト、期間分割テスト、パラメータ変更テスト、スプレッド耐性テストを組み合わせます。
複数の条件で崩れにくいEAほど、再現性を確認しやすくなります。

Strategy Testerの検証は、1回のバックテストで終わらせないことが重要です。
同じEAでも、期間、銘柄、時間足、スプレッド、パラメータが変わると結果は変わります。

3.1 単一条件テスト

単一条件テストは、1つの銘柄、1つの時間足、1つのパラメータでEAの基本動作を確認する方法です。
最初に行うべき検証は、利益の確認ではなく、EAが意図した条件でエントリーと決済をしているかの確認です。

3.2 期間分割テスト

期間分割テストでは、過去データを複数期間に分けて検証します。
特定期間だけで良い結果になっているEAは、相場環境に強く依存している可能性があります。

3.3 パラメータ変更テスト

パラメータ変更テストでは、移動平均期間、損切り幅、利確幅、ATR倍率などを少しずつ変えて確認します。
わずかな変更で結果が大きく崩れる場合、そのロジックはパラメータ依存が強い可能性があります。

3.4 スプレッド耐性テスト

スプレッド耐性テストでは、スプレッドが広がったときに成績がどの程度悪化するかを確認します。
短期売買EAほどスプレッドの影響を受けやすく、バックテストと実運用の差が大きくなる場合があります。

4. 実装方法

【結論】
MQL5のEAは、Strategy Testerで検証しやすいように、初期化、判定、注文前確認、ログ出力を分けて実装します。
インジケータを使う場合は、ハンドル作成とCopyBufferの失敗処理を必ず入れます。

バックテストで問題を見つけやすいEAは、処理の役割が分かれています。
売買条件がOnTick内に長く書かれているだけのEAは、検証時に原因を切り分けにくくなります。

4.1 OnInit、OnTick、OnDeinitの役割

関数役割Strategy Testerでの確認点
OnInit初期化処理を行うハンドル作成や入力値チェックが成功しているか
OnTickティック更新ごとに売買判断を行う条件判定と注文処理が意図どおりか
OnDeinit終了時の後処理を行うインジケータハンドルを解放しているか

MQL5では、インジケータ関数が値を直接返すのではなく、ハンドルを作成してからCopyBufferで値を取得する構造が多く使われます。
この構造を理解していないと、テスター上で値が取得できない原因を見落としやすくなります。

4.2 注文前チェックを分ける

注文処理を扱うEAでは、OrderSendの前に取引条件を確認します。
確認すべき項目は、ロット、証拠金、スプレッド、ストップレベル、フリーズレベル、取引可能時間、既存ポジションです。
MQL5では、MqlTradeRequest、MqlTradeResult、MqlTradeCheckResultを使い、必要に応じてOrderCheckで注文前確認を行います。

5. サンプルコード

【結論】
Strategy Tester用のEAサンプルでは、移動平均のハンドル作成、CopyBufferの取得確認、シグナル判定、注文前チェックを分けます。
以下のコードは検証用の最小構成であり、実運用前には銘柄仕様と口座条件に合わせた調整が必要です。

#property strict

input int    FastMAPeriod = 20;
input int    SlowMAPeriod = 50;
input double FixedLot     = 0.10;
input int    StopLossPts  = 300;
input int    TakeProfitPts = 600;

const int SHIFT_CURRENT = 0;
const int SHIFT_CLOSED = 1;
const int SHIFT_PREVIOUS = 2;

int fastMaHandle = INVALID_HANDLE;
int slowMaHandle = INVALID_HANDLE;

int OnInit()
{
   if(FastMAPeriod <= 0 || SlowMAPeriod <= 0 || FastMAPeriod >= SlowMAPeriod)
   {
      Print("Invalid MA period settings");
      return INIT_FAILED;
   }

   fastMaHandle = iMA(_Symbol, _Period, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
   slowMaHandle = iMA(_Symbol, _Period, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE);

   if(fastMaHandle == INVALID_HANDLE || slowMaHandle == INVALID_HANDLE)
   {
      Print("Failed to create indicator handles");
      return INIT_FAILED;
   }

   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
   if(fastMaHandle != INVALID_HANDLE)
      IndicatorRelease(fastMaHandle);

   if(slowMaHandle != INVALID_HANDLE)
      IndicatorRelease(slowMaHandle);
}

void OnTick()
{
   if(PositionSelect(_Symbol))
      return;

   double fastMa[];
   double slowMa[];
   ArraySetAsSeries(fastMa, true);
   ArraySetAsSeries(slowMa, true);

   int copiedFast = CopyBuffer(fastMaHandle, 0, 0, 3, fastMa);
   int copiedSlow = CopyBuffer(slowMaHandle, 0, 0, 3, slowMa);

   if(copiedFast < 3 || copiedSlow < 3)
   {
      Print("CopyBuffer failed or not enough data");
      return;
   }

   bool buySignal =
      fastMa[SHIFT_CLOSED] > slowMa[SHIFT_CLOSED] &&
      fastMa[SHIFT_PREVIOUS] <= slowMa[SHIFT_PREVIOUS];

   if(!buySignal)
      return;

   SendBuyOrder();
}

void SendBuyOrder()
{
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   double lot = MathMax(minLot, MathMin(FixedLot, maxLot));
   lot = MathFloor(lot / lotStep) * lotStep;

   MqlTradeRequest request;
   MqlTradeResult result;
   MqlTradeCheckResult check;
   ZeroMemory(request);
   ZeroMemory(result);
   ZeroMemory(check);

   request.action = TRADE_ACTION_DEAL;
   request.symbol = _Symbol;
   request.volume = lot;
   request.type = ORDER_TYPE_BUY;
   request.price = ask;
   request.sl = ask - StopLossPts * point;
   request.tp = ask + TakeProfitPts * point;
   request.deviation = 20;
   request.type_filling = ORDER_FILLING_FOK;

   if(!OrderCheck(request, check))
   {
      Print("OrderCheck failed. retcode=", check.retcode);
      return;
   }

   if(!OrderSend(request, result))
   {
      Print("OrderSend failed. retcode=", result.retcode);
      return;
   }

   Print("Buy order sent. ticket=", result.order);
}

このコードでは、最新足ではなく確定足に近い位置の値を使うために、SHIFT_CLOSED の値を判定に使っています。
最新足の値はティックごとに変化するため、バックテストと実運用でシグナルの見え方が変わる場合があります。

6. パターン別比較

【結論】
Strategy Testerの検証方法は、目的ごとに使い分けます。
最初は単一条件で動作確認を行い、その後に期間分割、パラメータ変更、スプレッド耐性を確認します。

方法メリットデメリット向いている場面
単一条件テストEAの基本動作を確認しやすい再現性の判断には弱い初期デバッグ
期間分割テスト相場環境ごとの強弱を見やすい検証回数が増えるロジックの安定性確認
パラメータ変更テスト過剰最適化を見つけやすい組み合わせが多くなりやすい入力値の耐性確認
スプレッド耐性テスト実運用との差を意識しやすい約定遅延までは再現しきれない短期売買EAの確認
複数銘柄テスト銘柄依存を見つけやすい銘柄仕様の差を考慮する必要がある汎用ロジックの検証

比較表で重要なのは、どの方法が優れているかではありません。
EAの目的に対して、どの弱点を確認したいかを明確にすることです。

7. 誤作動しやすい場面

【結論】
Strategy Testerでよく起きる誤作動は、インジケータ値の取得失敗、未確定足の使用、ロット条件の不一致、口座タイプ差です。
エラーが出ない場合でも、売買ロジックが意図と違う動きをしていることがあります。

7.1 CopyBufferの取得不足

CopyBufferは、指定した本数を取得できない場合があります。
取得件数が期待値未満のまま判定すると、古い値や不完全な値でシグナルを判断する可能性があります。

CopyBufferを使うEAでは、取得件数を必ず確認します。
必要に応じてBarsCalculatedでインジケータの計算状態も確認します。

7.2 最新足だけで判定する

最新足は形成中の足です。
価格が動くたびにインジケータ値も変わるため、バックテスト中の見え方と確定後の結果が変わる場合があります。

売買シグナルを安定させたい場合は、確定足を使う設計が検証しやすくなります。
ただし、確定足を使うとエントリーは遅くなります。

7.3 ロット条件を無視する

銘柄には、最小ロット、最大ロット、ロットステップが設定されています。
固定ロットをそのまま送信すると、銘柄仕様に合わず注文が失敗する場合があります。

EAでは、SymbolInfoDoubleで銘柄の取引条件を取得し、ロットを許容範囲に丸める必要があります。
証拠金不足やストップレベル違反も注文失敗の原因になります。

7.4 netting口座とhedging口座の違い

MQL5では、口座タイプによってポジション管理の挙動が異なる場合があります。
netting口座では同一銘柄のポジションが集約され、hedging口座では複数ポジションを持てる場合があります。

Strategy Testerでポジション管理を確認するときは、口座タイプの前提を明確にする必要があります。

8. バックテストで確認すべき項目

【結論】
バックテストでは、利益額よりも、損失の出方、取引回数、パラメータ依存性、スプレッド条件を重視します。
EAの弱点は、総損益だけでは見えません。

バックテストで確認すべき主な項目は次のとおりです。

  • 総損益
  • 最大ドローダウン
  • 勝率
  • 損益比
  • 取引回数
  • 連敗数
  • スプレッド条件
  • 期間依存性
  • パラメータ依存性

最大ドローダウンは、資金がどの程度減少したかを見る重要な指標です。
連敗数は、実運用時に心理的・資金的に耐えられるかを判断する材料になります。
取引回数が少ない場合は、統計的な判断が難しくなります。

8.1 パラメータ依存性の見方

パラメータ依存性が強いEAは、特定の設定だけで良い結果になりやすいです。
近い設定に変更しただけで成績が大きく崩れる場合、過剰最適化の可能性があります。

検証では、最も良い設定だけを探すのではなく、近い設定でも結果が極端に崩れないかを確認します。

9. フォワードテストで確認すべき項目

【結論】
フォワードテストでは、バックテストでは見えにくい約定差、スプレッド拡大、ブローカー差、VPS環境での安定性を確認します。
実運用に近い条件で動かすことで、EAの現実的な挙動を確認できます。

フォワードテストで確認すべき項目は次のとおりです。

  • 約定差
  • スプレッド拡大時の挙動
  • 取引頻度
  • ドローダウン
  • バックテストとの乖離
  • ブローカー差
  • VPS環境での安定性

バックテストとフォワードテストは一致しない場合があります。
主な理由は、スプレッド、約定方式、スリッページ、取引時間、サーバー環境が異なるためです。

9.1 バックテストとの乖離を記録する

フォワードテストでは、エントリー時刻、価格、スプレッド、決済理由を記録します。
バックテストと異なる結果が出た場合、どの条件で差が生じたかを確認しやすくなります。

ログ出力は、EAの検証精度を上げるために重要です。
エラー時だけでなく、シグナル発生時、注文前チェック時、決済時にも必要な情報を残します。

10. 実運用での注意点

【結論】
MT5 Strategy Testerで良い結果が出ても、実運用ではスプレッド、約定遅延、スリッページ、ブローカー仕様の差で成績が変わります。
実運用前には、リスク許容度、停止条件、ロット管理を決めておく必要があります。

EAを実運用する場合は、次のリスクを考慮します。

  • バックテストと実運用は一致しない
  • スプレッド拡大で成績が悪化する場合がある
  • 約定遅延やスリッページが発生する場合がある
  • 過剰最適化はフォワードで崩れやすい
  • パラメータ依存が強いロジックは再現性が低くなりやすい
  • ドローダウン許容度を事前に決める必要がある
  • ブローカー仕様によりEAの挙動が変わることがある
  • デモ口座とリアル口座で約定条件が異なる場合がある

レバレッジが高いほど、同じ値動きでも資金への影響が大きくなりやすいです。
ロットを大きくすると利益だけでなく損失も拡大します。
実運用では、バックテスト結果だけでロットを決めず、許容損失と最大ドローダウンを基準に考える必要があります。

11. 改善案と代替手段

【結論】
Strategy Testerの検証精度を高めるには、ログ出力、条件分離、リスク率ベースのロット計算、フォワードテストを組み合わせます。
EAの改善は、利益を増やす作業だけでなく、壊れやすい条件を減らす作業です。

改善案として、次の方法があります。

  • シグナル判定とフィルター判定を分ける
  • 固定ロットだけでなくリスク率ベースのロットを検討する
  • スプレッド上限を条件に入れる
  • 取引時間フィルターを入れる
  • 最大連敗数や日次損失で停止する
  • エントリー理由と決済理由をログに残す
  • 複数期間でバックテストする
  • フォワードテストでバックテストとの差を記録する

ロット計算を改善する場合は、最小ロット、最大ロット、ロットステップ、証拠金、許容リスク、損切り幅、口座残高、有効証拠金、ティックバリュー、ティックサイズを考慮します。
単純な固定ロットは実装しやすい一方で、資金変動に対応しにくいです。

12. まとめ

【結論】
MT5 Strategy Testerは、MQL5 EAの動作確認とリスク確認に欠かせない検証環境です。
ただし、バックテストは将来の利益を保証するものではなく、フォワードテストと実運用リスクの確認が必要です。

MT5 Strategy Testerを使うときは、総損益だけを見ず、最大ドローダウン、取引回数、損益比、連敗数、スプレッド条件を確認します。
MQL5のEAでは、OnInit、OnTick、OnDeinitの役割を分け、インジケータハンドルとCopyBufferの取得処理を正しく扱う必要があります。
注文処理では、OrderSendの前にOrderCheckや銘柄仕様の確認を入れると、テスト中の失敗原因を見つけやすくなります。

実運用では、スプレッド、約定、ブローカー仕様、口座タイプ、VPS環境によって結果が変わる場合があります。
EAの検証では、バックテストで弱点を見つけ、フォワードテストで再現性を確認し、リスク許容度に合わせて運用条件を決めることが重要です。

FAQ

MT5 Strategy Testerとは何ですか?

MT5 Strategy Testerは、MQL5で作成したEAを過去データ上で検証するための機能です。売買ロジック、リスク、取引回数、ドローダウンを確認するために使います。

Strategy Testerの結果だけでEAを実運用できますか?

Strategy Testerの結果だけで実運用を判断するのは危険です。バックテスト結果は将来の利益を保証せず、実運用前にフォワードテストで約定差やスプレッド条件を確認する必要があります。

MQL5のEAでCopyBufferが必要になるのはなぜですか?

MQL5では、多くのインジケータ関数が値ではなくハンドルを返します。EAでインジケータ値を使う場合は、ハンドル作成後にCopyBufferでバッファ値を取得します。

バックテストで最も重視すべき指標は何ですか?

総損益だけでなく、最大ドローダウン、取引回数、損益比、連敗数、パラメータ依存性を重視します。単独の指標だけではEAのリスクを判断しにくいです。

過剰最適化を避けるにはどうすればよいですか?

過剰最適化を避けるには、近いパラメータでも結果が極端に崩れないかを確認します。期間分割テストやフォワードテストを使うと、特定期間だけに合った設定を見つけやすくなります。

Strategy Testerで注文が通らない原因は何ですか?

注文が通らない原因には、ロット条件、証拠金不足、ストップレベル違反、取引時間外、約定方式の不一致があります。MQL5ではOrderSendの前にOrderCheckを使うと、注文前の問題を確認しやすくなります。

netting口座とhedging口座でテスト結果は変わりますか?

口座タイプによりポジション管理の挙動が変わる場合があります。netting口座では同一銘柄のポジションが集約され、hedging口座では複数ポジションを持てる場合があります。

フォワードテストでは何を確認すべきですか?

フォワードテストでは、約定差、スプレッド拡大、取引頻度、ドローダウン、バックテストとの乖離、ブローカー差、VPS環境での安定性を確認します。