[potatoshop] Volume Profile lower timeframe
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © potatoshop

//@version=5
indicator('[potatoshop] Volume Profile lower timeframe', 'VP LTF', overlay = true, max_boxes_count = 500)

TF = input.timeframe("10S","Resolution of bars used for VP calculation")
[lo,lh,ll,lc,lv] = request.security_lower_tf(syminfo.tickerid,TF,[open,high,low,close,volume])

Currentchart = timeframe.in_seconds(timeframe.period)
LTFqty = math.ceil(Currentchart/ timeframe.in_seconds(TF))
plot(LTFqty,display = display.status_line)

length = input.int(100, 'Lookback length', minval=1, maxval=1000, group='Volume Profile Basic')
row = input.int(15, 'Row Size', minval=1, maxval=500, group='Volume Profile Basic')

check_label = input.bool(true,"Show the qty and qty_percent", group='Option')
check_poc = input.bool(false,"Show POC line", group='Option')
check_Tpoc = input.bool(false,"Show TPOC line", group='Option')
check_reversal = input.bool(false,"Show Reversal line", group='Option')
check_up_dn_box = input.bool(false,"Show up down Box", group='Option')
text_position = input.string("1","Text side",options = ["1","2"]) 

width = input.int(50, 'Width (% of the box)', minval=1, maxval=100, group='Style')
line_width = input.int(2, 'Line(Poc,Reversal) Width', group='Style')
flip = input.bool(false, 'Flip Histogram', group='Style')

Area_color = input.color(color.rgb(33, 149, 243,97), 'Area_color',inline ="0",  group='Color Style')
Area_text_color = input.color(color.rgb(139, 147, 167), 'Area_text_color ',inline ="0",  group='Color Style')

TPOC_color = input.color(color.rgb(205, 243, 33, 68), 'TPOC_color ',  group='Color Style')
poc_color = input.color(#ff5d00, 'POC line Color', group='Color Style')
Reversal_color = input.color(#fafcfc, 'Revarsal Line Color', group='Color Style')

Box_color = input.color(#2156f341, 'Box_color',inline ="1",  group='Total Color Style')
Box_text_color = input.bool(true,"",inline ="1",  group='Total Color Style') ?  input.color(#e4e6ec41, 'text_color ',inline ="1",  group='Total Color Style') : chart.fg_color

Box_color_bull = input.color(#2d97fb, 'Box_color',inline = "2", group='Bull Color Style')
text_color_bull = input.bool(true,"",inline ="2",  group='Bull Color Style') ? input.color(#e2d1d1, 'text_color',inline = "2", group='Bull Color Style') :  chart.fg_color

Box_color_bear = input.color(#ff6929, 'Box_color',inline = "3", group='Bear Color Style')
text_color_bear = input.bool(true,"",inline ="3",  group='Bear Color Style') ? input.color(#040817, 'text_color',inline = "3", group='Bear Color Style') :  chart.fg_color

/////////////////////////////////////////////////////////////////////////////////////////////////////////

sum_V = 0.
for i = length-1 to 0 by 1
    sum_V := sum_V + volume[i]

highest = ta.highest(length)
lowest = ta.lowest(length)
//Dividing range 
divBlock = (highest - lowest) / row
block = array.new_float(row,0.)
block_v = array.new_float(row,0.)
for i = 0 to row-1 by 1
    array.set(block,i,lowest+i*divBlock)

show = table.new(position.top_center,1,5,bgcolor = color.rgb(43, 128, 57, 93), border_width = 1)
show2 = table.new(position.middle_right,1,row+1,bgcolor = color.rgb(43, 128, 57, 93), border_width = 1)

Tpoc_arr = array.new_float(row, 0.)
Bull_v = array.new_float(row , 0.)
Bear_v = array.new_float(row , 0.)
reversal_arr = array.new_int(row , 0)
var unconfirmedBox = array.new_box()
var unconfirmedBox_up = array.new_box()
var unconfirmedBox_dn = array.new_box()
line poc = na
box Tpoc = na
box last_area = na
var reversal = array.new_line()
maxTpoc = 0.

Vm = volume
var total_cell_V = 0.

ctime = time_close
mtime = (time+time_close)/2
lengthtime = time-time[length]


con = barstate.islast
if con
    if array.size(unconfirmedBox) > 0
        for i = 0 to array.size(unconfirmedBox) - 1
            box.delete(array.shift(unconfirmedBox))
            if check_up_dn_box
                box.delete(array.shift(unconfirmedBox_up))
                box.delete(array.shift(unconfirmedBox_dn))
    if array.size(reversal) > 0
        for i = 0 to array.size(reversal) - 1
            line.delete(array.shift(reversal))
    
    for Level = 0 to row-1
        sum = 0.
        sum_T = 0.
        up_sum = 0.
        dn_sum = 0.
        for j = length-1 to 1 by 1
            if array.size(lv[j]) == LTFqty
                for i = 0 to LTFqty-1 by 1
                    ltf_H = array.get(lh[j],i) , ltf_L = array.get(ll[j],i)
                    ltf_C = array.get(lc[j],i) , ltf_O = array.get(lo[j],i)                 
                    ltf_V = array.get(lv[j],i)
                    gap = (ltf_H-ltf_L)/syminfo.mintick > 1 ? (ltf_H-ltf_L)/syminfo.mintick : 1
                    unit_T =  (1/syminfo.mintick) /(gap)
                    unit_V =  (ltf_V/syminfo.mintick) /(gap)            
                    top_cut = math.min(ltf_H,array.get(block,Level)+divBlock) , bottom_cut = math.max(ltf_L,array.get(block,Level))
                    gap_T = math.abs(top_cut - bottom_cut)*unit_T 
                    gap_V = math.abs(top_cut - bottom_cut)*unit_V
                    sum := ltf_H > array.get(block, Level) and ltf_L < (array.get(block, Level)+divBlock) ? sum + gap_V : sum
                    sum_T := ltf_H > array.get(block, Level) and ltf_L < (array.get(block, Level)+divBlock) ? sum_T + gap_T : sum_T
                    if ltf_C > ltf_O
                        up_sum := ltf_H > array.get(block, Level) and ltf_L < (array.get(block, Level)+divBlock) ? up_sum + gap_V : up_sum
                    else           
                        dn_sum := ltf_H > array.get(block, Level) and ltf_L < (array.get(block, Level)+divBlock) ? dn_sum + gap_V : dn_sum
        for [i,value] in lv
            ltf_H = array.get(lh,i) , ltf_L = array.get(ll,i)
            ltf_C = array.get(lc,i) , ltf_O = array.get(lo,i) 
            ltf_V = array.get(lv,i)
            gap = (ltf_H-ltf_L)/syminfo.mintick > 1 ? (ltf_H-ltf_L)/syminfo.mintick : 1
            unit_T =  (1/syminfo.mintick) /(gap)
            unit_V =  (ltf_V/syminfo.mintick) /(gap)            
            top_cut = math.min(ltf_H,array.get(block,Level)+divBlock) , bottom_cut = math.max(ltf_L,array.get(block,Level))
            gap_T = math.abs(top_cut - bottom_cut)*unit_T 
            gap_V = math.abs(top_cut - bottom_cut)*unit_V
            sum := ltf_H > array.get(block, Level) and ltf_L < (array.get(block, Level)+divBlock) ? sum + gap_V : sum
            sum_T := ltf_H > array.get(block, Level) and ltf_L < (array.get(block, Level)+divBlock) ? sum_T + gap_T : sum_T
            if ltf_C > ltf_O
                up_sum := ltf_H > array.get(block, Level) and ltf_L < (array.get(block, Level)+divBlock) ? up_sum + gap_V : up_sum
            else           
                dn_sum := ltf_H > array.get(block, Level) and ltf_L < (array.get(block, Level)+divBlock) ? dn_sum + gap_V : dn_sum
        
        array.set(block_v,Level,sum)
        array.set(Bull_v,Level, up_sum)
        array.set(Bear_v,Level, dn_sum)
        array.set(Tpoc_arr,Level, dn_sum)
        if up_sum > dn_sum
            array.set(reversal_arr,Level,1)
        maxTpoc := array.indexof(Tpoc_arr,array.max(Tpoc_arr))

    for j = 0 to row-1 by 1                                                                 
        total_cell_V := array.sum(block_v)
        ssum = array.get(block_v, j)
        mult = ssum / array.max(block_v)
        perV = ssum / total_cell_V *100
        get = array.get(block, j)   

        ssum_up = array.get(Bull_v, j)
        mult_up = ssum_up / array.max(block_v)
        perV_up = ssum_up / total_cell_V *100 

        ssum_dn = array.get(Bear_v, j)
        mult_dn = ssum_dn / array.max(block_v)
        perV_dn = ssum_dn / total_cell_V *100 

        bottom = lowest + (j+0.05)*divBlock 
        bottom_up = lowest + (j+0.55)*divBlock 
        bottom_dn = lowest + (j+0.05)*divBlock 
        top = lowest + (j+0.95)*divBlock
        top_up = lowest + (j+0.95)*divBlock
        top_dn = lowest + (j+0.45)*divBlock
        
        if flip
            array.push(unconfirmedBox, box.new(mtime , top ,ctime - math.round(lengthtime * width / 100 * mult), bottom,xloc = xloc.bar_time, border_color= color.new(Box_color,100), bgcolor = Box_color ,  
             text_halign = text_position == "1" ? text.align_left : text.align_right, text_valign=text.align_bottom , text_size = size.small , text_color = Box_text_color,
             text = check_label ? str.tostring(perV,format.percent)+" "+str.tostring(ssum, format.volume) : na))
            
            if check_up_dn_box
                array.push(unconfirmedBox_up, box.new(mtime,top_up,ctime - math.round(lengthtime * width / 100 * mult_up), bottom_up,xloc = xloc.bar_time, border_color= color.new(Box_color_bull,100), bgcolor = Box_color_bull ,  
                 text_halign = text_position == "1" ? text.align_right : text.align_left, text_valign=text.align_bottom , text_size = size.small , text_color = text_color_bull,
                 text = check_label ? str.tostring(perV_up,format.percent)+" "+str.tostring(ssum_up, format.volume) : na))

                array.push(unconfirmedBox_dn, box.new(mtime,top_dn,ctime - math.round(lengthtime * width / 100 * mult_dn), bottom_dn,xloc = xloc.bar_time, border_color= color.new(Box_color_bear,100), bgcolor = Box_color_bear ,  
                 text_halign = text_position == "1" ? text.align_right : text.align_left, text_valign=text.align_bottom , text_size = size.small , text_color = text_color_bear,
                 text = check_label ? str.tostring(perV_dn,format.percent)+" "+str.tostring(ssum_dn, format.volume) : na))
        
        if not flip 
            array.push(unconfirmedBox, box.new(mtime - lengthtime ,top, mtime - lengthtime + math.round(lengthtime * width / 100 * mult), bottom,xloc = xloc.bar_time, border_color= color.new(Box_color,100), bgcolor = Box_color ,  
             text_halign= text_position == "1" ? text.align_right : text.align_left , text_valign=text.align_bottom , text_size = size.small , text_color = Box_text_color,
             text = check_label ? str.tostring(perV,format.percent)+" "+str.tostring(ssum, format.volume) : na))

            if check_up_dn_box 
                array.push(unconfirmedBox_up, box.new(mtime - lengthtime ,top_up, mtime - lengthtime + math.round(lengthtime * width / 100 * mult_up), bottom_up,xloc = xloc.bar_time, border_color= color.new(Box_color_bull,100), bgcolor = Box_color_bull ,  
                 text_halign= text_position == "1" ? text.align_left : text.align_right, text_valign=text.align_bottom , text_size = size.small , text_color = text_color_bull,
                 text = check_label ? str.tostring(perV_up,format.percent)+" "+str.tostring(ssum_up, format.volume) : na))

                array.push(unconfirmedBox_dn, box.new(mtime - lengthtime ,top_dn, mtime - lengthtime + math.round(lengthtime * width / 100 * mult_dn), bottom_dn,xloc = xloc.bar_time, border_color= color.new(Box_color_bear,100), bgcolor = Box_color_bear ,  
                 text_halign= text_position == "1" ? text.align_left : text.align_right, text_valign=text.align_bottom , text_size = size.small , text_color = text_color_bear,
                 text = check_label ? str.tostring(perV_dn,format.percent)+" "+str.tostring(ssum_dn, format.volume) : na))
      
        if mult == 1 and check_poc
            line.delete(poc[1])           
            avg = math.avg(get, (array.get(block, j)+divBlock))
            if flip
                poc := line.new(mtime, avg, ctime - lengthtime, avg,xloc = xloc.bar_time, color = poc_color , style = line.style_dotted , width = line_width)
            else
                poc := line.new(mtime - lengthtime, avg, ctime, avg,xloc = xloc.bar_time, color = poc_color , style = line.style_dotted , width = line_width)
        if maxTpoc == j and check_Tpoc
            box.delete(Tpoc[1])
            Tpoc := box.new(mtime - lengthtime ,top, ctime, bottom,xloc = xloc.bar_time, border_color= color.new(TPOC_color,100), bgcolor = TPOC_color ,  
             text_halign=text.align_right, text_valign=text.align_bottom , text_size = size.small , text_color = Box_text_color,
             text = check_label ? "TPOC" : na)
        con_reversal = row-1 > j ? array.get(reversal_arr,j+1) != array.get(reversal_arr,j) : false
        if check_reversal and con_reversal
            array.push(reversal, line.new(mtime - lengthtime,get+divBlock ,ctime ,get+divBlock, xloc = xloc.bar_time ,color = Reversal_color, style = line.style_dotted , width = line_width ))
    
    box.delete(last_area[1])
    last_area := box.new(mtime - lengthtime ,highest ,ctime ,lowest,xloc = xloc.bar_time, border_color=color.rgb(33, 149, 243, 80), 
     bgcolor = Area_color ,text="Highest : "+str.tostring(highest,format.mintick)+ "\n Lowest : "+str.tostring(lowest,format.mintick) +"\n Total cell V: "+ str.tostring(total_cell_V,format.volume)+ "\n Direct T_V : "+str.tostring(sum_V,format.volume) ,
     text_halign= flip? text.align_left : text.align_right, text_valign=text.align_bottom, text_size=size.tiny ,text_color= Area_text_color)
    


