変更箇所はたったの2行
トレイリングストップ関数とブレイクイーブン関数はどちらも自作ライブラリに包含されていますが、両方を併用するとトレイリングストップが打ち消されて、ブレイクイーブンが常に適用されてしまう問題があることが分かりました。
トレイリングストップとブレイクイーブンを併用したいという声が複数ありましたので、併用できるようにコードを変更します。
// 変更前 if(NormalizeDouble(oStopLoss, digits) != NormalizeDouble(oPrice + stop, digits)){ // 買い if(NormalizeDouble(oStopLoss, digits) != NormalizeDouble(oPrice - stop, digits)){ // 売り
// 変更後 if(oStopLoss == 0.0 || NormalizeDouble(oStopLoss, digits) < NormalizeDouble(oPrice + stop, digits)){ // 買い if(oStopLoss == 0.0 || NormalizeDouble(oStopLoss, digits) > NormalizeDouble(oPrice - stop, digits)){ // 売り
変更前のコードは、現在の損切り価格とブレイクイーブン後の損切り価格が不一致ならば、ブレイクイーブン後の損切り価格に変更するロジックになっています。
この場合、トレイリングストップで損切り価格を随時変更すると、上記条件が成立してしまうので、ブレイクイーブン後の損切り価格に戻っちゃうというわけです。
これを避けるために、変更後のコードでは、現在の損切り価格がブレイクイーブン後の損切り価格よりマイナス方向にあるか、そもそも損切り設定していない(oStopLoss == 0.0)場合のみ、ブレイクイーブン後の損切り価格に変更するようにしています。
これで併用できるようになります。アップロードしているライブラリも近いうちに最新化しますね。
なお、コードの抜粋だけだと分かりにくいでしょうから、変更前後の関数もそれぞれ載せておきます。
//+------------------------------------------------------------------+ //|【関数】ブレイクイーブン(トレイリングストップ関数と併用NG) | //| | //|【引数】 IN OUT 引数名 説明 | //| --------------------------------------------------------- | //| ○ aMagic マジックナンバー | //| ○ aMoveExecPips ストップ変更開始位置(pips) | //| ○ aMoveStopPips ストップ変更幅(pips) | //| | //|【戻値】なし | //| | //|【備考】なし | //+------------------------------------------------------------------+ void breakeven(int aMagic, double aMoveExecPips, double aMoveStopPips) { for(int i = 0; i < OrdersTotal(); i++){ // オーダーが1つもなければ処理終了 if(OrderSelect(i, SELECT_BY_POS) == false){ break; } string oSymbol = OrderSymbol(); // 別EAのオーダーはスキップ if(oSymbol != Symbol() || OrderMagicNumber() != aMagic){ continue; } int oType = OrderType(); // 待機オーダーはスキップ if(oType != OP_BUY && oType != OP_SELL){ continue; } int digits = (int)MarketInfo(oSymbol, MODE_DIGITS); double oPrice = NormalizeDouble(OrderOpenPrice(), digits); double oStopLoss = NormalizeDouble(OrderStopLoss(), digits); double oTakeProfit = NormalizeDouble(OrderTakeProfit(), digits); int oTicket = OrderTicket(); double exec = NormalizeDouble(aMoveExecPips * gPipsPoint, digits); double stop = NormalizeDouble(aMoveStopPips * gPipsPoint, digits); double price; if(oType == OP_BUY){ price = MarketInfo(oSymbol, MODE_BID); if(price >= oPrice + exec){ // 何度もmodifyしないためのif文 if(NormalizeDouble(oStopLoss, digits) != NormalizeDouble(oPrice + stop, digits)){ PrintFormatLog(__FILE__, __FUNCTION__, " Attempted to change the stoploss price of the LONG opend order. " + DoubleToStr(oStopLoss, digits) + " -> " + DoubleToStr(oPrice + stop, digits)); orderModifyReliable(oTicket, 0.0, NormalizeDouble(oPrice + stop, digits), oTakeProfit, 0, gArrowColor[oType]); } } }else if(oType == OP_SELL){ price = MarketInfo(oSymbol, MODE_ASK); if(price <= oPrice - exec){ // 何度もmodifyしないためのif文 if(NormalizeDouble(oStopLoss, digits) != NormalizeDouble(oPrice - stop, digits)){ PrintFormatLog(__FILE__, __FUNCTION__, " Attempted to change the stoploss price of the SHORT opend order. " + DoubleToStr(oStopLoss, digits) + " -> " + DoubleToStr(oPrice - stop, digits)); orderModifyReliable(oTicket, 0.0, NormalizeDouble(oPrice - stop, digits), oTakeProfit, 0, gArrowColor[oType]); } } } } }
//+------------------------------------------------------------------+ //|【関数】ブレイクイーブン(トレイリングストップ関数と併用OK) | //| | //|【引数】 IN OUT 引数名 説明 | //| --------------------------------------------------------- | //| ○ aMagic マジックナンバー | //| ○ aMoveExecPips ストップ変更開始位置(pips) | //| ○ aMoveStopPips ストップ変更幅(pips) | //| | //|【戻値】なし | //| | //|【備考】なし | //+------------------------------------------------------------------+ void breakeven2(int aMagic, double aMoveExecPips, double aMoveStopPips) { for(int i = 0; i < OrdersTotal(); i++){ // オーダーが1つもなければ処理終了 if(OrderSelect(i, SELECT_BY_POS) == false){ break; } string oSymbol = OrderSymbol(); // 別EAのオーダーはスキップ if(oSymbol != Symbol() || OrderMagicNumber() != aMagic){ continue; } int oType = OrderType(); // 待機オーダーはスキップ if(oType != OP_BUY && oType != OP_SELL){ continue; } int digits = (int)MarketInfo(oSymbol, MODE_DIGITS); double oPrice = NormalizeDouble(OrderOpenPrice(), digits); double oStopLoss = NormalizeDouble(OrderStopLoss(), digits); double oTakeProfit = NormalizeDouble(OrderTakeProfit(), digits); int oTicket = OrderTicket(); double exec = NormalizeDouble(aMoveExecPips * gPipsPoint, digits); double stop = NormalizeDouble(aMoveStopPips * gPipsPoint, digits); double price; if(oType == OP_BUY){ price = MarketInfo(oSymbol, MODE_BID); if(price >= oPrice + exec){ // 何度もmodifyしないためのif文 if(oStopLoss == 0.0 || NormalizeDouble(oStopLoss, digits) < NormalizeDouble(oPrice + stop, digits)){ PrintFormatLog(__FILE__, __FUNCTION__, " Attempted to change the stoploss price of the LONG opend order. " + DoubleToStr(oStopLoss, digits) + " -> " + DoubleToStr(oPrice + stop, digits)); orderModifyReliable(oTicket, 0.0, NormalizeDouble(oPrice + stop, digits), oTakeProfit, 0, gArrowColor[oType]); } } }else if(oType == OP_SELL){ price = MarketInfo(oSymbol, MODE_ASK); if(price <= oPrice - exec){ // 何度もmodifyしないためのif文 if(oStopLoss == 0.0 || NormalizeDouble(oStopLoss, digits) > NormalizeDouble(oPrice - stop, digits)){ PrintFormatLog(__FILE__, __FUNCTION__, " Attempted to change the stoploss price of the SHORT opend order. " + DoubleToStr(oStopLoss, digits) + " -> " + DoubleToStr(oPrice - stop, digits)); orderModifyReliable(oTicket, 0.0, NormalizeDouble(oPrice - stop, digits), oTakeProfit, 0, gArrowColor[oType]); } } } } }