Volume and vPOC Insights
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Texmoonbeam

//@version=5
indicator("Volume and vPOC Insights", overlay = true, max_boxes_count = 100, max_lines_count = 100, max_labels_count = 500, max_bars_back = 5000)
// hide candles where volume is not top x% based on lookback
// for shown candles show position.top_center
// optional draw lines from nPOC to next touch level

//Inputs
groupVis = "Visual settings"

lookback = input.int(defval=200, title="Lookback", minval = 1, maxval = 5000, group=groupVis)
hidecol = input.color(color.new(color.white, 30), "Hide Candle Colour", group=groupVis)
vol = input.float(defval=70, title="% of Highest Volume", minval=0, maxval = 100, group=groupVis, tooltip="This setting will cause any candle whose volume is less than x % of the highest within the lookback, to be obscured")
showrange = input.bool(defval = false, title="Show untapped highs/lows of volume candles", group=groupVis, inline = "1")
extendnpoc = input.bool(defval = false, title="Extend (naked) vPOCs", group=groupVis, inline = "2")
showema = input.bool(defval = false, title="Show EMA using vPOC prices", group=groupVis, inline = "3")
length = input.int(defval=50, title="Length", minval = 1, maxval = 999, group=groupVis, inline = "3")
i_vpocCol = input.color(color.teal, "VPOC     ", group=groupVis, inline = "4")
i_vpocThresholdCol = input.color(color.maroon, "Threshold exceeded", group=groupVis, inline = "4")
line_style = input.string(line.style_solid, 'Line Style', options=[line.style_solid, line.style_dotted, line.style_dashed],  group=groupVis, inline = "5")
line_width = input.int(defval=1, title="Line Width", minval = 1, maxval = 10, group=groupVis, inline = "5")

//POC inputs // credit quantifytools
groupPoc = "VPOC settings"

i_source = input.source(close, "Source for VPOC price", group=groupPoc, tooltip="E.g. With close as source, a point of control is calculated using LTF close.")
i_vpocThreshold = input.int(50, "Threshold % for VPOC highlight", maxval=100, minval=1, group=groupPoc)

//Timeframe inputs // credit quantifytools
groupTf = "Timeframe settings"

i_tf1 = input.timeframe("1", "LTF for charts <= 30 min", group=groupTf, tooltip="E.g. Lower timeframe data is fetched from 1 minute timeframe when viewing charts at or below 30 min. The lower the chosen timeframe, the more precision you get, but with the cost of less historical data and slower loading time.")
i_tf2 = input.timeframe("3", "LTF for charts > 30 min & <= 3 hours", group=groupTf)
i_tf3 = input.timeframe("15", "LTF for charts > 3 hours & <= 8 hours", group=groupTf)
i_tf4 = input.timeframe("60", "LTF for charts > 8 hours & <= 1D", group=groupTf)
i_tf5 = input.timeframe("120", "LTF for charts > 1D & <= 3D", group=groupTf)
i_tf6 = input.timeframe("240", "LTF for charts > 3D", group=groupTf)

//LTF data // credit quantifytools

//Current timeframe in minutes
currentTimeframe = timeframe.in_seconds(timeframe.period) / 60

//Dynamic timeframe
dynTf = currentTimeframe <= 30 ? i_tf1 : currentTimeframe > 30 and currentTimeframe <= 180 ? i_tf2 :
 currentTimeframe > 180 and currentTimeframe <= 480 ? i_tf3 : currentTimeframe > 480 and currentTimeframe <= 1440 ? i_tf4 :
  currentTimeframe > 1440 and currentTimeframe <= 4320 ? i_tf5 : currentTimeframe > 4320 ? i_tf6 : na

//Function to fetch LTF data // credit quantifytools
ltfStats() =>

    volpart = na(volume) == false ? volume : 0

    [i_source, volpart]

[ltfSrc, ltfVolume] = request.security_lower_tf(syminfo.tickerid, dynTf, ltfStats())

//VPOC // credit quantifytools

//Max volume from LTF volume array
maxVolume = array.max(ltfVolume)

//Array index of max volume
indexOfMaxVolume = array.indexof(ltfVolume, maxVolume)

//Price at max volume (VPOC)
maxVol = array.size(ltfSrc) > 0 ? array.get(ltfSrc, indexOfMaxVolume) : na

vpocThresholdMet = maxVolume >= (volume * (i_vpocThreshold / 100)) and barstate.isconfirmed

vpocColor = vpocThresholdMet ? i_vpocThresholdCol : i_vpocCol

vh = ta.highest(volume, lookback)

plotcandle(open, high, low, close, title='Noise', color = volume < (vh/100)*vol ? hidecol : color.new(color.white, 100), wickcolor=volume < (vh/100)*vol ? hidecol : color.new(color.white, 100), bordercolor=volume < (vh/100)*vol ? hidecol : color.new(color.white, 100))
plotshape(na(volume) == false and volume > (vh/100)*vol ? maxVol : na, title="VPOC", style=shape.cross, text="", color=vpocColor, location=location.absolute, size=size.tiny, textcolor=color.white)


// Lines for ema, Vol and vPOC

vema = ta.ema(maxVol, length)
plot(showema ? vema : na, color=i_vpocCol)

var npoclines = array.new_line()
var npocfloat = array.new_float()
var npoctime = array.new_int()
var npoctimetemp = array.new_int()
var npocfloattemp = array.new_float()
var npochighlines = array.new_line()
var npochigh = array.new_float()
var npochightime = array.new_int()
var npochightemp = array.new_float()
var npochightimetemp = array.new_int()
var npoclowlines = array.new_line()
var npoclow = array.new_float()
var npoclowtime = array.new_int()
var npoclowtemp = array.new_float()
var npoclowtimetemp = array.new_int()

arrayadd(n, arr1, arr2) =>
    array.push(arr2, array.get(arr1, n))

if (array.size(npoclines) > 0)
    for x = array.size((npoclines))-1 to 0
        delline1 = array.remove(npoclines, x) 
        line.delete(delline1)
        //label.new(x=time, y=high, text="deleted", xloc=xloc.bar_time, color=color.white, style=label.style_none, textcolor=color.green, size=size.normal, textalign=text.align_right)

if (array.size(npochighlines) > 0)
    for x = array.size((npochighlines))-1 to 0
        delline2 = array.remove(npochighlines, x) 
        line.delete(delline2)        

if (array.size(npoclowlines) > 0)
    for x = array.size((npoclowlines))-1 to 0
        delline3 = array.remove(npoclowlines, x) 
        line.delete(delline3)            
        
if (array.size((npocfloat)) > 0)
    for x = array.size((npocfloat))-1 to 0
        if array.get(npoctime, x) < time and not((high > array.get(npocfloat, x) and low <= array.get(npocfloat, x)) or (low < array.get(npocfloat, x) and high >= array.get(npocfloat, x)))
            //label.new(x=time, y=high, text="added", xloc=xloc.bar_time, color=color.white, style=label.style_none, textcolor=color.green, size=size.normal, textalign=text.align_right)
            arrayadd(x, npocfloat, npocfloattemp)
            arrayadd(x, npoctime, npoctimetemp)

npocfloat := array.copy(npocfloattemp)
array.clear(npocfloattemp)

npoctime := array.copy(npoctimetemp)
array.clear(npoctimetemp)

if (array.size((npochigh)) > 0)
    for x = array.size((npochigh))-1 to 0
        if array.get(npochightime, x) < time and not((high > array.get(npochigh, x) and low <= array.get(npochigh, x)) or (low < array.get(npochigh, x) and high >= array.get(npochigh, x)))
            //label.new(x=time, y=high, text="added", xloc=xloc.bar_time, color=color.white, style=label.style_none, textcolor=color.green, size=size.normal, textalign=text.align_right)
            arrayadd(x, npochigh, npochightemp)
            arrayadd(x, npochightime, npochightimetemp)

npochigh := array.copy(npochightemp)
array.clear(npochightemp)

npochightime := array.copy(npochightimetemp)
array.clear(npochightimetemp)

if (array.size((npoclow)) > 0)
    for x = array.size((npoclow))-1 to 0
        if array.get(npoclowtime, x) < time and not((high > array.get(npoclow, x) and low <= array.get(npoclow, x)) or (low < array.get(npoclow, x) and high >= array.get(npoclow, x)))
            //label.new(x=time, y=low, text="added", xloc=xloc.bar_time, color=color.white, style=label.style_none, textcolor=color.green, size=size.normal, textalign=text.align_right)
            arrayadd(x, npoclow, npoclowtemp)
            arrayadd(x, npoclowtime, npoclowtimetemp)

npoclow := array.copy(npoclowtemp)
array.clear(npoclowtemp)

npoclowtime := array.copy(npoclowtimetemp)
array.clear(npoclowtimetemp)

if (extendnpoc == true and volume >= (vh/100)*vol and maxVol > 0 )
    array.push(npocfloat, maxVol)
    array.push(npoctime, time)

if (showrange == true and volume >= (vh/100)*vol and maxVol > 0 )
    array.push(npochigh, high)
    array.push(npochightime, time)
    array.push(npoclow, low)
    array.push(npoclowtime, time)


if (bar_index == last_bar_index)
    
    //label.new(x=time, y=high, text=str.tostring(array.size(npocfloat)), xloc=xloc.bar_time, color=color.white, style=label.style_none, textcolor=color.green, size=size.normal, textalign=text.align_right)
    if (array.size((npocfloat)) > 0)
        for y = array.size((npocfloat))-1 to 0
            e = line.new(array.get(npoctime, y), array.get(npocfloat, y), time, array.get(npocfloat, y), xloc = xloc.bar_time, color= i_vpocCol,  width = line_width, style = line_style)
            array.push(npoclines, e)

    if (array.size((npochigh)) > 0)
        for y = array.size((npochigh))-1 to 0
            e = line.new(array.get(npochightime, y), array.get(npochigh, y), time, array.get(npochigh, y), xloc = xloc.bar_time, color= i_vpocCol, width = line_width, style = line_style)
            array.push(npochighlines, e)

    if (array.size((npoclow)) > 0)
        for y = array.size((npoclow))-1 to 0
            e = line.new(array.get(npoclowtime, y), array.get(npoclow, y), time, array.get(npoclow, y), xloc = xloc.bar_time, color= i_vpocCol,  width = line_width, style = line_style)
            array.push(npoclowlines, e)


// if barstate.islast 
//     label.new(x=time, y=high, text=str.tostring(array.get(npocfloat, 0)), xloc=xloc.bar_time, color=color.white, style=label.style_none, textcolor=color.green, size=size.normal, textalign=text.align_right)
