ブログタイトルを「FX自動売買システム開発部」から「autoFX」に変更しました!

トレイリングストップとブレイクイーブンを併用するために

変更箇所はたったの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]);
        }
      }
    }
  }
}

MQL4プログラミングの最新記事8件

>完全放ったらかしEA 「AutoEndlessCatchRange」

完全放ったらかしEA 「AutoEndlessCatchRange」

「本業が忙しい!」「でも資産運用したい!」そんなあなたに最適なEAです。兼業トレーダーの方はチャートを毎日みて分析してトレードする時間はなかなか確保できないものです。トレードは本EAに任せて、本業やプライベートの時間をもっと増やしませんか?元々は自分自身のために開発したEAですので、手抜き無しのガチものです。

CTR IMG