Feedback on ATR step based trailing stop

 

This is an ATR step based trailing stop and it works fine in the strategy tester but would like feedback on the SERIES_SYNCHRONIZED and iBarShift checking. Did I do it correctly or am I missing something crucial? Originally I was storing the ATR value in the trade comment since my broker never modified it but now I decided to change that because I may be using a different broker soon. Is there anything else I should add/am forgetting? 

void ATR_TrailingStop(string symbol){
   for (int i = PositionsTotal() - 1; i >= 0; i--) {                                                                                // Loop through all open positions
      ulong posTicket = PositionGetTicket(i);                                                                                       // Get the current position's ticket
      if (PositionSelectByTicket(posTicket)) {                                                                                      // Select the position
         if (PositionGetString(POSITION_SYMBOL) == symbol && PositionGetInteger(POSITION_MAGIC) == EA_main_magic_num) {
            double posOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);                                                           // Get the price the position was opened at
            datetime posOpenTime = (datetime)PositionGetInteger(POSITION_TIME);                                                     // Get the time the position was opened at
            double posSL = PositionGetDouble(POSITION_SL);                                                                          // Get the position stop loss
            double posTP = PositionGetDouble(POSITION_TP);                                                                          // Get the position take profit
            double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);                                                                      // Get current ask price
            double bid = SymbolInfoDouble(symbol, SYMBOL_BID);                                                                      // Get current bid price
            double point = SymbolInfoDouble(symbol, SYMBOL_POINT);                                                                  // Get symbol point size
            string comment = PositionGetString(POSITION_COMMENT);                                                                   // Get the position comment
            double initialATR = 0;                                                                                                  // Initialize variable for storing initial ATR
                       
            if(!SeriesInfoInteger(symbol,EA_tf,SERIES_SYNCHRONIZED)) continue;                                                      // Check if symbol data is synchronized (so we can safely use iBarShift)
            
            int shift = iBarShift(symbol,EA_tf,posOpenTime,false);                                                                  // Find the bar index corresponding to the position's open time (<= posOpenTime)
            if(shift < 0) continue;                                                                                                 // If no bar was found in case of not enough history, skip this position
            int atrShift = shift + 1;                                                                                               // Use the next bar so ATR comes from the last fully closed bar before/at entry
            if(BarsCalculated(handleATR) <= atrShift) continue;                                                                     // Ensure the ATR indicator has enough calculated bars
            if(CopyBuffer(handleATR,0,atrShift,1,bufferATR)!=1) continue;                                                           // Try to copy a single ATR value from buffer; skip if it fails
            initialATR = bufferATR[0];                                                                                              // Store the ATR value
            if(initialATR <= 0.0 || !MathIsValidNumber(initialATR)) continue;                                                       // Validate ATR: skip if it's invalid, <= 0, or NA

            double atrIncrement = initialATR * TrailATRMultiplier;                                                                  // Step size for SL adjustment
                                                                                                                                    
            if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {                                                           // Buy positions
               if (posSL != posOpenPrice && posOpenPrice > posSL && bid >= (posOpenPrice + initialATR * BreakevenATRMultiplier)) {  // check if position has reached breakeven threshold
                  double newSL = posOpenPrice;                                                                                      // Set SL to breakeven
                  trade.PositionModify(posTicket, newSL, posTP);                                                                    // Modify position
            } else if (posSL >= posOpenPrice) {                                                                                     // Start of Trailing Stop
               double priceDistance = bid - posOpenPrice;                                                                           // Distance from open price in points
               double atrDistance = priceDistance / initialATR;                                                                     // Distance in ATR units
               if (atrDistance >= BreakevenATRMultiplier + TrailATRMultiplier) {                                                    // Ensure price has moved beyond breakeven + 1 trailing stop increment
                  double steps = MathFloor((atrDistance - BreakevenATRMultiplier) / TrailATRMultiplier);                            // Number of ATR steps beyond breakeven
                  double newSL = posOpenPrice + (steps * atrIncrement);                                                             // New SL in ATR increments
                  if (newSL > posSL && MathAbs(newSL - posSL) > point) {                                                            // Only move SL if it's an improvement
                     trade.PositionModify(posTicket, newSL, posTP);                                                                 // Modify position
                  }
              }
             }
            }

            if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {                                                          // Sell positions
               if (posSL != posOpenPrice && posOpenPrice < posSL && ask <= (posOpenPrice - initialATR * BreakevenATRMultiplier)) {  // Check if position has reached breakeven threshold
                  double newSL = posOpenPrice;                                                                                      // Set SL to breakeven
                  trade.PositionModify(posTicket, newSL, posTP);                                                                    // Modify position
            } else if (posSL <= posOpenPrice) {                                                                                     // Start of Trailing Stop 
               double priceDistance = posOpenPrice - ask;                                                                           // Distance from open price in points
               double atrDistance = priceDistance / initialATR;                                                                     // Distance in ATR units
               if (atrDistance >= BreakevenATRMultiplier + TrailATRMultiplier) {                                                    // Ensure price has moved beyond breakeven + 1 ATR
                  double steps = MathFloor((atrDistance - BreakevenATRMultiplier) / TrailATRMultiplier);                            // Number of 1.0 ATR steps beyond breakeven
                  double newSL = posOpenPrice - (steps * atrIncrement);                                                             // New SL in 1.0 ATR increments
                  if (newSL < posSL && MathAbs(newSL - posSL) > point) {                                                            // Only move SL if it's an improvement
                     trade.PositionModify(posTicket, newSL, posTP);                                                                 // Modify position
                  }
           }
          }
         }
        }
       }
      }
}
 
The code is apparently correct. 

Anyway in my personal opinion it's far from having a logic. Checking which was the ATR value on the time on which the trade is placed seems beautiful to talk about, but have no sense in the reality.

Use ATR of bigger time-frames, like daily, use the last candle value which do not change, take a portion of it and use it.
 
Fabio Cavalloni #:
The code is apparently correct. 

Anyway in my personal opinion it's far from having a logic. Checking which was the ATR value on the time on which the trade is placed seems beautiful to talk about, but have no sense in the reality.

Use ATR of bigger time-frames, like daily, use the last candle value which do not change, take a portion of it and use it.

Thanks for feedback, I fully expect to be driving a Ferrari in two weeks.

Jokes aside since I keep swing trading more to forex and lower timeframe stuff for futures I already use ATR values from Daily and 4H. I'll probably code your recommendation eventually.