CandlestickPatterns.pine
Copy
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © FxCloudTrader
//@version=5
indicator(title="Candlestick Patterns", shorttitle="Candlestick", overlay=true, precision = 0)
atr = ta.atr(14)
offset_atr_hhll = 0.5
offset_atr_engulfing = 0.8
offset_atr_HOLPLOHP = 1.1
offset_atr_4barfractal = 1.4
offset_atr_bodymass = 2
//------------------- functions -------------------
setLocationByATR(con_dn, con_up, offset) =>
float con_dn_loc1 = na
if con_dn
con_dn_loc1 := high + offset * atr
float con_up_loc1 = na
if con_up
con_up_loc1 := low - offset * atr
[con_dn_loc1, con_up_loc1]
// ------------------------------------ COPY OF Engulfing Candlestick Pattern ------------------------------------
// indicator(title="Candlestick Pattern - Engulfing", shorttitle="Engulfing", overlay=true, precision = 0)
bool enableEngulfing = input.bool(true, 'Enable Engulfing signal', group = "1. Engulfing signal") // true
// Options for setting the minimum requirement of candlestick body to range percentage.
// It's less important for the left formation to have a fat body.
// However, for the right formation, namely the engulfing candle,
// we want to see higher percentage of body to price range and small wicks
min_body_to_range_pct_lt = input.int(0, 'Minimum body % for left bar', minval=0, maxval=100, step=5, tooltip = 'Minimum body to price range percentage for the left formation', group = "1. Engulfing signal")
min_body_to_range_pct_rt = input.int(0, 'Minimum body % for right bar', minval=0, maxval=100, step=5, tooltip = 'Minimum body to price range percentage for the right formation', group = "1. Engulfing signal")
// Only show engulfing signal if the body of the engulfing candle is larger than 1 Average True Range(ATR)
// The idea is we prefer engulfing candles that show dominance and mean business.
filter_by_atr = input.bool(false, "Only display superior engulfing signals", "Only display engulfing candles whose body range is larger than 1 ATR", group = "1. Engulfing signal")
display_body_to_range_label = input.bool(false, "Display body to price range percentage", group = "1. Engulfing signal")
display_body_range_label = input.bool(false, "Display body of price range", group = "1. Engulfing signal")
setting_engulfing_bar_close_beyond_prev_max = input.bool(true, "Engulfing Candle Closes Above/Below Prior Bar's High/Low", group = "1. Engulfing signal")
getRange(x, y) => math.abs(x - y)
engulfing_cond_dn = open >= math.max(close[1],open[1]) and
close <= math.min(close[1],open[1]) and
open > close and
getRange(open[1], close[1])/getRange(high[1], low[1]) * 100> min_body_to_range_pct_lt and
getRange(open, close)/getRange(high, low) * 100> min_body_to_range_pct_rt
con_dn = engulfing_cond_dn
if filter_by_atr and engulfing_cond_dn
con_dn := getRange(open, close)>atr?true:false
engulfing_bar_close_below_prev_max = close < low[1]
if setting_engulfing_bar_close_beyond_prev_max and engulfing_cond_dn
con_dn := engulfing_bar_close_below_prev_max ? true:false
if setting_engulfing_bar_close_beyond_prev_max and engulfing_cond_dn and filter_by_atr
con_dn := engulfing_bar_close_below_prev_max ? true:false
engulfing_cond_up = open <= math.min(close[1],open[1]) and
close >= math.max(close[1],open[1]) and
open < close and
getRange(open[1], close[1])/getRange(high[1], low[1]) * 100> min_body_to_range_pct_lt and
getRange(open, close)/getRange(high, low) * 100> min_body_to_range_pct_rt
con_up = engulfing_cond_up
if filter_by_atr and engulfing_cond_up
con_up := getRange(open, close)>atr?true:false
engulfing_bar_close_above_prev_max = close > high[1]
if setting_engulfing_bar_close_beyond_prev_max and engulfing_cond_up
con_up := engulfing_bar_close_above_prev_max ? true:false
if setting_engulfing_bar_close_beyond_prev_max and engulfing_cond_up and filter_by_atr
con_up := engulfing_bar_close_above_prev_max ? true:false
// Display engulfing body percentage in comparison with its range (high and low)
if display_body_to_range_label and (engulfing_cond_dn or engulfing_cond_up)
label.new(bar_index, engulfing_cond_dn?high:low,
str.tostring(math.ceil(getRange(open, close)/getRange(high, low) * 100)) + "%",
yloc = engulfing_cond_dn?yloc.abovebar:yloc.belowbar,
style = engulfing_cond_dn?label.style_label_down:label.style_label_up)
// Display engulfing body in points
if display_body_range_label and (engulfing_cond_dn or engulfing_cond_up)
label.new(bar_index, engulfing_cond_dn?high:low,
"body:" + str.tostring(getRange(open, close)) + "\natr:" + str.tostring(atr, format.mintick),
yloc = engulfing_cond_dn?yloc.abovebar:yloc.belowbar,
style = engulfing_cond_dn?label.style_label_down:label.style_label_up)
[con_engulfing_dn_loc, con_engulfing_up_loc] = setLocationByATR(con_dn, con_up, offset_atr_engulfing)
plotshape(con_engulfing_dn_loc, "Bearish Engulfing Circle", shape.square, location.absolute, color = color.new(color.blue, 50), size = size.auto, display = enableEngulfing?display.all:display.data_window)
plotshape(con_engulfing_up_loc, "Bullish Engulfing Circle", shape.square, location.absolute, color = color.new(color.blue, 50), size = size.auto, display = enableEngulfing?display.all:display.data_window)
// ------------------------------------ END OF COPY OF Engulfing Candlestick Pattern ------------------------------------
// ------------------------------------ COPY OF Inside Bar Candlestick Pattern ------------------------------------
// This is a 3-bar formation setup
// The range of -1 bar is capped within the -2 bar's
// The direction of current bar dictates the direction of the signal
// indicator(title="Inside Bar Candlestick Pattern", shorttitle="Inside Bar", overlay=true, precision = 0)
// getRange(x, y) => math.abs(x - y)
bool enableInsideBar = input.bool(false, "Enable Inside Bar signal", group = "2. Inside Bar signal") // true
int minimumCloseTriggerCandle = input.int(50, "Minimum Pencentage of Close of Price Candle Range", step = 5, group = "2. Inside Bar signal")// The default is 50%, meaning the closing price needs to be above 50% of its price range for a bullish candle
range_bar_2 = getRange(high[2], low[2])
range_bar_1 = getRange(high[1], low[1])
bool insbar_cond_up = low[2] < low[1] and high[2] > high[1] and close > open //and close >= hl2
bool insbar_cond_dn = low[2] < low[1] and high[2] > high[1] and close < open //and close <= hl2
bool weakUp = close < hl2
bool weakDn = close > hl2
// if insbar_cond_up and weakUp
// label.new(bar_index, na, "Weak", yloc = yloc.belowbar, style = label.style_none, textcolor = color.red, size = size.normal)
// if insbar_cond_dn and weakDn
// label.new(bar_index, na, "Weak", yloc = yloc.abovebar, style = label.style_none, textcolor = color.red, size = size.normal)
plotshape(insbar_cond_up, "Inside Bar Bullish", shape.cross, location.belowbar, color = color.new(weakUp?color.yellow:color.black, 50), size = size.auto, display = enableInsideBar?display.all:display.data_window)
plotshape(insbar_cond_dn, "Inside Bar Bearish", shape.cross, location.abovebar, color = color.new(weakDn?color.yellow:color.black, 50), size = size.auto, display = enableInsideBar?display.all:display.data_window)
// ------------------------------------END OF COPY OF Inside Bar Candlestick Pattern ------------------------------------
// ------------------------------------COPY OF HOLP/LOHP Candlestick Pattern ------------------------------------
bool enableHOLPLOHP = input.bool(true, "Enable HOLP/LOHP signal", group = "3. HOLP/LOHP signal") // true
bool _bPivot = input.bool(false, 'Enable Pivot Point', group = "3. HOLP/LOHP signal")
_p = input.int(title='Lookback Periods', defval=10, minval=2, group = "3. HOLP/LOHP signal")
_b2bar = input.bool(false, 'Trigger bar needs to close below/above pivot bar and its prior bar?', group = "3. HOLP/LOHP signal")
var _boolNewLow = 0
_sessionLow = 0.0
lastLoBar = -ta.lowestbars(low, _p + 1)
if low[0] < ta.lowest(_p)[1]
_sessionLow := low
_boolNewLow := 1
_arrowHOLP = 0.0
_conditionHOLP = if _b2bar
_boolNewLow == 1 and close[0] > high[lastLoBar] and close[0] > high[lastLoBar + 1] // The HOLP needs to close above the highs of session low bar and its prior bar, hence it's name
else
_boolNewLow == 1 and close[0] > high[lastLoBar] // The HOLP needs to close above the highs of session low bar
if _conditionHOLP
_arrowHOLP := close
_boolNewLow := 0
if _bPivot
label.new(bar_index[lastLoBar], na, "▲\n" + str.tostring(low[lastLoBar], format.mintick), yloc = yloc.belowbar, style = label.style_none, textcolor = color.black, size = size.normal)
var _boolNewHigh = 0
_sessionHigh = 0.0
lastHiBar = -ta.highestbars(high, _p + 1)
if high[0] > ta.highest(_p)[1]
_sessionHigh := high
_boolNewHigh := 1
_arrowLOHP = 0.0
_conditionLOHP = if _b2bar
_boolNewHigh == 1 and close[0] < low[lastHiBar] and close[0] < low[lastHiBar + 1]
else
_boolNewHigh == 1 and close[0] < low[lastHiBar]
if _conditionLOHP
_arrowLOHP := close
_boolNewHigh := 0
if _bPivot
label.new(bar_index[lastHiBar], na, str.tostring(high[lastHiBar], format.mintick) + "\n▼", yloc = yloc.abovebar, style = label.style_none, textcolor = color.black, size = size.normal)
[con_LOHP_loc1, con_HOLP_loc1] = setLocationByATR(_conditionLOHP, _conditionHOLP, offset_atr_HOLPLOHP)
plotshape(enableHOLPLOHP?con_LOHP_loc1:na, title = 'LOHP', style=shape.diamond, location=location.absolute, offset=0, color=color.new(color.orange, 50), size=size.auto, display = enableHOLPLOHP?display.all:display.data_window)
plotshape(enableHOLPLOHP?con_HOLP_loc1:na, title = 'HOLP', style=shape.diamond, location=location.absolute, offset=0, color=color.new(color.orange, 50), size=size.auto, display = enableHOLPLOHP?display.all:display.data_window)
plotshape(_sessionLow, title = 'Session Low', style=shape.xcross, location=location.belowbar, offset=0, color=color.new(color.maroon, 0), size=size.small, display=display.none)
plotshape(_sessionHigh, title = 'Session High', style=shape.xcross, location=location.abovebar, offset=0, color=color.new(color.maroon, 0), size=size.small, display=display.none)
// If ploting circles are confusing on the chart, use char instead
// plotchar(enableHOLPLOHP?_conditionLOHP:na, title = 'LOHP', char = '⌉', location = location.abovebar, color=color.new(color.maroon, 50), size=size.small, display=display.all)
// plotchar(enableHOLPLOHP?_conditionHOLP:na, title = 'HOLP', char = '⌋', location = location.belowbar, color=color.new(color.maroon, 50), size=size.small, display=display.all)
// ------------------------------------ END OF COPY OF HOLP/LOHP Candlestick Pattern ------------------------------------
//---------------------- COPY OF Candlestick Kicker --------------------------
bool enableKicker = input.bool(true, "Enable Candlestick Kicker Pattern", group = "4. Candlestick Kicker Signal") //true
_bodyPencLeft = input.int(0, 'Minimum body % for left bar', minval=0, maxval=100, step=5, tooltip = 'Minimum body to range percentage for the left formation', group = "4. Candlestick Kicker Signal")
_bodyPencRight = input.int(0, 'Minimum body % for right bar', minval=0, maxval=100, step=5, tooltip = 'Minimum body to range percentage for the right formation', group = "4. Candlestick Kicker Signal")
// getRange(x, y) => math.abs(x - y)
condition_kicker_up_threshold = open[1] > close[1] and
open < close and
open > open[1] and
low > low[1] and
getRange(open[1], close[1])/getRange(high[1], low[1]) * 100> _bodyPencLeft and
getRange(open, close)/getRange(high, low) * 100> _bodyPencRight
condition_kicker_dn_threshold = open[1] < close[1] and
open > close and
open < open[1] and
high < high[1] and
getRange(open[1], close[1])/getRange(high[1], low[1]) * 100> _bodyPencLeft and
getRange(open, close)/getRange(high, low) * 100> _bodyPencRight
plotshape(condition_kicker_up_threshold?close:na, 'kicker upwards', style = shape.circle, location = location.belowbar, size = size.auto, color = color.green, display = enableKicker?display.all:display.data_window)
plotshape(condition_kicker_dn_threshold?close:na, 'kicker downwards', style = shape.circle, location = location.abovebar, size = size.auto, color = color.red, display = enableKicker?display.all:display.data_window)
//---------------------- END OF COPY OF Candlestick Kicker --------------------------
//---------------------- COPY OF Body Mass Indicator --------------------------
// indicator("Body Mass Indicator", "BMI", overlay = true)
enableBodyMass = input.bool(true, "Enable Body Mass Indicator", group = "5. Body Mass Indicator") // true
enableBodyATRMass = input.bool(false, "Enable Body Mass ATR Indicator", group = "5. Body Mass Indicator")
lookbackperiod = input.int(10, "Look back periods", group = "5. Body Mass Indicator")
noOfAtr = input.int(1, "Number of ATRs vs body mass", group = "5. Body Mass Indicator")
GetPipSize() =>
pipSizeCalc = syminfo.type == "forex" ? syminfo.mintick *10 : 1
// label format messed up forex mintick, therefore forex format has to be specified, other types work with format.mintick
GetFormat() =>
stringFormat = syminfo.type == "forex" ? '#.##' : format.mintick
BodyRange() =>
math.abs(close - open)
GetBodyRangeFormatted(value) =>
value / GetPipSize()
// Get the highest body range of the past number of bars
highestBodyRange = ta.highest(BodyRange(), lookbackperiod)
// Signal biggest body mass candle of the last 10 candles
// if highestBodyRange==BodyRange() and enableBodyMass
// if close > open
// label.new(bar_index, na, str.tostring(GetBodyRangeFormatted(highestBodyRange)), yloc = yloc.belowbar, style = label.style_none, textcolor = color.new(color.black, 20), size = size.normal) //"▲\n" +
// else if close < open
// label.new(bar_index, na, str.tostring(GetBodyRangeFormatted(highestBodyRange)), yloc = yloc.abovebar, style = label.style_none, textcolor = color.new(color.black, 20), size = size.normal) // + "\n▼"
// Signal candles with body mass bigger than 1 ATR
bmass_cond_up = BodyRange()> ta.atr(lookbackperiod) * noOfAtr and enableBodyATRMass and close > open
bmass_cond_dn = BodyRange()> ta.atr(lookbackperiod) * noOfAtr and enableBodyATRMass and close < open
[con_bmass_loc1, con_bmass_loc2] = setLocationByATR(bmass_cond_dn, bmass_cond_up, offset_atr_bodymass)
if bmass_cond_up
label.new(bar_index, con_bmass_loc2, "▲\n" + str.tostring(GetBodyRangeFormatted(BodyRange()), GetFormat()), style = label.style_none, textcolor = color.new(color.black, 50), size = size.normal)
else if bmass_cond_dn
label.new(bar_index, con_bmass_loc1, str.tostring(GetBodyRangeFormatted(BodyRange()), GetFormat()) + "\n▼", style = label.style_none, textcolor = color.new(color.black, 50), size = size.normal)
//Display every candlestick range for testing environment
// label.new(bar_index[0], na, str.tostring(BodyRange(), format.mintick) + "", yloc = yloc.belowbar, style = label.style_none, textcolor = color.black, size = size.normal)
// plotshape(highestBodyRange==BodyRange()?highestBodyRange:na, title = 'Body Mass', style=shape.flag, location=location.bottom, offset=0, color=color.new(color.yellow, 50), size=size.small, display = enableBodyMass?display.all:display.data_window)
//---------------------- END OF COPY OF Body Mass Indicator --------------------------
//---------------------- Candlestick Higher Highs and Lower Lows ----------------------//
bool enableHHLL = input.bool(true, "Enable Higher Highs and Lower Lows Indicator", group = "6. Candlestick Higher Highs and Lower Lows Indicator")
// 3-bar formation, bar 0 close needs to be lower than bar 2 close
hhll_cond_dn = high[0] < high[1] and low[0] < low[1] and high[1] < high[2] and low[1] < low[2] and close[0] < close[2] //and close[1] < open[1]
hhll_cond_up = high[0] > high[1] and low[0] > low[1] and high[1] > high[2] and low[1] > low[2] and close[0] > close[2] //and close[1] > open[1]
[con_hhll_dn_loc, con_hhll_up_loc] = setLocationByATR(hhll_cond_dn, hhll_cond_up, offset_atr_hhll)
plotshape(con_hhll_dn_loc, 'downwards', style = shape.arrowdown, location = location.absolute, size = size.auto, color = color.new(color.red, 50), display = enableHHLL?display.all:display.data_window)
plotshape(con_hhll_up_loc, 'upwards', style = shape.arrowup, location = location.absolute, size = size.auto, color = color.new(color.green, 50), display = enableHHLL?display.all:display.data_window)
//---------------------- Candlestick Higher Highs and Lower Lows ----------------------//
//---------------------- ATR Warning Indicator ----------------------//
enableATR_warning = input.bool(false, "Enable ATR Warning Indicator", group = "7. ATR Warning") // true
int __atrWarning = input.int(14, "ATR", step = 1, group = "7. ATR Warning")
atr_current_bar = ta.atr(1)
atr_cond_over = atr_current_bar >= __atrWarning
atr_cond_uder = atr_current_bar < __atrWarning
plotshape(atr_cond_over, "Over ATR", style = shape.circle, location = location.bottom, color = color.new(color.black, 0), display = enableATR_warning?display.all:display.none)
plotshape(atr_cond_uder, "Under ATR", style = shape.circle, location = location.bottom, color = color.new(color.silver, (1-atr_current_bar/atr)*100), display = enableATR_warning?display.all:display.none)
//---------------------- ATR Warning Indicator ----------------------//
//---------------------- Tom's 4 bar fractal ----------------------//
bool enable4barf = input.bool(true, "Enable 4-Bar Fractalr", group = "8. 4-Bar Fractal - Tom Hougaard")
barf_cond_up = close[0] > high[1] and close[0] > high[3]
barf_cond_dn = close[0] < low[1] and close[0] < low[3]
[con_4bar_loc1, con_4bar_loc2] = setLocationByATR(barf_cond_dn, barf_cond_up, offset_atr_4barfractal)
plotshape(con_4bar_loc2, "4 Bar Fractal Up", style = shape.arrowup, location = location.absolute, size = size.auto, color = color.new(color.purple, 0), display = enable4barf?display.all:display.none)
plotshape(con_4bar_loc1, "4 Bar Fractal Down", style = shape.arrowdown, location = location.absolute, size = size.auto, color = color.new(color.purple, 0), display = enable4barf?display.all:display.none)
//---------------------- Tom's 4 bar fractal ----------------------//
Show all 284 lines