Zig-Zag Open Interest Footprint [Kioseff Trading]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © KioseffTrading

//@version=5
indicator("Zig-Zag Open Interest Footprint [Kioseff Trading]", max_lines_count = 500, max_labels_count = 500, overlay= true, max_polylines_count = 100, max_boxes_count = 500)

import TradingView/ZigZag/6 as ZigZagLib 
import RicardoSantos/MathOperator/2

show1         = input.bool  (defval = true, title = "Up OI Up Price Profile"    , group = "Profiles", inline = "Up")
show2         = input.bool  (defval = true, title = "Down OI Up Price Profile"  , group = "Profiles", inline = "Up")
show3         = input.bool  (defval = true, title = "Up OI Dn Price Profile"    , group = "Profiles", inline = "Dn")
show4         = input.bool  (defval = true, title = "Down OI Down Price Profile", group = "Profiles", inline = "Dn")


ROWS          = input.int   (defval = 2000, maxval = 9998, minval = 10, step = 10, title = "Profile Rows", group = "Profile Settings")
factor        = input.float (defval = 2.5, minval = 1.1, step = 0.1, title = "Scaling Factor", group = "Profile Settings")
offset        = input.int   (defval = 1, title = "Offset Placement", minval = 1, group = "Profile Settings")
curve         = input.bool  (defval = false, title = "Curved Profiles", group = "Profile Settings")
same          = input.string(defval = "Middle", title = "VP Plot Type", options = ["Middle", "Opposing Side"], group = "Profile Settings")
upCol         = input.color (defval = #14D990, title = "Up OI Up Price Color", group = "Profile Settings", inline = "Up3")
dnCol         = input.color (defval = #F2B807, title = "Dn OI Up Price Color", group = "Profile Settings", inline = "Up3")
upCol2        = input.color (defval = #6929F2, title = "Up OI Dn Price Color", group = "Profile Settings", inline = "Dn3")
dnCol2        = input.color (defval = #F24968, title = "Dn OI Dn Price Color", group = "Profile Settings", inline = "Dn3")
transp        = input.int   (defval = 90, minval = 0, maxval = 100, group = "Profile Settings", title = "Pofile Fill Transparency")
transp2       = input.int   (defval = 0 , minval = 0, maxval = 100, group = "Profile Settings", title = "Pofile Line Transparency")

showL         = input.bool  (defval = true, title = "Show Sum Labels", group = "Summed OI")
delta         = input.bool  (defval = false, title = "Show Footprints", group = "Summed OI")
deltaRows     = input.int   (defval = 20, minval = 5, title = "Rows", group = "Summed OI")
deltaSz       = input.string(defval = "Tiny", title = "Delta Text Size", options = ["Tiny", "Small", "Normal", "Large", "Huge"], group = "Summed OI")
transpd1      = input.int   (defval = 70, title = "Trasnparency For Low OI Levels", group = "Summed OI", minval = 0, maxval = 100)
transpd2      = input.int   (defval = 0, title = "Trasnparency For High OI Levels", group = "Summed OI", minval = 0, maxval = 100)
neon          = input.bool  (defval = true, title = "Neon Highlight Highest OI Levels", group = "Summed OI")

poc           = input.bool  (defval = false, title = "Use POCs", group = "POC Settings")
delet         = input.bool  (defval = false, title = "Delete Violated POCs",  group = "POC Settings")
useGen        = input.bool  (defval = false, title = "Use General POC", group = "POC Settings")
sp1           = input.bool  (defval = true , title = "Show Up OI Up POC", group = "POC Settings", inline = "Up2")
sp2           = input.bool  (defval = true , title = "Show Dn OI Up POC", group = "POC Settings", inline = "Up2")
sp3           = input.bool  (defval = true , title = "Show Up OI Dn POC", group = "POC Settings", inline = "Dn2")
sp4           = input.bool  (defval = true , title = "Show Dn OI Dn POC", group = "POC Settings", inline = "Dn2")
show          = input.int   (defval = 20, title = "POCs To Show", maxval = 250, minval = 1, group = "POC Settings") 
generalPOCcol = input.color (defval = color.yellow, title = "Normal POC Col", group = "POC Settings")
transp3       = input.int   (defval = 66, minval = 0, maxval = 100, group = "POC Settings", title = "POC Line Transparency")
N             = bar_index,  atr = ta.atr(14)

show    := switch useGen
    
    true => show + 1 
    =>      show * 4

if curve 
    ROWS := 60 

if same == "Middle" 
    offset := 0


var max = 0., var min = 0.

if time >= chart.left_visible_bar_time and time <= chart.right_visible_bar_time
    max := math.max(max, high), min := math.min(min, low)

req() => 
    
    cont = switch str.contains(syminfo.ticker, ".P")
        
        true => syminfo.ticker + "_OI"
        =>      str.endswith(syminfo.ticker, "USDT") ? syminfo.ticker + ".P_OI" : syminfo.ticker + "T.P_OI"

    switch syminfo.type

        "crypto" =>          cont
        =>                   string(na)

oi = request.security(req(), timeframe.period, close - close[1] , ignore_invalid_symbol = false)

// Create Zig Zag instance from user settings.
var zigZag = ZigZagLib.newInstance(
  ZigZagLib.Settings.new(
      input.float(0.00001, "Price deviation for reversals (%)", 0.00001, 100.0, 0.5, "0.00001 - 100", group = "Zig Zag Settings"),
      input.int(100, "Pivot legs", 2, group = "Zig Zag Settings"),
      input(color.new(color.white,50), "Line color", group = "Zig Zag Settings"),
      false, // input(false, "Extend to last bar"),
      input(false, "Display reversal price", group = "Zig Zag Settings"),
      input(false, "Display cumulative volume", group = "Zig Zag Settings"),
      input(false, "Display reversal price change", inline = "priceRev", group = "Zig Zag Settings"),
      input.string("Absolute", "", ["Absolute", "Percent"], inline = "priceRev", group = "Zig Zag Settings"),
      true)
 )

zigZag.update()


type dataStore

    matrix <float> timeOIMat 
    matrix <float> HLmat
    array  <int>   retArr 
    array  <box>   pocs 
    matrix <float> tickLevels
    array  <float> priceArr
    array  <box>   OIMeasures
    matrix <label> deltaLabels
    matrix <float> mappedLevel

var data = dataStore.new(matrix.new<float>(2, 0), matrix.new<float>(2, 0), array.new_int(), array.new_box(), priceArr = array.new_float(), OIMeasures = array.new_box()),                                                                                                                                                                       //kioseff
tLevels  = dataStore.new(tickLevels = matrix.new<float>(5, ROWS, 0.0)) 

determine( a, b) => 

    result = switch same 

        "Opposing Side" => a
        "Middle"        => b

method double_binary_search_leftmost(array <float> id, i) =>

    n  = id .binary_search_leftmost  (data.HLmat.get(0, i))
    n1 = id .binary_search_leftmost  (data.HLmat.get(1, i))

    [n, n1]

method double_binary_search_leftmost_delta(array <float> id, top, btm) =>

    n   = id .binary_search_leftmost  (top)
    n1  = id .binary_search_rightmost (btm)

    [n, n1]


method effSwitch(matrix<float> id, i, x, div, subtract) =>

    if data.priceArr.get(i) == 1 

        switch data.retArr.get(i)

            1  => id.set(1, x, id.get(1, x) + data.timeOIMat.get(1, i - subtract) / div)
            -1 => id.set(2, x, id.get(2, x) + math.abs(data.timeOIMat.get(1, i - subtract) / div))

    if data.priceArr.get(i) == -1

        switch data.retArr.get(i)

            1  => id.set(3, x, id.get(3, x) + data.timeOIMat.get(1, i - subtract) / div)
            -1 => id.set(4, x, id.get(4, x) + math.abs(data.timeOIMat.get(1, i - subtract) / div))


method pocCheck(array<box> id, array<float> timeRow, getx2) =>

    for i = 0 to timeRow.indexof(getx2) - 1

        if data.HLmat.get(0, i) >= id.last().get_top() and data.HLmat.get(1, i) <= id.last().get_top()
            id.last().set_right(N - i)

        if not useGen

            for x = 2 to 4

                if data.HLmat.get(0, i) >= id.get(id.size() - x).get_top() and data.HLmat.get(1, i) <= id.get(id.size() - x).get_top()
                    id.get(id.size() - x).set_right(N - i)


method drawPOC(array<box> id, difference, idrow, check, newRowUp, newRowUp2, newRowDn, newRowDn2, remove, 
                 array<float> timeRow = na, int getx2 = na, int getx = na, cond1 = false) => 
    
    if remove 
        if id.size() > 0 
            for i = 0 to id.size() - 1
                id.shift().delete()

    if poc 

        start = switch

            same == "Middle" => cond1 ?      math.round(math.avg(last_bar_index, last_bar_index - timeRow.indexof(line.all.last().get_x2()))) : 
                                         N - math.round(math.avg(timeRow.indexof(getx), timeRow.indexof(getx2))) + 1
            =>                  difference  + offset - 1

        if not useGen 

            if sp1
                id.push(box.new(start, idrow.get(newRowUp.indexof(newRowUp.max())), N, idrow.get(newRowUp.indexof(newRowUp.max())) ,
                         bgcolor = #00000000, border_color = color.new(upCol, transp3)))
            if sp2 
                id.push(box.new(start, idrow.get(newRowUp2.indexof(newRowUp2.max())), N, idrow.get(newRowUp2.indexof(newRowUp2.max())),
                         bgcolor = #00000000, border_color = color.new(dnCol, transp3)))
            if sp3 
                id.push(box.new(start, idrow.get(newRowDn.indexof(newRowDn.max())), N, idrow.get(newRowDn.indexof(newRowDn.max())),
                         bgcolor = #00000000, border_color = color.new(upCol2, transp3)))
            if sp4
                id.push(box.new(start, idrow.get(newRowDn2.indexof(newRowDn2.max())), N, idrow.get(newRowDn2.indexof(newRowDn2.max())),
                         bgcolor = #00000000, border_color = color.new(dnCol2, transp3)))
    
        else 

            for i = 0 to newRowUp.size() - 1
                newRowUp.set(i, newRowUp.get(i) + newRowDn.get(i) + newRowUp2.get(i) + newRowDn2.get(i))

            id.push(box.new(start, idrow.get(newRowUp.indexof(newRowUp.max())), N, idrow.get(newRowUp.indexof(newRowUp.max())) ,
                     bgcolor = #00000000, border_color = color.new(generalPOCcol, transp3)))

        if check

            id.pocCheck(timeRow, getx2)

method setLevels(matrix<float> id, float gety, float gety2, cond) =>

    rows = math.abs(gety2 - gety) / (ROWS - 1)

    start = switch cond 

        false => math.min(gety, gety2)
        =>       gety

    for i = 0 to ROWS - 1
        id.set(0, i, start + rows * i)


method quickSet(matrix <label> id, int row, int col, array<float> timeRow, float avg, int offset, int middle, string dsz) => 

    id.set(row, col, label.new(chart.point.from_index(middle - offset, avg), 
                         textcolor = color.white, 
                         style     = label.style_none, 
                         color     = #00000000, 
                         size      = dsz
     ))
                 

method calcDelta(array<float> id, array<float> newRowUp, array<float> newRowUp2, array<float> newRowDn, array<float> newRowDn2, float getY, float getY2, int middle, 
         array<float> timeRow) => 
 
    if delta 

        var dsz = switch deltaSz

            "Tiny"   => size.tiny 
            "Small"  => size.small 
            "Normal" => size.normal 
            "Large"  => size.large
            "Huge"   => size.huge

        db           = dataStore.new(mappedLevel = matrix.new<float>(deltaRows, 4, 0), deltaLabels = matrix.new<label>(deltaRows, 4))

        newSlice = (math.max(getY, getY2) - math.min(getY, getY2)) / deltaRows

        for i = 0 to deltaRows - 1
                
            btm = math.min(getY, getY2) + (newSlice * i)
            top = math.min(getY, getY2) + (newSlice * (i + 1))
            avg = math.avg(top, btm)


            db.deltaLabels.quickSet(i, 0, timeRow, avg, 8 , middle, dsz)
            db.deltaLabels.quickSet(i, 1, timeRow, avg, 4 , middle, dsz)
            db.deltaLabels.quickSet(i, 2, timeRow, avg, -4, middle, dsz)
            db.deltaLabels.quickSet(i, 3, timeRow, avg, -8, middle, dsz)


            [topCol, btmCol] = id.double_binary_search_leftmost_delta(top, btm)

            for x = btmCol to topCol

                for j = 0 to 3 

                    loopID = switch 
                        
                        j == 0 => newRowUp
                        j == 1 => newRowUp2 
                        j == 2 => newRowDn 
                        j == 3 => newRowDn2

                    db.mappedLevel.set(i, j, db.mappedLevel.get(i, j) + loopID.get(x))

        valArr = db.mappedLevel.col(0), valArr1 = db.mappedLevel.col(1), valArr2 = db.mappedLevel.col(2), valArr3 = db.mappedLevel.col(3)

        for i = 0 to deltaRows - 1

            for x = 0 to 3

                [loopID, loopCol] = switch 

                    x == 0 => [valArr , upCol ]
                    x == 1 => [valArr1, dnCol ] 
                    x == 2 => [valArr2, upCol2]
                    x == 3 => [valArr3, dnCol2]

                col = color.from_gradient(loopID.get(i), loopID.min(), loopID.max(), color.new(loopCol, transpd1), color.new(loopCol, transpd2))

                db.deltaLabels.get(i, x).set_textcolor        (col),
                db.deltaLabels.get(i, x).set_text(str.tostring(loopID.get(i) * (x == 1 or x == 3 ? -1 : 1), format.volume))

                if neon 
                    if loopID.get(i) == loopID.max() 
                        db.deltaLabels.get(i, x).set_style    (label.style_text_outline)
                        db.deltaLabels.get(i, x).set_textcolor(color.white)
                        db.deltaLabels.get(i, x).set_color    (col)


method createPoly(matrix<chart.point> id, array<float> timeRow, int add, int getx2, int getx, bool cond, int difference, 
                                     array<float> idrow, array<float> lows, array<float> highs) => 

    avg = switch cond 

        false => math.round(math.avg(timeRow.indexof(getx2), timeRow.indexof(getx)))
        =>       math.round(math.avg(last_bar_index, last_bar_index - timeRow.indexof(line.all.last().get_x2())))

    add2 = determine(N - timeRow.indexof(getx2), add)    

    oper = switch cond

        false => determine(add2 - offset + 1, N - avg + 1)
        =>       determine(N  - offset + 1,  avg)


    [finx, finDn, finUp] = if same != "Middle"    

        switch cond 

            false => [add + offset - 1, idrow.min(), idrow.max()]
            =>       [difference + offset - 1, lows.min(), highs.max()]

    else 

        switch cond 

            false => [N - avg + 1, idrow.min(), idrow.max()]
            =>       [avg, lows.min(), highs.max()]

    id.add_col(0, 
             array.from( chart.point.from_index(finx, finDn), chart.point.from_index(finx, finDn),
                         chart.point.from_index(oper, finDn), chart.point.from_index(oper, finDn)))

    id.add_col(id.columns(), 
             array.from( chart.point.from_index(finx, finUp),chart.point.from_index(finx, finUp),
                         chart.point.from_index(oper, finUp),chart.point.from_index(oper, finUp)))

    if show1
        polyline.new(id.row(0), fill_color = color.new(upCol , transp), line_color   = color.new(upCol, transp2) , curved = curve)
    if show2
        polyline.new(id.row(1), fill_color = color.new(dnCol , transp), line_color   = color.new(dnCol, transp2) , curved = curve)
    if show3
        polyline.new(id.row(2), fill_color = color.new(upCol2, transp), line_color  = color.new(upCol2, transp2), curved = curve)
    if show4
        polyline.new(id.row(3), fill_color = color.new(dnCol2, transp), line_color  = color.new(dnCol2, transp2), curved = curve)


norm(newRowUp, newRowUp2, newRowDn, newRowDn2, oldMin, oldMax, newRange, i) => 

    calcUp  = 1 + ((newRowUp .get(i) - oldMin) / (oldMax - oldMin)) * (newRange - 1)
    calcUp2 = 1 + ((newRowUp2.get(i) - oldMin) / (oldMax - oldMin)) * (newRange - 1)

    calcDn  = 1 + ((newRowDn .get(i) - oldMin) / (oldMax - oldMin)) * (newRange - 1)
    calcDn2 = 1 + ((newRowDn2.get(i) - oldMin) / (oldMax - oldMin)) * (newRange - 1)

    [calcUp, calcUp2, calcDn, calcDn2]

method setCoordsHistory(matrix<chart.point> id, newRowUp, newRowDn, newRowUp2, newRowDn2, oldMin, oldMax, newRange, timeRow, getx, getx2, idrow) =>

    avg = math.round(math.avg(timeRow.indexof(getx), timeRow.indexof(getx2)))
        // 
    for i = 0 to newRowUp.size() - 1

        [calcUp, calcUp2, calcDn, calcDn2] = norm(newRowUp, newRowUp2, newRowDn, newRowDn2, oldMin, oldMax, newRange, i)

        [newSwitchUp, newSwitchUp2] = switch same

            "Middle" => [N - avg + calcUp, N - avg + calcUp2]
            =>          [N - timeRow.indexof(getx) + offset - calcUp, N - timeRow.indexof(getx) + offset - calcUp2]

        [newXUp, newXUp2] = switch same 
            
            "Middle" =>  [math.min(newSwitchUp, N - avg), math.min(newSwitchUp2, N - avg)]
            =>           [math.max(newSwitchUp, N - timeRow.indexof(getx) + offset), math.max(newSwitchUp2, N - timeRow.indexof(getx) + offset)]

        [newSwitchDn, newSwitchDn2] = switch same 

            "Middle" => [N - avg  - calcDn, N - avg - calcDn2]   
            =>          [N - timeRow.indexof(getx2) - offset + calcDn, N - timeRow.indexof(getx2) - offset + calcDn2]

        [newXDn, newXDn2] = switch same 

            "Middle" => [math.max(newSwitchDn, N - avg) + 2, math.max(newSwitchDn2, N - avg) + 2]
            =>          [math.min(newSwitchDn, N - timeRow.indexof(getx2) - offset), math.min(newSwitchDn2, N - timeRow.indexof(getx2) - offset)]


        id.set(0, i, chart.point.from_index(math.round(newXUp ), idrow.get(i))), id.set(1, i, chart.point.from_index(math.round(newXUp2), idrow.get(i)))
        id.set(2, i, chart.point.from_index(math.round(newXDn ), idrow.get(i))), id.set(3, i, chart.point.from_index(math.round(newXDn2), idrow.get(i)))

method setCoordsLive(matrix<chart.point> id, newRowUp, newRowDn, newRowUp2, newRowDn2, oldMin, oldMax, newRange, difference, newLevelsMat, timeRow) =>

    avg = math.round(math.avg(last_bar_index, last_bar_index - timeRow.indexof(line.all.last().get_x2())))

    for i = 0 to newRowUp.size() - 1

        [calcUp, calcUp2, calcDn, calcDn2] = norm(newRowUp, newRowDn, newRowUp2, newRowDn2, oldMin, oldMax, newRange, i)

        [newSwitchUp, newSwitchUp2] = switch same

            "Middle" =>  [avg - calcUp, avg - calcUp2]
            =>           [difference + offset + calcUp - 1, difference + offset + calcUp2 - 1]

        [newXUp, newXUp2] = switch same 

            "Middle" => [math.min(newSwitchUp, avg - 1), math.min(newSwitchUp2, avg - 1)]
            =>          [math.max(newSwitchUp, difference + offset), math.max(newSwitchUp2, difference + offset)]

        [newSwitchDn, newSwitchDn2] = switch same

            "Middle" => [avg + calcDn - 1, avg + calcDn2 - 1]
            =>          [N - offset - calcDn, N - offset - calcDn2]

        [newXDn, newXDn2] = switch same

            "Middle" => [math.max(newSwitchDn, avg + 1), math.max(newSwitchDn2, avg + 1)]
            =>          [math.min(newSwitchDn, N - offset - 1), math.min(newSwitchDn2, N - offset - 1)]

        id.add_col(id.columns(), array.from(
                         chart.point.from_index(math.round(newXUp), newLevelsMat.get(0, i)), chart.point.from_index(math.round(newXUp2), newLevelsMat.get(0, i)),
                         chart.point.from_index(math.round(newXDn), newLevelsMat.get(0, i)), chart.point.from_index(math.round(newXDn2), newLevelsMat.get(0, i))))

method deltaBoxes(array<box> id, newRowUp, newRowUp2, newRowDn, newRowDn2, 
                         array<float> timeRow, int getx, int getx2, float gety, float gety2, bool cond = false, array<float> highs = na) => 

    if showL 

        f    = format.volume
        cols = switch cond 

            false => (timeRow.indexof(getx) - timeRow.indexof(getx2))      / 6,
            =>       (N - (N - timeRow.indexof(line.all.last().get_x2()))) / 6

        strArr = array.from( str.tostring(newRowUp .sum(), f), 
                             str.tostring(newRowUp2.sum() * -1, f), 
                             str.tostring(newRowDn .sum(), f),
                             str.tostring(newRowDn2.sum() * -1, f))

        colArr = array.from(upCol, dnCol, upCol2, dnCol2)

        for i = 0 to 3 

            start = math.round(N -timeRow.indexof(line.all.last().get_x2()))

            [left, right, top, bottom] = switch cond 

                false => [N - timeRow.indexof(getx) + ((i + 1) * cols), N - timeRow.indexof(getx) + ((i + 2) * cols), 
                         math.max(gety, gety2) + atr, math.max(gety, gety2) + atr * 2]

                =>       [start + ((i + 1) * cols), start + ((i + 2) * cols), 
                         highs.max() + atr, highs.max() + atr * 2]

            id.push(box.new(left, top, 
                                         right, bottom, 
                                         text         = strArr.get(i), 
                                         bgcolor      = color.new(colArr.get(i), 80), 
                                         border_color = colArr.get(i), 
                                         text_color   = color.white))

method update(matrix<float> id) => 


    if syminfo.type != "crypto"
        
        var tabl = table.new(position.top_right, 5, 5, bgcolor = #00000000, frame_color = color.white, border_color = color.white, 
             frame_width = 1, border_width = 1)
        
        tabl.cell(0, 0, "No OI Data For This Asset Type!\nUnpredictable Results", text_color = color.red, text_size = size.large)

    data.timeOIMat .add_col(0, array.from(time, oi))
    data.HLmat     .add_col(0, array.from(high, low))
    data.retArr    .unshift(int(math.sign(oi)))
    data.priceArr  .unshift(int(math.sign(close - open)))

    change = line.all.size() > line.all.size()[1] and line.all.size() > 2   

    if last_bar_index - N <= 10000
 
        barCond = barstate.islastconfirmedhistory

        [minus, minus1] = switch barCond

            true => [2, 1]
            =>      [3, 2]

        if change or barCond

            all = line.all, allSize = all.size()

            getx  = all.get(allSize - minus) .get_x2(), gety  = all.get(allSize - minus) .get_y2()
            getx2 = all.get(allSize - minus1).get_x2(), gety2 = all.get(allSize - minus1).get_y2()
 
            id.setLevels(gety, gety2, false)

            timeRow = data.timeOIMat.row(0), idrow = id.row(0)

            for i = timeRow.indexof(getx) to timeRow.indexof(getx2)

                [l1, l2] = idrow.double_binary_search_leftmost(i)
// 
                div = math.abs(l1 - l2) + 1

                for x = l1 to l2 

                    id.effSwitch(i, x, div, 0)

            newRange = math.floor((timeRow.indexof(getx2) - timeRow.indexof(getx)) / factor)
            newRowUp = id.row(1), newRowUp2 = id.row(2), newRowDn = id.row(3), newRowDn2 = id.row(4)
            oldMin   = math.min(newRowUp.min(), newRowDn.min(), newRowUp2.min(), newRowDn2.min())  
            oldMax   = math.max(newRowUp.max(), newRowDn.max(), newRowUp2.max(), newRowDn2.max())

            coordinates = matrix.new<chart.point>(4, newRowUp.size())

            add  = N - timeRow.indexof(getx)

            middle = N - math.round(math.avg(timeRow.indexof(getx), timeRow.indexof(getx2))) + 1

            coordinates    .setCoordsHistory(newRowUp, newRowUp2, newRowDn, newRowDn2, oldMin, oldMax, newRange, timeRow, getx, getx2, idrow)
            coordinates    .createPoly(timeRow, add, getx2, getx, false, na, idrow, na, na)
            idrow.calcDelta(newRowUp, newRowUp2, newRowDn, newRowDn2, gety, gety2, middle, timeRow)
            data.OIMeasures.deltaBoxes(newRowUp, newRowUp2, newRowDn, newRowDn2, timeRow, getx, getx2, gety, gety2)
            data.pocs      .drawPOC(add, idrow, true, newRowUp, newRowUp2, newRowDn, newRowDn2, false, timeRow, getx2, getx)


realtime () => 



    if barstate.islast

        var pocsLive    = dataStore.new(pocs = array.new_box(), OIMeasures = array.new_box())
        var coordinates = matrix.new<chart.point>(4, 0)
        
        if coordinates.columns() > 0 

            for i = 0 to 1
                polyline.all.pop().delete()

            for i = 0 to coordinates.columns() - 1
                coordinates.remove_col()

        timeRow    = data.timeOIMat.row(0)
        startIndex = timeRow.indexof(line.all.last().get_x2()) 

        highs = data.HLmat.row(0).slice(0, startIndex + 1)
        lows  = data.HLmat.row(1).slice(0, startIndex + 1)

        newLevelsMat = matrix.new<float>(5, ROWS, 0.0)
        newLevelsMat.setLevels(lows.min(), highs.max(), true)

        levelsArr = newLevelsMat.row(0)

        for i = 0 to startIndex
            
            [l1, l2] = levelsArr.double_binary_search_leftmost(i)

            div = math.abs(l1 - l2) + 1

            for x = l1 to l2 

                newLevelsMat.effSwitch(i, x, div, 0)

        difference = N - startIndex
        newRange   = math.floor((N - difference) / factor)
        newRowUp   = newLevelsMat.row(1), newRowUp2 = newLevelsMat.row(2)
        newRowDn   = newLevelsMat.row(3), newRowDn2 = newLevelsMat.row(4)
        oldMin     = math.min(newRowUp.min(), newRowDn.min())  
        oldMax     = math.max(newRowUp.max(), newRowDn.max())

// 
        coordinates.setCoordsLive(newRowUp, newRowUp2, newRowDn, newRowDn2, oldMin, oldMax, newRange, difference, newLevelsMat, timeRow)
        coordinates.createPoly(timeRow, na, na, na, true, difference, na, lows, highs)
        pocsLive.OIMeasures.deltaBoxes(newRowUp, newRowUp2, newRowDn, newRowDn2, timeRow, na, na, na, na, true, highs)
        levelsArr.calcDelta(newRowUp, newRowUp2, newRowDn, newRowDn2, lows.min(), highs.max(), math.round(math.avg(N, N - startIndex)), timeRow)
        pocsLive.pocs.drawPOC(difference, levelsArr, false, newRowUp, newRowUp2, newRowDn, newRowDn2, true, timeRow = timeRow, cond1 = true)



method pocUpdate(array<box> id) => 

    if id.size() > 0 
        for i = 0 to id.size() - 1

            if high < id.get(i).get_top() or low > id.get(i).get_top()
                if id.get(i).get_right() == N - 1 
                    id.get(i).set_right(N)

            else if delet 
                id.get(i).delete()
            
            if delet 
                if id.get(i).get_right() != N 
                    id.get(i).delete()

    if barstate.islast 

        if data.pocs.size() > show     
            for i = 0 to data.pocs.size() - show   
                data.pocs.get(i).delete()  

tLevels.tickLevels.update(), data.pocs.pocUpdate(), realtime()

