1. MQL5の「invalid stops」とは何か
【結論】
「invalid stops」は、注文時に設定したストップロス(SL)やテイクプロフィット(TP)が、ブローカーの許容条件を満たしていない場合に発生するエラーです。
主因は「価格距離不足」「価格精度の不一致」「取引条件の未考慮」です。
1.1 invalid stopsの定義
【結論】
invalid stopsとは、「注文に付与したSL/TPが、ブローカーの最小距離や価格ルールに違反している状態」を指します。
【定義】
MQL5における「invalid stops」は、OrderSendやtrade関数実行時に返されるエラーコードの一つであり、以下のような条件違反で発生します。
- ストップレベル(最小距離)未満
- 現在価格に対して不正な方向
- 桁数(Digits)不一致
- フリーズレベル違反
これらはすべて「注文条件(order条件)」の不整合に分類されます。
1.2 なぜinvalid stopsが発生するのか
【結論】
invalid stopsは「ブローカー仕様を無視した価格設定」により発生します。特に自動売買(EA)では頻発します。
主な原因は以下です。
- ストップレベル(SYMBOL_TRADE_STOPS_LEVEL)を考慮していない
- Bid/Askの違いを無視している
- スプレッド拡大時の距離不足
- Digits(価格精度)の丸めミス
例えば、買い注文(Buy)の場合:
- SLはBidより下
- TPはBidより上
でなければなりませんが、これを逆にすると即エラーになります。
さらに、ブローカーは「最小距離(例:10ポイント)」を要求するため、以下のようなコードは失敗します。
double sl = Bid - 5 * _Point; // 距離不足でinvalid stops
この場合、必要距離を満たしていないためエラーになります。
1.3 実際のエラー発生パターン
【結論】
invalid stopsは「正常に見えるコードでも発生する」ため、構造的に理解する必要があります。
代表的なパターン:
- バックテストでは通るがリアルで失敗
- スプレッド拡大時のみ失敗
- 指標発表時にのみ発生(slippage影響)
- ECN口座でのみ発生(約定条件が厳しい)
特に注意すべき点:
- execution方式(Market/Instant Execution)により挙動が変わる
- スプレッド(spread)が動的に変化する
- フリーズレベルで修正不可になるケース
これらはすべて「実行環境依存」の要素です。
1.4 初心者がつまずきやすいポイント
【結論】
最大の失敗は「固定値でSL/TPを決めてしまうこと」です。
よくあるミス:
- 固定ポイントでSL/TPを設定
- SYMBOL_TRADE_STOPS_LEVELを未取得
- NormalizeDoubleを使っていない
- Ask/Bidの使い分けミス
特に以下は典型例です。
double sl = Bid - 10 * _Point;
double tp = Bid + 10 * _Point;
問題点:
- 最小距離未考慮
- スプレッド無視
- 桁数調整なし
この状態では、環境によって成功・失敗が分かれます。
1.5 なぜ事前チェックが重要なのか
【結論】
invalid stopsは「事前に100%防げるエラー」であり、チェック処理の有無が品質差になります。
理由:
- 注文失敗=機会損失(期待値低下)
- EAの再現性が崩れる
- ログが汚れデバッグ困難になる
そのため、実務では必ず以下を行います。
- ストップレベル取得
- 現在価格との距離チェック
- 正規化(NormalizeDouble)
- 注文前バリデーション
これはアルゴリズムトレードにおける「リスク管理」の一部です。
2. invalid stopsを回避するための実装手順
【結論】
invalid stopsは「最小距離の取得 → 価格計算 → 正規化 → バリデーション」の順で処理すれば確実に防げます。
この4ステップをテンプレート化することが再現性の鍵です。
2.1 ストップレベル(最小距離)を取得する
【結論】
まず、ブローカーごとに異なる最小距離(ストップレベル)を必ず取得します。
MQL5では以下で取得できます。
int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double minDistance = stopLevel * _Point;
ポイント:
- stopLevelは「ポイント単位」
- _Pointを掛けて価格単位に変換する
注意点:
- 通貨ペアごとに異なる
- 口座タイプ(ECN/スタンダード)でも変わる
- 0が返る場合もある(その場合でも安全側で距離を取る)
なぜ必要か:
- ブローカーのexecution条件を満たさないと注文が拒否されるため
2.2 Bid/Askを正しく使ってSL/TPを計算する
【結論】
BuyとSellで基準価格が異なるため、Bid/Askを正確に使い分ける必要があります。
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
Buy注文の場合:
double sl = bid - minDistance;
double tp = bid + minDistance;
Sell注文の場合:
double sl = ask + minDistance;
double tp = ask - minDistance;
重要ポイント:
- BuyはBid基準、SellはAsk基準
- spreadを無視すると距離不足になる
よくある失敗:
- 全てBid基準で計算する
- spread拡大時にSLが近すぎる
2.3 価格をNormalizeDoubleで正規化する
【結論】
価格は必ずDigitsに合わせて丸める必要があります。これを怠るとinvalid stopsになります。
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
sl = NormalizeDouble(sl, digits);
tp = NormalizeDouble(tp, digits);
理由:
- ブローカーは価格精度(Digits)を厳密にチェックするため
- 小数誤差でも注文拒否される
補足:
- Normalizeしないと「見た目は正しいが内部的に不正」になる
2.4 注文前に距離チェックを行う
【結論】
最終的に「現在価格との距離」をチェックすれば、invalid stopsは完全に防げます。
if((bid - sl) < minDistance)
{
Print("SL too close");
return;
}
if((tp - bid) < minDistance)
{
Print("TP too close");
return;
}
Sellの場合は逆方向になるため注意:
if((sl - ask) < minDistance)
{
Print("SL too close");
return;
}
重要な考え方:
- 「注文前に落とす」ことで無駄なOrderSendを防ぐ
- ログが整理され、デバッグ効率が上がる
2.5 実務用テンプレートコード
【結論】
以下のように一連の処理をまとめると、再利用性が高くなります。
double GetValidSL(bool isBuy, double price)
{
int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double minDistance = stopLevel * _Point;
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
double sl;
if(isBuy)
sl = price - minDistance;
else
sl = price + minDistance;
return NormalizeDouble(sl, digits);
}
このように関数化することで:
- ロジックの統一
- バグの局所化
- EA全体の品質向上
が実現できます。
2.6 よくある失敗と対策
【結論】
invalid stopsの多くは「環境変化を考慮していない設計」によって発生します。
失敗例と対策:
- 固定値SL → 最小距離ベースに変更
- スプレッド無視 → ask/bid基準に変更
- 正規化なし → NormalizeDouble必須
- テストのみ確認 → 実口座で検証
特に重要:
- バックテストはspread固定のため再現性が低い
- 実運用ではslippageやexecutionの影響を受ける
3. それでもinvalid stopsが発生するケースと対処法
【結論】
適切に実装してもinvalid stopsが発生する場合は、「市場状態」または「ブローカー仕様」による例外が原因です。
この章では、実務で遭遇する再現性の低いケースと対処法を整理します。
3.1 スプレッド拡大による距離不足
【結論】
スプレッド(spread)が急拡大すると、事前に計算したSL/TPが瞬時に最小距離未満になることがあります。
典型例:
- 指標発表時
- ロールオーバー時間帯
- 流動性が低い時間帯(早朝など)
問題の構造:
- SL/TPはBid/Ask基準で計算
- しかし発注直前にspreadが変動
- 結果として距離不足になる
対策:
double spread = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - SymbolInfoDouble(_Symbol, SYMBOL_BID);
// 最低距離にスプレッドを上乗せ
double safeDistance = minDistance + spread;
重要ポイント:
- 「理論値」ではなく「安全マージン」を持たせる
- 実運用では+α(例:1.2倍)することもある
3.2 フリーズレベルによる制限
【結論】
フリーズレベル(SYMBOL_TRADE_FREEZE_LEVEL)により、注文直前や変更時に制限がかかることがあります。
取得方法:
int freezeLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL);
影響:
- 指定距離内では注文変更不可
- SL/TPの設定・修正が拒否される
よくあるケース:
- 成行注文後にSL/TPを後付け
- 価格が急変してフリーズ範囲に入る
対策:
- 初回注文時にSL/TPを同時設定
- もしくはフリーズ距離外でのみ変更
3.3 ECN口座特有の挙動
【結論】
ECN口座では「注文時にSL/TPを付けられない」ケースがあり、invalid stopsの原因になります。
特徴:
- 約定優先(execution重視)
- SL/TPは後付けが前提
典型的なエラー:
// 注文時にSL/TPを指定 → invalid stops
対処手順:
- OrderSendでポジションのみ取得
- 約定後にPositionModifyでSL/TP設定
// 疑似フロー
OrderSend(...);
PositionModify(...);
注意点:
- フリーズレベルと併用で失敗する場合あり
- 約定直後の価格変動に注意
3.4 約定遅延とslippageの影響
【結論】
注文送信から約定までの遅延により、価格が変化し、SL/TPが無効になることがあります。
原因:
- ネットワーク遅延
- サーバー負荷
- execution方式
影響:
- 計算時の価格 ≠ 約定時の価格
- 結果として距離条件を満たさない
対策:
double deviation = 10; // 許容スリッページ
さらに重要:
- SL/TPを「価格固定」ではなく「距離ベース」で再計算
- 約定後に再設定する設計も有効
3.5 バックテストとリアル環境の差異
【結論】
バックテストではinvalid stopsが出ないのに、リアルで発生するのは正常です。
理由:
- スプレッドが固定
- 約定遅延が存在しない
- execution条件が単純化されている
そのため:
- テストで通る = 安全ではない
- 実運用で検証が必須
実務対応:
- デモ口座でフォワードテスト
- ログを詳細に出力
Print("SL:", sl, " TP:", tp, " Bid:", bid);
3.6 例外を前提とした設計
【結論】
完全にエラーをゼロにするのではなく、「発生しても安全に処理する設計」が重要です。
推奨設計:
- OrderSend失敗時にリトライ
- 条件を再計算して再発注
- ログに原因を記録
例:
if(!OrderSend(request, result))
{
Print("Order failed, retrying...");
Sleep(500);
// 再計算して再送信
}
重要な視点:
- invalid stopsは「環境依存エラー」
- 完全排除ではなく「制御」が本質
4. よくある原因パターン
【結論】
invalid stopsの原因は多く見えますが、実務ではほぼ「価格距離」「価格方向」「価格精度」の3系統に整理できます。
原因をパターン化して理解すると、ログ解析と修正が一気に速くなります。
4.1 ストップレベルを考慮していない
【結論】
もっとも多い原因は、ブローカーが要求する最小距離を満たしていないことです。
MQL5では、SLやTPを現在価格の近くに置きすぎると、注文自体が拒否されます。
この最小距離はブローカーごと、銘柄ごとに異なり、同じEAでも環境が変わると急にinvalid stopsが出ることがあります。
典型例:
double sl = bid - 10 * _Point;
double tp = bid + 10 * _Point;
このコードは、一見すると正しそうに見えます。
しかし、実際のストップレベルが20ポイントなら、SLもTPも条件違反です。
つまずきやすい点:
- 自分の口座で一度通ったので他でも通ると思ってしまう
- 通貨ペアが変わっても同じ値で動くと考えてしまう
- テスターで問題が出なかったため本番でも安全だと誤認する
対策は明確です。
- SYMBOL_TRADE_STOPS_LEVELを毎回取得する
- 固定値ではなく、取得値ベースで距離を計算する
- 余裕を持たせるならspreadや安全マージンも加味する
4.2 BidとAskの使い分けを間違えている
【結論】
BuyとSellで基準価格が異なるのに、同じ式でSL/TPを計算するとinvalid stopsが起きやすくなります。
基本ルールは次のとおりです。
- Buy系はBid基準でSL/TPを見る
- Sell系はAsk基準でSL/TPを見る
初心者がやりがちな失敗は、どちらも現在価格としてBidだけを使うことです。
誤りやすい例:
double sl = bid - minDistance;
double tp = bid + minDistance;
// Sellでもそのまま使ってしまう
この書き方だと、Sell注文では価格方向が崩れます。
その結果、TPが不正方向になったり、必要距離を満たしていないと判定されたりします。
確認ポイント:
- BuyのSLは現在価格より下
- BuyのTPは現在価格より上
- SellのSLは現在価格より上
- SellのTPは現在価格より下
これは単純ですが、最も重要な基礎です。
価格の方向を誤ると、距離以前に注文条件そのものが不正になります。
4.3 _Pointとpipsを混同している
【結論】
MQL5では「ポイント」と「pips」は同じ意味ではありません。ここを混同すると距離計算がずれます。
たとえば5桁通貨ペアでは、1 pip = 10 points になることがあります。
そのため、「20pipsのつもり」で 20 * _Point と書くと、実際には2pipsしか確保できていないケースがあります。
典型例:
double sl = bid - 20 * _Point;
このコードは、銘柄によっては十分な距離になりません。
よくある失敗:
- MT4時代の感覚のまま書く
- USDJPYとEURUSDで同じ距離式を流用する
- goldや指数など、FX以外のsymbol仕様を無視する
なぜ危険か:
- 銘柄ごとの価格刻みが異なる
- 同じロジックでも実距離が変わる
- invalid stopsだけでなく、意図しない損切り幅にもつながる
対策:
- 距離の内部単位を「ポイント」に統一する
- 必要に応じてpip換算関数を用意する
- symbolごとの差を前提に設計する
4.4 NormalizeDoubleを使っていない
【結論】
SL/TPの見た目が正しくても、内部値に微小な誤差が残っているとinvalid stopsになることがあります。
MQL5の価格計算はdoubleで行われます。
doubleは便利ですが、小数を完全に表現できない場合があります。
そのため、計算結果をそのまま注文に使うと、ブローカー側で「不正な価格精度」とみなされることがあります。
例:
sl = bid - minDistance;
tp = bid + minDistance;
この段階では、内部的に余分な小数が含まれている可能性があります。
そこで必ず以下を行います。
sl = NormalizeDouble(sl, _Digits);
tp = NormalizeDouble(tp, _Digits);
注意点:
_Digitsを使わず固定桁数にすると、symbol変更時に破綻しやすい- NormalizeDoubleだけで全問題が解決するわけではない
- 先に距離計算、後で正規化、の順番が基本
つまり、NormalizeDoubleは万能ではありませんが、必須の仕上げ処理です。
4.5 スプレッドを無視している
【結論】
spreadを無視すると、静かな相場では通っても、実運用ではinvalid stopsが断続的に発生します。
特に次の時間帯は危険です。
- 経済指標前後
- ロールオーバー前後
- 早朝や流動性が薄い時間帯
このとき、BidとAskの差が急に広がります。
その結果、事前に計算したSL/TPが「発注時点では近すぎる」と判定されることがあります。
対策としては、最低距離にspreadを加味する方法が実務的です。
double spread = ask - bid;
double safeDistance = minDistance + spread;
さらに安全側に寄せるなら、
- safeDistance = minDistance + spread
- または safeDistance = minDistance * 1.2
のような設計もあります。
代替手段として、注文時にSL/TPを付けず、約定後に再設定する方法もあります。
ただし、これはフリーズレベルや約定遅延の影響を受けるため、別の注意が必要です。
4.6 固定値ロジックをそのまま流用している
【結論】
他のEA、古いコード、ネット上のサンプルをそのまま使うと、口座条件の違いでinvalid stopsが出やすくなります。
よくあるケース:
- 「SL=100ポイント」で固定
- 「TP=200ポイント」で固定
- symbolごとの条件分岐なし
- broker差を無視
サンプルコードは学習には便利ですが、実運用前提では不十分なことが多いです。
なぜなら、ブローカーのexecution、spread、stop level、freeze levelは統一されていないからです。
このため、実務では以下の発想が重要です。
- 固定値ではなく、環境に応じて計算する
- symbolと口座条件を毎回取得する
- 注文前チェックを標準化する
これができると、invalid stopsは「たまに出る厄介なエラー」ではなく、「設計で制御できる条件違反」に変わります。
5. invalid stops対策の設計比較
【結論】
invalid stops対策は複数ありますが、実務では「事前チェック型」が最も再現性・安定性・期待値のバランスに優れます。
他手法は状況依存であり、設計意図を理解して使い分ける必要があります。
5.1 主な対策手法の一覧
【結論】
対策は大きく4パターンに分類できます。
| 手法 | 概要 | 特徴 |
|---|---|---|
| 事前チェック型 | 注文前に条件検証 | 最も安定 |
| 後付け設定型 | 約定後にSL/TP設定 | ECN向け |
| リトライ型 | エラー後に再送信 | 応急処置 |
| 固定値型 | SL/TP固定 | 非推奨 |
この中で「どれを採用するか」で、EAの品質が大きく変わります。
5.2 事前チェック型(推奨)
【結論】
最も安全で再現性が高いのが事前チェック型です。
処理フロー:
- stop level取得
- spread取得
- SL/TP計算
- 距離チェック
- 正規化
- OrderSend
イメージコード:
double minDistance = stopLevel * _Point;
double spread = ask - bid;
double safeDistance = minDistance + spread;
// 距離チェック
if((bid - sl) < safeDistance)
return;
メリット:
- invalid stopsを事前に防げる
- ログが整理される
- 無駄な注文が減る(execution効率向上)
デメリット:
- 実装コストがやや高い
- 初心者には理解が難しい
ただし、長期運用では最も期待値が高くなります。
5.3 後付け設定型(ECN向け)
【結論】
ECN口座では有効ですが、設計難易度が上がります。
処理フロー:
- SL/TPなしで注文
- 約定確認
- PositionModifyで設定
コードイメージ:
// 注文
OrderSend(request, result);
// 約定後に設定
PositionModify(_Symbol, sl, tp);
メリット:
- ECN口座で安定
- execution優先の環境に適合
デメリット:
- フリーズレベルの影響を受ける
- 約定直後の価格変動に弱い
- ロジックが複雑化
リスク:
- SL設定前に急変すると損失拡大
そのため、リスク許容度に応じて採用判断が必要です。
5.4 リトライ型(補助的手法)
【結論】
invalid stops発生後に再試行する方法ですが、根本解決にはなりません。
例:
if(!OrderSend(request, result))
{
Sleep(500);
// 再計算して再送信
}
メリット:
- 実装が簡単
- 一時的な市場変動に対応
デメリット:
- エラー前提の設計になる
- ログが汚れる
- 無駄な通信が増える
評価:
- 単独使用は非推奨
- 事前チェック型と併用が現実的
5.5 固定値型(非推奨)
【結論】
SL/TPを固定値で設定するだけの設計は、現代の環境では破綻しやすいです。
例:
double sl = bid - 100 * _Point;
double tp = bid + 200 * _Point;
問題点:
- ブローカー差に対応できない
- スプレッド変動に弱い
- symbol変更で破綻
短期的には動いても、長期的には不安定です。
5.6 実務での最適設計
【結論】
現実的な最適解は「事前チェック型 + 必要に応じて後付け設定型」の組み合わせです。
設計指針:
- 基本は事前チェック型
- ECN口座では後付け併用
- リトライは例外処理として限定使用
評価軸で比較:
| 観点 | 事前チェック | 後付け | リトライ |
|---|---|---|---|
| 再現性 | 高 | 中 | 低 |
| 安定性 | 高 | 中 | 低 |
| 実装難易度 | 中 | 高 | 低 |
| リスク | 低 | 中 | 高 |
重要な考え方:
- invalid stopsは「設計で潰す」
- エラー処理ではなく予防が本質
- execution環境を前提にロジックを組む
6. invalid stopsを防ぐチェックリスト
【結論】
invalid stopsは「チェック項目を固定化」すれば再発をほぼ防げます。
実務では、注文前に以下の項目を機械的に確認することが重要です。
6.1 必須チェック項目一覧
【結論】
以下の6項目を満たしていれば、invalid stopsはほぼ発生しません。
チェックリスト:
- ストップレベルを取得している
- Bid/Askを正しく使い分けている
- SL/TPの方向が正しい
- 最小距離以上を確保している
- NormalizeDoubleで正規化している
- スプレッドを考慮している
この6つは「最低限の条件」です。
1つでも欠けると、環境によってエラーが発生します。
6.2 注文前チェックの実装テンプレート
【結論】
チェック処理は関数化して使い回すことで、ミスを防げます。
bool IsValidStops(bool isBuy, double sl, double tp)
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double minDistance = stopLevel * _Point;
double spread = ask - bid;
double safeDistance = minDistance + spread;
if(isBuy)
{
if(sl >= bid) return false;
if(tp <= bid) return false;
if((bid - sl) < safeDistance) return false;
if((tp - bid) < safeDistance) return false;
}
else
{
if(sl <= ask) return false;
if(tp >= ask) return false;
if((sl - ask) < safeDistance) return false;
if((ask - tp) < safeDistance) return false;
}
return true;
}
使い方:
if(!IsValidStops(true, sl, tp))
{
Print("Invalid stops detected");
return;
}
ポイント:
- 「注文前に落とす」設計
- OrderSend前に必ず通す
- ロジックの再利用性を確保
6.3 ログ出力によるデバッグ強化
【結論】
invalid stopsはログを見れば原因が特定できます。ログ設計は必須です。
Print("Bid:", bid, " Ask:", ask);
Print("SL:", sl, " TP:", tp);
Print("MinDistance:", minDistance, " Spread:", spread);
重要な観点:
- 数値を必ず出力する
- 条件違反の箇所を明確にする
- 「なぜ失敗したか」を残す
よくある問題:
- エラーコードだけ見て原因不明
- ログ不足で再現できない
ログは「後から検証できる状態」を作るためのものです。
6.4 実運用前の確認手順
【結論】
バックテストだけでは不十分で、必ずフォワードテストを行う必要があります。
推奨手順:
- ストラテジーテスターで基本動作確認
- デモ口座でフォワードテスト
- スプレッド拡大時間帯で検証
- 実口座で少額テスト
理由:
- テスターはexecution条件が簡略化されている
- real環境ではslippageや遅延が発生する
特に重要:
- 指標時にエラーが出ないか
- ロールオーバーで問題が出ないか
6.5 再発防止の設計思想
【結論】
invalid stops対策は「コード修正」ではなく「設計ルール化」が重要です。
実務ルール例:
- SL/TPは必ず関数経由で生成
- 注文前チェックを必須化
- 固定値ロジックは禁止
- symbol依存処理を明示
これにより:
- 開発者が変わっても品質維持
- バグの再発防止
- EA全体の安定性向上
6.6 最小構成チェック(簡易版)
【結論】
最低限、以下だけでも実装すれば大きな事故は防げます。
if((bid - sl) < minDistance || (tp - bid) < minDistance)
{
Print("Invalid stops");
return;
}
ただしこれは簡易版です。
実務では必ずフルチェックを推奨します。
7. まとめと実装ポイントの整理
【結論】
invalid stopsは「環境依存の例外」ではなく、「設計で制御できる条件違反」です。
最小距離・価格方向・価格精度の3点を統合的に管理すれば、再現性高く回避できます。
7.1 最重要ポイントの要約
【結論】
以下の5点を守るだけで、invalid stopsの大半は防げます。
- ストップレベルを必ず取得する
- Bid/Askを正しく使い分ける
- 最小距離+スプレッドを確保する
- NormalizeDoubleで価格を正規化する
- 注文前チェックを必須化する
これらは単体ではなく「セット」で機能します。
どれか1つ欠けると、環境によって破綻します。
7.2 実装フローの最適形
【結論】
実務では以下の順序で処理を統一すると安定します。
実装フロー:
- 現在価格取得(Bid/Ask)
- ストップレベル取得
- スプレッド取得
- SL/TP計算
- 正規化(NormalizeDouble)
- 距離チェック
- OrderSend
この順番を崩すと、微妙なズレが発生します。
特に重要:
- 計算 → 正規化 → チェック の順序
- チェック後に値を変更しない
7.3 再現性を高めるための考え方
【結論】
EAの品質は「エラーを出さないこと」ではなく「同じ条件で同じ結果になること」です。
invalid stopsが問題になる理由:
- 注文失敗でトレード機会を失う
- バックテストと実運用の乖離が発生する
- パフォーマンス(PF)が歪む
つまりこれは単なるエラーではなく、期待値に直結する問題です。
対策の本質:
- execution条件をロジックに組み込む
- ブローカー依存を前提にする
- 環境変動(spread・slippage)を考慮する
7.4 よくある誤解
【結論】
invalid stopsは「たまに起きる不可避の問題」ではありません。
誤解例:
- テスターで問題ないからOK
- 一部口座で通るから問題ない
- リトライすれば解決する
実際には:
- テスターは簡略化環境
- ブローカーごとに条件が異なる
- リトライは根本対策ではない
したがって、設計段階で潰すべき問題です。
7.5 実務での最終チェック
【結論】
実運用前に、以下を満たしていれば安全性は高いです。
最終確認:
- 異なるブローカーでテスト済み
- デモ口座でフォワード確認済み
- スプレッド拡大時も正常動作
- ログで全条件を確認できる
これにより、環境差による不具合を最小化できます。
7.6 実装者への指針
【結論】
invalid stops対策は「例外処理」ではなく「標準機能」として組み込むべきです。
実務ルール:
- SL/TP生成は必ず関数化する
- 注文前チェックは全EA共通化する
- 固定値ロジックは排除する
- ログ出力を標準化する
このレベルまで整理すると、EAの品質は一段上がります。
8. よくある質問
【結論】
invalid stopsは「ストップ価格がブローカー条件を満たしていない」ときに発生します。
実務では、StopLevel・Bid/Ask・価格精度の確認で大半を防げます。
8.1 invalid stopsとは何ですか
【結論】
invalid stopsとは、設定したストップロス(SL)やテイクプロフィット(TP)が不正で、注文条件に合っていない状態です。
具体的には、次のようなケースで発生します。
- 現在価格に近すぎる
- 価格の向きが逆
- 桁数が合っていない
- ブローカーの最小距離に違反している
つまり、単なる「MQL5の文法エラー」ではなく、「注文条件エラー」です。
8.2 StopLevelはどこで取得できますか
【結論】
StopLevelは SymbolInfoInteger で取得できます。
基本コードは次のとおりです。
int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double minDistance = stopLevel * _Point;
注意点:
- 値はポイント単位で返る
- 実際の価格差に使うには
_Pointを掛ける - symbolごと、brokerごとに異なる
この値を取らずに固定値でSL/TPを置くと、invalid stopsの原因になります。
8.3 なぜバックテストでは問題ないのに本番でエラーが出るのですか
【結論】
ストラテジーテスターは、実際のexecution環境を完全には再現しないためです。
本番との差は主に次のとおりです。
- spreadが固定または単純化される
- slippageが実環境ほど出ない
- 約定遅延が小さい
- broker固有の挙動が反映されにくい
そのため、バックテストで通ったコードでも、リアル口座やデモ口座ではinvalid stopsが出ることがあります。
8.4 SLやTPを付けずに注文すれば回避できますか
【結論】
一時的な回避は可能ですが、根本解決ではありません。
たしかに、ECN口座などでは以下の流れが有効な場合があります。
- まず成行注文だけ出す
- 約定後にSL/TPを後付けする
ただし、この方法にも注意点があります。
- フリーズレベルで変更できないことがある
- 約定直後の価格変動で失敗することがある
- リスク管理上、保護なし時間が発生する
したがって、これは「代替手段」であり、基本は事前チェック付きの設計が推奨です。
8.5 BuyとSellでSL/TPの計算は何が違いますか
【結論】
基準価格と方向が逆になります。
基本ルールは次のとおりです。
- Buy
- SLは現在価格より下
- TPは現在価格より上
- Sell
- SLは現在価格より上
- TPは現在価格より下
また、実装時には以下の点が重要です。
- BuyではBid基準で確認する
- SellではAsk基準で確認する
ここを間違えると、距離が足りていてもinvalid stopsになることがあります。
8.6 NormalizeDoubleは必須ですか
【結論】
はい、価格を注文に使う前にほぼ必須です。
理由は、double計算では内部的に微小な誤差が残ることがあるためです。
見た目は正しくても、broker側では不正な価格と判定されることがあります。
基本形は次のとおりです。
sl = NormalizeDouble(sl, _Digits);
tp = NormalizeDouble(tp, _Digits);
ただし、NormalizeDoubleだけでは不十分です。
StopLevelやspreadを無視していれば、正規化してもinvalid stopsは防げません。
8.7 spreadはどの程度考慮すべきですか
【結論】
最低でも、最小距離に現在のspreadを加味する設計が安全です。
たとえば次のように計算します。
double spread = ask - bid;
double safeDistance = minDistance + spread;
さらに、指標時や早朝など変動が大きい時間帯では、少し余裕を持たせる設計も有効です。
minDistance + spreadminDistance * 1.2minDistance + spread + α
どこまで余裕を取るかは、手法の性質とリスク許容度によります。
8.8 invalid stopsを最短で直すには何を見ればよいですか
【結論】
最短で直すには、まず「価格方向」「最小距離」「桁数」の3点を確認します。
優先順は次のとおりです。
- SL/TPの向きが正しいか
- StopLevel以上の距離があるか
- NormalizeDoubleしているか
- Bid/Askを正しく使っているか
- spread拡大時でも成立するか
この順で確認すると、ほとんどのケースで原因を特定できます。
9. invalid stopsと合わせて見直すべき関連項目
【結論】
invalid stopsは単独の問題ではなく、「注文処理全体の設計不備」の一部です。
同時に他の注文エラーや実行条件(execution条件)も見直すことで、EAの安定性と期待値が大きく向上します。
9.1 not enough money(証拠金不足)
【結論】
invalid stopsと同様に頻発するのが「not enough money」であり、ロットサイズと証拠金管理の問題です。
発生原因:
- ロットが口座残高に対して大きすぎる
- レバレッジ設定を考慮していない
- 複数ポジションで証拠金が圧迫されている
対策:
double freeMargin = AccountInfoDouble(ACCOUNT_FREEMARGIN);
重要ポイント:
- 注文前に必要証拠金を計算する
- ロットサイズを動的に調整する
- DD(ドローダウン)を前提に設計する
invalid stopsと同様、「事前チェック」で防ぐべきエラーです。
9.2 requote(再提示)
【結論】
requoteは価格変動により、提示価格で約定できない場合に発生します。
原因:
- 市場の急変(指標、ニュース)
- slippage許容値が小さい
- execution方式の影響
対策:
request.deviation = 10; // 許容スリッページ
補足:
- deviationを広げると約定率は上がる
- ただし価格のズレ(slippage)は増える
これは「約定優先か価格精度優先か」のトレードオフです。
9.3 off quotes / trade disabled
【結論】
市場が停止している、または取引不可の状態でも注文は失敗します。
典型例:
- 週末
- ロールオーバー直後
- broker側の制限
対策:
bool tradeAllowed = (bool)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE);
確認すべき点:
- 取引可能状態か
- セッション時間内か
- シンボルが有効か
これを無視すると、EAが「動いているのに取引しない」状態になります。
9.4 slippage(スリッページ)の設計
【結論】
slippageは避けるものではなく、「制御する対象」です。
影響:
- 約定価格がズレる
- SL/TP距離が変化する
- invalid stopsの間接原因になる
設計方針:
- 固定値ではなく、相場状況に応じて調整
- 指標時は許容値を広げる
- 平常時は狭める
例:
request.deviation = dynamicDeviation;
ここを固定にすると、約定率と価格精度のバランスが崩れます。
9.5 execution方式の違い
【結論】
execution方式(Market / Instant / Exchange)により、注文挙動は変わります。
主な違い:
| 方式 | 特徴 |
|---|---|
| Market Execution | 即時約定、価格変動あり |
| Instant Execution | 価格固定、requote発生 |
| Exchange Execution | 取引所ベース |
invalid stopsとの関係:
- Marketは価格ズレ → 距離不足になりやすい
- Instantは価格固定 → requoteになりやすい
対策:
- 口座仕様に合わせた設計
- 同一EAでも環境別チューニング
9.6 ロットサイズとリスク管理
【結論】
注文エラー対策は「ロット設計」とセットで考える必要があります。
理由:
- ロットが大きいほどエラーの影響が大きい
- DD時に証拠金不足と連鎖する
- execution失敗が期待値に直結する
実務設計:
- 口座残高に対する%ベース
- ボラティリティに応じた調整
- 最大ポジション数の制限
例:
double riskPercent = 0.01; // 1%
9.7 統合的な注文管理設計
【結論】
invalid stops対策は「注文管理モジュール」の一部として統合するべきです。
統合設計例:
- SL/TP生成モジュール
- 注文前チェックモジュール
- エラーハンドリングモジュール
- ログ出力モジュール
これにより:
- バグの局所化
- 再利用性向上
- EA全体の安定性向上
重要な視点:
- 個別対応ではなく構造対応
- エラーを「設計で吸収」する
9.8 実務における優先順位
【結論】
すべてを一度に対応する必要はなく、優先順位を付けることが重要です。
推奨順:
- invalid stops(基本条件)
- not enough money(資金管理)
- slippage / requote(execution)
- 取引可否チェック(環境)
この順番で整備すると、効率的に安定性が向上します。
10. 安定したEAを構築するための注文処理テンプレート
【結論】
EAの安定性は「注文処理のテンプレート化」で決まります。
invalid stopsを含むすべての注文エラーは、統一された処理フローで大幅に削減できます。
10.1 注文処理の基本構造
【結論】
注文処理は「取得 → 計算 → 検証 → 実行 → ログ」の5段階で設計します。
標準フロー:
- 市場情報取得(Bid / Ask / spread)
- パラメータ取得(StopLevel / Digits)
- SL/TP計算
- 注文前チェック
- OrderSend実行
- 結果ログ出力
この構造を崩さないことが最重要です。
10.2 テンプレートコード(基本形)
【結論】
以下のテンプレートをベースにすれば、invalid stopsを含む多くのエラーを回避できます。
bool ExecuteOrder(bool isBuy)
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double price = isBuy ? ask : bid;
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double minDistance = stopLevel * _Point;
double spread = ask - bid;
double safeDistance = minDistance + spread;
double sl, tp;
if(isBuy)
{
sl = bid - safeDistance;
tp = bid + safeDistance;
}
else
{
sl = ask + safeDistance;
tp = ask - safeDistance;
}
sl = NormalizeDouble(sl, digits);
tp = NormalizeDouble(tp, digits);
// チェック
if(!IsValidStops(isBuy, sl, tp))
{
Print("Invalid stops detected");
return false;
}
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.1;
request.type = isBuy ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
request.price = price;
request.sl = sl;
request.tp = tp;
request.deviation = 10;
if(!OrderSend(request, result))
{
Print("OrderSend failed: ", result.retcode);
return false;
}
return true;
}
重要ポイント:
- すべての処理を1つの流れに統合
- エラー発生前に検証
- ログを残す
10.3 モジュール分割による設計
【結論】
処理を分割することで、保守性と再利用性が大幅に向上します。
推奨構成:
- GetMarketInfo()
- CalculateStops()
- ValidateStops()
- ExecuteTrade()
例:
double CalculateSL(bool isBuy, double distance)
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(isBuy)
return bid - distance;
else
return ask + distance;
}
メリット:
- ロジックの分離
- テストしやすい
- バグの影響範囲が限定される
10.4 ログ設計のテンプレート
【結論】
ログは「再現性確保」のための必須要素です。
Print("Symbol:", _Symbol);
Print("Bid:", bid, " Ask:", ask);
Print("SL:", sl, " TP:", tp);
Print("StopLevel:", stopLevel, " Spread:", spread);
設計ポイント:
- 必ず数値を出す
- 失敗条件もログに残す
- 時系列で追えるようにする
これにより、問題発生時の原因特定が高速化します。
10.5 拡張設計(実務向け)
【結論】
実務では、さらに以下の要素を追加します。
拡張要素:
- 動的ロット計算(リスクベース)
- スプレッドフィルター(閾値以上は取引停止)
- 時間フィルター(指標・ロールオーバー回避)
- リトライ処理(例外時のみ)
例:
if(spread > maxSpread)
{
Print("Spread too high");
return false;
}
これにより:
- 無駄なトレードを削減
- リスク低減
- 安定運用が可能
10.6 実務での評価基準
【結論】
EAの注文処理は「動くか」ではなく「安定して動き続けるか」で評価します。
評価指標:
- エラー発生率
- 約定成功率
- ログの可読性
- 再現性(バックテスト vs 実運用)
特に重要:
- invalid stopsがゼロに近い状態
- 注文失敗時も制御されている
10.7 最終的な設計思想
【結論】
注文処理は「個別対応」ではなく「標準化されたインフラ」として構築するべきです。
重要な考え方:
- エラーは発生する前に防ぐ
- 環境依存を前提にする
- execution条件をロジックに組み込む
このレベルで設計できると、EAの品質は大きく向上します。