Intrabar Price/Volume Change (experimental)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © fikira
//@version=5
indicator('Intrabar Price/Volume Change', shorttitle='iPVc', max_lines_count=500, max_boxes_count=500, max_labels_count=500, overlay=false)

bool       i_sameSide  = input.bool (false                      , title='same side'                                 , inline='1'           )
bool       i_reverse   = input.bool (false                      , title='reverse'                                   , inline='2'           )
int        i_width     = input.int  (100                        , title='width'       , tooltip='maximum width of lines (bars)', maxval=500)
int        i_size      = input.int  (100                        , title='max drawings',                                minval=1, maxval=500)
int        i_barOffset = input.int  (  0                        , title='center line offset'                                               )
color      i_colUp     = input.color(color.new(color.lime  ,  0), title=''            , group='color Price up/down' , inline='pud'         )
color      i_colDn     = input.color(color.new(#FF0000     ,  0), title=''            , group='color Price up/down' , inline='pud'         )
color      i_colUpV    = input.color(color.new(color.green , 80), title=''            , group='color Volume up/down', inline='vud'         )
color      i_colDnV    = input.color(color.new(color.orange, 80), title=''            , group='color Volume up/down', inline='vud'         )
color      i_newBar1   = input.color(color.new(color.yellow, 50), title=''            , group='color (new bar)'     , inline='cc'          , 
  tooltip='when there is a new bar -> color changes \n(only on seconds/minutes timeframe)')
color      i_newBar2   = input.color(color.new(color.blue  , 50), title=''            , group='color (new bar)'     , inline='cc'          , 
  tooltip='when there is a new bar -> color changes \n(only on seconds/minutes timeframe)')

varip float[]  a_clo   = array.new_float()
varip float[]  a_vol   = array.new_float()
varip   int[]  a_bix   = array.new_int  ()

var   float[]  a_diffP = array.new_float()
var   float[]  a_diffV = array.new_float()

var    line[]  a_lineP = array.new_line ()
var   label[]  a_label = array.new_label()
var     box[]  a_boxV  = array.new_box  ()

var    line    vLine   = na

var   float    maxP    = 0., var float maxV    = 0.
var   float    minP    = 0., var float minV    = 0.
var   float    maxMinP = 0., var float maxMinV = 0.

var     int    change  = 0, change := nz(change[1]) == 0 and ta.change(bar_index) ? 1 : 0

if barstate.islastconfirmedhistory
    //
    for i = 0 to i_size
        array.unshift(a_lineP, line.new(bar_index, 0, bar_index, 0,   color=color.new(color.blue, 100)))
        array.unshift(a_boxV ,  box.new(bar_index, 0, bar_index, 0, bgcolor=color.new(color.blue, 100), border_color=color.new(color.blue, 100)))
        array.unshift(a_diffP,                                   0)
        array.unshift(a_clo  ,                               close)
        array.unshift(a_vol  ,                              volume)
        array.unshift(a_bix  ,                                   2)
        array.unshift(a_label,label.new(bar_index, 0, text='_'  , textcolor=color.new(color.blue, 100), style=label.style_none, size=size.huge))

if barstate.islast
    //
    // -------[ center line ]-------  
    vLine := line.new(bar_index + i_barOffset, 0, bar_index + i_barOffset, 0.001, extend=extend.both, style=line.style_dotted, color=color.new(color.blue, 50)), line.delete(vLine[1])
    //
    // -------[ every tick -> close, volume, bar_index is added to array, the last one in every array gets removed  {IN -> OUT}  ]-------  
    array.unshift(a_clo, close ), array.pop(a_clo)
    array.unshift(a_vol, volume), array.pop(a_vol)
    array.unshift(a_bix, change), array.pop(a_bix)
    //    
    for i = 0 to i_size -2
        // -------[ difference price/volume ~ last one ]-------
        diffP = (array.get(a_clo, i) - array.get(a_clo, i +1)), array.unshift(a_diffP, diffP)
        diffV = (array.get(a_vol, i) - array.get(a_vol, i +1)), array.unshift(a_diffV, diffV)
        //
        // -------[ calculate maximum/minimum of each array ]-------
        maxP :=  array.max(a_diffP), minP := array.min(a_diffP), maxMinP := math.max(maxP, math.abs(minP))
        maxV :=  array.max(a_diffV), minV := array.min(a_diffV), maxMinV := math.max(maxV, math.abs(minV))
        //
        l_col    = diffP > 0 ? i_colUp  : i_colDn
        bgcol    = diffP > 0 ? i_colUpV : i_colDnV
        b_col    = color.new(bgcol, 90) 
        //
        colBix   = array.get(a_bix, i) == 0 ? i_newBar1: array.get(a_bix, i) == 1 ? i_newBar2 : color.new(color.blue, 100)
        //
        // -------[ maximum/minimum of each array is now used as a limit -> this ensures the lines won't go further then max allowed ]-------
        int yP   = math.max(-500, math.min(500, 
          i_sameSide ? math.round(i_width / maxMinP * math.abs(diffP)) : math.round(i_width / maxMinP * diffP))) * (i_reverse ? -1 : 1)
        // -------[ if no difference in price, the volume won't be drawn -> * 0 ]-------  
        int yV   = math.max(-500, math.min(500, math.round(i_width / maxMinV * math.abs(diffV)))) * (yP < 0 ? -1 : yP > 0 ? 1 : 0) 
        //
        // -------[ on each tick -> all lines/boxes, labels are updated and redrawn ]-------  
        line.set_xy1        (array.get(a_lineP, i), bar_index + i_barOffset, i) 
        line.set_xy2        (array.get(a_lineP, i), bar_index + i_barOffset + math.round(yP), i) 
        line.set_color      (array.get(a_lineP, i), l_col) 
        //
        box.set_left        (array.get(a_boxV , i), bar_index + i_barOffset) 
        box.set_top         (array.get(a_boxV , i),   i + 0.4) 
        box.set_right       (array.get(a_boxV , i), bar_index + i_barOffset + math.round(yV)) 
        box.set_bottom      (array.get(a_boxV , i),   i - 0.4) 
        //
        box.set_bgcolor     (array.get(a_boxV , i), bgcol) 
        box.set_border_color(array.get(a_boxV , i), b_col) 
        //
        // -------[ gives an indication of bar progress, every time there is a new bar the color at the center line changes ]-------  
        if timeframe.isseconds or (timeframe.isminutes and timeframe.multiplier < 60)
            label.set_xy        (array.get(a_label, i), bar_index + i_barOffset, i) 
            label.set_textcolor (array.get(a_label, i), colBix                    ) 
        //
    if array.size(a_diffP) > i_size
        array.pop(a_diffP)


