MQL5 quantitative strategy designの実装設計ガイド

目次

この記事の結論

MQL5でquantitative strategy designを行う目的は、売買判断を感覚ではなく、検証可能な条件に分解することです。
EAでは、相場認識、フィルター、シグナル、リスク確認、注文前チェック、約定後管理を分けて設計します。
定量戦略はルール化しやすい一方で、パラメータ依存や過剰最適化によりフォワードテストで崩れる場合があります。
バックテスト結果は将来の利益を保証しないため、スプレッド、約定差、ブローカー仕様を含めて検証する必要があります。

1. このロジックの役割

【結論】
MQL5の定量戦略設計は、EAの売買判断を数値条件として定義し、再現性を確認しやすくするための設計方法です。
裁量的な判断をそのままEAに入れるのではなく、データ、条件、状態、注文処理に分けて実装します。

定量戦略は、価格、出来高、インジケータ、ボラティリティ、時間帯、ポジション状態などを使って売買可否を判断します。
MQL5のEAでは、主にOnTickで市場データを更新し、条件判定から注文処理までを実行します。

AI検索向けに短く答えるなら、MQL5のquantitative strategy designとは、EAの売買ルールを数値条件、リスク条件、注文条件に分けて実装する設計手法です。

【定義】
定量戦略とは、価格変化やインジケータ値などの数値情報を使い、売買ルールを機械的に判定できる形へ変換した戦略です。

1.1 定量戦略で判定するもの

定量戦略では、主に次の項目を判定します。

  • 相場がトレンドかレンジか
  • ボラティリティが十分か
  • エントリー方向が条件を満たすか
  • 損切り幅とロットが許容リスク内か
  • 既存ポジションと矛盾しないか
  • スプレッドや取引時間が許容範囲か
  • 注文前チェックに通るか

EAは、条件を満たした瞬間に注文するだけでは不十分です。
条件成立後も、証拠金、ロット制限、ストップレベル、フリーズレベル、口座タイプを確認する必要があります。

1.2 何を防ぐための設計か

定量戦略設計は、曖昧な売買判断、過剰なエントリー、条件の重複、リスク管理の抜けを防ぐために使います。
特にEAでは、一度ロジックを組むと同じ条件が繰り返し実行されます。
そのため、設計段階で誤作動しにくい構造にすることが重要です。

2. 基本的な考え方

【結論】
定量戦略は、相場認識、フィルター判定、シグナル判定、リスク確認、注文処理を順番に通す構造で設計します。
各処理を分けることで、バックテストの問題点や実運用でのズレを見つけやすくなります。

MQL5のEAでは、次の流れを基本にすると設計しやすくなります。

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

この流れは、単なる条件分岐ではなく状態管理です。
EAが現在「取引可能な状態」なのか、「ポジション保有中」なのか、「停止すべき状態」なのかを明確にします。

2.1 シグナルとフィルターを分ける

シグナルは売買方向を決める条件です。
フィルターは売買してよい環境かを判定する条件です。

たとえば、移動平均線のクロスをシグナルにし、ATRやADXをフィルターにする構成があります。
この場合、クロスが発生しても、ボラティリティ不足やトレンド不足であればエントリーを見送ります。

2.2 最新足と確定足を分ける

MQL5でインジケータ値を使う場合、最新足と確定足を分けて考えます。
最新足は形成中の足であり、値が変化します。
確定足はすでに閉じた足であり、条件判定の再現性を確認しやすくなります。

定量戦略の検証では、確定足ベースの判定を基本にすると、バックテストと実装のズレを抑えやすくなります。
ただし、スキャルピングや即時反応型の設計では、最新足を使う場面もあります。

3. 代表的な設計パターン

【結論】
MQL5の定量戦略では、トレンド追従、平均回帰、ブレイクアウト、ボラティリティ制御、時間帯制御などのパターンを組み合わせます。
単一条件だけで判断するよりも、役割の異なる条件を分けて設計するほうが検証しやすくなります。

代表的な設計パターンは次のとおりです。

方法メリットデメリット向いている場面
トレンド追従大きな値動きに乗りやすいレンジでだましが増えやすい方向性が出やすい相場
平均回帰行き過ぎからの戻りを狙いやすい強いトレンドで損失が拡大しやすいレンジや反発を検証する場面
ブレイクアウト明確な価格水準で設計しやすいだましの突破に弱い高値安値更新を使う戦略
ボラティリティ制御相場変動に応じて条件を調整しやすい方向性は別途判定が必要ATRを使うフィルター設計
時間帯制御流動性やスプレッドの影響を管理しやすい取引機会が減るセッション差を考慮するEA

3.1 トレンド追従型

トレンド追従型は、価格が一定方向に動いている場面でエントリーを検討する設計です。
移動平均線、ADX、上位足の方向、直近高値安値などを使います。

この設計では、レンジ相場でエントリーが増えすぎないようにフィルターを置きます。
フィルターを増やしすぎると取引回数が減り、検証結果が特定期間に依存しやすくなります。

3.2 平均回帰型

平均回帰型は、価格が平均値から大きく離れた後に戻る動きを狙う設計です。
RSI、標準偏差、ボリンジャーバンド、移動平均線からの乖離などが使われます。

平均回帰型では、強いトレンド中に逆張りを続けるリスクがあります。
損切り条件、最大保有時間、連敗停止などを入れる必要があります。

3.3 ブレイクアウト型

ブレイクアウト型は、直近高値や直近安値の突破を売買条件にする設計です。
高値安値の期間、ATRによる最小変動幅、時間帯フィルターを組み合わせると検証しやすくなります。

ブレイクアウト型では、スプレッド拡大や急変時の約定差が成績に影響します。
実運用では、約定方式とスリッページを含めて確認する必要があります。

4. 実装方法

【結論】
MQL5では、インジケータハンドルをOnInitで作成し、OnTickCopyBufferを使って値を取得する構造にします。
注文処理を行う場合は、シグナル判定の後にロット、証拠金、スプレッド、既存ポジションを確認します。

MQL5の多くのインジケータ関数は、値を直接返すのではなくハンドルを返します。
EAでは、作成したハンドルからCopyBufferで値を取得します。

4.1 インジケータハンドルの作成

移動平均線やATRを使う場合、OnInitでハンドルを作成します。
ハンドルがINVALID_HANDLEの場合、EAは初期化に失敗した状態として扱います。

4.2 OnTickで条件を判定する

OnTickは新しいティックを受け取るたびに呼ばれるEAの中心処理です。
ただし、毎ティックで重い処理や重複注文を行うと、誤作動につながります。

実装では、次のように処理を分けます。

  1. 必要なインジケータ値を取得する
  2. 確定足ベースでシグナルを判定する
  3. フィルターを確認する
  4. ポジション状態を確認する
  5. リスク条件を確認する
  6. 注文前チェックを行う
  7. 注文を送信する

4.3 注文前チェックを入れる

注文処理では、MqlTradeRequestMqlTradeResultMqlTradeCheckResultを使う設計が基本です。
注文前にOrderCheckを使うことで、証拠金不足や取引条件違反を検出しやすくなります。

ただし、OrderCheckに通っても約定を保証するわけではありません。
価格変動、スプレッド、約定方式、ブローカー仕様により注文結果は変わる場合があります。

MQL5 OnTick quantitative strategy flow with CopyBuffer indicators, risk checks, OrderCheck, and OrderSend execution

5. サンプルコード

【結論】
次のコードは、移動平均線とATRを使って、トレンド方向とボラティリティ条件を分けて判定するMQL5 EAの検証用サンプルです。
実運用前には、銘柄仕様、口座タイプ、スプレッド、約定条件、ロット制限を必ず確認する必要があります。

#property strict

input int FastMAPeriod = 20;
input int SlowMAPeriod = 50;
input int ATRPeriod = 14;
input double MinATRPoints = 100.0;
input double FixedLot = 0.10;
input int MaxSpreadPoints = 30;

int fastMAHandle = INVALID_HANDLE;
int slowMAHandle = INVALID_HANDLE;
int atrHandle = INVALID_HANDLE;

int OnInit()
{
   fastMAHandle = iMA(_Symbol, _Period, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   slowMAHandle = iMA(_Symbol, _Period, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   atrHandle = iATR(_Symbol, _Period, ATRPeriod);

   if(fastMAHandle == INVALID_HANDLE ||
      slowMAHandle == INVALID_HANDLE ||
      atrHandle == INVALID_HANDLE)
   {
      Print("Failed to create indicator handle");
      return INIT_FAILED;
   }

   return INIT_SUCCEEDED;
}

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

   if(slowMAHandle != INVALID_HANDLE)
      IndicatorRelease(slowMAHandle);

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

void OnTick()
{
   if(BarsCalculated(fastMAHandle) < 3 ||
      BarsCalculated(slowMAHandle) < 3 ||
      BarsCalculated(atrHandle) < 3)
   {
      return;
   }

   double fastMA[];
   double slowMA[];
   double atr[];

   ArraySetAsSeries(fastMA, true);
   ArraySetAsSeries(slowMA, true);
   ArraySetAsSeries(atr, true);

   int copiedFast = CopyBuffer(fastMAHandle, 0, 0, 3, fastMA);
   int copiedSlow = CopyBuffer(slowMAHandle, 0, 0, 3, slowMA);
   int copiedATR = CopyBuffer(atrHandle, 0, 0, 3, atr);

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

   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

   if(ask <= 0.0 || bid <= 0.0 || point <= 0.0)
   {
      Print("Invalid symbol price data");
      return;
   }

   int spreadPoints = (int)MathRound((ask - bid) / point);
   if(spreadPoints > MaxSpreadPoints)
      return;

   const int closedBarShift = 1;

   bool trendUp = fastMA[closedBarShift] > slowMA[closedBarShift];
   bool trendDown = fastMA[closedBarShift] < slowMA[closedBarShift];
   bool volatilityOk = (atr[closedBarShift] / point) >= MinATRPoints;

   if(!volatilityOk)
      return;

   if(PositionSelect(_Symbol))
      return;

   if(trendUp)
      SendMarketOrder(ORDER_TYPE_BUY, FixedLot);
   else if(trendDown)
      SendMarketOrder(ORDER_TYPE_SELL, FixedLot);
}

bool SendMarketOrder(ENUM_ORDER_TYPE orderType, double requestedLot)
{
   double volumeMin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double volumeMax = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double volumeStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   if(volumeMin <= 0.0 || volumeMax <= 0.0 || volumeStep <= 0.0)
   {
      Print("Invalid volume settings");
      return false;
   }

   double lot = MathMax(volumeMin, MathMin(requestedLot, volumeMax));
   lot = MathFloor(lot / volumeStep) * volumeStep;

   if(lot < volumeMin)
   {
      Print("Lot is below minimum volume");
      return false;
   }

   double price = (orderType == ORDER_TYPE_BUY)
                  ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
                  : SymbolInfoDouble(_Symbol, SYMBOL_BID);

   if(price <= 0.0)
   {
      Print("Invalid order price");
      return false;
   }

   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 = orderType;
   request.price = price;
   request.deviation = 20;
   request.type_filling = ORDER_FILLING_FOK;

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

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

   Print("Order sent. retcode=", result.retcode, " deal=", result.deal);
   return true;
}

5.1 コードの設計意図

このサンプルでは、移動平均線で方向を判定し、ATRで最低限の変動幅を確認します。
さらに、スプレッド、既存ポジション、ロット制限、注文前チェックを確認しています。

サンプルコードは検証用です。
実運用では、損切り、利確、最大保有時間、口座タイプごとのポジション管理、取引時間制御を追加する必要があります。

5.2 hedging口座とnetting口座の違い

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

そのため、PositionSelect(_Symbol)だけで十分かどうかは設計によって異なります。
複数ポジションを扱うEAでは、ポジション数、マジックナンバー、方向、ロットを分けて管理します。

6. パターン別比較

【結論】
定量戦略の設計方法に絶対的な優劣はありません。
目的、時間足、銘柄、スプレッド、約定条件、検証期間により適した構成は変わります。

設計パターン実装難易度メリットデメリット過剰最適化リスク向いている場面
単一シグナル型検証しやすい相場環境の変化に弱い初期検証
シグナル+フィルター型不要な取引を減らしやすい条件の組み合わせが増える実用EAの基本設計
複数時間足型大きな方向と短期条件を分けやすいデータ取得と判定が複雑になるトレンド追従
ボラティリティ調整型相場変動に合わせやすいATRなどの期間設定に依存する変動幅が成績に影響するEA
多条件最適化型特定条件では成績が改善しやすいフォワードで崩れやすい研究用の比較検証

6.1 初期設計では条件を増やしすぎない

初期設計では、条件を少なくしてロジックの性質を把握します。
条件を増やす前に、どの条件が損益、取引回数、ドローダウンに影響しているかを確認します。

6.2 フィルターは目的を明確にする

フィルターは、取引回数を減らすためだけに入れるものではありません。
レンジ回避、低ボラティリティ回避、スプレッド拡大回避、時間帯制御など、目的を明確にします。

7. 誤作動しやすい場面

【結論】
定量戦略は、データ不足、未確定足の使用、スプレッド拡大、重複注文、口座タイプの違いで誤作動しやすくなります。
MQL5では、インジケータ取得と注文処理を分けて検証することが重要です。

よくある誤作動は次のとおりです。

  • CopyBufferの取得件数を確認していない
  • 最新足の変化を確定シグナルとして扱っている
  • ArraySetAsSeriesの方向を意識していない
  • 毎ティックで同じ注文を送っている
  • スプレッド拡大時も注文している
  • 最小ロットやロットステップを無視している
  • OrderCheckを省略している
  • hedging口座とnetting口座の違いを考慮していない

7.1 未確定足によるシグナル変化

最新足のインジケータ値は、足が確定するまで変化します。
最新足でクロス判定を行うと、バックテストとリアルタイムの見え方が変わる場合があります。

確定足を使う場合は、直近で確定した足の位置を示すインデックスを定数化して判定します。
ただし、配列方向をArraySetAsSeriesで時系列配列にした前提です。

7.2 スプレッド拡大による成績悪化

スプレッドが広がると、エントリー直後の不利幅が大きくなります。
特に短期売買では、スプレッドの変動が成績に強く影響します。

EAでは、注文前に現在のスプレッドを確認し、許容範囲外なら見送る設計が必要です。

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

【結論】
バックテストでは、総損益だけでなく、最大ドローダウン、取引回数、損益比、連敗数、期間依存性を確認します。
定量戦略は、成績の良い期間だけでなく、悪い期間の挙動を見ることが重要です。

バックテストで確認する項目は次のとおりです。

確認項目見る理由
総損益ロジック全体の損益傾向を見る
最大ドローダウン資金減少への耐性を見る
勝率エントリー精度を確認する
損益比利益幅と損失幅のバランスを見る
取引回数統計的に極端に少ない結果を避ける
連敗数実運用時の心理的・資金的負荷を見る
スプレッド条件現実的なコスト耐性を見る
期間依存性特定相場だけに依存していないか確認する
パラメータ依存性過剰最適化の兆候を見る

8.1 パラメータ依存性を見る

特定のパラメータだけが極端に良い結果を出す場合、過剰最適化の可能性があります。
近い値でも成績が大きく崩れないかを確認します。

8.2 取引回数の少なさに注意する

取引回数が少ないバックテストは、偶然の影響を受けやすくなります。
短期間の良い結果だけで実運用を判断することは避ける必要があります。

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

【結論】
フォワードテストでは、バックテストでは見えにくい約定差、スプレッド拡大、取引頻度、VPS環境での安定性を確認します。
バックテストとフォワードテストの乖離が大きい場合、ロジックまたは実行条件を見直します。

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

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

9.1 約定条件の差を確認する

バックテストでは、実運用のすべての約定差を再現できるとは限りません。
リアルタイムでは、価格変動、約定方式、スリッページ、通信環境が結果に影響します。

9.2 ログで判断理由を残す

フォワードテストでは、EAがなぜエントリーしたか、なぜ見送ったかをログで確認できる設計が有効です。
ログがないEAは、成績悪化の原因を切り分けにくくなります。

10. 実運用での注意点

【結論】
実運用では、バックテスト結果をそのまま信用せず、スプレッド、約定、ブローカー仕様、レバレッジ、ドローダウン許容度を確認します。
自動売買では、ロジックの正しさだけでなく、停止条件と異常時対応が重要です。

実運用前に確認すべき項目は次のとおりです。

  • 最小ロット、最大ロット、ロットステップ
  • 必要証拠金と有効証拠金
  • ストップレベルとフリーズレベル
  • 取引可能時間
  • 約定方式
  • スプレッドの通常時と拡大時
  • netting口座とhedging口座の違い
  • 最大ドローダウンの許容範囲
  • EA停止条件

10.1 ロット計算は固定ロットだけで終わらせない

固定ロットは実装しやすい一方で、口座残高の変化に対応しにくい方式です。
実運用を想定する場合は、残高比例、リスク率ベース、ボラティリティ調整も検討します。

方式特徴注意点
固定ロット実装が簡単資金変動に弱い
残高比例資金に応じて調整しやすいロット増加時に損失も増える
リスク率ベース損切り幅と許容損失から計算するティックバリューとティックサイズの確認が必要
ボラティリティ調整ATRなどで相場変動に合わせるパラメータ依存が強くなりやすい

10.2 停止条件を設計する

EAには、損失が続いた場合や異常な相場環境になった場合の停止条件が必要です。
たとえば、日次損失、連敗数、スプレッド上限、証拠金維持率、取引時間外などで停止します。

レバレッジが高いほど、同じ値動きでもドローダウンが大きくなりやすくなります。
資金管理は、売買ロジックと同じ重要度で設計します。

11. 改善案と代替手段

【結論】
定量戦略を改善する場合は、条件を増やす前に、シグナル、フィルター、リスク管理、注文処理のどこに問題があるかを分けて確認します。
改善は、成績の良い設定を探す作業ではなく、再現性を確認する作業として進めます。

改善案には次のようなものがあります。

  • 確定足ベースの判定に変更する
  • ATRで最低ボラティリティを確認する
  • スプレッド上限を追加する
  • 時間帯フィルターを追加する
  • 損切り幅を固定値からボラティリティ連動にする
  • ロット計算をリスク率ベースにする
  • エントリー条件と決済条件を別々に検証する
  • フォワードテストのログを増やす

11.1 条件追加よりも分解を優先する

成績が悪いときに条件を増やすだけでは、原因が分からなくなります。
まず、エントリー精度、損切り位置、利確幅、取引時間、スプレッド耐性を分けて見ます。

11.2 代替手段を比較する

移動平均線の期間を変えるだけでなく、トレンド判定そのものを比較します。
たとえば、移動平均線、ADX、上位足方向、直近高値安値などを同じ検証条件で比較します。

12. まとめ

【結論】
MQL5のquantitative strategy designでは、売買条件を数値化し、EAの処理を状態管理として設計することが重要です。
シグナル、フィルター、リスク確認、注文前チェック、約定後管理を分けることで、検証と改善がしやすくなります。

定量戦略は、検証しやすい構造を作れる一方で、過剰最適化や実運用との乖離に注意が必要です。
バックテストでは、総損益だけでなく、最大ドローダウン、取引回数、連敗数、パラメータ依存性を確認します。
フォワードテストでは、約定差、スプレッド拡大、ブローカー差、VPS環境での安定性を確認します。

実運用では、バックテスト結果は将来の利益を保証しません。
EAを運用する前に、取引条件、資金管理、停止条件、ログ出力を含めて検証する必要があります。

FAQ

MQL5のquantitative strategy designとは何ですか?

MQL5のquantitative strategy designとは、EAの売買判断を数値条件、フィルター、リスク管理、注文処理に分けて設計する方法です。感覚的な判断ではなく、検証可能なルールとして実装します。

MQL5で定量戦略を作るときの基本構造は何ですか?

基本構造は、相場認識、フィルター判定、シグナル判定、リスク確認、注文前チェック、注文送信、約定後管理です。各処理を分けることで、バックテストやフォワードテストで問題点を確認しやすくなります。

CopyBufferを使うときに注意すべき点は何ですか?

CopyBufferでは、取得件数が期待値に届いているかを確認する必要があります。さらに、配列の時系列方向、最新足と確定足の違い、ハンドルが有効かどうかを確認します。

トレンド追従と平均回帰はどちらが優れていますか?

トレンド追従と平均回帰に絶対的な優劣はありません。銘柄、時間足、スプレッド、相場環境、検証期間により適した設計は変わります。

定量戦略でよくある失敗は何ですか?

よくある失敗は、条件を増やしすぎて過剰最適化することです。未確定足の使用、スプレッド無視、ロット制限の無視、OrderCheckの省略も誤作動の原因になります。

バックテストでは何を確認すべきですか?

バックテストでは、総損益、最大ドローダウン、勝率、損益比、取引回数、連敗数、スプレッド条件、期間依存性、パラメータ依存性を確認します。総損益だけで判断すると、実運用でのリスクを見落としやすくなります。

フォワードテストはなぜ必要ですか?

フォワードテストは、バックテストでは見えにくい約定差、スプレッド拡大、取引頻度、ブローカー差を確認するために必要です。バックテスト結果は将来の利益を保証しないため、実運用前の検証が重要です。

実運用前に確認すべきリスクは何ですか?

実運用前には、ドローダウン許容度、スプレッド拡大、約定遅延、スリッページ、ロット制限、証拠金、口座タイプ、EA停止条件を確認します。ブローカー仕様によりEAの挙動が変わる場合があります。