ATRや最高値/最安値を使った変動幅のトレイリングストップ関数

値動きが激しい時に有効か?

一般的なトレイリングストップ関数の改良版(階段型) の最後で予告したATRや最高値/最安値を使った変動幅のトレイリングストップ関数を紹介します。

変動幅のトレイリングストップは値動きが激しい時に有効なようです。ネタ元は、豊嶋氏の「FXメタトレーダー実践プログラミング」です。

豊嶋氏は尊敬する1人ですが、書籍で載っている関数ではエラーが発生するケースがあるように思いましたので、少し手を加えさせていただきました。私が誤解しているだけかもしれませんが…。

//+------------------------------------------------------------------+
//|【関数】ATRを用いたトレイリングストップ                           |
//|                                                                  |
//|【引数】 IN OUT  引数名             説明                          |
//|        --------------------------------------------------------- |
//|         ○      aMagic             マジックナンバー              |
//|         ○      aTS_ATR_Period     ATRの算出期間(本数)         |
//|         ○      aTS_ATR_Multi      ATRの倍率                     |
//|                                                                  |
//|【戻値】なし                                                      |
//|                                                                  |
//|【備考】1つ前の足の高値/安値とATRを使って損切り値を設定          |
//+------------------------------------------------------------------+
void trailingStopATR(int aMagic, int aTS_ATR_Period, double aTS_ATR_Multi)
{
  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;
    }

    double digits = MarketInfo(oSymbol, MODE_DIGITS);

    double oPrice    = NormalizeDouble(OrderOpenPrice(), digits);
    double oStopLoss = NormalizeDouble(OrderStopLoss(), digits);
    int    oTicket   = OrderTicket();
    double stopLevel = MarketInfo(oSymbol, MODE_STOPLEVEL) * MarketInfo(oSymbol, MODE_POINT);
  
    double stop = iATR(oSymbol, 0, aTS_ATR_Period, 1) * aTS_ATR_Multi;

    if(oType == OP_BUY){
      double highPrice      = iHigh(oSymbol, 0, 1);
      double price          = MarketInfo(oSymbol, MODE_BID);
      double modifyStopLoss = highPrice - stop;

      if(price - modifyStopLoss >= stopLevel){
        if(modifyStopLoss > oStopLoss){
          orderModifyReliable(oTicket, 0.0, modifyStopLoss, 0.0, 0, gArrowColor[oType]);
        }
      }
    }else if(oType == OP_SELL){
      // iLowはBidで算出。ショートの決済はAskになるので、スプレッドを足す必要がある
      double lowPrice = iLow(oSymbol, 0, 1) + MarketInfo(oSymbol, MODE_SPREAD); 
      price           = MarketInfo(oSymbol, MODE_ASK);
      modifyStopLoss  = lowPrice + stop;

      // ショートの場合、条件式にoStopLoss == 0.0が必要
      // oStopLoss = 0.0の場合、modifyStopLossには価格(正の値)が格納されるため、
      // modifyStopLoss < oStopLossの条件が永久に成立しなくなるため
      if(modifyStopLoss - price >= stopLevel){
        if(modifyStopLoss < oStopLoss || oStopLoss == 0.0){
          orderModifyReliable(oTicket, 0.0, modifyStopLoss, 0.0, 0, gArrowColor[oType]);
        }
      } 
    }
  }
}

//+------------------------------------------------------------------+
//|【関数】一定期間内の最高値/最安値を用いたトレイリングストップ    |
//|                                                                  |
//|【引数】 IN OUT  引数名             説明                          |
//|        --------------------------------------------------------- |
//|         ○      aMagic             マジックナンバー              |
//|         ○      aTS_HL_Period      高値/安値の算出期間(本数)  |
//|                                                                  |
//|【戻値】なし                                                      |
//|                                                                  |
//|【備考】1つ前の足の高値/安値とATRを使って損切り値を設定          |
//+------------------------------------------------------------------+
void trailingStopHL(int aMagic, int aTS_HL_Period)
{
  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;
    }

    double digits = MarketInfo(oSymbol, MODE_DIGITS);

    double oPrice    = NormalizeDouble(OrderOpenPrice(), digits);
    double oStopLoss = NormalizeDouble(OrderStopLoss(), digits);
    int    oTicket   = OrderTicket();
    double stopLevel = MarketInfo(oSymbol, MODE_STOPLEVEL) * MarketInfo(oSymbol, MODE_POINT);

    if(oType == OP_BUY){
      double price          = MarketInfo(oSymbol, MODE_BID);
      double modifyStopLoss = iHigh(oSymbol, 0, iHighest(oSymbol, 0, MODE_HIGH, aTS_HL_Period, 1));

      if(price - modifyStopLoss >= stopLevel){
        if(modifyStopLoss > oStopLoss){
          orderModifyReliable(oTicket, 0.0, modifyStopLoss, 0.0, 0, gArrowColor[oType]);
        }
      }
    }else if(oType == OP_SELL){
      // iLowはBidで算出。ショートの決済はAskになるので、スプレッドを足す必要がある
      price          = MarketInfo(oSymbol, MODE_ASK);
      modifyStopLoss = iLow(oSymbol, 0, iLowest(oSymbol, 0, MODE_LOW, aTS_HL_Period, 1)) + MarketInfo(oSymbol, MODE_SPREAD);

      // ショートの場合、条件式にoStopLoss == 0.0が必要
      // oStopLoss = 0.0の場合、modifyStopLossには価格(正の値)が格納されるため、
      // modifyStopLoss < oStopLossの条件が永久に成立しなくなるため
      if(modifyStopLoss - price >= stopLevel){
        if(modifyStopLoss < oStopLoss || oStopLoss == 0.0){
          orderModifyReliable(oTicket, 0.0, modifyStopLoss, 0.0, 0, gArrowColor[oType]);
        }
      }
    }
  }
}

書籍との主な変更点は、ストップレベルの考慮の有無になっています。価格を変動幅で更新する場合は、ストップレベルの考慮が必要だと思います。まぁ考慮しなくてもエラーで弾かれるだけなので、実害は無いのかもしれませんが、エラーログが出力されるのは、あまり気持ちの良いものではありません(職業柄特に)。

あと、書籍では最高値/最安値のトレイリングストップについては現在の損切り価格との比較は不要とありますが、なぜなのか理由を読んでもいまいち分かりません。何も考えずに毎ティック、書籍の関数を呼び出したら更新価格が現在の損切り価格に近すぎて価格更新できないよーってMT4に怒られることがあると思うんですけどねぇ。私が誤解しているのかなぁ。

MT4の無料プログラミング講座

LINE公式アカウントを友だち追加して、MT4のプログラミング講座を無料で受けちゃおう!

超豪華プレゼントも盛りだくさん♪

MT4プログラミングを習得すると、オリジナルEA運用、作成代行、商品販売等、複数の収入源を手に入れられるよ。副業に最適だね!

↓↓↓ 詳細はこちら ↓↓↓

アイキャッチ

>

エターナル・パートナーPRO ~MT4裁量トレード支援ツール~ 「MT4は裁量トレーダーに優しくない」そう思ったことありませんか?もっと快適にトレードするための強力な売買ツールが必要だと考え、開発したのが「エターナル・パートナーPRO」です。元々は自分自身のために開発したツールですので、手抜き無しのガチものです。既に200名近い方に手に取っていただき、喜びの声が続々と届いております。ぜひご覧ください!

CTR IMG