OIf you follow my work closely, you know my obsession with OrderBlocks and Retracements. We will reuse the same logic, but using candle engulfments and candle engulfment reversals. It is the latter that we will interpret as OrderBlocks, and candle engulfments as buy or sell signals.Instead of using the price and the average of the candles, here we prefer to use 4 exponential moving averages over 4 different periods with a true range for detecting volatility and determining if a candle should be considered engulfed or not.
(note : if you know the principle of candle engulfment you should know that a bullish engulfment does not necessarily mean a buy signal).
1 • We use last detected ‘Bearish/ Bullish Reversal Engulfing Candle’ as an Retracement Level.
(Keep in mind Historical Retracements with extended lines is still useful and can still have an impact on the actual trend).
2 • We use ‘Bearish/Bullish Candle’ as confirmation of entry point.
3 • You can play with the ‘Maximum Volatility’ value or the ‘True Range’ Multiplier value to filter detected engulfing as you want.
4 • HTF and Auto HTF option available.
5 • Everything is customizable in settings (show inputs, colors, lines size etc…)
6 • Alerts is available for Engulfing Candle and Crossing Lines.
–NOTE : This script is not beginner’s Level and is intended for Traders with advanced knowledge of Candlestick Patterns and the work of Michael j. Huddleston on the OrderBlocks.
Next-Gen Engulfing Retracement in action on S&P500 Index.

Here is the complete list of features present in this indicator :
- Full Indicator Customization
- Engulfing Retracement and Labels
- Strong Engulfing Retracement and Labels
- Retracement lines automatically plotted when an Engulfment is detected until the line is cross.
- Full Range (High/Low) for Bearish/Bullish Retracement Lines
- Extend Lines option
- Last Retracement Lines Prices
- Wick – Zone Lines Type Choice
- Engulfing OB Labels with Price
This indicator contain Alerts, you can set them by choosing the ‘Any Alerts Function Call‘ to automatically configure them.
Or copy / paste the source code into your pine editor :
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © RickSimpson //@version=5 indicator('Next-Gen Engulfing Retracement', 'Next-Gen Engulfing Retracement', overlay=true, max_bars_back=500, max_lines_count=500, max_labels_count=500) ///////////////////////////////////// // Next-Gen Engulfing Retracement // ///////////////////////////////////// //Groups Setup groupcolor = "COLOR SETUP" groupretracement = "RETRACEMENT LINES SETTINGS" groupengulfing = "ENGULFING SETTINGS" groupalert = "ALERTS SETUP" //Customization Inputs bearishengulfingcolor = input.color(color.red, 'Bearish Engulfing Color', group=groupcolor) bullishengulfingcolor = input.color(color.green, 'Bullish engulfing Color', group=groupcolor) //Inputs showstrong = input.bool(true, 'Show Strong Engulfing Retracements?', group=groupretracement) show = input.bool(true, 'Show Engulfing Retracements?', group=groupretracement) maxlines = input.int(10, 'Maximum Lines', minval=1, maxval=500, group=groupretracement, inline='lines') layout = input.string('Wick', 'Lines Type', options=['Wick', 'Zone'], group=groupretracement, inline='lines') linessize = input.int(1, 'Lines Width ', minval=1, maxval=3, group=groupretracement, inline='lines style') linestyle = input.string('Dotted', 'Lines Style', options=['Solid', 'Dotted', 'Dashed'], group=groupretracement, inline='lines style') extend = input.bool(false, 'Extend Lines?', group=groupretracement, inline='lines style') showengulfing = input.bool(true, 'Strong Engulfing Labels?', group=groupengulfing) showallengulfing = input.bool(false, 'Engulfing Labels?', group=groupengulfing) engulfingalerts = input.bool(true, 'Enable Engulfing Candles Alerts?', group=groupalert) crossingalerts = input.bool(true, 'Enable Retracement Lines Crossing Alerts?', group=groupalert) //Price Variables Declaration open_ = open high_ = high low_ = low close_ = close bar_index_ = bar_index //Color Call Function fzonecolor(obcolor, _call) => c1 = color.r(obcolor) c2 = color.g(obcolor) c3 = color.b(obcolor) color.rgb(c1, c2, c3, _call) //Round Function round_f(x) => math.round(x / syminfo.mintick) * syminfo.mintick //Truncated Percentile Function percent_1(x, y) => z = x * 100 / y z //Lines Styles String Function f_linestyle(_style) => _style == 'Solid' ? line.style_solid : _style == 'Dotted' ? line.style_dotted : line.style_dashed //Directions Variables Declaration beardir = close < open bulldir = close > open //Body Candle Size Calculation body = math.abs(close - open) //Momentum Calculation math = math.max(high - low, math.abs(high - close[1]), math.abs(low - close[1])) //Average True Range Built-in Function atr = ta.atr(100) //Engulfment Size Calculation bodysizetop = atr * 1.1 bodysizebottom = atr / 3 smallbodysizetop = atr / 3 smallbodysizebottom = atr / 8 //Engulfment Conditions bodyengulfing = body > bodysizebottom and body < bodysizetop smallbodyengulfing = body > smallbodysizebottom and body < smallbodysizetop //Engulfing Calculation bearengulfing = (smallbodyengulfing[1] or bodyengulfing[1]) and bulldir[1] and beardir and open[1] > close bullengulfing = (smallbodyengulfing[1] or bodyengulfing[1]) and beardir[1] and bulldir and close > open[1] //Boolean Conditions to Float var float bearengulfingprice = na if bearengulfing bearengulfingprice := high bearengulfingprice var float bullengulfingprice = na if bullengulfing bullengulfingprice := low bullengulfingprice if showallengulfing l = ta.change(bearengulfingprice) ? label.new(bar_index_, bearengulfingprice[1] + 0.01, str.tostring(round_f(bearengulfingprice)), color=color.new(bearishengulfingcolor, 100), textcolor=bearishengulfingcolor, style=label.style_label_down, yloc=yloc.abovebar, size=size.small) : ta.change(bullengulfingprice) ? label.new(bar_index_, bullengulfingprice[1] - 0.01, str.tostring(round_f(bullengulfingprice)), color=color.new(bullishengulfingcolor, 100), textcolor=bullishengulfingcolor, style=label.style_label_up, yloc=yloc.belowbar, size=size.small) : na l //Strong Engulfing Calculation strongbearengulfing = beardir[2] and bullengulfing[1] and bearengulfing strongbullengulfing = bulldir[2] and bearengulfing[1] and bullengulfing //Boolean Conditions to Float var float strongbearengulfingprice = na if strongbearengulfing strongbearengulfingprice := high strongbearengulfingprice var float strongbullengulfingprice = na if strongbullengulfing strongbullengulfingprice := low strongbullengulfingprice if showengulfing l = ta.change(strongbearengulfingprice) ? label.new(bar_index_, strongbearengulfingprice[1] + 0.01, str.tostring(round_f(strongbearengulfingprice)), color=color.new(bearishengulfingcolor, 100), textcolor=bearishengulfingcolor, style=label.style_label_down, yloc=yloc.abovebar, size=size.small) : ta.change(strongbullengulfingprice) ? label.new(bar_index_, strongbullengulfingprice[1] - 0.01, str.tostring(round_f(strongbullengulfingprice)), color=color.new(bullishengulfingcolor, 100), textcolor=bullishengulfingcolor, style=label.style_label_up, yloc=yloc.belowbar, size=size.small) : na l //Plotting plotshape(strongbearengulfing, title='Strong Bearish Engulfing', text=' ', color=bearishengulfingcolor, style=shape.triangledown, location=location.abovebar, size=size.small) barcolor(beardir[2] and bullengulfing[1] and bearengulfing ? bearishengulfingcolor : na) plotshape(strongbullengulfing, title='Strong Bullish Engulfing', text=' ', color=bullishengulfingcolor, style=shape.triangleup, location=location.belowbar, size=size.small) barcolor(bulldir[2] and bearengulfing[1] and bullengulfing ? bullishengulfingcolor : na) plotshape(showallengulfing ? bearengulfing : na, title= "Bearish Engulfing", color=bearishengulfingcolor, text=' ', textcolor=bearishengulfingcolor, style=shape.arrowdown, location=location.abovebar, size=size.tiny) plotshape(showallengulfing ? bullengulfing : na, title= "Bullish Engulfing", color=bullishengulfingcolor, text=' ', textcolor=bullishengulfingcolor, style=shape.arrowup, location=location.belowbar, size=size.tiny) //Alerts if engulfingalerts and strongbearengulfing == 1 alert('Strong Bearish Engulfing Detected! At ' + str.tostring(strongbearengulfingprice), alert.freq_once_per_bar) if engulfingalerts and strongbullengulfing == 1 alert('Strong Bullish Engulfing Detected! At ' + str.tostring(strongbullengulfingprice), alert.freq_once_per_bar) if engulfingalerts and bearengulfing == 1 alert('Bearish Engulfing Detected! At ' + str.tostring(bearengulfingprice), alert.freq_once_per_bar) if engulfingalerts and bullengulfing == 1 alert('Bullish Engulfing Detected! At ' + str.tostring(bullengulfingprice), alert.freq_once_per_bar) //Retracement Lines Variables Declaration var int numberofline = maxlines var float upperphzone = na var float upperplzone = na var float lowerphzone = na var float lowerplzone = na var line[] upperphzonearr = array.new_line(0, na) var line[] upperplzonearr = array.new_line(0, na) var line[] lowerphzonearr = array.new_line(0, na) var line[] lowerplzonearr = array.new_line(0, na) var line upperphzoneline = na var line upperplzoneline = na var line lowerphzoneline = na var line lowerplzoneline = na var bool[] upperzonetestedarr = array.new_bool(0, false) var bool[] lowerzonetestedarr = array.new_bool(0, false) var bool upperzonetested = false var bool lowerzonetested = false var bool nobool = true var bool showprice = true var color upperzonecolor = bearishengulfingcolor var color lowerzonecolor = bullishengulfingcolor var label[] labelpharr = array.new_label(0, na) var label[] labelplarr = array.new_label(0, na) var label labelph = na var label labelpl = na var int numberofline2 = maxlines var float upperphzone2 = na var float upperplzone2 = na var float lowerphzone2 = na var float lowerplzone2 = na var line[] upperphzonearr2 = array.new_line(0, na) var line[] upperplzonearr2 = array.new_line(0, na) var line[] lowerphzonearr2 = array.new_line(0, na) var line[] lowerplzonearr2 = array.new_line(0, na) var line upperphzoneline2 = na var line upperplzoneline2 = na var line lowerphzoneline2 = na var line lowerplzoneline2 = na var bool[] upperzonetestedarr2 = array.new_bool(0, false) var bool[] lowerzonetestedarr2 = array.new_bool(0, false) var bool upperzonetested2 = false var bool lowerzonetested2 = false var bool nobool2 = true var color upperzonecolor2 = bearishengulfingcolor var color lowerzonecolor2 = bullishengulfingcolor var string stronglinestyle = 'Solid' var label[] labelpharr2 = array.new_label(0, na) var label[] labelplarr2 = array.new_label(0, na) var label labelph2 = na var label labelpl2 = na //Strong Bearish Engulfing Retracement Lines Calculation if showstrong and strongbearengulfing upperphzone := high_ upperplzone := close_ < open_ ? close_ : open_ upperplzoneline := layout == 'Zone' ? line.new(bar_index_, upperplzone, bar_index, upperplzone, width=linessize) : na upperphzoneline := nobool ? line.new(bar_index_, upperphzone, bar_index, upperphzone, width=linessize) : line.new(bar_index_, (upperphzone + upperplzone) / 2, bar_index, (upperphzone + upperplzone) / 2, width=linessize) labelph := showprice ? label.new(bar_index_, nobool ? upperphzone : (upperphzone + upperplzone) / 2, text=str.tostring(bar_index - bar_index_), textcolor=upperzonecolor, style=label.style_none) : na if array.size(upperphzonearr) > numberofline line.delete(array.shift(upperphzonearr)) line.delete(array.shift(upperplzonearr)) array.shift(upperzonetestedarr) label.delete(array.shift(labelpharr)) array.push(upperphzonearr, upperphzoneline) array.push(upperplzonearr, upperplzoneline) array.push(upperzonetestedarr, extend ? true : false) array.push(labelpharr, labelph) if array.size(upperplzonearr) > 0 for i = 0 to array.size(upperplzonearr) - 1 by 1 line tempupperline = array.get(upperphzonearr, i) line templowerline = array.get(upperplzonearr, i) label linepricelabel = array.get(labelpharr, i) bool tested = array.get(upperzonetestedarr, i) line.set_style(tempupperline, f_linestyle(stronglinestyle)) line.set_style(templowerline, f_linestyle(stronglinestyle)) line.set_color(tempupperline, color.from_gradient(i, 1, numberofline, fzonecolor(upperzonecolor, 00), fzonecolor(upperzonecolor, 00))) line.set_color(templowerline, color.from_gradient(i, 1, numberofline, fzonecolor(upperzonecolor, 00), fzonecolor(upperzonecolor, 00))) label.set_textcolor(linepricelabel, color.from_gradient(i, 1, numberofline, fzonecolor(upperzonecolor, 00), upperzonecolor)) label.set_text(linepricelabel, str.tostring(round_f(line.get_y1(tempupperline)))) label.set_text(linepricelabel, ' Bearish Engulfing - ' + str.tostring(round_f(line.get_y1(tempupperline)))) label.set_x(linepricelabel, bar_index) crossed = high > line.get_y1(tempupperline) if crossed and not tested array.set(upperzonetestedarr, i, true) label.delete(linepricelabel) if crossingalerts and crossed and not tested array.set(upperzonetestedarr, i, true) label.delete(linepricelabel) alert('Strong Bearish Engulfing Line Has Been Crossed! At ' + str.tostring(close), alert.freq_once_per_bar) else if extend ? tested : not tested line.set_x2(tempupperline, bar_index) array.set(upperphzonearr, i, tempupperline) line.set_x2(templowerline, bar_index) array.set(upperplzonearr, i, templowerline) //Strong Bullish Engulfing Retracement Lines Calculation if showstrong and strongbullengulfing lowerplzone := low_ lowerphzone := close_ < open_ ? open_ : close_ lowerphzoneline := layout == 'Zone' ? line.new(bar_index_, lowerphzone, bar_index, lowerphzone, width=linessize) : na lowerplzoneline := nobool ? line.new(bar_index_, lowerplzone, bar_index, lowerplzone, width=linessize) : line.new(bar_index_, (lowerphzone + lowerplzone) / 2, bar_index, (lowerphzone + lowerplzone) / 2, width=linessize) labelpl := showprice ? label.new(bar_index_, nobool ? lowerplzone : (lowerphzone + lowerplzone) / 2, text=str.tostring(bar_index - bar_index_), textcolor=lowerzonecolor, style=label.style_none) : na if array.size(lowerphzonearr) > numberofline line.delete(array.shift(lowerphzonearr)) line.delete(array.shift(lowerplzonearr)) array.shift(lowerzonetestedarr) label.delete(array.shift(labelplarr)) array.push(lowerphzonearr, lowerphzoneline) array.push(lowerplzonearr, lowerplzoneline) array.push(lowerzonetestedarr, extend ? true : false) array.push(labelplarr, labelpl) if array.size(lowerplzonearr) > 0 for i = 0 to array.size(lowerplzonearr) - 1 by 1 line tempupperline = array.get(lowerphzonearr, i) line templowerline = array.get(lowerplzonearr, i) label linepricelabel = array.get(labelplarr, i) bool tested = array.get(lowerzonetestedarr, i) line.set_style(tempupperline, f_linestyle(stronglinestyle)) line.set_style(templowerline, f_linestyle(stronglinestyle)) line.set_color(tempupperline, color.from_gradient(i, 1, numberofline, fzonecolor(lowerzonecolor, 00), fzonecolor(lowerzonecolor, 00))) line.set_color(templowerline, color.from_gradient(i, 1, numberofline, fzonecolor(lowerzonecolor, 00), fzonecolor(lowerzonecolor, 00))) label.set_textcolor(linepricelabel, color.from_gradient(i, 1, numberofline, fzonecolor(lowerzonecolor, 00), lowerzonecolor)) label.set_text(linepricelabel, str.tostring(round_f(line.get_y1(templowerline)))) label.set_text(linepricelabel, ' Bullish Engulfing - ' + str.tostring(round_f(line.get_y1(templowerline)))) label.set_x(linepricelabel, bar_index) crossed = low < line.get_y1(templowerline) if crossed and not tested array.set(lowerzonetestedarr, i, true) label.delete(linepricelabel) if crossingalerts and crossed and not tested array.set(lowerzonetestedarr, i, true) label.delete(linepricelabel) alert('Strong Bullish Engulfing Line Has Been Crossed! At ' + str.tostring(close), alert.freq_once_per_bar) else if extend ? tested : not tested line.set_x2(tempupperline, bar_index) array.set(lowerphzonearr, i, tempupperline) line.set_x2(templowerline, bar_index) array.set(lowerplzonearr, i, templowerline) //Bearish Engulfing Retracement Lines Calculation if show and bearengulfing upperphzone2 := high_ upperplzone2 := close_ < open_ ? close_ : open_ upperplzoneline2 := layout == 'Zone' ? line.new(bar_index_, upperplzone2, bar_index, upperplzone2, width=linessize) : na upperphzoneline2 := nobool ? line.new(bar_index_, upperphzone2, bar_index, upperphzone2, width=linessize) : line.new(bar_index_, (upperphzone2 + upperplzone2) / 2, bar_index, (upperphzone2 + upperplzone2) / 2, width=linessize) labelph2 := showprice ? label.new(bar_index_, nobool ? upperphzone2 : (upperphzone2 + upperplzone2) / 2, text=str.tostring(bar_index - bar_index_), textcolor=upperzonecolor2, style=label.style_none) : na if array.size(upperphzonearr2) > numberofline2 line.delete(array.shift(upperphzonearr2)) line.delete(array.shift(upperplzonearr2)) array.shift(upperzonetestedarr2) label.delete(array.shift(labelpharr2)) array.push(upperphzonearr2, upperphzoneline2) array.push(upperplzonearr2, upperplzoneline2) array.push(upperzonetestedarr2, extend ? true : false) array.push(labelpharr2, labelph2) if array.size(upperplzonearr2) > 0 for i = 0 to array.size(upperplzonearr2) - 1 by 1 line tempupperline2 = array.get(upperphzonearr2, i) line templowerline2 = array.get(upperplzonearr2, i) label linepricelabel2 = array.get(labelpharr2, i) bool tested2 = array.get(upperzonetestedarr2, i) line.set_style(tempupperline2, f_linestyle(linestyle)) line.set_style(templowerline2, f_linestyle(linestyle)) line.set_color(tempupperline2, color.from_gradient(i, 1, numberofline2, fzonecolor(upperzonecolor2, 00), fzonecolor(upperzonecolor2, 00))) line.set_color(templowerline2, color.from_gradient(i, 1, numberofline2, fzonecolor(upperzonecolor2, 00), fzonecolor(upperzonecolor2, 00))) label.set_textcolor(linepricelabel2, color.from_gradient(i, 1, numberofline2, fzonecolor(upperzonecolor2, 00), upperzonecolor2)) label.set_text(linepricelabel2, str.tostring(round_f(line.get_y1(tempupperline2)))) label.set_text(linepricelabel2, ' Bearish Engulfing - ' + str.tostring(round_f(line.get_y1(tempupperline2)))) label.set_x(linepricelabel2, bar_index) crossed = high > line.get_y1(tempupperline2) if crossed and not tested2 array.set(upperzonetestedarr2, i, true) label.delete(linepricelabel2) if crossingalerts and crossed and not tested2 array.set(upperzonetestedarr2, i, true) label.delete(linepricelabel2) alert('Bearish Engulfing Line Has Been Crossed! At ' + str.tostring(close), alert.freq_once_per_bar) else if extend ? tested2 : not tested2 line.set_x2(tempupperline2, bar_index) array.set(upperphzonearr2, i, tempupperline2) line.set_x2(templowerline2, bar_index) array.set(upperplzonearr2, i, templowerline2) //Bullish Engulfing Retracement Lines Calculation if show and bullengulfing lowerplzone2 := low_ lowerphzone2 := close_ < open_ ? open_ : close_ lowerphzoneline2 := layout == 'Zone' ? line.new(bar_index_, lowerphzone2, bar_index, lowerphzone2, width=linessize) : na lowerplzoneline2 := nobool ? line.new(bar_index_, lowerplzone2, bar_index, lowerplzone2, width=linessize) : line.new(bar_index_, (lowerphzone2 + lowerplzone2) / 2, bar_index, (lowerphzone2 + lowerplzone2) / 2, width=linessize) labelpl2 := showprice ? label.new(bar_index_, nobool ? lowerplzone2 : (lowerphzone2 + lowerplzone2) / 2, text=str.tostring(bar_index - bar_index_), textcolor=lowerzonecolor2, style=label.style_none) : na if array.size(lowerphzonearr2) > numberofline2 line.delete(array.shift(lowerphzonearr2)) line.delete(array.shift(lowerplzonearr2)) array.shift(lowerzonetestedarr2) label.delete(array.shift(labelplarr2)) array.push(lowerphzonearr2, lowerphzoneline2) array.push(lowerplzonearr2, lowerplzoneline2) array.push(lowerzonetestedarr2, extend ? true : false) array.push(labelplarr2, labelpl2) if array.size(lowerplzonearr2) > 0 for i = 0 to array.size(lowerplzonearr2) - 1 by 1 line tempupperline2 = array.get(lowerphzonearr2, i) line templowerline2 = array.get(lowerplzonearr2, i) label linepricelabel2 = array.get(labelplarr2, i) bool tested2 = array.get(lowerzonetestedarr2, i) line.set_style(tempupperline2, f_linestyle(linestyle)) line.set_style(templowerline2, f_linestyle(linestyle)) line.set_color(tempupperline2, color.from_gradient(i, 1, numberofline2, fzonecolor(lowerzonecolor2, 00), fzonecolor(lowerzonecolor2, 00))) line.set_color(templowerline2, color.from_gradient(i, 1, numberofline2, fzonecolor(lowerzonecolor2, 00), fzonecolor(lowerzonecolor2, 00))) label.set_textcolor(linepricelabel2, color.from_gradient(i, 1, numberofline2, fzonecolor(lowerzonecolor2, 00), lowerzonecolor2)) label.set_text(linepricelabel2, str.tostring(round_f(line.get_y1(templowerline2)))) label.set_text(linepricelabel2, ' Bullish Engulfing - ' + str.tostring(round_f(line.get_y1(templowerline2)))) label.set_x(linepricelabel2, bar_index) crossed = low < line.get_y1(templowerline2) if crossed and not tested2 array.set(lowerzonetestedarr2, i, true) label.delete(linepricelabel2) if crossingalerts and crossed and not tested2 array.set(lowerzonetestedarr2, i, true) label.delete(linepricelabel2) alert('Bullish Engulfing Line Has Been Crossed! At ' + str.tostring(close), alert.freq_once_per_bar) else if extend ? tested2 : not tested2 line.set_x2(tempupperline2, bar_index) array.set(lowerphzonearr2, i, tempupperline2) line.set_x2(templowerline2, bar_index) array.set(lowerplzonearr2, i, templowerline2)
The content covered on this website is NOT investment advice and I am not a financial advisor.