How to Detect Pullbacks in Pine
This lesson demonstrates how to detect high-quality trend-continuation pullbacks in price action using Pine Script code.
Check out my other free lessons!Source Code
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © ZenAndTheArtOfTrading / PineScriptMastery.com // @version=5 indicator(title="TheArtOfTrading.com|", overlay=true) // Import ZenLibrary as zen import ZenAndTheArtOfTrading/ZenLibrary/7 as zen // Get user input EMA_LENGTH = input.int(title="EMA Length", defval=50, minval=1, tooltip="Exponential moving average period") STOP_SIZE_INPUT = input.float(title="Stop Distance (xATR)", defval=1.0, minval=0.0, tooltip="Stop loss distance from highs/lows as an ATR multiplier") RISK_REWARD = input.float(title="Risk:Reward", defval=1.0, minval=0.1, tooltip="Risk:Reward profile") SIGNAL_TYPE = input.string(title="Enable Signals", defval="Both", options=["Both", "Long", "Short"], tooltip="Enable/disable long/short signals") // Check what signals are enabled var bool TAKE_LONGS = SIGNAL_TYPE == "Both" or SIGNAL_TYPE == "Long" var bool TAKE_SHORTS = SIGNAL_TYPE == "Both" or SIGNAL_TYPE == "Short" // Get EMA & ATR & Stop Size ema = ta.ema(close, EMA_LENGTH) currentATR = ta.atr(14) stopSize = currentATR * STOP_SIZE_INPUT // Get SL and Target prices tradeStopPrice = 0.0 tradeTargetPrice = 0.0 longStopDistance = close - ta.lowest(low, 5) + stopSize shortStopDistance = ta.highest(high, 5) - close + stopSize // SIGNAL RULES: // rule1 = Engulfing candle above/below EMA // rule2 = Current swing high/low // rule3 = Ensure engulfing candle is not massive // Validate long signals rule1L = close > ema and zen.barsBelowMA(3, ema) <= 1 and zen.isBullishEC() rule2L = low == ta.lowest(low, 7) or low[1] == ta.lowest(low, 7) rule3L = close < ta.highest(open, 5) and ta.tr < (currentATR * 2) validLong = TAKE_LONGS and rule1L and rule2L and rule3L // Validate short signals rule1S = close < ema and zen.barsAboveMA(3, ema) <= 1 and zen.isBearishEC() rule2S = high == ta.highest(high, 7) or high[1] == ta.highest(high, 7) rule3S = close > ta.lowest(open, 5) and ta.tr < (currentATR * 2) validShort = TAKE_SHORTS and rule1S and rule2S and rule3S // Store long signal stop loss & target for drawing if validLong tradeStopPrice := close - longStopDistance tradeTargetPrice := close + longStopDistance * RISK_REWARD // Store short signal stop loss & target for drawing if validShort tradeStopPrice := close + shortStopDistance tradeTargetPrice := close - shortStopDistance * RISK_REWARD // Draw EMA plot(ema, title="EMA", color=color.red, linewidth=1) // Draw signals plotshape(validLong, title="Bullish Engulfing", location=location.belowbar, color=color.green, style=shape.triangleup) plotshape(validShort, title="Bearish Engulfing", color=color.red, style=shape.triangledown) // Draw stops & targets over 2 bars so the lines are more visible plot(validLong or validLong[1] ? validLong ? tradeStopPrice : tradeStopPrice[1] : na, title="Long Stop Price", color=color.red, style=plot.style_linebr) plot(validShort or validShort[1] ? validShort ? tradeStopPrice : tradeStopPrice[1] : na, title="Short Stop Price", color=color.red, style=plot.style_linebr) plot(validLong or validLong[1] ? validLong ? tradeTargetPrice : tradeTargetPrice[1] : na, title="Long Target Price", color=color.green, style=plot.style_linebr) plot(validShort or validShort[1] ? validShort ? tradeTargetPrice : tradeTargetPrice[1] : na, title="Short Target Price", color=color.green, style=plot.style_linebr) // Send out an alert if this candle meets our conditions alertcondition(validLong or validShort, title="API Alert!", message="Pullback signal for {{ticker}}")