本記事で公開しているライブラリーは公開当時のままで、古くなっております。最新版のライブラリーはメルマガ登録いただくことでダウンロードできます。
仕切り注文が失敗したら泣くに泣けないじゃない?
仕切り注文を出す、MQL4の標準関数にOrderClose()があります。
注文が必ず通るのであれば、OrderClose()を使えば良いわけですが、実際はそうでもありません。
…この流れデジャヴですね。OrderSend()と一緒です。
というわけで、OrderClose()の注文が失敗した時を考慮した仕切り注文関数を紹介します。
//+------------------------------------------------------------------+ //|【関数】信頼できる仕切り注文 | //| | //|【引数】 IN OUT 引数名 説明 | //| --------------------------------------------------------- | //| ○ aTicket チケット番号 | //| ○ aLots ロット数 | //| ○ aPrice 仕切り価格 | //| ○ aSlippage スリッページ(ポイント) | //| △ aArrow_color チャート上の矢印の色 | //| | //|【戻値】true :正常終了 | //| false:異常終了 | //| | //|【備考】△:初期値あり | //+------------------------------------------------------------------+ bool orderCloseReliable(int aTicket, double aLots, double aPrice, int aSlippage, color aArrow_color = CLR_NONE) { bool result = false; int startTime = GetTickCount(); Print("Attempted orderCloseReliable(#" + aTicket + ", " + aLots + "lots, " + aPrice + ", Slippage:" + aSlippage + ", ArrowColor:" + aArrow_color + ")"); bool selected = OrderSelect(aTicket, SELECT_BY_TICKET, MODE_TRADES); string symbol = OrderSymbol(); int type = OrderType(); double digits = MarketInfo(symbol, MODE_DIGITS); while(true){ if(IsStopped()){ Print("Trading is stopped!"); return(-1); } if(GetTickCount() - startTime > MAX_RETRY_TIME * MILLISEC_2_SEC){ Print("Retry attempts maxed at " + MAX_RETRY_TIME + "sec"); return(-1); } // MarketInfo関数でレートを取得しており、定義済変数であるAskとBidは未使用のため、不要のはずだけど、念のため RefreshRates(); if(type == OP_BUY){ aPrice = MarketInfo(symbol, MODE_BID); }else if(type == OP_SELL){ aPrice = MarketInfo(symbol, MODE_ASK); } aPrice = NormalizeDouble(aPrice, digits); if(IsTradeContextBusy()){ Print("Must wait for trade context"); }else{ result = OrderClose(aTicket, aLots, aPrice, aSlippage, aArrow_color); if(result){ Print("Successful close of Ticket #" + aTicket); return(result); } int err = GetLastError(); // 一時的エラーの場合はリトライするが、恒常的エラーの場合は処理中断(リトライしてもエラーになるため) if(err == ERR_NO_ERROR || err == ERR_COMMON_ERROR || err == ERR_SERVER_BUSY || err == ERR_NO_CONNECTION || err == ERR_TOO_FREQUENT_REQUESTS || err == ERR_TRADE_TIMEOUT || err == ERR_INVALID_PRICE || err == ERR_TRADE_DISABLED || err == ERR_PRICE_CHANGED || err == ERR_OFF_QUOTES || err == ERR_BROKER_BUSY || err == ERR_REQUOTE || err == ERR_TOO_MANY_REQUESTS || err == ERR_TRADE_CONTEXT_BUSY){ Print("Temporary Error: " + err + " " + ErrorDescription(err) + ". waiting"); }else{ Print("Permanent Error: " + err + " " + ErrorDescription(err) + ". giving up"); return(result); } // 最適化とバックテスト時はリトライは不要 if(IsOptimization() || IsTesting()){ return(result); } } Sleep(SLEEP_TIME * MILLISEC_2_SEC); } return(result); }
関数のベースはorderSendReliable()です。注意事項としては、ロングの仕掛けにはBid、ショートの仕掛けにはAskの価格を使うことです。
一時的エラーの種類がorderSendReliable()よりも若干増えていますが、これは7bit氏の「common_function.mqh」及びMatthew Kennel氏らの「LibOrderReliable.mq4」を足して2で割ったような形にしたためです。公式サイトのエラーコードの説明文を読んでも、内容が貧弱過ぎてよく分からないのです。例えば、ERR_COMMON_ERRORの説明は「Common error」。説明になってないですから。こんなわけなので、一時的エラーの選定は正直手探り状態です。
サンプルEA
関数だけではイメージが沸きづらいと思いますので、サンプルEAを載せておきます。