Coding a Step Based ATR Trailing Stop Function

 
There are some groups of people out there who used a step based ATR trailing stoploss for their trend following systems so I decided to code this since I couldn't find any free source code out there on the mql5 forum. It seems to be working properly for me right now so here is part of the source code but not the full EA
double atrValue[];   // for storing initial value of ATR so it can later be put into position comment for further storage

void executeBuy(){
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double sl = ask - bufferATR[0] * ATR_SL_multiplier;
   double tp = ask + bufferATR[0] * ATR_TP_multiplier;
   double Lots = calcLots(ask-sl);
   CopyBuffer(handleATR,0,1,1,atrValue);
   string comment = "ATR:" + DoubleToString(atrValue[0], 8);      // store ATR value in the position comment 
   trade.Buy(Lots, _Symbol, ask, sl, tp, comment);  
   Print("executeBuy original ATR value: ", atrValue[0]);
} 
void executeSell(){
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double sl = bid + bufferATR[0] * ATR_SL_multiplier;
   double tp = bid - bufferATR[0] * ATR_TP_multiplier;
   double Lots = calcLots(sl-bid);  
   CopyBuffer(handleATR,0,1,1,atrValue);
   string comment = "ATR:" + DoubleToString(atrValue[0], 8);      // store ATR value in the position comment 
   trade.Sell(Lots, _Symbol, bid, sl, tp, comment);
   Print("executeSell original ATR value: ", atrValue[0]);
}

void TrailStop(){
   for (int i = PositionsTotal()-1; i >= 0; i--){                                                                                // Loop through all open positions
      ulong posTicket = PositionGetTicket(i);                                                                                    // Get the current position's ticket in the loop
      if(PositionSelectByTicket(posTicket)){                                                                                     // Select the position
         double posOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);                                                           // Get the price the position is opened at
         double posSL = PositionGetDouble(POSITION_SL);                                                                          // Get the position stoploss
         double posTP = PositionGetDouble(POSITION_TP);                                                                          // Get the position takeprofit
         double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);                                                                     // Get current ask price
         double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);                                                                     // Get current bid price
         string comment = PositionGetString(POSITION_COMMENT);                                                                   // Get the position comment
         double initialATR = 0;                                                                                                  // initalize variable for storing the value of the inital ATR when the position was opened
         if (StringFind(comment, "ATR:") != -1){                                                                                 // if the position comment has "ATR:" in it then
            initialATR = StringToDouble(StringSubstr(comment, StringFind(comment, "ATR:") + 4, 8));                              // get the atr values after the "ATR:"
         } else {
            continue;                                                                                                            // ATR not stored correctly, so skip trailing stop for this position and go back to beginning loop
         }
         Print("Inital ATR of position: ", initialATR);                                                                          // debug statement
         double atrIncrement = initialATR * TrailATRMultiplier;                                                                  // Step size for SL adjustment
         
                                                                                                                                 // Start of position modifying scheme
         if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){                                                             // Buy positions
            if(posSL != posOpenPrice && posOpenPrice > posSL && bid > (initialATR * BreakevenATRMultiplier + posOpenPrice)){     // if the position's SL is not equal to the open price and the open price is greater than the SL (meaning the SL hasn't been moved yet) 
               double newSL = posOpenPrice;                                                                                      // and the current price (bid) is greater than Nx the ATR above the position's open price then:
               trade.PositionModify(posTicket,newSL,posTP);                                                                      // Set new SL to breakeven
            } else if (posSL == posOpenPrice || posSL > posOpenPrice){                                                           // if the position's SL is equal to the position's open price (meaning it has already been moved to breakeven) or the stoploss is greater than the open price
               double nextSL = posSL + atrIncrement;                                                                             // define nextSL increment
               if(bid >= nextSL + atrIncrement){                                                                                 // Move in steps only when price has moved by another ATR increment
                  trade.PositionModify(posTicket, nextSL, posTP);                                                                // Modify the position                     
               }                                                                  
            }
         } 
         
         if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){                                                            // Sell positions
            if(posSL != posOpenPrice && posOpenPrice < posSL && ask < (posOpenPrice - initialATR * BreakevenATRMultiplier)){     // if the position's SL is not equal to the open price and the open price is less than the SL (meaning the SL hasn't been moved yet)
               double newSL = posOpenPrice;                                                                                      // and the current price (ask) is less than Nx the ATR above the position's open price then:
               trade.PositionModify(posTicket,newSL,posTP);                                                                      // Set new SL to breakeven
            } else if (posSL == posOpenPrice || posSL < posOpenPrice){                                                           // if the position's SL is equal to the position's open price (meaning it has already been moved to breakeven) or the stoploss is less than the open price
               double nextSL = posSL - atrIncrement;                                                                             // define nextSL increment
               if(ask <= nextSL - atrIncrement){                                                                                 // Move in steps only when price has moved by another ATR increment
                  trade.PositionModify(posTicket, nextSL, posTP);                                                                // Modify the position
               }
            }
         }     
      }
   }
}

The reason I am posting this here is because I want to know what the rest of you (especially the moderators) think I should add for error checking. Currently I know problems will occur if the trade doesn't have a stoploss and I also want to add error checking for if the trigger for the breakeven is > than the trigger for the trailing stop then it might do weird things. Also its not multisymbol yet so I will eventually add that capability. 

 
Casey Courtney:
   CopyBuffer(handleATR,0,1,1,atrValue);

Generally you should check returned value of CopyBuffer. There may be errors during execution of this function, although in your case it only affects the comment value but in other cases it could be catastrophic.

Casey Courtney:
if(posSL != posOpenPrice

Comparing two doubles is not something that works always... I prefer to do it this way:

if(MathAbs(posSL-posOpenPrice)>2*_Point ...
 
Yashar Seyyedin #:

Generally you should check returned value of CopyBuffer. There may be errors during execution of this function, although in your case it only affects the comment value but in other cases it could be catastrophic.

Comparing two doubles is not something that works always... I prefer to do it this way:

Thanks I'll add that stuff in. I'll add multisymbol capability too, shouldn't be that hard