-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathPrice_Action_in_Action.ps
328 lines (268 loc) · 24.6 KB
/
Price_Action_in_Action.ps
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
//@version=5
indicator(title="Price Action in action", shorttitle="Price-Action", format=format.price, precision=2, overlay=true)
// RSI based support-resistance inputs
dontShowRsi = input.bool(defval=false, title="Don't show SRI", tooltip="This option to turn off the RSI. Default: False.")
show1 = input.bool(defval=true, title="Level-1 Support/Resistance Line", group="Levels", tooltip="Opt-in/opt-out for the level-1 RSI.")
show2 = input.bool(defval=true, title="Level-2 Support/Resistance Line", group="Levels", tooltip="Opt-in/opt-out for the level-2 RSI.")
show3 = input.bool(defval=true, title="Level-3 Support/Resistance Line", group="Levels", tooltip="Opt-in/opt-out for the level-3 RSI.")
show4 = input.bool(defval=true, title="Level-4 Support/Resistance Line", group="Levels", tooltip="Opt-in/opt-out for the level-1 RSI.")
showStrengh = input.bool(defval=true, title="Strength of Support/Resistance", group="Levels", tooltip="Opt-in/opt-out the indication of: whether a particular Support/Resistance line is revisited by multiple RSI levels, prints the count.")
rsiLen1 = input.int(defval=7, minval=1, title="RSI Level-1 Length", group="RSI Settings", tooltip="First, lowest level of the Relative Strength Index (RSI) period. Default:7.")
rsiLen2 = input.int(defval=14, minval=1, title="RSI Level-2 Length", group="RSI Settings", tooltip="Second level of the Relative Strength Index (RSI) period. Default: 14.")
rsiLen3 = input.int(defval=21, minval=1, title="RSI Level-3 Length", group="RSI Settings", tooltip="Second level of the Relative Strength Index (RSI) period. Default: 14.")
rsiLen4 = input.int(defval=28, minval=1, title="RSI Level-4 Length", group="RSI Settings", tooltip="Second level of the Relative Strength Index (RSI) period. Default: 14.")
rsiOBLimit = input.float(defval=70.0, minval=1.0, title="Overbought threshold", group="RSI Settings", tooltip="Above which value of RSI we can infer the market is overbought (too much runup happened already).")
rsiOSLimit = input.float(defval=30.0, minval=1.0, title="Oversold threshold", group="RSI Settings", tooltip="Above which value of RSI we can infer the market is oversold (too much selloff happened already).")
extendTrendlines = input.bool(defval=false, title="Extend support/resistance lines to right", group="Trendline", tooltip="Extending the trendlines to right. Note: this will clutter the chart. Use it judiciously.")
defaultTrendlineLength = input.int(defval=20, minval=1, title="Defauft support/resistance lines length", group="Trendline", tooltip="How lengthy the trendlines will be, in case you did not choose Extend support/resistance lines to right flag above.")
supportLineColor = input.color(defval=color.green, title="Support Line color", group="Trendline", tooltip="The color of support line. Default is green.")
resistanceLineColor = input.color(defval=color.red, title="Resistance Line color", group="Trendline", tooltip="The color of resistance line. Default is red.")
lineStyleOption = input.string(defval="solid (─)", title="Support/Resistance Lines Style", options=["solid (─)", "dotted (┈)", "dashed (╌)"], tooltip="The style of support/resistance lines: solid, dashed, dotted. Default: solid.")
// Candlestick Inputs
dontShowCandle = input.bool(defval=false, title="Don't show candlestick patterns", tooltip="This option to turn off the candlestick pattern. Default: False.")
OnBarClosing = input.bool(defval=true, title="Candlestick pattern detection only after bar closing", tooltip="The candlestick will be drawn only after barstate.isconfirmed. Default: True")
DojiSize = input.float(defval=0.1, minval=0.01, step=0.01, maxval=1.0, title="Doji size", tooltip="How thin the body will be compared to the whole candle high-low. Default is 10%.")
DojiGravestoneDragonFlySize = input.float(defval=0.2, minval=0.01, step=0.01, maxval=1.0, title="GraveStone/Dragonfly size", tooltip="How close the Doji is to the high (Dragonfly) or low (Gravestone) of the candle, default 20%.")
MarubozoSize = input.float(defval=0.9, minval=0.0, step=0.01, title="Marubozo Threshold", tooltip="How much the candle body will be considered as marubozo compared to the whole candle size. Default: 90%.")
HammerBodySize = input.float(group="Hammer", defval=0.2, step=0.01, minval=0.01, maxval=1.0, title="Hammer Body Size", tooltip="How thin the Hammer body will be.Default is 20%.")
HammerBodyPlacement = input.float(group="Hammer", defval=0.2, step=0.01, minval=0.01, maxval=1.0, title="Hammer Body Placement", tooltip="How below (or above) from high (or low) it will be placed. Default is 20%.")
SpinningTopRangeToBodyRatio = input.int(defval=3, minval=1, step=1, maxval=10, title="SpinningTop", tooltip="The ratio of Candle's range to body. Default is 3:1.")
StrictEngulf = input.bool(defval=true, title="Strict Engulfing", tooltip="For Strict mode, the whole previous candle including wicks will be engulfed inside the body part of the current big candle. For non-strict mode, the current candle just engulfs the previous candle, possibly by wicks. Default: Strict")
StrictInsideCandle = input.bool(defval=true, title="Strict Inside Candle(Harami)", tooltip="For Strict mode, the whole current candle including wicks will be inside the body part of the previous big candle. For non-strict mode, the current candle just inside the previous candle, possibly by wicks. Default: Strict")
KickerGap = input.int(defval=1, step=1, minval=0, maxval=100, title="Kicker Gap (in percent)", tooltip="How much Gap Up or Gap Down the current candle compared to previous candle, in percentage. Default: 1 %.")
TweezerGap = input.int(defval=10, step=1, minval=0, title="Tweezer Gap (in points)", tooltip="In Tweezer Top/Bottom, the high or low should be same. However that seldom happens. This flag is to provide the tolerance limit, in points. Default: 10 points.")
// Volume Average
showVolume = input.bool(defval=true, title="Volume Information", group="Volumes", tooltip="Whether to include the volume information also in the chart.")
volAvgLen = input.int(defval=20, minval=1, title="Volume Average Period", group="Volumes", tooltip="The period of calculating Volume Weighted Moving Average (VWMA). Default: 20.")
volThresholdMultiplier = input.float(defval=1.0, minval=1.0, maxval=5.0, step=0.1, title="Current Volume : Average Volume Ratio", group="Volumes", tooltip="How many times the current volume should be higher than the avg volume to be flagged.")
// Global Variables
var float[] supports = array.new_float(4)
var float[] resistances = array.new_float(4)
// Utilities
lineStyle = lineStyleOption == "dotted (┈)" ? line.style_dotted :
lineStyleOption == "dashed (╌)" ? line.style_dashed :
line.style_solid
count(arr, key) =>
var int size = 0
for i = 0 to (array.size(arr) == 0 ? na : array.size(arr) - 1)
if (array.get(arr, i) == key)
size := size + 1
size
calculateStrengh(support) =>
// This method calculates if there are multiple levels corresponds to multiple RSI based lines. E.g. some level may appear more than once in multiple Levels (Level-1, Level-2 ... so on)
levels = support ? supports : resistances
for i = 0 to (array.size(levels) == 0 ? na : array.size(levels) - 1)
level = array.get(levels, i)
countLabel = label.new(x=bar_index, y=level, text=str.tostring(array.size(levels)), color=support ? color.green : color.red, style=support ? label.style_label_up : label.style_label_down, size=size.tiny)
/////// RSI Based Support Resistance Calculation methods
calculateRSISupportResistance(lenght, trans) =>
rsi = ta.rsi(close, lenght)
////////////////////// Oversold (OS) region handling
var float[] rsiOSRsiValues = array.new_float(0)
var float[] rsiOSLowPrices = array.new_float(0)
var int[] OSRegionBarIndices = array.new_int(0)
var int rsiOSRegionEntryBarIndex = na
var int rsiOSRegionExitBarIndex = na
if ((ta.crossunder(rsi, rsiOSLimit) or rsi < rsiOSLimit) and barstate.isconfirmed)
// Is inside the RSI OS region, keep on recording the RSI value and price on the respective arrays
rsiOSRegionEntryBarIndex := bar_index
array.push(rsiOSRsiValues, rsi)
array.push(rsiOSLowPrices, low)
array.push(OSRegionBarIndices, bar_index)
if (ta.crossover(rsi, rsiOSLimit) and (not na(rsiOSRegionEntryBarIndex)) and barstate.isconfirmed)
// Now RSI comes up from the OS region. So it's good time to do the calculation. Which calculation?
// - Find out the lowest RSI value from the RSI array
// - Get the corresponding low price from the price array
// - Get the corresponding bar_index from bar_index array
// - Draw the demand/support line on that price
rsiOSRegionExitBarIndex := bar_index
minRsi = array.min(rsiOSRsiValues)
minRsiIndex = array.indexof(rsiOSRsiValues, minRsi)
minPrice = array.get(rsiOSLowPrices, minRsiIndex)
minPriceBarIndex = array.get(OSRegionBarIndices, minRsiIndex)
supportLine = line.new(minPriceBarIndex, minPrice, minPriceBarIndex+defaultTrendlineLength, minPrice, extend=extendTrendlines ? extend.right : extend.none, color=color.new(supportLineColor, trans), width=2, style=lineStyle)
// Pushing to support array for book-keeping
array.push(supports, minPrice)
// Reset action for re-entry
rsiOSRegionEntryBarIndex := na
rsiOSRegionExitBarIndex := na
array.clear(rsiOSRsiValues)
array.clear(rsiOSLowPrices)
array.clear(OSRegionBarIndices)
////////////////////// Overbought (OB) region handling
var float[] rsiOBRsiValues = array.new_float(0)
var float[] rsiOBHighPrices = array.new_float(0)
var int[] OBRegionBarIndices = array.new_int(0)
var int rsiOBRegionEntryBarIndex = na
var int rsiOBRegionExitBarIndex = na
if ((ta.crossover(rsi, rsiOBLimit) or rsi > rsiOBLimit) and barstate.isconfirmed)
// Is inside the RSI OB region, keep on recording the RSI value and price on the respective arrays
rsiOBRegionEntryBarIndex := bar_index
array.push(rsiOBRsiValues, rsi)
array.push(rsiOBHighPrices, high)
array.push(OBRegionBarIndices, bar_index)
if (ta.crossunder(rsi, rsiOBLimit) and (not na(rsiOBRegionEntryBarIndex)) and barstate.isconfirmed)
// Now RSI comes down from the OB region. So it's good time to do the calculation. Which calculation?
// - Find out the highest RSI value from the RSI array
// - Get the corresponding high price from the price array
// - Get the corresponding bar_index from bar_index array
// - Draw the demand/support line on that price
rsiOBRegionExitBarIndex := bar_index
maxRsi = array.max(rsiOBRsiValues)
maxRsiIndex = array.indexof(rsiOBRsiValues, maxRsi)
maxPrice = array.get(rsiOBHighPrices, maxRsiIndex)
maxPriceBarIndex = array.get(OBRegionBarIndices, maxRsiIndex)
resistanceLine = line.new(maxPriceBarIndex, maxPrice, maxPriceBarIndex+defaultTrendlineLength, maxPrice, extend=extendTrendlines ? extend.right : extend.none, color=color.new(resistanceLineColor,trans), width=2, style=lineStyle)
// Pushing to resistance array for book-keeping
array.push(resistances, maxPrice)
// Reset action for re-entry
rsiOBRegionEntryBarIndex := na
rsiOBRegionExitBarIndex := na
array.clear(rsiOBRsiValues)
array.clear(rsiOBHighPrices)
array.clear(OBRegionBarIndices)
/// Now calling RSI calculator 4 fimes for each RSI lennghts
if (not dontShowRsi)
if (show1)
calculateRSISupportResistance(rsiLen1, 0)
if (show2)
calculateRSISupportResistance(rsiLen2, 20)
if (show3)
calculateRSISupportResistance(rsiLen3, 40)
if (show4)
calculateRSISupportResistance(rsiLen4, 60)
// Calculate the strength of support/resistance
if (showStrengh)
calculateStrengh(true)
calculateStrengh(false)
// cleanup supports and resistances arrays
array.clear(supports)
array.clear(resistances)
///////////////////////////////////////////////// Candlestick pattern starts /////////////////////////////////////////////////////////////////////
// Utils
green(open, close) => close > open ? true : false
red(open, close) => close < open ? true : false
body(open, close) => math.abs(open - close)
lowerwick = green(open, close) ? open - low : close - low
upperwick = green(open, close) ? high - close : high - open
crange = high - low
crangep = high[1] - low[1] // previous candle's candle-range
bullish = close > open ? true : false
bearish = close < open ? true : false
oc = OnBarClosing ? barstate.isconfirmed : true
c = not dontShowCandle
// Single Candle Patterns ///////////////////////////////////////////////////////////////////////////////////////
// Doji Logic
doji(open, close, high, low) => body(open, close) <= crange * DojiSize
gravestone(o, c, h, l) => doji(o, c, h, l) and lowerwick / crange <= DojiGravestoneDragonFlySize
dragonfly(o, c, h, l) => doji(o, c, h, l) and upperwick / crange <= DojiGravestoneDragonFlySize
normaldoji(o, c, h, l) => doji(o, c, h, l) and (not gravestone(o, c, h, l)) and (not dragonfly(o, c, h, l))
plotchar(c and oc and normaldoji(open, close, high, low), title='Normal Doji', text='Doji', color=color.gray, display=display.none)
plotchar(c and oc and gravestone(open, close, high, low), title='GraveStone Doji', text='GS\nDoji', color=color.gray, display=display.none)
plotchar(c and oc and dragonfly(open, close, high, low), title='DragonFly Doji', text='DF\nDoji', color=color.gray, display=display.none)
// Marubozo Logic
marubozo(o, c, h, l) => body(o, c) / crange >= MarubozoSize
plotshape(c and oc and marubozo(open, close, high, low), title='Marubozo', text='Marubozo', location=location.abovebar, style=shape.triangledown, color=color.blue)
// Hammer & Inverted Hammer (Pinbar)
hammer(o, c, h, l, inverted = false) => (not doji(o,c,h,l)) and (body(o, c) <= crange * HammerBodySize) and ((inverted ? lowerwick : upperwick) / crange <= HammerBodyPlacement)
plotshape(c and oc and hammer(open, close, high, low), title='Hammer', text='Hammer', location=location.belowbar, style=shape.arrowup, color=color.green, textcolor=color.green)
plotshape(c and oc and hammer(open, close, high, low, true), title='I-Hammer\n/Pinbar', text='I-Hammer\n/Pinbar', location=location.abovebar, style=shape.arrowdown, color=color.red, textcolor=color.red)
// Spinning Top
wickratio = upperwick < lowerwick ? upperwick / lowerwick : lowerwick / upperwick
spinner(o, c, h, l) => (not doji(o,c,h,l)) and (crange / body(o, c) >= SpinningTopRangeToBodyRatio) and (wickratio >= 0.9)
plotshape(c and oc and spinner(open, close, high, low), title='Spinner', text='Spinner', location=location.belowbar, style=shape.cross, color=color.maroon, textcolor=color.maroon)
// Two Candles Patterns ///////////////////////////////////////////////////////////////////////////////////////
lowest = math.min(low,low[1])
highest = math.max(high,high[1])
// Engulfing Pattern
// op: Open Prev, cp: Close Prev .. so on
bullish_engulfing(op, cp, hp, lp, o, c, h, l) => red(op, cp) and green(o, c) and (StrictEngulf ? (c > hp and o < lp) : (h > hp and l < lp))
bearish_engulfing(op, cp, hp, lp, o, c, h, l) => green(op, cp) and red(o, c) and (StrictEngulf ? (o > hp and c < lp) : (h > hp and l < lp))
bullish_engulf_data = bullish_engulfing(open[1], close[1], high[1], low[1], open, close, high, low)
bearish_engulf_data = bearish_engulfing(open[1], close[1], high[1], low[1], open, close, high, low)
plotshape(c and oc and bullish_engulf_data, title='Bull-Engulf', text='Bull-Engulf', location=location.belowbar, style=shape.triangleup, color=color.green, textcolor=color.green)
if (bullish_engulf_data and barstate.isconfirmed)
box.new(bar_index-1, highest, bar_index, lowest, border_color=color.green, border_style=line.style_dotted, border_width=2, bgcolor=color.new(color.white, 100))
plotshape(bearish_engulf_data, title='Bear-Engulf', text='Bear-Engulf', location=location.abovebar, style=shape.triangledown, color=color.red, textcolor=color.red)
if (bearish_engulf_data and barstate.isconfirmed)
box.new(bar_index-1, highest, bar_index, lowest, border_color=color.red, border_style=line.style_dotted, border_width=2, bgcolor=color.new(color.white, 100))
//// Piercing and Dark Cloud Cover Pattern
// These patterns are similar to the engulfing patten. The differences are (ditto from Zerodha Versity):
// The piercing pattern is very similar to the bullish engulfing pattern with a minor variation. In a bullish engulfing pattern, the P2’s green candle engulfs P1’s red candle.
// However in a piercing pattern P2’s green candle partially engulfs P1’s red candle. However, engulfing should be between 50% and less than 100%.
// For example, if P1’s range (Open-Close) is 12, P2’s range should be at least 6 or higher,r but below 12.
prev_candle_middle = (open[1] + close[1]) / 2
bullish_piercing(op, cp, hp, lp, o, c, h, l) => (not doji(op,cp,hp,lp)) and (not doji(o,c,h,l)) and red(op, cp) and green(o, c) and (o <= lp and c > prev_candle_middle and c < op) //
bullish_piering_data = bullish_piercing(open[1], close[1], high[1], low[1], open, close, high, low)
plotshape(c and oc and bullish_piering_data, title='Piercing', text='Piercing', location=location.belowbar, style=shape.triangleup, color=color.green, textcolor=color.green)
if (bullish_piering_data and barstate.isconfirmed)
box.new(bar_index-1, highest, bar_index, lowest, border_color=color.green, border_style=line.style_dotted, border_width=2, bgcolor=color.new(color.white, 100))
// Dark Cloud Cover
// Definition (from Zerodha Versity):
// The dark cloud cover is very similar to the bearish engulfing pattern with a minor variation.
// In a bearish engulfing pattern the red candle on P2 engulfs P1’s green candle.
// However, in a dark cloud cover, the red candle on P2 engulfs about 50 to 100% of P1’s blue candle.
dark_cloud_cover(op, cp, hp, lp, o, c, h, l) => (not doji(op,cp,hp,lp)) and (not doji(o,c,h,l)) and green(op, cp) and red(o, c) and (o >= hp and c < prev_candle_middle and c > op)
ddc_data = dark_cloud_cover(open[1], close[1], high[1], low[1], open, close, high, low)
plotshape(c and oc and ddc_data, title='Dark Cloud Cover', text='DCC', location=location.abovebar, style=shape.triangledown, color=color.red, textcolor=color.red)
if (ddc_data and barstate.isconfirmed)
box.new(bar_index-1, highest, bar_index, lowest, border_color=color.red, border_style=line.style_dotted, border_width=2, bgcolor=color.new(color.white, 100))
// Inside Candle (Harami) Pattern
// op: Open Prev, cp: Close Prev .. so on
bullish_inside_candle(op, cp, hp, lp, o, c, h, l) => red(op, cp) and green(o, c) and (StrictInsideCandle ? (op > h and cp < l) : (hp > h and lp < l))
bearish_inside_candle(op, cp, hp, lp, o, c, h, l) => green(op, cp) and red(o, c) and (StrictInsideCandle ? (cp > h and op < l) : (hp > h and lp < l))
bullish_inside_data = bullish_inside_candle(open[1], close[1], high[1], low[1], open, close, high, low)
bearish_inside_data = bearish_inside_candle(open[1], close[1], high[1], low[1], open, close, high, low)
plotshape(c and oc and bullish_inside_data, title='Bull-IC', text='Bull-IC', location=location.belowbar, style=shape.triangleup, color=color.green, textcolor=color.green)
if (bullish_inside_data and barstate.isconfirmed)
box.new(bar_index-1, highest, bar_index, lowest, border_color=color.green, border_style=line.style_dotted, border_width=2, bgcolor=color.new(color.white, 100))
plotshape(c and oc and bearish_inside_data, title='Bear-IC', text='Bear-IC', location=location.abovebar, style=shape.triangledown, color=color.red, textcolor=color.red)
if (bearish_inside_data and barstate.isconfirmed)
box.new(bar_index-1, highest, bar_index, lowest, border_color=color.red, border_style=line.style_dotted, border_width=2, bgcolor=color.new(color.white, 100))
// Bullish and Bearish Kicker
bullish_kicker(op, cp, o, c) => red(op, cp) and green(o, c) and (o > (op * (1 + (KickerGap / 100))))
bullish_kicker_data = bullish_kicker(open[1], close[1], open, close)
plotshape(c and oc and bullish_kicker_data, title='Bullish Kicker', text='Bull\nKicker', location=location.belowbar, style=shape.arrowup, color=color.green, textcolor=color.green)
if (bullish_kicker_data and barstate.isconfirmed)
box.new(bar_index-1, highest, bar_index, lowest, border_color=color.green, border_style=line.style_dotted, border_width=2, bgcolor=color.new(color.white, 100))
bearish_kicker(op, cp, o, c) => green(op, cp) and red(o, c) and (o < (op * (1 - (KickerGap / 100))))
bearish_kicker_data = bearish_kicker(open[1], close[1], open, close)
plotshape(c and oc and bearish_kicker_data, title='Bearish Kicker', text='Bear\nKicker', location=location.abovebar, style=shape.arrowdown, color=color.red, textcolor=color.red)
if (bearish_kicker_data and barstate.isconfirmed)
box.new(bar_index-1, highest, bar_index, lowest, border_color=color.red, border_style=line.style_dotted, border_width=2, bgcolor=color.new(color.white, 100))
// Tweezers Top and Bottom
tweezer_top(op, cp, hp, lp, o, c, h, l) => (not doji(op,cp,hp,lp)) and (not doji(o,c,h,l)) and green(op, cp) and red(o, c) and (math.abs(crange-crangep) <= TweezerGap) and (math.abs(h-hp) <= TweezerGap)
tweezer_top_data = tweezer_top(open[1], close[1], high[1], low[1], open, close, high, low)
plotshape(c and oc and tweezer_top_data, title='Tweezer Top', text='Bear\nTweezer', location=location.abovebar, style=shape.arrowdown, color=color.red, textcolor=color.red)
if (tweezer_top_data and barstate.isconfirmed)
box.new(bar_index-1, highest, bar_index, lowest, border_color=color.red, border_style=line.style_dotted, border_width=2, bgcolor=color.new(color.white, 100))
tweezer_bottom(op, cp, hp, lp, o, c, h, l) => (not doji(op,cp,hp,lp)) and (not doji(o,c,h,l)) and red(op, cp) and green(o, c) and (math.abs(crange-crangep) <= TweezerGap) and (math.abs(l-lp) <= TweezerGap)
tweezer_bottom_data = tweezer_bottom(open[1], close[1], high[1], low[1], open, close, high, low)
plotshape(c and oc and tweezer_bottom_data, title='Tweezer Bottom', text='Bull\nTweezer', location=location.belowbar, style=shape.arrowup, color=color.green, textcolor=color.green)
if (tweezer_bottom_data and barstate.isconfirmed)
box.new(bar_index-1, highest, bar_index, lowest, border_color=color.green, border_style=line.style_dotted, border_width=2, bgcolor=color.new(color.white, 100))
////// Tripple CandleStick Pattern
// Morning Star (ms_)
// Explanation (from https://zerodha.com/varsity/chapter/multiple-candlestick-patterns-part-3)
ms_day1 = red(open[2],close[2]) and (not doji(open[2], close[2], high[2], low[2]))
ms_day2 = (open[1] < close[2]) and (doji(open[1], close[1], high[1], low[1]) or spinner(open[1], close[1], high[1], low[1]))
ms_day3 = (green(open[1],close[1]) ? open > close[1] : open > open[1]) and green(open, close) and (close > open[2])
ms_cond = ms_day1 and ms_day2 and ms_day3
plotshape(c and oc and ms_cond, title='Morning-Star', text='Morning-Star', location=location.belowbar, style=shape.triangleup, color=color.green, textcolor=color.green)
lowestp = math.min(low,low[1],low[2])
highestp = math.max(high,high[1],high[2])
if (ms_cond and barstate.isconfirmed)
box.new(bar_index-2, highestp, bar_index, lowestp, border_color=color.green, border_style=line.style_dashed, border_width=2, bgcolor=color.new(color.white, 100))
// Evening Star (es_)
// Explanation (from https://zerodha.com/varsity/chapter/multiple-candlestick-patterns-part-3)
es_day1 = green(open[2],close[2]) and (not doji(open[2], close[2], high[2], low[2]))
es_day2 = (open[1] > close[2]) and (doji(open[1], close[1], high[1], low[1]) or spinner(open[1], close[1], high[1], low[1]))
es_day3 = (green(open[1],close[1]) ? open < open[1] : open < close[1]) and red(open, close) and (close < open[2])
es_cond = es_day1 and es_day2 and es_day3
plotshape(c and oc and es_cond, title='Evening-Star', text='Evening-Star', location=location.abovebar, style=shape.triangledown, color=color.red, textcolor=color.red)
if (es_cond and barstate.isconfirmed)
box.new(bar_index-2, highestp, bar_index, lowestp, border_color=color.red, border_style=line.style_dashed, border_width=2, bgcolor=color.new(color.white, 100))
// Volume-Weighed Moving Average calculation
vwmaAvg = ta.vwma(close, volAvgLen)
vwma_latest = ta.vwma(close, 1)
plotshape((showVolume and barstate.isconfirmed and (vwma_latest > (vwmaAvg * volThresholdMultiplier))), title='VolumeData', text='', location=location.abovebar, style=shape.diamond, color=color.gray, textcolor=color.gray, size=size.tiny)