
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
1. MT4 のクライアントターミナルの「トレードコンテキスト」とは何でしょう。
メタエディタのリファレンスから参照します。
一度に 1つのEAだけ (スクリプト) トレードが可能と言って良いでしょう。トレードを開始しようとすると、他のすべてのEAは、エラー146 によってストップされます。この記事では、この問題の解決策を見出します。
2. IsTradeAllowed()
トレード状況がビジー状態かどうかを調べる最も簡単なメソッドは、IsTradeAllowed() という名前の関数を使用することです。
メタエディタのリファレンスから参照します。
"bool IsTradeAllowed()
EAに対してトレードが許可されいる場合true、それ以外の場合は false を返します。
つまり、IsTradeAllowed() 関数がTRUEを返す場合にのみトレードできます。
トレード操作の前にチェックを行う必要があります。
関数の間違った使用法の例:
int start() { //トレード状況がフリーかどうかを確認してください。 if(!IsTradeAllowed()) { //sTradeAllowed() 関数がFALSE が返された場合 Print(「トレード状況がビジー状態!EAはポジションを持たない!"); //エキスパートの操作を終了します。このようになり、次のティック時リスタートします。 // return(-1); } else { //IsTradeAllowed() 関数が true の場合、その旨がユーザーに通知されます //続き Print(「トレード状況クリアです!稼働中..."); } //エントリーするかどうかを確認してください。 ... //ストップロスとテイクプロフィトのサイズを計算します。 ... //ポジションを開く if(OrderSend(...) < 0) Alert("Error opening position # ", GetLastError()); return(0); }
この例では、コンテキストのトレード状態は start() 関数の非常に初めにチェックされます。これは間違った考えです。つまり、トレードコンテキストは他のEAによって占有されている可能性があります。このような場合は、ポジションは開きません。
適切な使用例:
int start() { //エントリーするかどうかを確認してください。 ... //ストップロスとテイクプロフィト レベルだけでなく、ロットサイズを計算します。 ... //トレード状況がフリーかどうかを確認 if(!IsTradeAllowed()) { Print(「トレード状況がビジー状態!EAはポジションを持たない!"); return(-1); } else Print(「トレード状況クリアです!ポジションを開く..."); //チェックが成功した場合は、ポジションを開く if(OrderSend(...) < 0) Alert("Error opening position # ", GetLastError()); return(0); }
ポジションを開く前に、トレードコンテキスト状態はここですぐに確認されます。 このわずかな間に他のEAが邪魔をする可能性は極めて少ないです。しかし、まだ考慮すべきものが存在します。
このメソッドは、2 つの重要な欠点があります。
- EAの状態を同時チェックし、同時にトレードしようとする可能性があります。
- チェックが失敗した場合、EAは次のティックでトレードをもう一度します。このような遅延は非常に望ましくありません。
2番目の問題は比較的シンプルに解決できます。トレードのコンテキストをエントリーされるまで待機するだけです。EAは、他のEAがを完了した後すぐにトレードを開始します。
おそらく次のようになります。
int start() { //エントリーするかどうかを確認してください。 ... //ストップロスとテイクプロフィト レベルとロットサイズを計算します。 ... //トレード状況がフリーかどうかを確認してください。 if(!IsTradeAllowed()) { Print(「トレード状況がビジー状態!フリーになるまで、待機); //無限ループ while(true) { //EAがユーザーによってストップされた場合、停止します。 if(IsStopped()) { Print(「EAはユーザーによってストップされました!」); return(-1); } //トレード状況はフリーとなっている場合、ループを終了し、トレードを開始 if(IsTradeAllowed()) { Print("Trade context has become free!"); break; } //ループ脱出条件を満たしてない場合""0.1 秒待ってください。 //再起動の確認 Sleep(100); } } else Print(「トレード状況クリアです!ポジションを持つ..."); //ポジションを開くしようとしました。 if(OrderSend(...) < 0) Alert("Error opening position # ", GetLastError()); return(0); }再び問題点があります。
- IsTradeAllowed() 関数は、コンテキスト状態に対してだけでなく、EAのトレード有効化/無効化にも有効なので、EAが無限ループの中にい続け、チャートから手動で外さない限り、終わらない可能性があります。
- EAがトレードコンテキストがフリーになるまで待機した場合、わずか数秒ですが、レートが変化します。また、前のレートでトレードすることはできません。データはリフレッシュされるべきであり、トレードの前に再計算する必要があります。
修正後のコードは次のようになります。
//EAが、トレードまで待機する時間 (単位は秒) //コンテキストが (ビジー状態) の場合はフリー int MaxWaiting_sec = 30; int start() { //エントリーするかどうかを確認してください。 ... //ストップロスとテイクプロフィト レベルとロットのサイズを計算します。 ... //トレード状況がフリーかどうかを確認してください。 if(!IsTradeAllowed()) { int StartWaitingTime = GetTickCount(); Print(「トレード状況がビジー状態!フリーになるまで、待機); //無限ループ while(true) { //EAがユーザーによって終了した場合は、操作をストップします。 if(IsStopped()) { Print(「EAはユーザーによってストップされました!」); return(-1); } //変数で指定された時間より長く待っていた場合 //MaxWaiting_sec、ストップ操作 if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000) { Print("The standby limit (" + MaxWaiting_sec + " sec) exceeded!"); return(-2); } //トレード状況がフリーになっている場合 if(IsTradeAllowed()) { Print(「トレードコンテキストがフリー!」); //相場情報を更新します。 RefreshRates(); //ストップロスとテイクプロフィト レベルを再計算します。 ... //ループから離れ、トレードを開始 break; } //ループ脱出条件を満たしてない場合、0.1秒待つ //チェックを再開します Sleep(100); } } else Print(「トレード状況クリアです!ポジションを持つ..."); //ポジションを開くしようとしました。 if(OrderSend(...) < 0) Alert("Error opening position # ", GetLastError()); return(0); }上記の例では、次のものを追加しました。
- RefreshRates() とそれに伴うストップロスとテイクプロフィトの再計算、相場情報の更新です。
- 最大待機時間はMaxWaiting_secで、これを超えた場合EAはストップします。
これは、すでにEAで上記のコードで使用できます。
最後の仕上げです。別の関数をチェックします。EAとその使用法の統合を簡素化させます。
///////////////////////////////////////////////////////////////////////////////// //nt _IsTradeAllowed (int MaxWaiting_sec = 30) // //トレードのコンテキスト状態を調べます。リターン コード: //1-トレードコンテクストがフリーの場合、トレードを許可 //0 - トレードコンテクストがビジーで、その後フリーにフリー時にのみトレードを許可します。 //マーケット情報が更新されています。 //-1 - トレード状況がビジー状態か、ユーザーによって中断された (EAはから削除されました //グラフ、ターミナルはシャット ダウン、チャートの期間/シンボルを変更したなど。) //-2 - トレード状況がビジー状態、最大待機時間制限に達すると (MaxWaiting_sec)。 //EAは、(チェック ボックス許可ライブトレード」トレードすることはできません。 //エキスパート設定で)。 // //MaxWaiting_sec - 関数が待機する時間 (単位は秒) //トレード状況がフリー (忙しい場合)。既定では、30。 ///////////////////////////////////////////////////////////////////////////////// int _IsTradeAllowed(int MaxWaiting_sec = 30) { //トレード状況がフリーかどうかを確認してください。 if(!IsTradeAllowed()) { int StartWaitingTime = GetTickCount(); Print(「トレード状況がビジー状態!フリーになるまで、待機); //無限ループ while(true) { //EAがユーザーによって終了した場合は、操作をストップします。 if(IsStopped()) { Print(「EAはユーザーによって終了されました!」); return(-1); } //待機時間が指定した時間を超える場合、 //MaxWaiting_sec 変数、ストップ操作 if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000) { Print("The waiting limit exceeded (" + MaxWaiting_sec + " seconds)!"); return(-2); } //トレード状況がフリーになっている場合 if(IsTradeAllowed()) { Print("Trade context has become free!"); return(0); } //ループ脱出条件を満たしてない場合、0.1秒待つ //チェックを再開します Sleep(100); } } else { Print(「トレードコンテキストがフリー!」); return(1); } }
この関数を使用したEAのテンプレート:
int start() { //エントリーするかどうかを確認してください。 ... //ストップロスとテイクプロフィト レベルとロットサイズを計算します。 ... //トレード状況がフリーかどうかを確認してください。 int TradeAllow = _IsTradeAllowed(); if(TradeAllow < 0) { return(-1); } if(TradeAllow == 0) { RefreshRates(); //ストップロスとテイクプロフィト レベルを再計算します。 ... } //ポジションを開く if(OrderSend(...) < 0) Alert("Error opening position # ", GetLastError()); return(0); }
結論です。
IsTradeAllowed() 関数は、使いやすいですし、同時に 2 つまたは 3 つのEAのコンテキストのトレードへのアクセスに最適です。多くのEAが同時に働くときエラー 146 から保証しません。「許可するライブトレード」が無効な場合、EAの「ハングアップ」も原因になります。
よって、グローバル変数の「セマフォ」の代替ソリューションを検討します。
3. クライアント ターミナルのグローバル変数
まず、定義です:
クライアント ターミナルのグローバル変数は、すべてのEA、スクリプトおよび評価インジケーターにアクセスできる変数です。(アクセスを分散する) 他のEA、EAによって作成されたグローバル変数を作成することを意味します。
グローバル変数を操作する MQL 4 で提供される関数があります。
- GlobalVariableCheck() - グローバル変数が存在するかどうかを確認する
- GlobalVariableDel() - グローバル変数を削除する
- GlobalVariableGet() - グローバル変数の値を取得する
- GlobalVariableSet() - 作成またはグローバル変数を変更する
- GlobalVariableSetOnCondition() - ユーザーが指定したグローバル変数の値を変更。前の値は新しい値が設定され、GlobalVariableSet() とは異なります。セマフォを作成する関数は、この関数です。
- GlobalVariablesDeleteAll() - すべてのグローバル変数を削除する (誰がこれを必要としているのでしょう:)
なぜ、GlobalVariableSetOnCondition()を使い、GlobalVariableGet() と GlobalVariableSet()を使わないのでしょうか。同じ理由で、 2 つの関数の使用の間には隙間があります。セマフォの切り替えに別のEAを置くことができます。しかし、これは我々が今必要なものではありません。
4. セマフォの基本的な概念
トレードEAは、セマフォの状態を確認する必要があります。セマフォが「レッドライト」を示している場合 (グローバル変数 = 1)、待機する必要があるので、別のEAがトレードされていることを意味します。「グリーン ライト」が表示されている場合 (グローバル変数 = 0)、すぐにトレードを開始できます。
したがって、2つの関数を作成します。:「レッドライト」、「グリーン ライト」このタスクは簡単です。しかし 早急に結論付けてはいけません。各関数によって実行されるアクションのシーケンスを定式化しましょう (TradeIsBusy()、TradeIsNotBusy())。
5. TradeIsBusy()
前に言われているようにこの関数の主なタスクは「グリーン ライト」が表示されるまで待ち、「レッドライト」にスイッチすることです。また、グローバル変数が存在するかどうかをチェックする必要があります。このチェックにより合理的 (でより効率的) となります。init()から関数を実行します。しかし、ユーザーがグローバル変数を削除し、どのEAもトレードすることができない可能性が存在します。よって、 作成された関数の本体に格納されます。
このすべての情報を表示して、グローバル変数を操作するときに発生したエラーの処理をする必要があります。「ハングアップ」を忘れてはなりません。同様に、関数の操作時間を制限する必要があります。
これが最終的なものになります。
///////////////////////////////////////////////////////////////////////////////// //nt TradeIsBusy (int MaxWaiting_sec = 30) // //この関数は、TradeIsBusy の値を0から 1 に置き換えます。 //TradeIsBusy = 1の場合、 TradeIsBusy が 0 になるまで待機します //置き換え。 //グローバル変数 TradeIsBusy が存在しない場合は作成されます。 //リターン コード: //1-正常に完了。1の値を持つグローバル変数 TradeIsBusy が割り当てられていた //-1 - TradeIsBusy = 1 関数の起動の瞬間、ユーザーによって中断されました //EAがグラフから削除され、 //または変更など)。 //-2 - TradeIsBusy = 1 関数の起動の瞬間、待っている制限を超えました //MaxWaiting_sec) ///////////////////////////////////////////////////////////////////////////////// int TradeIsBusy( int MaxWaiting_sec = 30 ) { //テストでトレード状況を分割 - 終了する理由はありません。 //関数 if(IsTesting()) return(1); int _GetLastError = 0, StartWaitingTime = GetTickCount(); //+------------------------------------------------------------------+ //グローバル変数が存在するかどうかを確認し、そうでない場合は、作成 | //+------------------------------------------------------------------+ while(true) { //EAがユーザーによって終了した場合は、操作をストップします。 if(IsStopped()) { Print(「EAはユーザーによって終了されました!」); return(-1); } //変数で指定された待機時間を超える場合 //MaxWaiting_sec、ストップ操作 if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000) { Print("Waiting time (" + MaxWaiting_sec + " sec) exceeded!"); return(-2); } //グローバル変数が存在するかどうかを確認します。 //ある場合は、ループを出て、変更のブロックへ //TradeIsBusy if(GlobalVariableCheck( "TradeIsBusy" )) break; else //GlobalVariableCheck が FALSE を返した場合、存在しないことを意味します //チェック中にエラーが発生しました { _GetLastError = GetLastError(); //エラーの場合、0.1 秒間待機 //再開します。 if(_GetLastError != 0) { Print("TradeIsBusy()-GlobalVariableCheck(\"TradeIsBusy\")-Error #", _GetLastError ); Sleep(100); continue; } } //グローバル変数がないことを意味するエラーがない場合、作成 // //GlobalVariableSet > 0 の場合、グローバル変数が正常に作成されたことを意味します。 //関数を離れる if(GlobalVariableSet( "TradeIsBusy", 1.0 ) > 0 ) return(1); else //GlobalVariableSet の値が返された場合はエラー //変数の作成時に発生。 { _GetLastError = GetLastError(); //情報を表示、0.1 秒間待機、もう一度試してください。 if(_GetLastError != 0) { Print("TradeIsBusy()-GlobalVariableSet(\"TradeIsBusy\",0.0 )-Error #", _GetLastError ); Sleep(100); continue; } } } //+----------------------------------------------------------------------------------+ //この関数がこのポイントに達した場合、グローバル変数| //が存在します。 | //TradeIsBusy = 0になるまで待機、TradeIsBusy の値を1に変更 | //+----------------------------------------------------------------------------------+ while(true) { //EAがユーザーによって終了した場合は、操作をストップします。 if(IsStopped()) { Print(「EAはユーザーによって終了されました!」); return(-1); } //変数で指定された待機時間を超える場合 //MaxWaiting_sec、ストップ操作 if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000) { Print("The waiting time (" + MaxWaiting_sec + " sec) exceeded!"); return(-2); } //TradeIsBusy の値を 0 から 1 に変更してみてください。 //成功した場合、 1 (「正常完了」) を返す if(GlobalVariableSetOnCondition( "TradeIsBusy", 1.0, 0.0 )) return(1); else //そうでない場合、2つの理由が考えられます。つまり、 TradeIsBusy = 1 もしくは、 //エラーが発生しました ( がチェックされます) { _GetLastError = GetLastError(); //エラーがまだある場合、情報を表示し、もう一度やり直してください。 if(_GetLastError != 0) { Print("TradeIsBusy()-GlobalVariableSetOnCondition(\"TradeIsBusy\",1.0,0.0 )-Error #", _GetLastError ); continue; } } //エラーがない場合、TradeIsBusy = 1 (別のEAのトレード)です //情報と待機. Comment("Wait until another expert finishes trading..."); Sleep(1000); Comment(""); } }
まあ、すべてはここに明らかだと思われます。
- グローバル変数が存在するかどうかチェックし、なければ作成
- グローバル変数の値を 0 から 1 に変更しようとしました。その値は = 0 場合にのみトリガーされます。
最大時間は MaxWaiting_sec です。この関数には、グラフからエキスパートの削除することに反論はありません。
発生したすべてのエラーに関する情報がログに表示されます。
6. TradeIsNotBusy()
TradeIsNotBusy 関数は、逆の問題を解決します。つまり、「グリーン ライト」が切り替わります。
長時間稼働による制限はなく、ユーザーによって終了することはできません。シンプルです。「グリーン ライト」がオフの場合、EAはトレードできません。
すべてのリターン コードにありません。正常な場合、結果で確認できます。
外観です。
///////////////////////////////////////////////////////////////////////////////// //void TradeIsNotBusy() // //この関数は、グローバル変数 TradeIsBusy の値を0に設定します。 //TradeIsBusy が存在しない場合、作成されます。 ///////////////////////////////////////////////////////////////////////////////// void TradeIsNotBusy() { int _GetLastError; //テストでトレード状況を分割 - 終了しても意味がありません。 //関数 if(IsTesting()) { return(0); } while(true) { //EAがユーザーによって終了した場合は、動作をストップします。 if(IsStopped()) { Print(「EAはユーザーによって終了されました!」); return(-1); } //グローバル変数の値を0に設定しようとすると、 (またはグローバルの作成 //変数) //GlobalVariableSet は、 > 0 を返します。 //これは、成功しています。関数を離れます。 if(GlobalVariableSet( "TradeIsBusy", 0.0 ) > 0) return(1); else //GlobalVariableSetが < = 0 の値を返した場合、エラーが発生したことを意味します。 //情報を表示、待機、およびもう一度やり直してください。 { _GetLastError = GetLastError(); if(_GetLastError != 0 ) Print("TradeIsNotBusy()-GlobalVariableSet(\"TradeIsBusy\",0.0)-Error #", _GetLastError ); } Sleep(100); } }
7. EAの統合
トレードフローへのアクセスを分散する3つの関数があります。EAの統合をシンプルにするには、TradeContext.mq4 ファイルを作成し、#include ディレクティブ (添付ファイル) を使用して有効にします。
TradeIsBusy() と TradeIsNotBusy() 関数を使用したEAのテンプレートです。
#include<TradeContext.mq4> int start() { //エントリーするかどうかを確認してください。 ... //StopLoss と有効期限のレベル、およびロットサイズを計算します。 ... //トレード状況が空くまで待ち、(エラーが発生した場合に使用する //離れる) if(TradeIsBusy() < 0) return(-1); //相場情報を更新します。 RefreshRates(); //レベルの StopLoss と有効期限を再計算します。 ... //ポジションを開く if(OrderSend(...) < 0) { Alert("Error opening position # ", GetLastError()); } //フリートレード コンテキストを設定します。 TradeIsNotBusy(); return(0); }
TradeIsBusy() と TradeIsNotBusy() 関数は、1 つだけ問題が発生します。トレード状況がビジー状態になったあとにEAをグラフから削除すると、変数 TradeIsBusy が 1 に等しくなります。他のEAはその後トレードすることができません。
この問題はシンプルに解決することができます。トレード時、EAをグラフから削除しないでください。;)
TradeIsBusyを0にしないことでも可能です。この場合、EAの init() 関数から TradeIsNotBusy() 関数を使用できます。
そして、もちろん、変数の値は、ターミナルでF3 ボタンでいつでも裁量で変更できます。
komposter (komposterius@mail.ru)、2006.04.11
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1412



- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索