1. MQL5の「trade context busy」とは何か
1.1 エラーの意味(trade context busy)
「trade context busy」は、MQL5でトレード処理(注文・決済など)がすでに実行中で、新しい注文を受け付けられない状態を意味するエラーです。
より正確に言うと、MetaTrader内部には「トレードコンテキスト」と呼ばれる処理領域があり、ここは同時に1つのトレード操作しか実行できない仕様になっています。
そのため、以下のような状況になるとエラーが発生します。
- 注文処理がまだ完了していない
- サーバーからの応答待ち状態
- 別の注文が直前に送信されている
初心者向けに簡単に言い換えると、
「まだ前の注文が終わっていないのに、次の注文を出してしまった」状態です。
1.2 どの場面で発生するか
このエラーは、主に以下の関数を使う場面で発生します。
OrderSend()(注文送信)OrderSendAsync()(非同期注文)- ポジション決済・変更処理
特に発生しやすいのは以下のケースです。
- OnTick内で条件成立ごとに連続注文している
- ループ処理で短時間に複数注文を送っている
- 高速EA(スキャルピング系)を使用している
- 複数EAが同じ口座で同時に動いている
例(危険なパターン):
void OnTick()
{
if(条件)
{
OrderSend(request, result);
OrderSend(request, result); // 連続実行 → エラーになりやすい
}
}
このように、処理完了を待たずに連続実行すると高確率で発生します。
1.3 初心者向けの直感理解
このエラーは、プログラムの問題というよりも処理の順番管理ミスです。
イメージとしては以下の通りです。
- レジが1つしかないのに
- お客が同時に2人並ばずに「割り込んで」会計しようとする
→ 結果:処理が混雑(busy)して拒否される
つまりMQL5では、
- トレード処理 = シングルスレッド(同時1件)
- 注文 = キュー処理(順番待ちが必要)
という前提を理解することが重要です。
つまずきやすいポイント・注意点
- 「回線が悪いからエラー」と誤解しがち(実際はロジック問題が多い)
- Sleepなしで高速実行すると発生しやすい
- バックテストでは再現しにくく、リアル環境で初めて出るケースが多い
OrderSendAsyncなら回避できると誤解(むしろ悪化する場合あり)
よくある失敗
- エラーを無視してそのまま運用
- ログを確認せず原因を特定しない
- 「たまたま」と判断して放置(再発率が高い)
- EAを複数稼働させて競合を起こす
2. 主な原因(発生メカニズムを理解する)
このセクションで書く要点:
trade context busyは「偶然のエラー」ではなく、明確な構造(トレード処理の排他制御)に基づいて発生する。原因を分解し、再現性のある理解にする。
2.1 同時注文(連続OrderSend)
最も多い原因は、短時間に複数の注文を連続送信していることです。
MQL5では、1回の注文処理が完了するまで、次の注文は受け付けられません。
しかし、以下のようなコードでは連続送信が発生します。
void OnTick()
{
if(買い条件)
OrderSend(request, result);
if(別の条件)
OrderSend(request, result);
}
この場合、1つ目の注文がまだ処理中でも2つ目が実行され、
結果として「busy」になります。
注意点
- 条件が複数成立する設計は非常に危険
- 特にスキャルピングEAで発生しやすい
2.2 非同期処理の誤用(OrderSendAsync)
OrderSendAsync()は「非同期(待たずに次へ進む)」関数です。
一見高速化できるように見えますが、実際には以下の問題があります。
- 処理完了を待たない
- 状態管理が必要になる
- 連続送信が発生しやすい
OrderSendAsync(request, result);
OrderSendAsync(request, result); // 高確率で競合
初心者の誤解
- 「Asyncなら速い=安全」ではない
- 実際は制御しないとエラーを増やす
2.3 複数EA・スクリプトの競合
同一口座で複数EAを動かすと、
異なるEA同士が同時に注文を送る可能性があります。
例:
- EA①:エントリー
- EA②:決済
- EA③:ロット調整
これらが同時に動くと、
→ トレードコンテキストを奪い合う
→ busy発生
重要ポイント
- MQL5の制御は「口座単位」
- EA単位では分離されていない
2.4 ブローカー・サーバー遅延
注文はローカルで完結せず、ブローカーサーバーとの通信が発生します。
そのため以下の要因で遅延が起こります。
- VPSの品質
- 回線速度
- サーバー負荷
- 約定処理の遅延
この間、トレードコンテキストは「占有状態」になります。
結果
- 次の注文 → busy
補足
- 環境により発生頻度は変動する
- 特に海外ブローカーで顕著なケースあり
2.5 トレード処理のロック状態
MQL5内部では、トレード処理中にロック(排他制御)がかかります。
このロックは以下で解放されます。
- 注文完了
- エラー返却
- サーバー応答完了
しかし、以下の場合は長時間ロックされることがあります。
- 約定待ち
- 再試行処理中
- サーバー応答遅延
この状態で新しい注文を送ると、確実にbusyになります。
つまずきやすいポイント・注意点
- 「自分のEAだけ動いている」と思い込みがち(他EAが原因のことが多い)
- テスト環境では問題なく、本番でだけ発生
- 通信遅延を考慮していない設計
- 非同期処理を理解せず使用
よくある失敗
- OnTickで条件成立ごとに即OrderSend
- フラグ管理なし
- Sleepなし高速ループ
- EAを複数起動して干渉
- エラー処理を実装していない
3. 最短で解決する方法(実装ベース)
このセクションで書く要点:
trade context busyは設計で防げる。まずは「確実に効く対処」を優先し、再現性のある実装パターンを提示する。
3.1 基本対策①:処理間に待機(Sleep)
最もシンプルかつ即効性がある対策は、注文間に待機時間を入れることです。
void OnTick()
{
if(条件)
{
OrderSend(request, result);
Sleep(500); // 500ミリ秒待機
}
}
ポイント
- 目安:300〜1000ms(環境により調整)
- VPSやブローカーによって最適値は変わる
メリット
- 実装が簡単
- 即効でエラーが減る
デメリット
- 過剰に入れると機会損失(特にスキャル)
- 根本解決ではない
3.2 基本対策②:フラグ管理(再入防止)
最も重要な対策がこれです。
「注文中は次の注文を出さない」状態を作ります。
bool isTrading = false;
void OnTick()
{
if(isTrading) return;
if(条件)
{
isTrading = true;
if(OrderSend(request, result))
{
// 成功
}
isTrading = false;
}
}
ポイント
- フラグで排他制御(同時実行防止)
- ほぼ全EAで必須
注意点
- エラー時もフラグ解除すること
- 解除漏れ → EA停止バグ
3.3 基本対策③:注文結果を必ず確認する
OrderSendの結果を無視すると、状態管理が崩れます。
MqlTradeResult result;
if(OrderSend(request, result))
{
Print("注文成功");
}
else
{
Print("エラーコード: ", GetLastError());
}
重要
- 成功・失敗を必ず分岐
- ログ出力は必須(デバッグ)
3.4 基本対策④:トレード可能状態を確認
注文前に「今トレードできるか」を確認します。
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
{
return;
}
または
if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
{
return;
}
効果
- 無駄な注文送信を防止
- エラー頻度を低減
3.5 実務で推奨される組み合わせ(テンプレ)
実務では以下の組み合わせが安定します。
bool isTrading = false;
void OnTick()
{
if(isTrading) return;
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
return;
if(条件)
{
isTrading = true;
if(OrderSend(request, result))
{
Print("注文成功");
}
else
{
Print("エラー: ", GetLastError());
}
Sleep(300);
isTrading = false;
}
}
つまずきやすいポイント・注意点
- Sleepだけに頼る(設計的に不十分)
- フラグ解除忘れ → EA停止
- エラー時の分岐未実装
- VPS遅延を考慮していない
よくある失敗
- 「とりあえずSleep」で終わる
- Async+Sleepの併用(逆に不安定)
- 複数EAで同じ口座を共有
- ログを見ないまま運用
4. 実装例(コピペ対応コード)
4.1 シンプルな回避コード(Sleepを入れる)
まずは最小構成です。
連続注文の間に待機時間を入れて、トレード処理の競合を避けます。
void SendBuyOrder()
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.10;
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.deviation= 10;
request.magic = 123456;
if(OrderSend(request, result))
{
Print("注文成功: ", result.order);
Sleep(500);
}
else
{
Print("注文失敗: ", GetLastError());
}
}
使いどころ
- まずエラー頻度を下げたいとき
- 検証用EAをすぐ安定化したいとき
注意点
Sleep()は応急処置です- 高頻度売買では待機時間が長すぎると不利になる場合があります
4.2 リトライ付きOrderSend実装
実務では、1回失敗しただけで終了させるより、少し待って再試行したほうが安定しやすいです。
bool SendBuyOrderWithRetry(int max_retry = 3, int wait_ms = 500)
{
for(int i = 0; i < max_retry; i++)
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.10;
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.deviation = 10;
request.magic = 123456;
if(OrderSend(request, result))
{
Print("注文成功: ", result.order);
return true;
}
int err = GetLastError();
Print("注文失敗(", i + 1, "/", max_retry, ") err=", err);
Sleep(wait_ms);
}
return false;
}
ポイント
- 失敗しても即終了しない
- 通信遅延や一時的競合に強くなる
つまずきやすい点
- 無制限リトライは危険です
- 最大回数を決めずに回すと、無限ループ化しやすくなります
4.3 フラグ管理による制御
trade context busy対策で最も重要なのは、注文中フラグで再入を防ぐことです。
bool isTrading = false;
void OnTick()
{
if(isTrading) return;
if(買い条件)
{
isTrading = true;
bool ok = SendBuyOrderWithRetry();
if(!ok)
{
Print("注文最終失敗");
}
isTrading = false;
}
}
重要
isTrading = false;の解除漏れに注意- 途中で
return;するとフラグが戻らない実装は危険です
4.4 OnTickでの安全な実装パターン
OnTickでは、毎ティック注文しない構造にするのが基本です。
datetime last_trade_time = 0;
bool isTrading = false;
void OnTick()
{
if(isTrading) return;
if(TimeCurrent() - last_trade_time < 2)
return;
if(買い条件)
{
isTrading = true;
if(SendBuyOrderWithRetry())
{
last_trade_time = TimeCurrent();
}
isTrading = false;
}
}
このように、フラグ管理+最小間隔制御を組み合わせると、busyの再発率は大きく下がります。
よくある失敗
ZeroMemory()を入れず、前回の値が残るOnTick()で毎回注文条件を通してしまうSleep()だけで解決したと思い込む- リトライ回数を増やしすぎて逆に遅くなる
5. よくある失敗(重要)
5.1 無限ループで連続注文してしまう
trade context busyで最も危険なのは、失敗したらすぐ再注文する無限ループです。
while(true)
{
if(OrderSend(request, result))
break;
}
一見すると「通るまで注文する」安全策に見えますが、実際には逆です。
注文処理がまだ終わっていない間に何度も再送するため、busyをさらに悪化させます。
問題点
- トレードコンテキストを埋め続ける
- CPU負荷が上がる
- EA全体が不安定になる
対策
- 最大試行回数を決める
- 各試行の間に待機時間を入れる
for(int i = 0; i < 3; i++)
{
if(OrderSend(request, result))
break;
Sleep(500);
}
5.2 Sleepなし高速EA
スキャルピング系や短期売買EAで多いのが、高速でOnTickが回るのに待機処理がないケースです。
void OnTick()
{
if(条件)
{
OrderSend(request, result);
}
}
このコード自体は文法的に問題ありません。
ただし実運用では、ティックが連続して来るため、同じ条件で連続注文が発生しやすくなります。
つまずきやすい点
- バックテストでは正常に見える
- 実口座・VPS環境でだけbusyが出る
対策
Sleep()を補助的に入れる- 注文間隔制御を導入する
- 1ティックごとではなく、状態変化ごとに注文する
5.3 複数EAの同時運用
同一口座・同一端末で複数EAを動かしていると、自分のEAが正しくてもbusyが発生することがあります。
例:
- EA A が買い注文
- EA B が決済注文
- EA C がストップ更新
これらが同時刻付近に動けば、競合が起こります。
よくある誤解
- 「このEAは単独でテストしたから問題ない」
- 実際は本番環境で他EAと干渉している
対策
- 口座単位でEAの役割を整理する
- 複数EAを同時稼働させる場合は注文タイミングを分離する
- 可能なら統合EAに寄せる
5.4 エラーを無視してログを見ない
OrderSend()が失敗しても、ログを出していないと原因が見えません。
OrderSend(request, result);
この書き方だけでは、何が起きたか分かりません。
結果として、
- busyなのか
- volumeエラーなのか
- 市場クローズなのか
を切り分けられなくなります。
最低限必要な実装
if(!OrderSend(request, result))
{
Print("OrderSend失敗 err=", GetLastError());
}
注意点
- ExpertsタブだけでなくJournalタブも確認する
- 「たまに出る」エラーほど記録が重要
5.5 OrderSendAsyncの誤用
OrderSendAsync()は便利そうに見えますが、状態管理を理解せず使うと失敗率が上がります。
非同期とは、処理完了を待たずに次へ進む方式です。
そのため、以下のようなコードは危険です。
OrderSendAsync(request1, result1);
OrderSendAsync(request2, result2);
これでは、1件目の処理中に2件目を投げる可能性があります。
初心者がハマりやすい点
- 「Async = 高速で優秀」と考える
- 実際は「制御責任が自分側に増える」
対策
- 初学段階では
OrderSend()を優先 - 非同期を使う場合は状態遷移設計を入れる
5.6 フラグ解除漏れ
排他制御でフラグを使うのは有効ですが、解除漏れがあると別の重大なバグになります。
isTrading = true;
if(!OrderSend(request, result))
{
return; // ここで終了するとフラグが戻らない
}
isTrading = false;
このコードでは、注文失敗時に isTrading が true のまま残る可能性があります。
その結果、以後一切注文しないEAになります。
対策
- 失敗時も必ず解除する
- 処理終了位置を統一する
つまずきやすいポイント・注意点
- エラー対策のつもりが別の停止バグを作りやすい
- busyは単独原因ではなく、複数要因が重なることが多い
- 「1回だけ出たから無視」で済ませない
6. 実務での対策(再発防止)
6.1 トレード制御フラグを設計として入れる
trade context busyを安定して減らすには、その場しのぎのSleepだけでなく、EAの設計段階で「同時注文しない仕組み」を入れることが重要です。
最も基本になるのは、注文中フラグです。
bool isTrading = false;
bool SafeSendOrder(MqlTradeRequest &request, MqlTradeResult &result)
{
if(isTrading)
return false;
isTrading = true;
bool ok = OrderSend(request, result);
isTrading = false;
return ok;
}
このように、注文関数そのものをラップ(包む)しておくと、
EA全体で再利用しやすくなります。
実務上の利点
- 注文処理の入口を1か所に集約できる
- 仕様変更時の修正範囲が小さくなる
- うっかり連続OrderSendを書く事故を減らせる
注意点
- 失敗時・例外的な分岐でも必ずフラグを戻す
- 関数を複数作る場合、共通化しないと制御がばらける
6.2 注文キューの概念を入れる
複数条件から注文が発生するEAでは、条件が出た瞬間に即注文する設計がbusyの温床になります。
この場合は、注文を一度キュー的にためて、順番に1件ずつ処理する考え方が有効です。
初心者向けに簡略化すると、以下のような流れです。
- シグナル判定は行う
- ただしその場で即注文しない
- 「注文予定あり」という状態だけ保存する
- 実際の注文は専用処理で1件ずつ送る
簡易例:
bool buySignalPending = false;
void OnTick()
{
if(買い条件)
buySignalPending = true;
ProcessTradeQueue();
}
void ProcessTradeQueue()
{
if(isTrading) return;
if(!buySignalPending) return;
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.10;
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.deviation = 10;
request.magic = 123456;
isTrading = true;
if(OrderSend(request, result))
{
buySignalPending = false;
Print("買い注文成功");
}
else
{
Print("買い注文失敗 err=", GetLastError());
}
isTrading = false;
}
ポイント
- 判定と発注を分ける
- 発注処理を1本化する
- シグナルが重なっても処理が崩れにくい
6.3 EAごとの役割を分離する
複数EAが同じ口座で動く場合、busyの原因はコード品質だけでなく、役割設計の悪さであることも多いです。
危険な構成例:
- EA A:エントリー
- EA B:ナンピン
- EA C:利確・決済
- EA D:ストップ調整
この構成では、相場急変時に各EAが同時に注文・変更を出しやすくなります。
実務では、次のどちらかに寄せると安定しやすいです。
- A案:統合EA化する
1本のEAでエントリーから決済まで管理する - B案:責務分離を明確にする
例えば「注文を出すEAは1本だけ」に固定する
判断基準
- シンプルさ重視なら統合EA
- 大規模設計なら責務分離+中央制御
よくある失敗
- 便利だからと機能別EAを増やす
- 口座全体の排他制御を考えずに運用する
6.4 VPS・通信環境を最適化する
trade context busyはロジック要因が中心ですが、
通信遅延が発生頻度を押し上げることもあります。
特に見直すべき点は以下です。
- VPSの設置場所(ブローカーサーバーに近いか)
- VPSの負荷(CPU・メモリ不足がないか)
- 回線の安定性
- 同時稼働しているMT5端末数
通信遅延が大きいと、1注文あたりの処理時間が伸びます。
その結果、次の注文がぶつかりやすくなります。
確認ポイント
- 約定までの体感時間が長くないか
- Journalに通信系エラーが混ざっていないか
- VPS上で不要なEAや端末を動かしていないか
重要
- VPS改善だけで根本解決はしない
- ただし設計が適正でも、環境が悪いとbusyは増える
6.5 注文頻度そのものを下げる
busy対策として見落とされやすいのが、そもそも注文を出しすぎていないかという視点です。
以下のような条件を入れると、無駄な注文を減らせます。
- 前回注文から数秒以内は新規注文しない
- 同一バー内では1回まで
- 同一方向ポジション保有中は追加注文しない
- スプレッド拡大時は注文しない
例:
datetime lastOrderTime = 0;
bool CanSendNewOrder()
{
if(TimeCurrent() - lastOrderTime < 3)
return false;
return true;
}
これだけでも、実運用でのbusy発生率は大きく下がる場合があります。
つまずきやすいポイント・注意点
- Sleepだけを入れて「対策完了」と判断しやすい
- EA単体最適で考え、口座全体の競合を見落としやすい
- 注文判定ロジックと発注ロジックが混在し、修正が難しくなりやすい
よくある失敗
- 発注関数が複数箇所に散らばる
- 条件判定のたびに直接OrderSendする
- VPS改善だけで直そうとする
- 複数EA構成のまま責任境界を決めない
7. パフォーマンスと設計視点(中級者向け)
7.1 trade contextの仕組みをどう捉えるべきか
実務では、trade context busy を単なる一時エラーではなく、「注文処理の直列化に失敗しているサイン」として扱うのが有効です。
MQL5では、注文送信は OrderSend() または OrderSendAsync() で行い、その後の結果や状態変化は OnTrade() や OnTradeTransaction() で受け取れます。しかも 1回のリクエストが複数の取引イベントに分かれて到着することがあり、到着順も固定ではありません。 そのため、「注文を送った直後に次の状態が必ずこうなる」と決め打ちした実装は崩れやすいです。(MQL5)
ここで重要なのは、注文送信と約定完了を同じ瞬間の出来事として扱わないことです。
特に OnTradeTransaction() は、取引要求の結果処理向けのイベントハンドラであり、EA側で状態遷移を管理する前提に向いています。(MQL5)
7.2 同時注文制御のベストプラクティス
設計上は、以下の順で制御するのが再現性が高いです。
- 注文判定
- 送信許可判定
- 送信中フラグON
- 注文送信
- 結果イベント受信後に状態更新
- 送信中フラグOFF
つまり、OnTick() の中で全部を完結させようとせず、送信と結果反映を分離します。
MQL5公式ドキュメントでも、1つのリクエストが複数イベントを生み、OnTrade() だけでは「1リクエスト=1イベント」とは見なせないと明示されています。(MQL5)
簡易イメージは以下です。
bool trade_pending = false;
void OnTick()
{
if(trade_pending) return;
if(エントリー条件)
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.10;
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.deviation = 10;
request.magic = 123456;
trade_pending = true;
if(!OrderSend(request, result))
{
Print("OrderSend failed: ", GetLastError());
trade_pending = false;
}
}
}
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
trade_pending = false;
}
この形の利点は、ティック連打と約定処理を分離できることです。
7.3 高頻度EAでの設計注意点
OrderSendAsync() は、サーバー応答を待たずに非同期で送信するため、高頻度取引向けの関数です。
ただし、これは「簡単に速くなる関数」ではありません。公式にも高頻度取引向けとされていますが、非同期化した分だけ、状態管理の責任がEA側に増えます。 送信後の結果はイベントで追う必要があり、制御を誤るとbusy系の競合や重複注文を増やしやすくなります。(MQL5)
高頻度EAで特に注意すべき点は以下です。
OnTick()ごとに即送信しない- 送信済みリクエストIDや状態を保持する
- 約定確認前に同方向の追加注文を許さない
OnTradeTransaction()ベースで状態遷移する
よくある失敗
OrderSendAsync()を入れただけで高速化完了と思う- 応答待ちを消した代わりに、重複送信を増やしてしまう
OnTrade()だけで全状態を追おうとして取りこぼす
7.4 Sleep依存設計から卒業する
Sleep() は短期対処として有効ですが、設計の中心に置くべきではありません。
公式ドキュメント上、Sleep はプログラムを一時停止する時間制御の一手段ですが、これで取引状態の整合性が保証されるわけではありません。テスターや実環境では時間の進み方・イベントの入り方も異なるため、「500ms待ったから安全」とは限りません。(MQL5)
そのため、中級者以上では次の発想に切り替えるべきです。
- 時間待ちではなく状態待ち
- 再送ではなくイベント確認
- その場しのぎではなく注文ライフサイクル管理
実務では、Sleep() は補助、主役は 状態フラグ・イベント処理・注文間隔制御 です。
7.5 性能最適化の考え方
busy系エラーを減らす最適化は、CPU最適化よりも先に、注文回数の削減と注文経路の一本化を優先したほうが効果が出やすいです。
具体的には次の順で改善すると効率的です。
- 同一バー内の重複注文を禁止する
- ポジション保有中の追加発注条件を見直す
- 発注関数を1か所に集約する
- 送信結果をイベントで反映する
- 必要な場合のみ
OrderSendAsync()を使う
この順番にする理由は、trade context busy の多くが演算性能不足ではなく、注文設計の競合だからです。
MQL5では、取引イベントが段階的に発生し得る以上、「軽いコード」より「矛盾しない状態管理」のほうが重要です。(MQL5)
つまずきやすいポイント・注意点
OnTick()だけで完結させようとすると設計が破綻しやすいOnTrade()とOnTradeTransaction()の役割差を理解しないと状態がずれる- 非同期化は高速化であって、簡略化ではない
Sleep()は環境差を吸収しきれない
よくある失敗
- イベント処理を使わず、送信直後の変数だけで約定管理する
- リクエストごとの状態を持たない
- 重複注文防止を時間待ちだけで実装する
- 高頻度EAで
OrderSendAsync()を使いながら結果追跡を省略する
8. 類似エラーとの違い(混同防止)
このセクションで書く要点:trade context busyは「処理競合」のエラー。他の注文エラーと原因が根本的に異なるため、誤診すると対策が外れる。主要エラーを分類して切り分け基準を明確化する。
8.1 trade context busy vs requote
違いの本質
| エラー | 原因 | 対象 |
|---|---|---|
| trade context busy | 処理競合(内部ロック) | EA側の設計 |
| requote | 価格変動 | 市場・ブローカー |
requoteとは
- 注文価格がズレたため再提示される現象
- 主に高速相場・スプレッド変動時に発生
request.deviation = 10; // 許容スリッページ
重要ポイント
- requoteは「価格問題」
- busyは「処理問題」
→ 対策は完全に別物
8.2 trade context busy vs trade disabled
違いの本質
| エラー | 原因 |
|---|---|
| trade context busy | 処理中 |
| trade disabled | 取引禁止状態 |
trade disabledが発生するケース
- 市場クローズ
- 自動売買OFF
- ブローカー制限
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
{
Print("トレード禁止状態");
}
重要
- busyは「待てば通る可能性あり」
- disabledは「そもそも不可能」
8.3 trade context busy vs invalid volume
違いの本質
| エラー | 原因 |
|---|---|
| trade context busy | タイミング問題 |
| invalid volume | パラメータ不正 |
invalid volumeの例
- 最小ロット未満
- ロットステップ違反
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
重要
- busyは「タイミング制御」
- volumeエラーは「数値チェック」
8.4 trade context busy vs no connection
違いの本質
| エラー | 原因 |
|---|---|
| trade context busy | 内部処理 |
| no connection | 通信断 |
no connectionの特徴
- サーバー未接続
- VPS停止
- 回線障害
判別方法
- Journalに接続ログが出る
- Pingが異常
8.5 実務での切り分け手順
エラー対応で重要なのは、1回で原因を特定することです。
推奨手順:
① ログ確認
Print("err=", GetLastError());
② エラー種別を分類
- busy → 設計見直し
- requote → deviation調整
- disabled → 環境確認
- volume → 数値修正
③ 再現性を確認
- 毎回出る → ロジック問題
- たまに出る → タイミング or 環境
つまずきやすいポイント・注意点
- busyを通信エラーと誤認
- requoteと混同
- すべてSleepで解決しようとする
- ログを見ずに推測で修正
よくある失敗
- エラーコードを見ない
- 原因別に対策を分けない
- busy対策にロット調整をする(無意味)
- 複数エラーが混在しているのに1つしか見ない
9. FAQ(よくある質問)
このセクションで書く要点:
初心者が実際に詰まるポイントを短時間で解決できるように、原因→対処の最短ルートで整理する。
Q1. trade context busyは無視しても大丈夫ですか?
回答方針:
無視は非推奨。単発なら致命的ではないが、頻発する場合はEAの設計不備。
解説:
一時的に発生するだけなら大きな問題にならないこともありますが、
頻発する場合は以下のリスクがあります。
- 注文機会の損失
- EAのロジック破綻
- 想定外のポジション状態
→ 必ず原因を特定し、再発防止するべきです。
Q2. Sleepを入れれば完全に解決しますか?
回答方針:
部分的に有効だが、根本解決ではない。
解説:
Sleepは「時間で回避」する手法です。
しかし、busyの本質は「状態競合」です。
- 通信遅延が長い → Sleep不足
- 高速相場 → Sleep無意味
→ フラグ管理・注文制御と併用が必須です。
Q3. OrderSendAsyncを使えばbusyは回避できますか?
回答方針:
むしろ悪化する可能性あり。
解説:
非同期処理は「待たない」ため、
制御しないと以下が発生します。
- 重複注文
- 状態不整合
- busy増加
→ 初心者は OrderSend() を優先するべきです。
Q4. バックテストでは出ないのに、本番で出るのはなぜ?
回答方針:
テスターと実環境の構造差。
解説:
バックテスト:
- 通信なし
- 即時処理
- 同期的
実環境:
- サーバー通信あり
- 約定遅延あり
- 非同期イベントあり
→ 実環境では競合が発生しやすい
Q5. 複数EAを動かすと必ず発生しますか?
回答方針:
必ずではないが、確率は上がる。
解説:
- EA同士は独立していない(口座共有)
- 同時注文で競合が発生
→ 対策:
- 発注EAを1つに統合
- タイミング分離
- 中央制御
Q6. VPSを変えれば解決しますか?
回答方針:
改善はするが根本解決ではない。
解説:
VPS改善で変わるもの:
- 通信速度
- 応答時間
変わらないもの:
- ロジック競合
- 設計ミス
→ 「設計+環境」の両方が必要
Q7. 一番効果の高い対策は何ですか?
回答方針:
フラグ管理+注文制御。
結論:
優先順位:
- フラグによる排他制御
- 注文間隔制御
- ログ監視
- Sleep(補助)
→ この順で実装するのが最も安定
Q8. 完全に0にできますか?
回答方針:
理論上は困難だが、実務上ほぼゼロには可能。
解説:
- 通信遅延はゼロにならない
- サーバー状態も変動する
ただし、
- 設計を最適化
- 注文頻度を制御
- 状態管理を徹底
→ 実務では「発生しないレベル」まで抑えられます