Skip to content

Instantly share code, notes, and snippets.

@kuldeepkeshwar
Created March 26, 2022 17:57
Show Gist options
  • Save kuldeepkeshwar/b65c194b22efb02b3cd0e3562d928263 to your computer and use it in GitHub Desktop.
Save kuldeepkeshwar/b65c194b22efb02b3cd0e3562d928263 to your computer and use it in GitHub Desktop.
//@version=5
// ══════════════════════════════════════════════════════════════════════════════════════════════════ //
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
//# *
//# * Study : Price Action - Support & Resistance
//# * - Support & Resistance based on Volume
//# * - Volume Weighted Colored Bars and Sign of Exhaustion Indication Add-On
//# * Author : © dgtrd
//# *
//# * Revision History
//# * Release : Jan 25, 2021
//# * Update : Jan 26, 2021 : User Request : Add price option for intruments with no volume data
//# * Update : Mar 18, 2021 : Ability to draw lines and cofigure alerts when volume spikes detected
//# * Update : Mar 21, 2021 : Ability to draw lines and cofigure alerts when high volatility detected
//# * - line customization abaility
//# * Update : Sep 03, 2021 : Ability to control number of lines drawn
//# * Update : Feb 21, 2022 : Added Volume Profile, inspired by Ildar Akhmetgaleev's 'Poor man's volume profile'
//# *
//# * ══════════════════════════════════════════════════════════════════════════════════════════════
// ══════════════════════════════════════════════════════════════════════════════════════════════════ //
indicator('Price Actio', 'S&R', true, max_bars_back = 500, max_lines_count = 500, max_boxes_count = 500)
// -Inputs ══════════════════════════════════════════════════════════════════════════════════════ //
// ---------------------------------------------------------------------------------------------- //
// Definitions ---------------------------------------------------------------------------------- //
group_support_and_resistance = 'Consecutively Increasing Volume / Price'
tooltip_support_and_resistance = 'Moments where\n' +
'- price is bullish or bearish consecutively for minimum 3 bars and on increasing volume with at least one bar\'s volume is above volume moving average\n' +
'or\n' +
'- price is bullish or bearish consecutively on increasing/decreasing price for minimum 3 bars'
group_volume_spike_sign_of_exhaustion = 'Volume Spike - Sign of Exhaustion'
tooltip_volume_spike_sign_of_exhaustion = 'Moments where\n' +
'huge volume detected : current volume is grater than the product of the theshold value and volume moving average\n' +
'presents idea : huge volume may be a sign of exhaustion and may lead to sharp reversals'
group_high_volatility = 'High Volatility'
tooltip_high_volatility = 'Moments where\n' +
'price range of the current bar is grater than the product of the theshold value and average true range value of defined period'
group_volume_weighted_colored_bars = 'Volume Weighted Colored Bars'
tooltip_volume_weighted_colored_bars = 'Colors bars based on the bar\'s volume relative to volume moving average\n' +
'trading tip : a potential breakout trading opportunity may occur when price moves above a resistance level or moves below a support level on increasing volume'
tooltip_volume_moving_average = 'Volume simple moving average, serves as reference to\n' +
'- Support and Resistance,\n' +
'- Volume Weighted Colored Bars,\n' +
'- Volume Spike - Sign of Exhaustion\ncalculations'
// User Input Declarations ---------------------------------------------------------------------- //
// ---------------------------------------------------------------------------------------------- //
// Consecutively Increasing Volume / Price ----------------------------------------------------- //
i_lenLookback = input.int(360, 'Lookback Interval (Bars)', minval=0, step=10)
i_sourceSnR = input.string('Volume', 'S & R Calculation Source', options=['Price', 'Volume'], group=group_support_and_resistance, tooltip=tooltip_support_and_resistance)
i_isSnR = input.bool(true, 'S & R Lines', inline='SR', group=group_support_and_resistance)
i_srLnColor = input.color(#4dd0e141, '', inline='SR', group=group_support_and_resistance)
i_srLnWidth = input.int(3, '', inline='SR', group=group_support_and_resistance)
i_srLnStyle = input.string('Solid', '', options=['Dashed', 'Dotted', 'Solid'], inline='SR', group=group_support_and_resistance)
// ---------------------------------------------------------------------------------------------- //
// Volume Spike - Sign of Exhaustion ------------------------------------------------------------ //
i_vSpikeLb = input.bool(true, '🚦', inline='SRS1', group=group_volume_spike_sign_of_exhaustion, tooltip=tooltip_volume_spike_sign_of_exhaustion)
i_vSpikeThresh = input.float(4.669, 'Volume Spike Theshold', minval=.1, step=.1, inline='SRS1', group=group_volume_spike_sign_of_exhaustion)
i_isSnRSpike = input.bool(true, 'S & R Lines', inline='SRS2', group=group_volume_spike_sign_of_exhaustion)
i_spLnColor = input.color(#ffb74d69, '', inline='SRS2', group=group_volume_spike_sign_of_exhaustion)
i_spLnWidth = input.int(3, '', inline='SRS2', group=group_volume_spike_sign_of_exhaustion)
i_spLnStyle = input.string('Solid', '', options=['Dashed', 'Dotted', 'Solid'], inline='SRS2', group=group_volume_spike_sign_of_exhaustion)
i_spLnBullLevel = input.string('Both', 'Levels : Bullish', options=['High', 'Close', 'Both'], inline='SRS3', group=group_volume_spike_sign_of_exhaustion)
i_spLnBearLevel = input.string('Both', ' Bearish', options=['Low', 'Close', 'Both'], inline='SRS3', group=group_volume_spike_sign_of_exhaustion)
// ---------------------------------------------------------------------------------------------- //
// High Volatility ------------------------------------------------------------------------------ //
i_hATRLb = input.bool(true, '⚡', inline='ATR', group=group_high_volatility, tooltip=tooltip_high_volatility)
i_atrLength = input.int(11, 'ATR : Length', inline='ATR', group=group_high_volatility)
i_atrMult = input.float(2.718, 'Mult', minval=.1, step=.1, inline='ATR', group=group_high_volatility)
i_hATRLn = input.bool(true, 'S & R Lines', inline='AT1', group=group_high_volatility)
i_hATRLnColor = input.color(#81c78455, '', inline='AT1', group=group_high_volatility)
i_hATRLnWidth = input.int(3, '', inline='AT1', group=group_high_volatility)
i_hATRLnStyle = input.string('Solid', '', options=['Dashed', 'Dotted', 'Solid'], inline='AT1', group=group_high_volatility)
i_haLnBullLevel = input.string('Both', 'Levels : Bullish', options=['High', 'Close', 'Both'], inline='AT2', group=group_high_volatility)
i_haLnBearLevel = input.string('Both', ' Bearish', options=['Low', 'Close', 'Both'], inline='AT2', group=group_high_volatility)
// ---------------------------------------------------------------------------------------------- //
// Volume Weighted Colored Bars ----------------------------------------------------------------- //
i_vwcb = input.bool(true, '', inline='VWC', group=group_volume_weighted_colored_bars, tooltip=tooltip_volume_weighted_colored_bars)
i_vwcbHighThresh = input.float(1.618, 'Thesholds : High ', minval=1., step=.1, inline='VWC', group=group_volume_weighted_colored_bars)
i_vwcbLowThresh = input.float(0.618, 'Low', minval=.1, step=.1, inline='VWC', group=group_volume_weighted_colored_bars)
// ---------------------------------------------------------------------------------------------- //
// Volume Moving Average : Base ----------------------------------------------------------------- //
i_vSMA = ta.sma(nz(volume), input.int(89, 'Volume Moving Average Length', group='General Settings', tooltip=tooltip_volume_moving_average))
// -Calculations ════════════════════════════════════════════════════════════════════════════════ //
// ---------------------------------------------------------------------------------------------- //
// Definitions ---------------------------------------------------------------------------------- //
nzVolume = nz(volume)
risingVol = nzVolume >= nzVolume[1]
bullCandle = close > open
bearCandle = close < open
risingPrice = close > close[1]
fallingPrice = close < close[1]
lwstPrice = ta.lowest (low , 3)
hstPrice = ta.highest(high, 3)
weightedATR = i_atrMult * ta.atr(i_atrLength)
range_1 = math.abs(high - low)
x2 = timenow + 7 * math.round(ta.change(time))
sProcessing = time > timenow - i_lenLookback * (timeframe.isintraday ? timeframe.multiplier * 86400000 / 1440 : timeframe.multiplier * 86400000)
// ---------------------------------------------------------------------------------------------- //
// Consecutively Increasing Volume / Price ----------------------------------------------------- //
falling = if i_sourceSnR == 'Volume'
bearCandle and bearCandle[1] and bearCandle[2] and nzVolume > i_vSMA and risingVol and risingVol[1]
else
bearCandle and bearCandle[1] and bearCandle[2] and fallingPrice and fallingPrice[1] and fallingPrice[2]
rising = if i_sourceSnR == 'Volume'
bullCandle and bullCandle[1] and bullCandle[2] and nzVolume > i_vSMA and risingVol and risingVol[1]
else
bullCandle and bullCandle[1] and bullCandle[2] and risingPrice and risingPrice[1] and risingPrice[2]
y = ta.valuewhen(falling or rising, falling ? lwstPrice : hstPrice, 0)
x1 = ta.valuewhen(falling or rising, time, 0)
// ---------------------------------------------------------------------------------------------- //
// Volume Spike - Sign of Exhaustion ------------------------------------------------------------ //
exhaustVol = nzVolume > i_vSpikeThresh * i_vSMA
x1V = ta.valuewhen(exhaustVol, time, 0)
// ---------------------------------------------------------------------------------------------- //
// High Volatility ------------------------------------------------------------------------------ //
highVolatility = range_1 > weightedATR
x1hV = ta.valuewhen(highVolatility, time, 0)
// ---------------------------------------------------------------------------------------------- //
// Volume Weighted Colored Bars ----------------------------------------------------------------- //
vwcbCol = nzVolume > i_vSMA * i_vwcbHighThresh ? bearCandle ? #910000 : #006400 : nzVolume < i_vSMA * i_vwcbLowThresh ? bearCandle ? #FF9800 : #7FFFD4 : na
// -Plotting ════════════════════════════════════════════════════════════════════════════════════ //
f_getStyle(_s) =>
_s == 'Solid' ? line.style_solid : _s == 'Dotted' ? line.style_dotted : line.style_dashed
// ---------------------------------------------------------------------------------------------- //
// Consecutively Increasing Volume / Price ----------------------------------------------------- //
var line srLine = na
if i_isSnR and falling and sProcessing
if falling == falling[1]
line.delete(srLine[1])
srLine := line.new(x1, y, x2, y, xloc.bar_time, extend.none, i_srLnColor, f_getStyle(i_srLnStyle), i_srLnWidth)
srLine
if i_isSnR and rising and sProcessing
if rising == rising[1]
line.delete(srLine[1])
srLine := line.new(x1, y, x2, y, xloc.bar_time, extend.none, i_srLnColor, f_getStyle(i_srLnStyle), i_srLnWidth)
srLine
// ---------------------------------------------------------------------------------------------- //
// Volume Spike - Sign of Exhaustion ------------------------------------------------------------ //
var line spikeLine = na
var line spikeLine1 = na
var line spikeLine2 = na
var line spikeLine3 = na
if i_isSnRSpike and exhaustVol and sProcessing
if bullCandle
if i_spLnBullLevel == 'High'
if exhaustVol == exhaustVol[1] and not bearCandle[1]
line.delete(spikeLine[1])
spikeLine := line.new(x1V, high, x2, high, xloc.bar_time, extend.none, i_spLnColor, f_getStyle(i_spLnStyle), i_spLnWidth)
spikeLine
else if i_spLnBullLevel == 'Close'
if exhaustVol == exhaustVol[1] and not bearCandle[1]
line.delete(spikeLine[1])
spikeLine := line.new(x1V, close, x2, close, xloc.bar_time, extend.none, i_spLnColor, f_getStyle(i_spLnStyle), i_spLnWidth)
spikeLine
else
if exhaustVol == exhaustVol[1] and not bearCandle[1]
line.delete(spikeLine1[1]), line.delete(spikeLine2[1]), line.delete(spikeLine3[1])
spikeLine1 := line.new(x1V, close, x2, close, xloc.bar_time, extend.none, i_spLnColor, f_getStyle(i_spLnStyle), i_spLnWidth)
spikeLine2 := line.new(x1V, math.avg(high, close), x2, math.avg(high, close), xloc.bar_time, extend.none, i_spLnColor, f_getStyle('Dotted'), i_spLnWidth - 1)
spikeLine3 := line.new(x1V, high, x2, high, xloc.bar_time, extend.none, i_spLnColor, f_getStyle(i_spLnStyle), i_spLnWidth)
spikeLine3
if bearCandle
if i_spLnBearLevel == 'Low'
if exhaustVol == exhaustVol[1] and not bullCandle[1]
line.delete(spikeLine[1])
spikeLine := line.new(x1V, low, x2, low, xloc.bar_time, extend.none, i_spLnColor, f_getStyle(i_spLnStyle), i_spLnWidth)
spikeLine
else if i_spLnBearLevel == 'Close'
if exhaustVol == exhaustVol[1] and not bullCandle[1]
line.delete(spikeLine[1])
spikeLine := line.new(x1V, close, x2, close, xloc.bar_time, extend.none, i_spLnColor, f_getStyle(i_spLnStyle), i_spLnWidth)
spikeLine
else
if exhaustVol == exhaustVol[1] and not bullCandle[1]
line.delete(spikeLine1[1]), line.delete(spikeLine2[1]), line.delete(spikeLine3[1])
spikeLine1 := line.new(x1V, low, x2, low, xloc.bar_time, extend.none, i_spLnColor, f_getStyle(i_spLnStyle), i_spLnWidth)
spikeLine2 := line.new(x1V, math.avg(low, close), x2, math.avg(low, close), xloc.bar_time, extend.none, i_spLnColor, f_getStyle('Dotted'), i_spLnWidth - 1)
spikeLine3 := line.new(x1V, close, x2, close, xloc.bar_time, extend.none, i_spLnColor, f_getStyle(i_spLnStyle), i_spLnWidth)
spikeLine3
plotchar(i_vSpikeLb and nzVolume and sProcessing ? exhaustVol : na, 'Exhaustion Bar', '🚦', location.abovebar, size=size.tiny)
alertcondition(ta.crossover(nzVolume, i_vSMA * i_vSpikeThresh), 'Volume Spikes', 'sign of exhaustion, huge volume increase detected\n{{exchange}}:{{ticker}}->\nOpen = {{open}}, Current = {{close}},\nTime = {{time}}')
// ---------------------------------------------------------------------------------------------- //
// High Volatility ------------------------------------------------------------------------------ //
var line volatileLine = na
var line volatileLine1 = na
var line volatileLine2 = na
var line volatileLine3 = na
if i_hATRLn and highVolatility and sProcessing
if bullCandle
if i_haLnBullLevel == 'High'
if highVolatility == highVolatility[1] and not bearCandle[1]
line.delete(volatileLine[1])
volatileLine := line.new(x1hV, high, x2, high, xloc.bar_time, extend.none, i_hATRLnColor, f_getStyle(i_hATRLnStyle), i_hATRLnWidth)
volatileLine
else if i_haLnBullLevel == 'Close'
if highVolatility == highVolatility[1] and not bearCandle[1]
line.delete(volatileLine[1])
volatileLine := line.new(x1hV, close, x2, close, xloc.bar_time, extend.none, i_hATRLnColor, f_getStyle(i_hATRLnStyle), i_hATRLnWidth)
volatileLine
else
if highVolatility == highVolatility[1] and not bearCandle[1]
line.delete(volatileLine1[1]), line.delete(volatileLine2[1]), line.delete(volatileLine3[1])
volatileLine1 := line.new(x1hV, close, x2, close, xloc.bar_time, extend.none, i_hATRLnColor, f_getStyle(i_hATRLnStyle), i_hATRLnWidth)
volatileLine2 := line.new(x1hV, math.avg(high, close), x2, math.avg(high, close), xloc.bar_time, extend.none, i_hATRLnColor, f_getStyle('Dotted'), i_hATRLnWidth - 1)
volatileLine3 := line.new(x1hV, high, x2, high, xloc.bar_time, extend.none, i_hATRLnColor, f_getStyle(i_hATRLnStyle), i_hATRLnWidth)
volatileLine3
if bearCandle
if i_haLnBearLevel == 'Low'
if highVolatility == highVolatility[1] and not bullCandle[1]
line.delete(volatileLine[1])
volatileLine := line.new(x1hV, low, x2, low, xloc.bar_time, extend.none, i_hATRLnColor, f_getStyle(i_hATRLnStyle), i_hATRLnWidth)
volatileLine
else if i_haLnBearLevel == 'Close'
if highVolatility == highVolatility[1] and not bullCandle[1]
line.delete(volatileLine[1])
volatileLine := line.new(x1hV, close, x2, close, xloc.bar_time, extend.none, i_hATRLnColor, f_getStyle(i_hATRLnStyle), i_hATRLnWidth)
volatileLine
else
if highVolatility == highVolatility[1] and not bullCandle[1]
line.delete(volatileLine1[1]), line.delete(volatileLine2[1]), line.delete(volatileLine3[1])
volatileLine1 := line.new(x1hV, low, x2, low, xloc.bar_time, extend.none, i_hATRLnColor, f_getStyle(i_hATRLnStyle), i_hATRLnWidth)
volatileLine2 := line.new(x1hV, math.avg(low, close), x2, math.avg(low, close), xloc.bar_time, extend.none, i_hATRLnColor, f_getStyle('Dotted'), i_hATRLnWidth - 1)
volatileLine3 := line.new(x1hV, close, x2, close, xloc.bar_time, extend.none, i_hATRLnColor, f_getStyle(i_hATRLnStyle), i_hATRLnWidth)
volatileLine3
plotchar(i_hATRLb and sProcessing ? highVolatility : na, 'High Volatile Bar', '⚡', location.belowbar, size=size.tiny)
alertcondition(ta.crossover(range_1, weightedATR), 'High Volatility', 'high volatility detected\n{{exchange}}:{{ticker}}->\nOpen = {{open}}, Current = {{close}},\nTime = {{time}}')
// ---------------------------------------------------------------------------------------------- //
// Volume Weighted Colored Bars ----------------------------------------------------------------- //
barcolor(i_vwcb and nzVolume ? vwcbCol : na, title='Volume Weighted Colored Bars')
// ---------------------------------------------------------------------------------------------- //
// Volume Profile (Price by Volume) ------------------------------------------------------------ //
group_volume_profile = 'Volume Profile / Price by Volume'
tooltip_volume_profile = 'Volume Profile (also known as Price by Volume) is an charting study that displays trading activity over a specified time period at specific price levels'
volumeProfile = input.bool(true, group = group_volume_profile, tooltip = tooltip_volume_profile)
lookbackLength = input.int(360, 'Lookback Length', minval = 10, maxval = 500, step = 10, inline = 'VP', group = group_volume_profile)
profileLevels = input.int(100, 'Number of Rows' , minval = 10, maxval = 500, step = 10, inline = 'VP', group = group_volume_profile)
priceHighest = ta.highest(high, lookbackLength)
priceLowest = ta.lowest (low , lookbackLength)
barPriceLow = low
barPriceHigh = high
volumeStorage = array.new_float(profileLevels + 1, 0.)
var a_box = array.new_box()
if barstate.islast and nzVolume and volumeProfile
if array.size(a_box) > 0
for i = 1 to array.size(a_box)
box.delete(array.shift(a_box))
priceStep = (priceHighest - priceLowest) / profileLevels
for barIndex = 0 to lookbackLength - 1
level = 0
for priceLevel = priceLowest to priceHighest by priceStep
if barPriceHigh[barIndex] >= priceLevel and barPriceLow[barIndex] < priceLevel + priceStep
array.set(volumeStorage, level, array.get(volumeStorage, level) + nzVolume[barIndex] * (timeframe.isseconds or (barPriceHigh[barIndex] - barPriceLow[barIndex]) == 0 ? 1 : priceStep / (barPriceHigh[barIndex] - barPriceLow[barIndex])) )//* (1 - (barPriceHigh[barIndex] - barPriceLow[barIndex]) / (priceHighest - priceLowest) ) )
level += 1
for level = 0 to profileLevels - 1
levelColor = array.get(volumeStorage, level) / array.max(volumeStorage) > .9 ? color.new(color.orange, 69) : color.new(color.gray, 69)
array.push(a_box, box.new( bar_index + 49 - int( array.get(volumeStorage, level) / array.max(volumeStorage) * 41), priceLowest + (level + 0.25) * priceStep, bar_index + 50, priceLowest + (level + 0.75) * priceStep, levelColor, bgcolor = levelColor ))
array.push(a_box, box.new(bar_index - lookbackLength + 1, priceLowest, bar_index + 50, priceHighest, color.new(color.gray, 37), 2, line.style_dotted, bgcolor=#00000000 ))
// Volume Profile (Price by Volume) ------------------------------------------------------------ //
// ---------------------------------------------------------------------------------------------- //
var table logo = table.new(position.bottom_right, 1, 1)
if barstate.islast
table.cell(logo, 0, 0, '☼☾ ', text_size=size.normal, text_color=color.teal)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment