Market Pivot Levels [Past & Live]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © serkany88

//@version=5
indicator(title="Market Levels [Past&Live]", max_labels_count=500, overlay=true, precision=2, max_lines_count=500)

showDC = input.bool(true, title="Show Present Daily", group="Present", inline="dc")
dcH_col = input.color(color.white, title="", group="Present", inline="dc")
dcL_col = input.color(color.white, title="", group="Present", inline="dc")
dcL_line = input.string(line.style_dashed, title="", options=[line.style_solid, line.style_dashed, line.style_dotted],group="Present", inline="dc")
showYC = input.bool(true, title="Show Present Yesterday", group="Present", inline="yc")
ycH_col = input.color(color.rgb(83,169,149,0), title="", group="Present", inline="yc")
ycC_col = input.color(color.rgb(229, 193, 94), title="", group="Present", inline="yc")
ycL_col = input.color(color.rgb(229,94,100,0), title="", group="Present", inline="yc")
ycL_line = input.string(line.style_solid, title="", options=[line.style_solid, line.style_dashed, line.style_dotted],group="Present", inline="yc")
showPreC = input.bool(false, title="Show Present Premarket", group="Present", inline="prec")
PrecH_col = input.color(color.rgb(83,169,149,50), title="", group="Present", inline="prec")
PrecL_col = input.color(color.rgb(229,94,100,50), title="", group="Present", inline="prec")
precL_line = input.string(line.style_dotted, title="", options=[line.style_solid, line.style_dashed, line.style_dotted],group="Present", inline="prec")

showD = input.bool(true, title="Show Past Daily", group="Past", inline="d")
dH_col = input.color(color.white, title="", group="Past", inline="d")
dL_col = input.color(color.white, title="", group="Past", inline="d")
d_line = input.string(line.style_dashed, title="", options=[line.style_solid, line.style_dashed, line.style_dotted],group="Past", inline="d")
showY = input.bool(true, title="Show Past Yesterday", group="Past", inline="y")
yH_col = input.color(color.rgb(83,169,149,0), title="", group="Past", inline="y")
yC_col = input.color(color.rgb(229, 193, 94), title="", group="Past", inline="y")
yL_col = input.color(color.rgb(229,94,100,0), title="", group="Past", inline="y")
y_line = input.string(line.style_solid, title="", options=[line.style_solid, line.style_dashed, line.style_dotted],group="Past", inline="y")
showPre = input.bool(false, title="Show Past Premarket", group="Past", inline="pre")
preH_col = input.color(color.rgb(83,169,149,50), title="", group="Past", inline="pre")
preL_col = input.color(color.rgb(229,94,100,50), title="", group="Past", inline="pre")
pre_line = input.string(line.style_dotted, title="", options=[line.style_solid, line.style_dashed, line.style_dotted],group="Past", inline="pre")

// Create our custom type to hold values
type valueHold
    float highVal = high
    float lowVal = low
    float pre_highVal = high
    float pre_clsVal = close
    float pre_lowVal = low
    int timeVal = time
    float preHigh = high
    float preLow = low

f_arrayCheck(simple int size, arr) =>
    if arr.size() > size
        arr.shift()
    arr

// Let's get ticker extended no matter what the current chart is
tc = ticker.new(syminfo.prefix, syminfo.ticker, session.extended)

//Let's create our arrays for polylines for daily drawing 
var cpArrHigh = array.new<chart.point>(3, chart.point.from_time(time, close))
var cpArrLow = array.new<chart.point>(3, chart.point.from_time(time, close))
var prevArrh = array.new<chart.point>(3, chart.point.from_time(time, close))
var prevArrl = array.new<chart.point>(3, chart.point.from_time(time, close))
var prevArrc = array.new<chart.point>(3, chart.point.from_time(time, close))
var prevMarh = array.new<chart.point>(3, chart.point.from_time(time, close))
var prevMarl = array.new<chart.point>(3, chart.point.from_time(time, close))
var valHolder = array.new<valueHold>(3, valueHold.new(high, low, high, close, low, time, high, low))

// Let's find premarket high and low via function
f_preFind() =>
    _close = close
    var float pre_high = na
    var float pre_low = na
    if session.ispremarket
        pre_high := math.max(nz(pre_high, high), high) 
        pre_low := math.min(nz(pre_low, low), low)
    else if session.ispostmarket
        pre_high := na
        pre_low := na
    [pre_high, pre_low]


// Get the pre high and pre low as arrays and draw max and min of them
[pre_high, pre_low] = request.security(tc, timeframe.period , f_preFind())

// Let's use polylines for previous market points with arrays
highPoly = polyline.new(showD ? cpArrHigh : na, false, false, xloc.bar_time, dH_col, na, d_line, 1)
lowPoly = polyline.new(showD ? cpArrLow : na, false, false, xloc.bar_time, dL_col, na, d_line, 1)

// Let's use polylines for previous market points with arrays
prevhighPoly = polyline.new(showY ? prevArrh : na, false, false, xloc.bar_time, yH_col, na, y_line, 1)
prevlowPoly = polyline.new(showY ? prevArrl : na, false, false, xloc.bar_time, yL_col, na, y_line, 1)
prevclsPoly = polyline.new(showY ? prevArrc : na, false, false, xloc.bar_time, yC_col, na, y_line, 1)

preMarhPoly = polyline.new(showPre ? prevMarh : na, false, false, xloc.bar_time, preH_col, na, pre_line, 1)
preMarlPoly = polyline.new(showPre ? prevMarl : na, false, false, xloc.bar_time, preL_col, na, pre_line, 1)

// Daily change points
changeD = timeframe.change("D")

// How many bars since last time new day started
changeLast = ta.barssince(changeD)

// On the fly function to calculate daily highlows instead of tv inbuilt because tv's length cannot take series
f_highlow(int last) =>
    bardiff = last
    float _low = low, float _high = high
    for i = bardiff to 0 by 1
        if high[i] > _high
            _high := high[i]
        if low[i] < _low
            _low := low[i]
    [_high, _low, close]

// Calculate daily high's and lows
[_high, _low, _close] = f_highlow(changeLast[1])
pr_h = fixnan(pre_high)[1]
pr_l = fixnan(pre_low)[1]
pr_c = fixnan(_close)[1]
_ph = valHolder.get(0).pre_highVal[1]
_pl = valHolder.get(0).pre_lowVal[1]
_pc = valHolder.get(0).pre_clsVal[1]

//Fill the array as a function just in case we will need to use later
f_arrFill(chart.point[] highArr, chart.point[] lowArr, chart.point[] prevHigh, chart.point[] prevLow, chart.point[] prevCls, chart.point[] prevMarh, chart.point[] prevMarl) =>
    _t = valHolder.get(0).timeVal
    // Yesterday Poly
    prevHigh.push(chart.point.from_time(_t, valHolder.get(1).pre_highVal))
    prevHigh.push(chart.point.from_time(_t, _ph))
    prevHigh.push(chart.point.from_time(time, _ph))
    prevCls.push(chart.point.from_time(_t, valHolder.get(1).pre_clsVal))
    prevCls.push(chart.point.from_time(_t, _pc))
    prevCls.push(chart.point.from_time(time, _pc))
    prevLow.push(chart.point.from_time(_t, valHolder.get(1).pre_lowVal))
    prevLow.push(chart.point.from_time(_t, _pl))
    prevLow.push(chart.point.from_time(time, _pl))
    // Daily Poly
    highArr.push(chart.point.from_time(_t, valHolder.get(0).highVal))
    highArr.push(chart.point.from_time(_t, _high))
    highArr.push(chart.point.from_time(time, _high))
    lowArr.push(chart.point.from_time(_t, valHolder.get(0).lowVal))
    lowArr.push(chart.point.from_time(_t, _low))
    lowArr.push(chart.point.from_time(time, _low))
    // Prev Market Poly
    prevMarh.push(chart.point.from_time(_t, valHolder.get(0).preHigh))
    prevMarh.push(chart.point.from_time(_t, pr_h))
    prevMarh.push(chart.point.from_time(time, pr_h))
    prevMarl.push(chart.point.from_time(_t, valHolder.get(0).preLow))
    prevMarl.push(chart.point.from_time(_t, pr_l))
    prevMarl.push(chart.point.from_time(time, pr_l))
    1

// When new day starts fill polyline arrays with previous day values for polylines to draw on chart
// We also update prevtime values with current ones after we pushed to the arrays
if changeD
    f_arrFill(cpArrHigh, cpArrLow, prevArrh, prevArrl, prevArrc, prevMarh, prevMarl)
    valHolder.unshift(valueHold.new(_high, _low, _high, _close, _low, time, pr_h, pr_l))

//Clear arrays after certain size so the script don't take forever to load
int arrLimit = 300

if valHolder.size() > arrLimit
    valHolder.pop()
    
f_arrayCheck(arrLimit, cpArrHigh)
f_arrayCheck(arrLimit, cpArrLow)
f_arrayCheck(arrLimit, prevArrh)
f_arrayCheck(arrLimit, prevArrl)
f_arrayCheck(arrLimit, prevArrc)
f_arrayCheck(arrLimit, prevMarh)
f_arrayCheck(arrLimit, prevMarl)

// Current Daily high and low lines using normal lines and labels
td = time - time[5] //time for text
int prevTime = valHolder.get(0).timeVal
float prevHigh = valHolder.get(1).pre_highVal
float prevLow = valHolder.get(1).pre_lowVal
float prevCls = valHolder.get(1).pre_clsVal

// Daily Lines
var line d_high_line = line.new(showDC ? prevTime : na, _high, time, _high, xloc=xloc.bar_time, color=dcH_col, style=dcL_line, width=1)
var line p_high_line = line.new(showYC ? prevTime : na, prevHigh, time, prevHigh, xloc=xloc.bar_time, color=ycH_col, style=ycL_line, width=1)
var line prem_high_line = line.new(showPreC ? prevTime : na, pr_h, time, pr_h, xloc=xloc.bar_time, color=PrecH_col, style=precL_line, width=1)

var line d_low_line = line.new(showDC ? prevTime : na, _low, time, _low, xloc=xloc.bar_time, color=dcL_col, style=dcL_line, width=1)
var line p_low_line = line.new(showYC ? prevTime : na, prevLow, time, prevLow, xloc=xloc.bar_time, color=ycL_col, style=ycL_line, width=1)
var line p_cls_line = line.new(showYC ? prevTime : na, prevCls, time, prevCls, xloc=xloc.bar_time, color=ycC_col, style=ycL_line, width=1)
var line prem_low_line = line.new(showPreC ? prevTime : na, pr_l, time, pr_l, xloc=xloc.bar_time, color=PrecL_col, style=precL_line, width=1)

// Daily Labels
var label dh = label.new(x=showDC ? time+td : na, y=_high, text="Daily High", xloc=xloc.bar_time, style=label.style_none, textcolor=dcH_col, size=size.normal, textalign=text.align_right)
var label dl = label.new(x=showDC ? time+td : na, y=_low, text="Daily Low", xloc=xloc.bar_time, style=label.style_none, textcolor=dcL_col, size=size.normal, textalign=text.align_right)

// Yesterday's Labels
var label yh = label.new(x=showYC ? prevTime+td : na, y=prevHigh, text="Yesterday's High", xloc=xloc.bar_time, style=label.style_none, textcolor=ycH_col, size=size.normal, textalign=text.align_right)
var label yl = label.new(x=showYC ? prevTime+td : na, y=prevLow, text="Yesterday's Low", xloc=xloc.bar_time, style=label.style_none, textcolor=ycL_col, size=size.normal, textalign=text.align_right)
var label yc = label.new(x=showYC ? prevTime+td : na, y=prevCls, text="Yesterday's Close", xloc=xloc.bar_time, style=label.style_none, textcolor=ycC_col, size=size.normal, textalign=text.align_right)

// Pre-market Labels
var label prmh = label.new(x=showPreC ? prevTime+td : na, y=pr_h, text="Pre-market High", xloc=xloc.bar_time, style=label.style_none, textcolor=PrecH_col, size=size.normal, textalign=text.align_right)
var label prml = label.new(x=showPreC ? prevTime+td : na, y=pr_l, text="Pre-market Low", xloc=xloc.bar_time, style=label.style_none, textcolor=PrecL_col, size=size.normal, textalign=text.align_right)

//Adjust x/y locations accordingly in each bar if selected to show
if showDC
    d_high_line.set_xy1(prevTime, _high)
    d_high_line.set_xy2(time, _high)
    d_low_line.set_xy1(prevTime, _low)
    d_low_line.set_xy2(time, _low)
    dh.set_xy(time+td, _high)
    dl.set_xy(time+td, _low)

if showYC
    p_high_line.set_xy1(prevTime, prevHigh)
    p_high_line.set_xy2(time, prevHigh)
    p_cls_line.set_xy1(prevTime, prevCls)
    p_cls_line.set_xy2(time, prevCls)
    p_low_line.set_xy1(prevTime, prevLow)
    p_low_line.set_xy2(time, prevLow)
    yh.set_xy(time+td, prevHigh)
    yc.set_xy(time+td, prevCls)
    yl.set_xy(time+td, prevLow)

if showPreC
    prem_high_line.set_xy1(prevTime, pr_h)
    prem_high_line.set_xy2(time, pr_h)
    prem_low_line.set_xy1(prevTime, pr_l)
    prem_low_line.set_xy2(time, pr_l)
    prmh.set_xy(time+td, pr_h)
    prml.set_xy(time+td, pr_l)

//Vertical day end an finish line, can be disabled from style tab of indicator
bgcolor(changeD ? color.new(color.aqua, 90) : na, title="New Day Line")