本記事で公開しているライブラリーは公開当時のままで、古くなっております。最新版のライブラリーはメルマガ登録いただくことでダウンロードできます。
注文変更はトレイリングストップで活躍する
注文時から利食いや損切り等の価格を変更する、MQL4の標準関数にOrderModify()があります。
このくだり、OrderSend()、OrderClose()及びOrderDelete()と一緒なので以下割愛です。OrderModify()が失敗した時を考慮した注文変更関数を紹介します。
//+------------------------------------------------------------------+ //|【関数】信頼できる注文変更 | //| | //|【引数】 IN OUT 引数名 説明 | //| --------------------------------------------------------- | //| ○ aTicket チケット番号 | //| ○ aPrice 待機注文の新しい仕掛け価格 | //| ○ aStoploss 損切り価格 | //| ○ aTakeprofit 利食い価格 | //| ○ aExpiration 待機注文の有効期限 | //| △ aArrow_color チャート上の矢印の色 | //| | //|【戻値】true :正常終了 | //| false:異常終了 | //| | //|【備考】△:既定値あり | //+------------------------------------------------------------------+ bool orderModifyReliable(int aTicket, double aPrice, double aStoploss, double aTakeprofit, datetime aExpiration, color aArrow_color = CLR_NONE) { bool result = false; int startTime = GetTickCount(); Print("Attempted orderModifyReliable(#" + aTicket + ", " + aPrice + ", SL:"+ aStoploss + ", TP:" + aTakeprofit + ", Expiration:" + TimeToStr(aExpiration) + ", ArrowColor:" + aArrow_color + ")"); bool selected = OrderSelect(aTicket, SELECT_BY_TICKET, MODE_TRADES); string symbol = OrderSymbol(); int type = OrderType(); double digits = MarketInfo(symbol, MODE_DIGITS); double price = NormalizeDouble(OrderOpenPrice(), digits); double stoploss = NormalizeDouble(OrderStopLoss(), digits); double takeprofit = NormalizeDouble(OrderTakeProfit(), digits); aPrice = NormalizeDouble(aPrice, digits); aStoploss = NormalizeDouble(aStoploss, digits); aTakeprofit = NormalizeDouble(aTakeprofit, digits); double stopLevel = MarketInfo(symbol, MODE_STOPLEVEL) * MarketInfo(symbol, MODE_POINT); double freezeLevel = MarketInfo(symbol, MODE_FREEZELEVEL) * MarketInfo(symbol, MODE_POINT); 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); } double ask = NormalizeDouble(MarketInfo(symbol, MODE_ASK), digits); double bid = NormalizeDouble(MarketInfo(symbol, MODE_BID), digits); // 仕掛け/損切り/利食いがストップレベル未満かフリーズレベル以下の場合、エラー if(type == OP_BUY){ if(MathAbs(bid - aStoploss) < stopLevel){ Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aTakeprofit - bid) < stopLevel){ Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(bid - aStoploss) <= freezeLevel){ Print("FreezeLevel: SL was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aTakeprofit - bid) <= freezeLevel){ Print("FreezeLevel: TP was too close to brokers min distance (" + stopLevel + ")"); return(-1); } }else if(type == OP_SELL){ if(MathAbs(aStoploss - ask) < stopLevel){ Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(ask - aTakeprofit) < stopLevel){ Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aStoploss - ask) <= freezeLevel){ Print("FreezeLevel: SL was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(ask - aTakeprofit) <= freezeLevel){ Print("FreezeLevel: TP was too close to brokers min distance (" + stopLevel + ")"); return(-1); } }else if(type == OP_BUYLIMIT){ if(MathAbs(ask - aPrice) < stopLevel && (aPrice != 0.0 && aPrice != price)){ Print("StopLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aPrice - aStoploss) < stopLevel && ((aPrice != 0.0 && aPrice != price) || (aStoploss != 0.0 && aStoploss != stoploss))){ Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aTakeprofit - aPrice) < stopLevel && ((aPrice != 0.0 && aPrice != price) || (aTakeprofit != 0.0 && aTakeprofit != takeprofit))){ Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(ask - aPrice) <= freezeLevel && (aPrice != 0.0 && aPrice != price)){ Print("FreezeLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")"); return(-1); } }else if(type == OP_SELLLIMIT){ if(MathAbs(aPrice - bid) < stopLevel && (aPrice != 0.0 && aPrice != price)){ Print("StopLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aStoploss - aPrice) < stopLevel && ((aPrice != 0.0 && aPrice != price) || (aStoploss != 0.0 && aStoploss != stoploss))){ Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aPrice - aTakeprofit) < stopLevel && ((aPrice != 0.0 && aPrice != price) || (aTakeprofit != 0.0 && aTakeprofit != takeprofit))){ Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aPrice - bid) <= freezeLevel && (aPrice != 0.0 && aPrice != price)){ Print("FreezeLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")"); return(-1); } }else if(type == OP_BUYSTOP){ if(MathAbs(aPrice - ask) < stopLevel && (aPrice != 0.0 && aPrice != price)){ Print("StopLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aPrice - aStoploss) < stopLevel && ((aPrice != 0.0 && aPrice != price) || (aStoploss != 0.0 && aStoploss != stoploss))){ Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aTakeprofit - aPrice) < stopLevel && ((aPrice != 0.0 && aPrice != price) || (aTakeprofit != 0.0 && aTakeprofit != takeprofit))){ Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aPrice - ask) <= freezeLevel && (aPrice != 0.0 && aPrice != price)){ Print("FreezeLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")"); return(-1); } }else if(type == OP_SELLSTOP){ if(MathAbs(bid - aPrice) < stopLevel && (aPrice != 0.0 && aPrice != price)){ Print("StopLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aStoploss - aPrice) < stopLevel && ((aPrice != 0.0 && aPrice != price) || (aStoploss != 0.0 && aStoploss != stoploss))){ Print("StopLevel: SL was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(aPrice - aTakeprofit) < stopLevel && ((aPrice != 0.0 && aPrice != price) || (aTakeprofit != 0.0 && aTakeprofit != takeprofit))){ Print("StopLevel: TP was too close to brokers min distance (" + stopLevel + ")"); return(-1); }else if(MathAbs(bid - aPrice) <= freezeLevel && (aPrice != 0.0 && aPrice != price)){ Print("FreezeLevel: OpenPrice was too close to brokers min distance (" + stopLevel + ")"); return(-1); } } if(IsTradeContextBusy()){ Print("Must wait for trade context"); }else{ result = OrderModify(aTicket, aPrice, aStoploss, aTakeprofit, aExpiration, aArrow_color); if(result){ Print("Success! Ticket #", aTicket, " order modified, details follow"); selected = OrderSelect(aTicket, SELECT_BY_TICKET, MODE_TRADES); OrderPrint(); return(result); } int err = GetLastError(); // 一時的エラーの場合はリトライするが、恒常的エラーの場合は処理中断(リトライしてもエラーになるため) if(err == ERR_NO_ERROR || err == ERR_COMMON_ERROR || err == ERR_SERVER_BUSY || err == ERR_NO_CONNECTION || err == ERR_TRADE_TIMEOUT || err == ERR_INVALID_PRICE || err == ERR_PRICE_CHANGED || err == ERR_OFF_QUOTES || err == ERR_BROKER_BUSY || err == ERR_REQUOTE || 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()と殆ど同じ作りですね。違いは待機注文の時だけ有効になるaPriceの考慮(オープンポジションの変更の場合、aPrice=0.0になりますので、その点の考慮)があるぐらいでしょうか。
サンプルEA
関数だけではイメージが沸きづらいと思いますので、サンプルEAを載せておきます。