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
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.
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;
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 } } } } } } } }
You are missing trading opportunities:
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
Registration
Log in
You agree to website policy and terms of use
If you do not have an account, please register
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?