MQL5のスリッページ制御とは?EA実装設計を解説

目次

この記事の結論

MQL5でスリッページ制御を設計する目的は、EAの注文が想定価格から大きくずれて約定するリスクを抑えやすくすることです。
MqlTradeRequest.deviation だけで完結させるのではなく、スプレッド確認、価格再取得、OrderCheck、約定方式の確認、約定後の結果判定を組み合わせて管理します。
スリッページは完全に消せるものではなく、相場急変、流動性、ブローカー仕様、VPS環境により発生条件が変わります。
バックテスト結果は将来の約定品質を保証しないため、フォワードテストで約定差とスプレッド拡大時の挙動を確認する必要があります。

1. この設計が必要な理由

【結論】
MQL5のスリッページ制御は、注文価格と実際の約定価格の差を一定範囲に収めるための実行管理です。
EAでは売買シグナルが正しくても、約定価格が悪化すると損益、損切り幅、リスクリワードが変わります。

スリッページとは、注文時に想定した価格と、実際に約定した価格の差です。成行注文では価格が動き続けるため、送信時点の価格とサーバーで処理される価格が一致しない場合があります。

MQL5のEAでは、スリッページ制御を次のような実行品質の問題として扱います。

  • スプレッドが広がりすぎていないか
  • 注文直前のBid、Askを再取得しているか
  • 許容偏差を銘柄の桁数に合わせて設定しているか
  • OrderCheckで証拠金や取引条件を確認しているか
  • OrderSend後に約定結果とリターンコードを確認しているか
  • netting口座とhedging口座の違いを考慮しているか

MQL5のスリッページ制御は、単に注文時の許容偏差を設定するだけでは不十分です。EAの実行設計として、注文前、注文時、注文後の3段階で確認する必要があります。

1.1 スリッページがEA成績に与える影響

スリッページが大きいと、エントリー価格、損切り価格、利確価格の実質的なバランスが変わります。特に短期売買、スキャルピング、高頻度のエントリーでは、わずかな約定差が成績に影響しやすくなります。

ただし、スリッページを厳しく制限しすぎると、注文が拒否されやすくなります。約定率と約定品質のどちらを優先するかを、EAの設計目的に合わせて決める必要があります。

1.2 完全な回避ではなく制御として考える

スリッページは、通信速度だけで決まるものではありません。相場変動、流動性、約定方式、サーバー処理、銘柄仕様、取引時間帯が影響します。

EA設計では、スリッページをゼロにする発想ではなく、許容できる範囲を決めて、範囲外の注文を避ける構造にします。

2. EA全体の設計思想

【結論】
スリッページ制御は、シグナル判定から切り離した実行制御モジュールとして設計します。
売買条件、リスク確認、注文前チェック、注文送信、約定後管理を分離すると、検証しやすいEAになります。

EAの処理は、次の順序で整理すると実装しやすくなります。

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

スリッページ制御は、主に「注文前チェック」「注文送信」「約定後管理」に関係します。シグナル判定と混ぜると、エントリー条件の問題なのか、実行品質の問題なのかを切り分けにくくなります。

MQL5のEAでは、OnInitで初期設定を行い、OnTickで価格更新ごとの判断を行い、必要に応じてOnTradeTransactionで注文、約定、ポジション変化を追跡します。

2.1 注文前に判断する項目

注文前には、少なくとも次の項目を確認します。

  • 現在スプレッドが許容範囲内か
  • 銘柄が取引可能か
  • ロットが最小ロット、最大ロット、ロットステップに合っているか
  • 損切り価格がストップレベルに違反していないか
  • 証拠金が不足していないか
  • 同一銘柄の既存ポジションをどう扱うか
  • 現在価格が古いティックではないか

スリッページ制御は、約定差だけではなく、注文を出してよい相場状態かを判定する仕組みです。

2.2 注文後に判断する項目

注文後には、MqlTradeResultの内容を確認します。注文が送信できたか、約定したか、どの価格で約定したか、どのリターンコードが返ったかをログに残します。

約定後の価格差を記録しておくと、バックテストとフォワードテストの乖離を確認しやすくなります。

3. 基本構造

【結論】
MQL5のスリッページ制御は、許容偏差、スプレッド上限、注文前チェック、約定結果ログの4つを基本構造にします。
この4つを分けると、原因分析とパラメータ調整がしやすくなります。

基本構造は次のように分けます。

設計要素役割主な確認内容注意点
許容偏差注文価格からの許容ずれを指定するMqlTradeRequest.deviation銘柄の桁数に合わせる
スプレッド上限不利な相場で注文を避けるBidとAskの差指標発表時に広がりやすい
注文前チェック取引条件を確認するOrderCheck、証拠金、ロット成功しても約定保証ではない
約定後ログ実際の約定差を記録する約定価格、リターンコードフォワード検証で重要
MQL5 OrderSend slippage control flow with MqlTradeRequest.deviation, OrderCheck, chart prices, and retcode logs

3.1 deviationの考え方

MqlTradeRequest.deviationは、成行注文で許容する価格のずれをポイント単位で指定する項目です。ポイントは銘柄の最小価格単位に依存します。

たとえば、5桁銘柄では1ポイントが小さい価格単位になります。pipsとpointsを混同すると、許容幅が意図より狭すぎたり広すぎたりします。

3.2 スプレッド上限との違い

スプレッド上限は、注文を出す前に相場状態を判定するための条件です。deviationは、注文送信後の価格ずれを許容するための条件です。

スプレッド制御とスリッページ制御は別の役割を持ちます。両方を使うことで、悪い条件での注文を避けやすくなります。

4. 主要モジュールの役割

【結論】
スリッページ制御を安定させるには、価格取得、スプレッド判定、ロット正規化、注文前チェック、注文実行、結果記録を別々の関数にします。
関数を分けることで、バックテスト時とフォワードテスト時の問題点を切り分けやすくなります。

主要モジュールは次のように設計します。

モジュール役割失敗時の対応
価格取得Bid、Ask、Point、Digitsを取得する注文しない
スプレッド判定現在スプレッドが上限以内か調べるエントリーを見送る
ロット調整銘柄仕様に合わせてロットを丸める最小・最大範囲外なら注文しない
注文前確認OrderCheckで条件を確認するエラー内容をログに残す
注文送信OrderSendで注文するリターンコードを確認する
約定後記録約定価格と想定価格の差を記録するフォワード検証に使う

4.1 価格取得モジュール

MQL5では、買い注文はAsk、売り注文はBidを基準にします。注文直前に価格を再取得しないと、古い価格を使って注文する可能性があります。

EAでは、SymbolInfoDoubleでBid、Ask、Pointを取得し、取得に失敗した場合は注文を中止します。

4.2 ロット調整モジュール

ロットは、最小ロット、最大ロット、ロットステップに合わせる必要があります。リスク率ベースのロット計算を使う場合でも、最後に銘柄仕様へ合わせて丸めます。

ロット制限を無視すると、注文前チェックや注文送信で失敗しやすくなります。

5. 実装パターン

【結論】
実装パターンは、固定許容幅、スプレッド連動、ボラティリティ連動、時間帯制御の4つに分けられます。
初心者は固定許容幅とスプレッド上限から始めると、挙動を検証しやすくなります。

スリッページ制御の設計パターンは、EAの取引頻度と時間軸に合わせて選びます。

方法メリットデメリット向いている場面
固定許容幅実装が簡単相場変動に対応しにくい初期実装、低頻度EA
スプレッド連動悪条件を避けやすい取引機会が減る場合がある短期売買、スキャルピング検証
ボラティリティ連動相場変動を反映しやすいパラメータ依存が強くなりやすいATRなどを使うEA
時間帯制御指標前後や薄商いを避けやすい汎用性が低い場合がある時間帯の影響が大きい銘柄

5.1 固定許容幅

固定許容幅は、deviationを一定値にする方法です。実装しやすく、検証結果を比較しやすい点が利点です。

ただし、相場が急変する時間帯やスプレッドが広がる銘柄では、固定値だけでは不十分になる場合があります。

5.2 スプレッド連動

スプレッド連動は、現在スプレッドが一定範囲内のときだけ注文する方法です。スプレッドが広い状態のエントリーを避けやすくなります。

スプレッド上限を厳しくすると、約定品質は改善しやすい一方で、取引回数が減る可能性があります。

5.3 ボラティリティ連動

ボラティリティ連動は、ATRなどの変動幅を使って許容条件を調整する考え方です。MQL5でATRを使う場合は、OnInitでインジケータハンドルを作成し、OnTickCopyBufferから値を取得する流れになります。

この方法は柔軟ですが、パラメータを増やしすぎると過剰最適化につながりやすくなります。

6. サンプルコード

【結論】
サンプルコードでは、スプレッド上限、ロット制限、OrderCheckOrderSend、結果ログを一つの流れとして実装します。
このコードは検証用の基本形であり、実運用では銘柄仕様と口座タイプに合わせた調整が必要です。

#property strict

input double InpLots = 0.10;
input int    InpMaxSpreadPoints = 25;
input int    InpDeviationPoints = 10;
input ulong  InpMagicNumber = 20260518;

bool GetPrices(double &bid, double &ask, double &point)
{
   if(!SymbolInfoDouble(_Symbol, SYMBOL_BID, bid))
   {
      Print("Failed to get bid price");
      return false;
   }

   if(!SymbolInfoDouble(_Symbol, SYMBOL_ASK, ask))
   {
      Print("Failed to get ask price");
      return false;
   }

   if(!SymbolInfoDouble(_Symbol, SYMBOL_POINT, point))
   {
      Print("Failed to get point size");
      return false;
   }

   return true;
}

bool IsSpreadAcceptable()
{
   double bid, ask, point;

   if(!GetPrices(bid, ask, point))
      return false;

   int spread_points = (int)MathRound((ask - bid) / point);

   if(spread_points > InpMaxSpreadPoints)
   {
      Print("Spread is too wide. spread_points=", spread_points);
      return false;
   }

   return true;
}

double NormalizeLots(double lots)
{
   double min_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double max_lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double step    = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   if(step <= 0.0)
      return 0.0;

   lots = MathMax(min_lot, MathMin(max_lot, lots));
   lots = MathFloor(lots / step) * step;

   return NormalizeDouble(lots, 2);
}

bool SendBuyOrder()
{
   if(!IsSpreadAcceptable())
      return false;

   double bid, ask, point;

   if(!GetPrices(bid, ask, point))
      return false;

   double lots = NormalizeLots(InpLots);

   if(lots <= 0.0)
   {
      Print("Invalid lot size after normalization");
      return false;
   }

   MqlTradeRequest request;
   MqlTradeCheckResult check;
   MqlTradeResult result;

   ZeroMemory(request);
   ZeroMemory(check);
   ZeroMemory(result);

   request.action       = TRADE_ACTION_DEAL;
   request.symbol       = _Symbol;
   request.volume       = lots;
   request.type         = ORDER_TYPE_BUY;
   request.price        = ask;
   request.deviation    = InpDeviationPoints;
   request.magic        = InpMagicNumber;
   request.type_filling = ORDER_FILLING_FOK;
   request.comment      = "slippage-control-test";

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

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

   if(result.retcode != TRADE_RETCODE_DONE &&
      result.retcode != TRADE_RETCODE_PLACED)
   {
      Print("Order was not completed as expected. retcode=", result.retcode);
      return false;
   }

   double slippage_points = MathAbs(result.price - request.price) / point;

   Print("OrderSend result. retcode=", result.retcode,
         " request_price=", request.price,
         " result_price=", result.price,
         " slippage_points=", slippage_points);

   return true;
}

int OnInit()
{
   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
}

void OnTick()
{
   static datetime last_bar_time = 0;
   datetime current_bar_time = iTime(_Symbol, _Period, 0);

   if(current_bar_time == last_bar_time)
      return;

   last_bar_time = current_bar_time;

   bool sample_signal = false;

   if(sample_signal)
   {
      SendBuyOrder();
   }
}

6.1 コードの読み方

このコードは、シグナル判定をsample_signalとして分離しています。実際のEAでは、移動平均線、RSI、ブレイクアウト条件などの判定結果をこの部分に接続します。

注文前には、スプレッドを確認し、価格を再取得し、ロットを銘柄仕様に合わせます。その後、OrderCheckで注文条件を確認してからOrderSendを実行します。

6.2 type_fillingの注意点

request.type_fillingは、銘柄やブローカー仕様により利用できる方式が異なります。ORDER_FILLING_FOKが使えない銘柄では、別の約定方式が必要になる場合があります。

実運用では、銘柄の対応する約定方式を確認し、注文失敗時のログを残す設計が必要です。

7. 設計パターン比較

【結論】
スリッページ制御の設計は、約定率を優先するか、約定品質を優先するかで変わります。
短期EAほど厳しい制御が必要になりやすく、長期EAほど過度な制限が機会損失につながる場合があります。

設計方針メリットデメリット向いている場面実運用での注意点
約定率重視注文が通りやすい不利な約定を受けやすい長期保有、低頻度EA急変時の損益悪化に注意
約定品質重視不利な約定を避けやすい注文拒否が増える場合がある短期売買、狭い利幅のEA取引回数の減少を確認する
スプレッド重視悪条件の取引を避けやすい指標前後で停止しやすいスプレッド影響が大きいEA期間依存性を確認する
ボラティリティ重視相場変動に合わせやすい設計が複雑になりやすいATR連動のEA過剰最適化に注意する

7.1 約定率と約定品質のトレードオフ

許容偏差を広げると注文は通りやすくなりますが、不利な価格で約定する可能性があります。許容偏差を狭くすると不利な約定は避けやすくなりますが、注文が拒否される可能性が高くなります。

EA設計では、注文が通らないリスクと、不利な価格で約定するリスクの両方を検証します。

7.2 netting口座とhedging口座の違い

netting口座では、同一銘柄のポジションは原則として一つに集約されます。hedging口座では、同一銘柄で複数ポジションを持てる場合があります。

スリッページ制御そのものの考え方は共通ですが、注文後のポジション管理は口座タイプにより変わります。約定後にどのポジションが更新されたかを確認する処理が重要です。

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

【結論】
バックテストでは、スリッページ制御によって損益だけでなく、取引回数、最大ドローダウン、連敗数、スプレッド条件がどう変わるかを確認します。
総損益だけを見ると、実行品質の悪化を見落とす場合があります。

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

  • 総損益
  • 最大ドローダウン
  • 勝率
  • 損益比
  • 取引回数
  • 連敗数
  • スプレッド条件
  • 期間依存性
  • パラメータ依存性
  • 注文拒否が想定される条件

8.1 取引回数の変化

スプレッド上限や許容偏差を厳しくすると、取引回数が減る場合があります。取引回数が極端に少ないバックテストは、少数の取引結果に依存しやすくなります。

スリッページ制御は成績改善のためだけではなく、悪条件の注文を避けるための設計です。取引回数と約定品質を合わせて確認します。

8.2 パラメータ依存性

InpMaxSpreadPointsInpDeviationPointsを細かく最適化しすぎると、特定期間だけに合った設定になる場合があります。

過剰最適化を避けるには、複数期間、複数銘柄、異なるスプレッド条件で挙動を確認します。

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

【結論】
フォワードテストでは、実際の約定差、スプレッド拡大、注文拒否、VPS環境での安定性を確認します。
バックテストでは再現しにくい実行条件が、リアルタイム運用では成績に影響します。

フォワードテストでは次の項目を記録します。

  • 約定差
  • スプレッド拡大時の挙動
  • 取引頻度
  • ドローダウン
  • バックテストとの乖離
  • ブローカー差
  • VPS環境での安定性
  • 注文失敗時のリターンコード
  • デモ口座とリアル口座の差

9.1 約定差ログの重要性

注文時の想定価格と実際の約定価格をログに残すと、EAの問題と取引環境の問題を切り分けやすくなります。

約定差が特定の時間帯に集中する場合は、取引時間帯フィルターやスプレッド上限の見直しが必要になることがあります。

9.2 デモ口座とリアル口座の違い

デモ口座とリアル口座では、約定条件やスプレッド条件が異なる場合があります。デモ口座で問題が少なくても、リアル口座で同じ挙動になるとは限りません。

実運用前には、小さいロットや限定条件でフォワードテストを行い、注文失敗、約定差、ドローダウンを確認します。

10. 実運用での注意点

【結論】
実運用では、スリッページ制御だけで損失を防げるわけではありません。
スプレッド拡大、約定遅延、証拠金不足、レバレッジ、ブローカー仕様を含めてリスク管理を行います。

実運用で注意すべき点は次のとおりです。

  • 指標発表時はスプレッドと約定差が拡大しやすい
  • 流動性が低い時間帯は不利な約定が発生しやすい
  • VPSの遅延が注文処理に影響する場合がある
  • 高いレバレッジではドローダウンが大きくなりやすい
  • ブローカーの約定方式により注文結果が変わる場合がある
  • バックテスト結果は将来の利益を保証しない

10.1 損切り幅との関係

損切り幅が狭いEAでは、スリッページの影響が大きくなります。数ポイントの約定差でも、想定したリスクリワードが崩れる場合があります。

損切り幅、スプレッド上限、許容偏差は別々に設定するのではなく、売買ロジック全体の前提として整合させます。

10.2 注文拒否の扱い

注文が拒否された場合に、無条件で再注文を繰り返す設計は避けます。相場急変時に連続注文が発生すると、意図しない約定やログ肥大化につながる場合があります。

再注文を行う場合は、回数制限、待機時間、価格再取得、スプレッド再確認を組み合わせます。

11. よくある設計ミス

【結論】
よくあるミスは、deviationだけで制御できると考えること、pipsとpointsを混同すること、注文後の結果確認を省略することです。
スリッページ制御は、注文前後の状態管理まで含めて設計します。

11.1 pipsとpointsの混同

deviationはpoints単位で指定します。pipsの感覚で数値を入れると、意図より狭い許容幅や広い許容幅になる場合があります。

銘柄のSYMBOL_POINTと桁数を使い、EA内で数値の意味を明確にします。

11.2 古い価格で注文する

OnTick内で受け取った価格を長く保持し、注文直前に価格を再取得しない設計は避けます。価格が古いと、注文価格と現在価格がずれやすくなります。

注文直前にはBidとAskを再取得し、スプレッドも再確認します。

11.3 OrderCheckを省略する

OrderCheckを省略すると、証拠金不足、ロット不正、ストップレベル違反などの原因を事前に把握しにくくなります。

OrderCheckは約定を保証する処理ではありませんが、注文前の条件確認として有効です。

11.4 ログを残さない

約定価格、想定価格、スプレッド、リターンコードを記録しないEAは、フォワードテストで問題を分析しにくくなります。

実運用に近い検証では、損益だけでなく実行品質のログを残します。

12. まとめ

【結論】
MQL5のスリッページ制御は、MqlTradeRequest.deviation、スプレッド上限、OrderCheckOrderSend後の結果確認を組み合わせて設計します。
注文価格のずれを完全に防ぐのではなく、許容範囲を決め、悪条件の注文を避け、約定後に検証できる状態を作ることが重要です。

MQL5のEAでは、売買シグナルと注文実行を分離すると、実行品質の問題を分析しやすくなります。スプレッド、約定方式、ロット制限、口座タイプ、ブローカー仕様を考慮しない設計では、バックテストと実運用の差が大きくなる場合があります。

スリッページ制御は利益を保証する仕組みではありません。実運用前には、バックテストだけでなくフォワードテストで約定差、注文拒否、スプレッド拡大時の挙動を確認する必要があります。

FAQ

Q1. MQL5のスリッページ制御とは何ですか?

MQL5のスリッページ制御とは、注文時の想定価格と実際の約定価格の差を管理する設計です。deviation、スプレッド上限、注文前チェック、約定後ログを組み合わせて実装します。

Q2. deviationを設定すればスリッページは防げますか?

deviationは許容する価格ずれを指定する項目ですが、スリッページを完全に防ぐものではありません。相場急変、約定方式、流動性、ブローカー仕様により結果は変わります。

Q3. スプレッド制御とスリッページ制御は何が違いますか?

スプレッド制御は注文前の市場条件を判定する仕組みです。スリッページ制御は、注文価格と約定価格のずれを許容範囲に収めるための実行管理です。

Q4. OrderCheckは必ず使うべきですか?

EAで注文処理を行う場合、OrderCheckで証拠金、ロット、取引条件を確認すると原因分析がしやすくなります。OrderCheckは約定を保証しませんが、注文前チェックとして有効です。

Q5. pipsとpointsを間違えると何が起きますか?

deviationはpoints単位で扱うため、pipsと混同すると許容幅が意図とずれる場合があります。銘柄の桁数とSYMBOL_POINTを確認して設定する必要があります。

Q6. バックテストでスリッページ制御は確認できますか?

バックテストでは取引回数、損益、ドローダウン、スプレッド条件への影響を確認できます。ただし、実際の約定差やサーバー処理は再現しきれないため、フォワードテストが必要です。

Q7. 実運用で特に注意すべき点は何ですか?

実運用では、指標発表時のスプレッド拡大、約定遅延、VPS環境、ブローカー仕様、口座タイプの違いに注意します。バックテスト結果は将来の利益を保証しないため、約定差のログを継続的に確認します。