What’s the Best Way to Decide TP/SL Levels Across Different Timeframes based on Indicator value?

[Deleted]  
Hello,  

For example, let’s take the RSI indicator and EURUSD. Suppose you buy at oversold and sell at overbought, and you are trading across all timeframes. How do you decide what Take Profit and Stop Loss levels to set?  

On the 1-minute timeframe, the average gap in points/pips between overbought and oversold is around ~80 points, but on the 5-minute timeframe the average gap is about 300 points. The bigger the timeframe, the bigger the gap between overbought and oversold.  

So, how do you decide the Take Profit and Stop Loss levels based on the indicator and timeframe? What should the TP and SL values be?  

I am asking this because I created a simple EA to test different indicators like RSI, Bollinger Bands, Moving Averages, etc. It checks all timeframes and trades whenever there is a signal. The problem is the EA uses fixed Take Profit and Stop Loss values for all timeframes. For example, if I set 100 points for TP and 100 points for SL, it works well for a 1-minute oversold/overbought signal, but it is too small for signals on higher timeframes. How can I decide these values so they can be automated?  
 
anuj71:
TP/SL should be adapted to the volatility of the timeframe.

A standard way is to use multiples of the ATR of the current period, or a percentage of the range between overbought and oversold, maintaining the same risk/reward ratio in all timeframes.

This prevents a TP of 100 points from being too low in H1 or too high in M1.
 
Miguel Angel Vico Alba #:
TP/SL should be adapted to the volatility of the timeframe.

A standard way is to use multiples of the ATR of the current period

I'm still interested in this concept of linking the TP to volatility. Do you add the ATR value with a multiplier to the current close price (for a buy position)?

 
Conor Mcnamara #I'm still interested in this concept of linking the TP to volatility. Do you add the ATR value with a multiplier to the current close price (for a buy position)?
For a buy you usually set SL = Close − ATR × k and TP = Close + ATR × m, with k and m as chosen multipliers to keep a consistent risk/reward ratio.
[Deleted]  
Miguel Angel Vico Alba #:

Setting Risk to reward

extern int ATR_Period = 14;
extern int RiskToReward_TP = 2;
extern int RiskToReward_SL = 1;
enum ATRMode_enum {AverageATR, FirstATR, LastATR};
extern ATRMode_enum ATRMode = AverageATR;

Getting ATR Value

//+------------------------------------------------------------------+
//| Extract ATR based on first/last TF from comment                  |
//+------------------------------------------------------------------+
int GetATRFromComment(string comment, string symbol)
  {
   double fPoint = MarketInfo(symbol, MODE_POINT);
//--- detect first TF (scan from left)
   string firstTF = "";
   if(StringFind(comment, "1M")  != -1)
      firstTF = "1M";
   else
      if(StringFind(comment, "5M")  != -1)
         firstTF = "5M";
      else
         if(StringFind(comment, "15-M") != -1)
            firstTF = "15-M";
         else
            if(StringFind(comment, "30M") != -1)
               firstTF = "30M";
            else
               if(StringFind(comment, "1H")  != -1)
                  firstTF = "1H";
               else
                  if(StringFind(comment, "4H")  != -1)
                     firstTF = "4H";
                  else
                     if(StringFind(comment, "1D")  != -1)
                        firstTF = "1D";

//--- detect last TF (scan from right side)
   string lastTF = "";
   if(StringFind(comment, "1D") != -1)
      lastTF = "1D";
   else
      if(StringFind(comment, "4H") != -1)
         lastTF = "4H";
      else
         if(StringFind(comment, "1H") != -1)
            lastTF = "1H";
         else
            if(StringFind(comment, "30M") != -1)
               lastTF = "30M";
            else
               if(StringFind(comment, "15-M") != -1)
                  lastTF = "15-M";
               else
                  if(StringFind(comment, "5M")  != -1)
                     lastTF = "5M";
                  else
                     if(StringFind(comment, "1M")  != -1)
                        lastTF = "1M";

//--- convert TF strings to ENUM
   ENUM_TIMEFRAMES tfFirst = PERIOD_CURRENT;
   ENUM_TIMEFRAMES tfLast  = PERIOD_CURRENT;

   if(firstTF == "1M")
      tfFirst = PERIOD_M1;
   if(firstTF == "5M")
      tfFirst = PERIOD_M5;
   if(firstTF == "15-M")
      tfFirst = PERIOD_M15;
   if(firstTF == "30M")
      tfFirst = PERIOD_M30;
   if(firstTF == "1H")
      tfFirst = PERIOD_H1;
   if(firstTF == "4H")
      tfFirst = PERIOD_H4;
   if(firstTF == "1D")
      tfFirst = PERIOD_D1;

   if(lastTF == "1M")
      tfLast = PERIOD_M1;
   if(lastTF == "5M")
      tfLast = PERIOD_M5;
   if(lastTF == "15-M")
      tfLast = PERIOD_M15;
   if(lastTF == "30M")
      tfLast = PERIOD_M30;
   if(lastTF == "1H")
      tfLast = PERIOD_H1;
   if(lastTF == "4H")
      tfLast = PERIOD_H4;
   if(lastTF == "1D")
      tfLast = PERIOD_D1;

//--- ATR values
   double atrFirst = iATR(symbol, tfFirst, ATR_Period, 0);
   double atrLast  = iATR(symbol, tfLast, ATR_Period, 0);

//--- if only one TF found, both first and last will be same
   if(tfFirst == tfLast)
      return (int)MathRound(atrFirst / fPoint);

//--- choose based on mode
   if(ATRMode == AverageATR)
      return (int)MathRound(((atrFirst + atrLast) / 2.0) / fPoint);
   if(ATRMode == FirstATR)
      return (int)MathRound(atrFirst / fPoint);
   if(ATRMode == LastATR)
      return (int)MathRound(atrLast / fPoint);

   return 0; // default
  }

Calling function and setting Take Profit and StopLoss based on Risk to Reward

int fATRValue = GetATRFromComment("1M", "EURUSD");
      TakeProfit = fATRValue * RiskToReward_TP;
      StopLoss = fATRValue * RiskToReward_SL;
 
anuj71 #:
You are on the right track. 👍
 
Usually people do not recommend storing ATR values in the trade comment because your broker can change it. Here's how I do it for a stepped ATR trailing stop:


If I did something wrong or if anyone has any suggestions please let me know. I don't actually use this for anything because I now force all my trailing stops to react only a new 1 min bars so I can use 1 min OHLC during testing. 

void Stepped_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
            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)
            
            // Block for finding ATR from bar position was opened on instead of storing it in comments                                                                                                                     
            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 NaN

            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
                  }
           }
          }
         }
        }
       }
      }
}