Overnight inventory
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © sl-wk

//@version=5
indicator("Overnight inventory", overlay=true)

//-------------------------------inputs---------------------------------------//
t_y_pos                                 = input.string(defval="middle", title=" Table Position", inline="11", options=["top", "middle", "bottom"], group="Table")
t_x_pos                                 = input.string(defval="right", title="", inline="11", options=["left", "center", "right"], group="Table")
input_on                                = input.session("1615-0930", title="Overnight session (EST)", group="ON settings")
i_length                                = input.int(defval=16, title="ON range lookback", minval=1, maxval=200, group="ON settings")

var on_range_arr                        = array.new_float(i_length, 0)
on_len                                  = 465
var above_arr                           = array.new_float(on_len, 0)
var below_arr                           = array.new_float(on_len, 0)
var volume_arr                          = array.new_float(i_length, 0)


//------------------------------adding values to arrays-----------------------//
f_add_to_array(_arr, _val, _len) =>
    len = array.size(_arr)
 
    if (len == _len)    
        array.pop(_arr)     
        array.unshift(_arr, _val)   
    else    
        array.unshift(_arr, _val)


//---------------------------previous close calculations----------------------//
getValueAt(_h, _m, _value) =>
    v_period        = timestamp('GMT-4',year(time), month(time), dayofmonth(time)[1], _h, _m)
    b_period        = time >= v_period and time[1] < v_period
    valueAt         = ta.valuewhen(b_period, _value, 0)

on_session                              = time(timeframe.period,str.format("{0}:1234567", input_on), "GMT-4")
cr_close                                = on_session ? getValueAt(16,15, open) : getValueAt(16,14, close)

isToday                                 = false
if year(timenow) == year(time) and month(timenow) == month(time) and dayofmonth(timenow) == dayofmonth(time)
    isToday := true
    isToday

//-------------------------calculations of overnight's volume-----------------//
if on_session
    if close > cr_close
        f_add_to_array(above_arr, volume, on_len)
    else 
        f_add_to_array(below_arr, volume, on_len)		    
else 
    array.clear(above_arr)
	array.clear(below_arr)
		
sum_above                               = array.sum(above_arr)
sum_below                               = array.sum(below_arr)

volume_long                             = math.round((sum_above / (sum_above + sum_below))*100)
volume_short                            = math.round((sum_below / (sum_above + sum_below))*100)
volume_net                              = na(sum_above) and close < cr_close ? -100 : na(sum_below) and close > cr_close ? 100 : volume_long - volume_short


//-------------------------Volume Traded function-----------------------------//
getVolume(period) =>
    gt_session                          = time(timeframe.period,str.format("{0}:1234567", period), "GMT-4")
    var volume_sum                      = 0.0

    if gt_session
        if not gt_session[1]
            volume_sum := volume
        else
            volume_sum := volume + nz(volume_sum[1])
    formated_vol = math.round(volume_sum /1000)



//---------------------previous ON ranges calculations------------------------//
getRange(period) =>
    gt_session      = time(timeframe.period,str.format("{0}:1234567", period), "GMT-4")
    var period_high = 0.0
    var period_low  = 0.0

    if gt_session
        if not gt_session[1]
            period_low := low
            period_high := high
        else
            period_low := math.min(low, period_low)
            period_high := math.max(high, period_high)
            
    period_high - period_low


//--------------------------------final calculations--------------------------//
vol_traded                              = getVolume(input_on)
on_range                                = getRange(input_on)
savePeriod_i                            = timestamp('GMT-4',year(time), month(time), dayofmonth(time), 16, 00)
savePeriod                              = time >= savePeriod_i and time[1] < savePeriod_i
if savePeriod
    f_add_to_array(on_range_arr, on_range, i_length)
    f_add_to_array(volume_arr, vol_traded, i_length)
    
avg_on_range                            = array.median(on_range_arr)
st_on_range                             = array.stdev(on_range_arr)
z_on_range                              = (on_range - avg_on_range) / st_on_range
on_range_color                          = z_on_range > 1 ? color.lime : z_on_range < -1 ? color.red : color.gray

vol_avg                                 = array.avg(volume_arr)
vol_st                                  = array.stdev(volume_arr)
vol_zsc                                 = math.round((vol_traded - vol_avg) / vol_st,2)

plotchar(volume_net,         'SL low', '',           location.top, color.gray,         size=size.tiny)

//---------------------------------forming the table--------------------------//
if barstate.islast
    if timeframe.isminutes and timeframe.multiplier < 60
        table rangeTable = table.new(t_y_pos + "_" + t_x_pos, 2, 4)
        
        table.cell(rangeTable, 0, 0, "ON range:",                                       text_color=color.gray,      text_halign=text.align_right)
        table.cell(rangeTable, 1, 0, na(z_on_range) ? "-" : str.tostring(math.round(z_on_range,2))+"σ",          text_color=on_range_color,  text_halign=text.align_left)
        
        table.cell(rangeTable, 0, 1, "Inv. net:",                                       text_color=color.gray,      text_halign=text.align_right)
        table.cell(rangeTable, 1, 1, na(volume_net) ? "-" : str.tostring(volume_net)+"%",        text_color=color.gray,      text_halign=text.align_left)

        table.cell(rangeTable, 0, 2, "Vol traded:", text_color=color.gray, text_halign=text.align_right)
        table.cell(rangeTable, 1, 2, na(vol_traded) ? "-" : str.tostring(math.round(vol_traded,0))+"k", text_color=color.gray, text_halign=text.align_left)

        table.cell(rangeTable, 0, 3, "Vol range:", text_color=color.gray, text_halign=text.align_right)
        table.cell(rangeTable, 1, 3, na(vol_zsc) ? "-" : str.tostring(vol_zsc)+"σ", text_color=color.gray, text_halign=text.align_left)