Intrabar OBV/PVT
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © HeWhoMustNotBeNamed

//   __    __            __       __  __                  __       __                        __      __    __              __      _______             __    __                                          __ 
//  /  |  /  |          /  |  _  /  |/  |                /  \     /  |                      /  |    /  \  /  |            /  |    /       \           /  \  /  |                                        /  |
//  $$ |  $$ |  ______  $$ | / \ $$ |$$ |____    ______  $$  \   /$$ | __    __   _______  _$$ |_   $$  \ $$ |  ______   _$$ |_   $$$$$$$  |  ______  $$  \ $$ |  ______   _____  ____    ______    ____$$ |
//  $$ |__$$ | /      \ $$ |/$  \$$ |$$      \  /      \ $$$  \ /$$$ |/  |  /  | /       |/ $$   |  $$$  \$$ | /      \ / $$   |  $$ |__$$ | /      \ $$$  \$$ | /      \ /     \/    \  /      \  /    $$ |
//  $$    $$ |/$$$$$$  |$$ /$$$  $$ |$$$$$$$  |/$$$$$$  |$$$$  /$$$$ |$$ |  $$ |/$$$$$$$/ $$$$$$/   $$$$  $$ |/$$$$$$  |$$$$$$/   $$    $$< /$$$$$$  |$$$$  $$ | $$$$$$  |$$$$$$ $$$$  |/$$$$$$  |/$$$$$$$ |
//  $$$$$$$$ |$$    $$ |$$ $$/$$ $$ |$$ |  $$ |$$ |  $$ |$$ $$ $$/$$ |$$ |  $$ |$$      \   $$ | __ $$ $$ $$ |$$ |  $$ |  $$ | __ $$$$$$$  |$$    $$ |$$ $$ $$ | /    $$ |$$ | $$ | $$ |$$    $$ |$$ |  $$ |
//  $$ |  $$ |$$$$$$$$/ $$$$/  $$$$ |$$ |  $$ |$$ \__$$ |$$ |$$$/ $$ |$$ \__$$ | $$$$$$  |  $$ |/  |$$ |$$$$ |$$ \__$$ |  $$ |/  |$$ |__$$ |$$$$$$$$/ $$ |$$$$ |/$$$$$$$ |$$ | $$ | $$ |$$$$$$$$/ $$ \__$$ |
//  $$ |  $$ |$$       |$$$/    $$$ |$$ |  $$ |$$    $$/ $$ | $/  $$ |$$    $$/ /     $$/   $$  $$/ $$ | $$$ |$$    $$/   $$  $$/ $$    $$/ $$       |$$ | $$$ |$$    $$ |$$ | $$ | $$ |$$       |$$    $$ |
//  $$/   $$/  $$$$$$$/ $$/      $$/ $$/   $$/  $$$$$$/  $$/      $$/  $$$$$$/  $$$$$$$/     $$$$/  $$/   $$/  $$$$$$/     $$$$/  $$$$$$$/   $$$$$$$/ $$/   $$/  $$$$$$$/ $$/  $$/  $$/  $$$$$$$/  $$$$$$$/ 
//                                                                                                                                                                                                          
//                                                                                                                                                                                                          
//
//@version=5
indicator("Intrabar Volume", overlay=true)
import HeWhoMustNotBeNamed/arrayutils/17 as pa

maxItems = input.int(100, "Loopback", minval=10, maxval=100, step=10)
resetOnNewBar = input.bool(true, "Reset On New Bar")
statsPosition = input.string(defval=position.top_right, title='', options=[position.bottom_right, position.bottom_left, position.bottom_center,
                                                                             position.top_right, position.top_center, 
                                                                             position.middle_left, position.middle_right], group='Table', inline="s1")
lblSize = input.string(size.small, title='', options=[size.tiny, size.small, size.normal, size.large, size.huge], group='Table', inline="s1")
varip float[] cArray   = array.new_float()
varip float[] vArray   = array.new_float()

varip float[] obvArray = array.new_float()
varip float[] pvtArray = array.new_float()
varip intrabarObv = 0.0
varip intrabarPvt = 0.0

change = ta.change(close)
if barstate.islast
    pa.unshift(cArray, close, maxItems)
    pa.unshift(vArray, volume, maxItems)
    
    if(array.size(cArray) >= 2)
        priceDiff = array.get(cArray, 0) - array.get(cArray, 1)
        volumeDiff = array.get(vArray, 0) - array.get(vArray, 1)
        if(volumeDiff >= 0)
            intrabarObv := priceDiff > 0? intrabarObv + volumeDiff*priceDiff/math.abs(priceDiff): priceDiff < 0? intrabarObv - volumeDiff : intrabarObv
            intrabarPvt := intrabarPvt + volumeDiff*priceDiff/array.get(cArray, 1)
            pa.unshift(obvArray, intrabarObv, maxItems)
            pa.unshift(pvtArray, intrabarPvt, maxItems)
        else
            if(resetOnNewBar)
                array.clear(cArray)
                array.clear(vArray)
                array.clear(obvArray)
                array.clear(pvtArray)
            else
                pa.unshift(obvArray, intrabarObv, maxItems)
                pa.unshift(pvtArray, intrabarPvt, maxItems)

        
    stats = table.new(position=statsPosition, columns=8, rows=maxItems + 2, border_width=1)
    table.cell(table_id=stats, column=0, row=0, text="Price", bgcolor=color.maroon, text_color=color.white, text_size=lblSize)
    table.cell(table_id=stats, column=2, row=0, text="Volume", bgcolor=color.maroon, text_color=color.white, text_size=lblSize)
    table.cell(table_id=stats, column=4, row=0, text="OBV", bgcolor=color.maroon, text_color=color.white, text_size=lblSize)
    table.cell(table_id=stats, column=6, row=0, text="PVT", bgcolor=color.maroon, text_color=color.white, text_size=lblSize)
    table.cell(table_id=stats, column=0, row=1, text="Value", bgcolor=color.teal, text_color=color.white, text_size=lblSize)
    table.cell(table_id=stats, column=1, row=1, text="Difference", bgcolor=color.teal, text_color=color.white, text_size=lblSize)
    table.cell(table_id=stats, column=2, row=1, text="Value", bgcolor=color.teal, text_color=color.white, text_size=lblSize)
    table.cell(table_id=stats, column=3, row=1, text="Difference", bgcolor=color.teal, text_color=color.white, text_size=lblSize)
    table.cell(table_id=stats, column=4, row=1, text="Value", bgcolor=color.teal, text_color=color.white, text_size=lblSize)
    table.cell(table_id=stats, column=5, row=1, text="MA", bgcolor=color.teal, text_color=color.white, text_size=lblSize)
    table.cell(table_id=stats, column=6, row=1, text="Value", bgcolor=color.teal, text_color=color.white, text_size=lblSize)
    table.cell(table_id=stats, column=7, row=1, text="MA", bgcolor=color.teal, text_color=color.white, text_size=lblSize)

    for i=0 to array.size(cArray) >= 2? array.size(cArray)-2 : na
        price = array.get(cArray, i)
        vol = array.get(vArray, i)
        lPrice = array.get(cArray, i+1)
        lVol = array.get(vArray, i+1)
        
        pChange = price - lPrice
        vChange = vol - lVol
        iObv = array.get(obvArray, i)
        iPvt = array.get(pvtArray, i)

        obvMA = array.avg(obvArray)
        pvtMA = array.avg(pvtArray)

        bColor = pChange > 0? color.lime : color.orange
        table.cell(table_id=stats, column=0, row=i+2, text=str.tostring(price), bgcolor=bColor, text_color=color.black, text_size=lblSize)
        table.cell(table_id=stats, column=2, row=i+2, text=str.tostring(vol), bgcolor=bColor, text_color=color.black, text_size=lblSize)
        table.cell(table_id=stats, column=1, row=i+2, text=str.tostring(pChange), bgcolor=bColor, text_color=color.black, text_size=lblSize)
        table.cell(table_id=stats, column=3, row=i+2, text=str.tostring(vChange), bgcolor=bColor, text_color=color.black, text_size=lblSize)
        obvColor = iObv > 0? (iObv >obvMA? color.green : color.orange) : (iObv >obvMA ? color.lime: color.red)
        table.cell(table_id=stats, column=4, row=i+2, text=str.tostring(math.round(iObv,2)), bgcolor=obvColor, text_color=color.black, text_size=lblSize)
        table.cell(table_id=stats, column=5, row=i+2, text=str.tostring(math.round(obvMA,2)), bgcolor=obvColor, text_color=color.black, text_size=lblSize)
        pvtColor = iPvt > 0? (iPvt > pvtMA? color.green : color.orange) : (iPvt > pvtMA? color.lime : color.red)
        table.cell(table_id=stats, column=6, row=i+2, text=str.tostring(math.round(iPvt, 2)), bgcolor=pvtColor, text_color=color.black, text_size=lblSize)
        table.cell(table_id=stats, column=7, row=i+2, text=str.tostring(math.round(pvtMA, 2)), bgcolor=pvtColor, text_color=color.black, text_size=lblSize)


    alertMessage = '\nOBV :'+str.tostring(math.round(intrabarObv,2))+' , OBVMA : '+str.tostring(math.round(array.avg(obvArray),2))+
                     '\nPVT : '+str.tostring(math.round(intrabarPvt,2))+' , PVTMA : '+str.tostring(math.round(array.avg(pvtArray),2))+
                     '\nClose : '+str.tostring(close)+
                     '\nChange : '+str.tostring(change)+
                     '\nPercent : '+str.tostring(math.round(change*100/close[1], 2))+'\n'
    alert(alertMessage, alert.freq_once_per_bar_close)