// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © PrasadJoshi12
//@version=5
indicator("Volume Insignts Analyzer", overlay = false, max_labels_count = 50, format = format.volume)
vduVolumeThreshold = input.int(defval = 35, title = "VDU Threshold", tooltip = "VDU volume percentage threashold")
color5LengthPP = input.color(defval = color.yellow, title = "Pocket Pivot Volume (5)", tooltip = "Pocket pivot volume for 5 length")
color10LengthPP = input.color(defval = color.blue, title = "Pocket Pivot Volume (10)", tooltip = "Pocket pivot volume for 10 length")
showVolumeMaLine = input.bool(defval = true, title = "Show MA line", tooltip = "Show volume moving average line instead of corsses")
showMajorVolumeBars = input.bool(defval = false, title = "Display Major Volume", tooltip = "Show major (above average) volume bars")
showMinorVolumeBars = input.bool(defval = false, title = "Display Minor Volume", tooltip = "Show below average volume bars")
isDarkTheme = input.bool(defval = true, title = "Dark Theme", tooltip = "Toggle between dark mode.")
string maTableGroup = "===== MA Options ====="
dailyPrimaryMaLength = input.int(defval = 51, title = "Primary MA Length", tooltip = "Main MA for daily and intraday chart.", group = maTableGroup)
dailyFastMaLength = input.int(defval = 10, title = "Secondary MA Length", tooltip = "Second MA for daily and intraday chart.", group = maTableGroup)
weeklyPrimaryMaLength = input.int(defval = 10, title = "Weekly Primary MA Length", tooltip = "Main MA for weekly chart.", group = maTableGroup)
weeklyFastMaLength = input.int(defval = 2, title = "Weekly Secondary MA Length", tooltip = "Second MA for weekly chart.", group = maTableGroup)
monthlyPrimaryMaLength = input.int(defval = 4, title = "Monthly Primary MA Length", tooltip = "Main MA for monthly chart.", group = maTableGroup)
monthlyFastMaLength = input.int(defval = 2, title = "Monthly Secondary MA Length", tooltip = "Second MA for monthly chart.", group = maTableGroup)
// Volume Table
string volTableGroup = "════════ Volume Table Options ═════════"
string volTableSize = input.string("small", "Size", inline = "21", group = volTableGroup, options = ["tiny", "small", "normal", "large", "huge", "auto"])
string volTablePositionY = input.string("top", "↕", inline = "21", group = volTableGroup, options = ["top", "middle", "bottom"])
string volTablePositionX = input.string("left", "↔", inline = "21", group = volTableGroup, options = ["left", "center", "right"])
horiVolumeTable = input.bool(defval = true, title = "Horizontal Table", tooltip = "Disaply horizontal table.")
var tableBGColor = isDarkTheme ? color.new(color.white, 100): color.new(color.black, 100)
var tableTextColor = isDarkTheme ? color.new(color.white, 0): color.new(color.black, 0)
var tableFrameColor = isDarkTheme ? color.new(#999999, 50) : color.rgb(241, 241, 241)
var tableBorderColor = isDarkTheme ? color.new(#999999, 50) : color.rgb(241, 241, 241)
var tableTextSize = volTableSize
queuePush(_queueArray, _queueSize, _value) =>
if array.size(_queueArray) >= _queueSize
array.shift(_queueArray)
array.push(_queueArray, _value)
queueCount(_queueArray) =>
array.sum(_queueArray)
// Function to calculate the maximum selling volume
getMaxSellingVolume(lookbackPeriod) =>
maxSellingVolume = 0.0
for i = 1 to lookbackPeriod by 1
if close[i+1] >= close[i]
maxSellingVolume := math.max(maxSellingVolume, volume[i])
maxSellingVolume
volumeTableCell(_table, _row, _column, _value, _bgcolor) =>
table.cell(table_id = _table, column = _column, row = _row, text = _value, bgcolor = _bgcolor, text_color = tableTextColor, text_size = tableTextSize)
vrtVolumeTableRow(_table, _row, _key, _value, _valueBgColor) =>
volumeTableCell(_table = _table, _row = _row, _column = 0, _value = _key, _bgcolor = (isDarkTheme ? color.black : color.white))
volumeTableCell(_table = _table, _row = _row, _column = 1, _value = _value, _bgcolor = _valueBgColor)
hzVolumeTableRow(_table, _col, _key, _value, _valueBgColor) =>
volumeTableCell(_table = _table, _row = 0, _column = _col, _value = _key, _bgcolor = (isDarkTheme ? color.black : color.white))
volumeTableCell(_table = _table, _row = 0, _column = _col + 1, _value = _value, _bgcolor = _valueBgColor)
getPriceMAPercentageDistance(_maLength) =>
_ma = ta.ema(close, _maLength)
(math.abs(close - _ma) * 100) / close
getPrimaryVolumeMALength() =>
(timeframe.ismonthly ? (monthlyPrimaryMaLength) : (timeframe.isweekly ? (weeklyPrimaryMaLength) : (timeframe.isdaily? dailyPrimaryMaLength : dailyPrimaryMaLength)))
getSecondaryMALength() =>
(timeframe.ismonthly ? (monthlyFastMaLength) : (timeframe.isweekly ? (weeklyFastMaLength) : (timeframe.isdaily? dailyFastMaLength : dailyFastMaLength)))
getVDUMADistance() =>
timeframe.isweekly ? 4 : (timeframe.isdaily ? 2 : timeframe.isintraday ? 1 : 1)
showVduMarkers() =>
var _last_bar = last_bar_index
var _last_bars_filter = 100
_show_vdu = (_last_bar - bar_index <= _last_bars_filter) or barstate.isrealtime
_show_vdu
isTooOldPocketPivotVolume() =>
var _last_bar = last_bar_index
var _last_bars_filter = 300
_too_old = (_last_bar - bar_index > _last_bars_filter)
_too_old
var totalLookbackForHigherVolumeBars = getPrimaryVolumeMALength()
var higherVolumeBars = array.new_int(totalLookbackForHigherVolumeBars, 0)
var accumulationVolumeBars = array.new_int(totalLookbackForHigherVolumeBars, 0)
var distributionVolumeBars = array.new_int(totalLookbackForHigherVolumeBars, 0)
// volume moving average
var primaryMALength = getPrimaryVolumeMALength()
primaryVolMA = ta.sma(volume, primaryMALength)
turnoverCr = (primaryVolMA * ta.sma(close, primaryMALength)) / 10000000
secondVolMA = ta.sma(volume, getSecondaryMALength())
// volume dry up (VDU) close to price moving average
// 1. Get moving average distance
ma10Distance = getPriceMAPercentageDistance(10)
ma21Distance = getPriceMAPercentageDistance(21)
ma51Distance = getPriceMAPercentageDistance(51)
ma65Distance = getPriceMAPercentageDistance(65)
ma200Distance = getPriceMAPercentageDistance(200)
// 2. check if current bar is a VDU day
percentageVolume = (volume / primaryVolMA) * 100
isVduVolume = (percentageVolume <= vduVolumeThreshold)
// 3. now check if current bar is close to MA and is a VDU bar
var vduThreshold = getVDUMADistance()
vdu200 = (ma200Distance <= vduThreshold and isVduVolume) and (timeframe.isintraday == false)
vdu65 = (ma65Distance <= vduThreshold and isVduVolume) and (vdu200 == false) and (timeframe.isintraday == false)
vdu51 = (ma51Distance <= vduThreshold and isVduVolume) and (vdu200 == false and vdu65 == false) and (timeframe.isintraday == false)
vdu21 = (ma21Distance <= vduThreshold and isVduVolume) and (vdu200 == false and vdu65 == false and vdu51 == false) and (timeframe.isintraday == false)
vdu10 = (ma10Distance <= vduThreshold and isVduVolume) and (vdu200 == false and vdu65 == false and vdu51 == false and vdu21 == false) and (timeframe.isintraday == false)
// pocket pivot or significant volume day
isGreenDay = (close < close[1] ? false : (close > close[1] ? true : (close > open)))
maxSellVolume10 = getMaxSellingVolume(10)
maxSellVolume5 = getMaxSellingVolume(5)
is5PPVolume = (volume >= maxSellVolume5) and (isGreenDay)
is10PPVolume = (volume >= maxSellVolume10) and (isGreenDay)
percentVolume10PP = (volume / maxSellVolume10) * 100
percentVolume5PP = (volume / maxSellVolume5) * 100
isVeryHighVolume = (percentageVolume >= 200)
queuePush(_queueArray = higherVolumeBars, _queueSize = totalLookbackForHigherVolumeBars, _value = (isVeryHighVolume ? 1 : 0))
var noConfigDisplay = display.pane
var vduVolumeColor = color.orange
plotchar(series = (vdu200), char="*", text = "200", title = "VDU", location = location.bottom, color = vduVolumeColor, size = size.auto, display = noConfigDisplay, editable=false, show_last=100)
plotchar(series = (vdu65), char="*", text = "65", title = "VDU", location = location.bottom, color = vduVolumeColor, size = size.auto, display = noConfigDisplay, editable=false, show_last=100)
plotchar(series = (vdu51), char="*", text = "51", title = "VDU", location = location.bottom, color = vduVolumeColor, size = size.auto, display = noConfigDisplay, editable=false, show_last=100)
plotchar(series = (vdu21), char="*", text = "21", title = "VDU", location = location.bottom, color = vduVolumeColor, size = size.auto, display = noConfigDisplay, editable=false, show_last=100)
plotchar(series = (vdu10), char="*", text = "10", title = "VDU", location = location.bottom, color = vduVolumeColor, size = size.auto, display = noConfigDisplay, editable=false, show_last=100)
// Show arrows on the top
isBullishClose = (close >= (low + 0.75 * (high - low))) and (percentageVolume >= 100)
isBearishClose = (close <= (low + 0.25 * (high - low))) and (percentageVolume >= 100)
plotshape(series = isBullishClose, style = shape.arrowup, color = color.green, location = location.top, display = noConfigDisplay, editable=false)
plotshape(series = isBearishClose, style = shape.arrowdown, color = color.red, location = location.top, display = noConfigDisplay, editable=false)
queuePush(_queueArray = accumulationVolumeBars, _queueSize = totalLookbackForHigherVolumeBars, _value = (isBullishClose ? 1 : 0))
queuePush(_queueArray = distributionVolumeBars, _queueSize = totalLookbackForHigherVolumeBars, _value = (isBearishClose ? 1 : 0))
volDisplay = (showMajorVolumeBars and (percentageVolume >= 100 or is10PPVolume or is5PPVolume)) or (showMinorVolumeBars and percentageVolume < 100)
barColor = color.gray
showVolPPMarker = not volDisplay
volPPColor = color.black
if is10PPVolume
barColor := (isVeryHighVolume) ? color.purple : color10LengthPP
showVolPPMarker := true
volPPColor := barColor
else if is5PPVolume
barColor := (percentageVolume >= 100) ? color.green : color5LengthPP
showVolPPMarker := true // Always display 5D PP volume
volPPColor := color5LengthPP
else if isVduVolume
barColor := vduVolumeColor
showVolPPMarker := false
else if percentageVolume >= 100
barColor := isGreenDay? color.green : color.red
volPPColor := barColor
else
showVolPPMarker := false
plot(series = volDisplay ? volume : na, title = "Volume", color = barColor, style = plot.style_histogram, format = format.volume, linewidth = 1, editable = true)
plot(showVolumeMaLine ? primaryVolMA : na, title = "Volume MA", color = barColor, format = format.volume, linewidth = 2, style = plot.style_line, editable = false)
plot(showVolumeMaLine ? secondVolMA : na, title = "Volume MA", color = color.aqua, format = format.volume, linewidth = 1, style = plot.style_line, editable = false)
// Display major volume information if volume bars are disabled
plotshape(showVolPPMarker, style=shape.circle, color = volPPColor, size = size.auto, location = location.belowbar, display = noConfigDisplay, editable=false)
if percentageVolume >= 200
volText = str.tostring(percentageVolume / 100, "#") + "X"
textColor = isGreenDay ? color.purple : color.red
if volDisplay
volLabel = label.new(x = bar_index, y = volume, text = volText, textcolor = textColor, style = label.style_none, size=size.small)
else
volLabel = label.new(x = bar_index, y = close, text = volText, textcolor = textColor, style = label.style_none, size=size.small, yloc = yloc.price)
// Volume Table
volTableTotalRows = horiVolumeTable ? 1 : 7
volTableTotalColumns = horiVolumeTable ? 14 : 2
var tablePvgBgColor = color.green
var tableNvgBgColor = color.red
totalHighVolBars = queueCount(_queueArray = higherVolumeBars)
totalAccumulationVolBars = queueCount(_queueArray = accumulationVolumeBars)
totalDistributionVolBars = queueCount(_queueArray = distributionVolumeBars)
volumeTable = table.new(volTablePositionY + "_" + volTablePositionX, columns = volTableTotalColumns, rows = volTableTotalRows, bgcolor = tableBGColor, frame_color=tableFrameColor, frame_width=1, border_color=tableBorderColor, border_width=1)
if not horiVolumeTable
vrtVolumeTableRow(_table = volumeTable, _row = 0, _key = "RVOL", _value = str.tostring(percentageVolume, "#"), _valueBgColor = (percentageVolume >= 100) ? tablePvgBgColor : tableNvgBgColor)
vrtVolumeTableRow(_table = volumeTable, _row = 1, _key = "RVOL-10DPP", _value = str.tostring(percentVolume10PP, "#"), _valueBgColor = (percentVolume10PP >= 100) ? tablePvgBgColor : tableNvgBgColor)
vrtVolumeTableRow(_table = volumeTable, _row = 2, _key = "RVOL-5DPP", _value = str.tostring(percentVolume5PP, "#"), _valueBgColor = (percentVolume5PP >= 100) ? tablePvgBgColor : tableNvgBgColor)
vrtVolumeTableRow(_table = volumeTable, _row = 3, _key = "Turnover", _value = str.tostring(turnoverCr, "#") + " Cr.", _valueBgColor = (turnoverCr >= 10) ? tablePvgBgColor : tableNvgBgColor)
vrtVolumeTableRow(_table = volumeTable, _row = 4, _key = "ExtremeVolDays", _value = str.tostring(totalHighVolBars, "#"), _valueBgColor = (totalHighVolBars * 100 / totalLookbackForHigherVolumeBars) >= 10 ? tablePvgBgColor : tableNvgBgColor)
vrtVolumeTableRow(_table = volumeTable, _row = 5, _key = "AccVolDays", _value = str.tostring(totalAccumulationVolBars, "#"), _valueBgColor = (totalAccumulationVolBars * 100 / totalLookbackForHigherVolumeBars) >= 10 ? tablePvgBgColor : tableNvgBgColor)
vrtVolumeTableRow(_table = volumeTable, _row = 6, _key = "DistVolDays", _value = str.tostring(totalDistributionVolBars, "#"), _valueBgColor = (totalDistributionVolBars * 100 / totalLookbackForHigherVolumeBars) >= 10 ? tableNvgBgColor : tablePvgBgColor)
else
hzVolumeTableRow(_table = volumeTable, _col = 0, _key = "RVOL", _value = str.tostring(percentageVolume, "#"), _valueBgColor = (percentageVolume >= 100) ? tablePvgBgColor : tableNvgBgColor)
hzVolumeTableRow(_table = volumeTable, _col = 2, _key = "RVOL-10DPP", _value = str.tostring(percentVolume10PP, "#"), _valueBgColor = (percentVolume10PP >= 100) ?tablePvgBgColor : tableNvgBgColor)
hzVolumeTableRow(_table = volumeTable, _col = 4, _key = "RVOL-5DPP", _value = str.tostring(percentVolume5PP, "#"), _valueBgColor = (percentVolume5PP >= 100) ? tablePvgBgColor : tableNvgBgColor)
hzVolumeTableRow(_table = volumeTable, _col = 6, _key = "Turnover", _value = str.tostring(turnoverCr , "#") + " Cr.", _valueBgColor = (turnoverCr >= 10) ? tablePvgBgColor : tableNvgBgColor)
hzVolumeTableRow(_table = volumeTable, _col = 8, _key = "ExtremeVolDays", _value = str.tostring(totalHighVolBars , "#"), _valueBgColor = (totalHighVolBars * 100 / totalLookbackForHigherVolumeBars) >= 10 ? tablePvgBgColor : tableNvgBgColor)
hzVolumeTableRow(_table = volumeTable, _col = 10, _key = "AccVolDays", _value = str.tostring(totalAccumulationVolBars , "#"), _valueBgColor = (totalAccumulationVolBars * 100 / totalLookbackForHigherVolumeBars) >= 10 ? tablePvgBgColor : tableNvgBgColor)
hzVolumeTableRow(_table = volumeTable, _col = 12, _key = "DistVolDays", _value = str.tostring(totalDistributionVolBars , "#"), _valueBgColor = (totalDistributionVolBars * 100 / totalLookbackForHigherVolumeBars) >= 10 ? tableNvgBgColor : tablePvgBgColor)