-
Notifications
You must be signed in to change notification settings - Fork 14
/
CandlestickPatterns.pine
284 lines (225 loc) · 18.5 KB
/
CandlestickPatterns.pine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
// 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 ----------------------//