Liquidation Ranges + Volume/OI Dots [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("Volume Dots", overlay = true, max_lines_count = 500, max_labels_count = 500, max_boxes_count = 500)
// 
import            PineCoders/Time/4              as pct
import HeWhoMustNotBeNamed/BinaryInsertionSort/1 as HeWho
// 
action2                        = input.bool  (defval = true, title = "Show Liquidation Ranges",    group = "Show Liquidation Ranges" , inline = "0")
showValues                     = input.bool  (defval = true, title = "Show VOL/OI Values in Grid", group = "Show Liquidation Ranges", inline = "0")
action                         = input.string(defval = "Find As Many Vol/OI Extremities As Possible", title = "Volume/OI Dots Should: ", options = ["Find As Many Vol/OI Extremities As Possible", "Show Extremities For The Data On My Screen", "Show The Highest Vol./OI Per Bar", "Off"], group = "Volume/OI Dots Main Settings"), stringBool =  "Find As Many Vol/OI Extremities As Possible"
data                           = input.bool  (defval = false, title = "Use OI Instead Of Volume For Dots?", group = "Use OI Instead")
agg                            = 100 - input.float (minval = 0.01, title = "Aggressiveness", maxval = 10, defval = 0.01, group =  'If You Selected "Find As Many Vol/OI Extremities As Possible"', tooltip = "Corresponds To The Required Percent Rank For A Value To Be Distinguished. Sclaed 0.01-9.99 For Simplicity; However, Uses Percent Rank (100 Subtracted By Number In This Box) - Works Only For 'Find As Many Vol/OI Extremities As Possible'") 
nake                           = input.bool  (defval = false, title = "Naked Levels Only?", group = "Naked Levels")
actint                         = input.int   (defval = 20, title = 'If You Selected "Show Extremities For The Data On My Screen: How Many Levels Should Be Shown?',  group = "Volume/OI Dots (Screen Only)", minval = 1, maxval = 500)
ti                             = input.bool  (defval = false, title = "Use Fixed Range", inline = "1",  group = "Volume/OI Dots Misc Settings")
ti2                            = input.time  (defval = timestamp("04 Apr 2022 00:00 +0300"), title = "Start", inline = "1",  group = "Volume/OI Dots Misc Settings")
dt                             = input.int   (defval = 15, title = "Levels In Table Shown", minval = 0, maxval = 99,  group = "Volume/OI Dots Misc Settings" , inline = "Levels")
showl                          = input.int   (defval = 10, title = "Lines Shown", minval = 0, maxval = 500,  group = "Volume/OI Dots Misc Settings", inline = "Levels")
linebool                       = input.bool  (defval = false, title = "Only Show Lines Within a % of Price", group = "Volume/OI Dots Misc Settings", inline = "line" )
linedist                       = input.float (defval = 3, title = "%", minval = 0, group = "Volume/OI Dots Misc Settings", inline = "line") / 100
srcol                          = input.bool  (defval = false, title = "Color Lines As Support/Resistance", group = "Volume/OI Dots Misc Settings"), atr = ta.atr(14)
upcol                          = input.color (defval = color.lime, title = "Up Color Vol                ", inline = "20",             group = "Volume/OI Dots Misc Settings")
dncol                          = input.color (defval = color.red , title = "Down Color Vol            ", inline = "20",           group = "Volume/OI Dots Misc Settings")
upcoloi                        = input.color (defval = color.blue, title = "OI Up + Price Up      ", inline = "21",        group = "Volume/OI Dots Misc Settings")
dncoloi                        = input.color (defval = color.orange , title = "OI Down + Price Down", inline = "21",  group = "Volume/OI Dots Misc Settings")
upcoloi2                       = input.color (defval = color.yellow, title = "OI Up + Price Down ", inline = "21",    group = "Volume/OI Dots Misc Settings")
dncoloi2                       = input.color (defval = color.purple , title = "OI Down + Price Up     ", inline = "21",    group = "Volume/OI Dots Misc Settings")
sort                           = input.string(defval = "Descending", title = "Sort Table Data", options = ["Occurrence", "Descending"],  group = "Volume/OI Dots Misc Settings", inline = "Misc")
siz                            = input.string(defval = "Normal", title = "Table Size", options = ["Auto", "Tiny", "Small", "Normal", "Large", "Huge"],  inline = "Misc", group = "Volume/OI Dots Misc Settings")
move                           = input.bool  (defval = true, title = "Show OI Delta Lines", group = "Liquidation Range")
showcir                        = input.bool  (defval = true, title = "Show Violation Circles", group = "Liquidation Range")
box2Line                       = input.bool (defval = false,         title = "Change Liquidation Boxes to Lines", group = "Liquidation Range")
minlevl                        = input.string(defval = "Auto", title = "Min Liquidation Level Shown", options = ["Auto", "10", "20", "30", "40", "50"], group = "Liquidation Range")
userDefinedTime                = input.bool  (defval = false, title = "Fixed Range", group = "Liquidation Range")
timtest                        = input.time  (defval = timestamp("04 Apr 2023 00:00 +0300"), title = "Start Liquidation Range"),
timtest2                       = input.time  (defval = timestamp("20 Apr 2023 00:00 +0300"), title = "End Liquidation Range")

method equal                   (string id, value) => id == value
method notEqual                (string id, value) => id != value


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)

r3() => 
    [R1, R2, R3, R4, R5] = switch syminfo.type
        "crypto" => [  close-close[1], high, low, open, close    ]
        => [float(na), float(na), float(na), float(na), float(na)]


// Thank you PineCoders

float chartTfInMinutes = timeframe.in_seconds() / 60.
int  ONE_MIN    = 1
int  ONE_SEC    = ONE_MIN  / 60
int  ONE_HOUR   = ONE_MIN  * 60
int  ONE_DAY    = ONE_HOUR * 24
int  ONE_WEEK   = ONE_DAY  * 7
bool  marketIs24Hours  = syminfo.type == "crypto" or syminfo.type == "forex"

ltfint = switch 

    chartTfInMinutes <= ONE_MIN * 30  => "1"
    chartTfInMinutes <= ONE_HOUR      => "3"
    chartTfInMinutes <  ONE_HOUR * 2  => "5"
    chartTfInMinutes <  ONE_HOUR * 4  => "15"
    chartTfInMinutes <  ONE_HOUR * 6  => "30"
    chartTfInMinutes <  ONE_HOUR * 12 => marketIs24Hours ? "60"  : "30"
    chartTfInMinutes <  ONE_DAY       => marketIs24Hours ? "120" : "30"
    chartTfInMinutes <  ONE_WEEK      => marketIs24Hours ? "720" : "120"

// Thank you PineCoders

[oic, oih, oil, oio, trueOic    ] = request.security_lower_tf(req(), ltfint, r3()    )
timeframeDiff                     = request.security(req(),   timeframe.period, close-close[1]     )
[vol, clo, clo1, hi, lo, clocalc, ltf, volSign] = request.security_lower_tf(syminfo.tickerid, ltfint, 
             [
             volume, close, close[1], high, low, close - close[1], time, close >= open ? volume : volume * -1
             ])


comparison(id, value, string ) =>
    
    switch string 
        
        ">"  => id >  value
        ">=" => id >= value
        "==" => id == value
        "<=" => id <= value
        "<"  => id <  value
        "!=" => id != value


method floatGreatEqual   (float  id, value) => comparison(id, value, ">=") 
method floatEqual        (float  id, value) => comparison(id, value, "==") 
method floatLessEqual    (float  id, value) => comparison(id, value, "<=") 
method floatNotEqual     (float  id, value) => comparison(id, value, "!=") 


method intGreatEqual     (int    id, value) => comparison(id, value, ">=") 
method intEqual          (int    id, value) => comparison(id, value, "==") 
method intLessEqual      (int    id, value) => comparison(id, value, "<=") 
method intNotEqual       (int    id, value) => comparison(id, value, "!=") 
   
method HeWhoSort(float [] id, value, order) => 
    
    HeWho.binary_insertion_sort(id, value, order)


method determine   (bool id, value, value2) =>
    
    switch id 
        
        true => value
        =>      value2

type timeValues

    float [] Difference 
    float [] Close
    int   [] Time

type dotValues 
    
    float [] Volume
    float [] Close
    float [] Difference
    float [] OI 
    float [] OI2
    int   [] Time
    label [] Circle
    line  [] Zone
    float [] Rank
    float [] perBar
    float [] volSignArr
    int      Start

type sortedMat
    
    float   volM
    float   oicM
    int     timM
    float   cloM
    float   clcM
    float   toiM
    color   colM
    string  valM


var timeMat        = timeValues.new(array.new_float(), array.new_float(), array.new_int())

timeMat.Difference.unshift(timeframeDiff), timeMat.Close.unshift(close), timeMat.Time.unshift(time)


var dotMat = dotValues.new(
             
             array.new_float(), array.new_float(),
             array.new_float(), array.new_float(),
             array.new_float(), array.new_int  (), 
             array.new_label(), array.new_line (), 
             array.new_float(), array.new_float(),
             array.new_float(),        0
             
             )

obj = switch syminfo.type.equal("crypto")
    
    true  => oic
    false => vol

if action.notEqual("Off")

    conditionX = switch action
        
        "Find As Many Vol/OI Extremities As Possible"   => last_bar_index - bar_index <= (4.5e6)/(timeframe.in_seconds(timeframe.period)) and not ti or 
                 time >= ti2 and ti and vol.size().intGreatEqual(1)
        
        "Show Extremities For The Data On My Screen" => time >= chart.left_visible_bar_time and time <= chart.right_visible_bar_time 
                     and not ti and vol.size().intGreatEqual(1) or time >= ti2 and ti and vol.size().intGreatEqual(1)
        
        => last_bar_index - bar_index <= 500

    if conditionX
        
        if obj.size().intGreatEqual(1)
            
            if action.notEqual("Show The Highest Vol./OI Per Bar")

                if nake and dotMat.Volume.size().intGreatEqual(1)

                    for i = 0 to dotMat.Volume.size() - 1
                        if not na(dotMat.Close.get(i))
                            
                            if     dotMat.Close.get(i).floatLessEqual(high) 
                                if dotMat.Close.get(i).floatGreatEqual(low)
                                
                                    dotMat.Close.set(i, na)

                for i = math.min(obj.size() - 1, clo.size() - 1) to 0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             // In Honor of Spunky - Rest Comfortably Sweet Princess. You'll be Loved and Cherished Forever & Always <3            

                    dotMat.Volume     .unshift(vol.get(i))     , dotMat.Close    .unshift(clo.get(i))
                    dotMat.Difference .unshift(clocalc.get(i)) , dotMat.OI       .unshift(math.abs(oic.get(i)))
                    dotMat.Time       .unshift(ltf.get(i))     , dotMat.OI2      .unshift(oic.get(i)),
                                             dotMat.volSignArr.unshift(volSign.get(i))
            
            else 

                for i = math.min(obj.size() - 1, clo.size() - 1) to 0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    

                    cond = switch data 

                        false => vol.get(i).floatEqual(vol.max())
                        =>       oic.get(i).floatEqual(math.max(oic.max(), math.abs(oic.min())))

                    if cond 
                        
                        col = switch data 
                            
                            false => color.new(math.sign(clocalc.get(i)).floatEqual(-1).determine(color.lime , color.red), 33)
                            
                            =>       color.new(math.sign(oic.get(i)).floatEqual(-1).determine  (
                                     math.sign(clocalc.get(i))      .floatEqual(-1).determine  (
                                     dncoloi, dncoloi2),  math.sign(clocalc.get(i)).floatEqual (
                                     -1).determine(upcoloi2, upcoloi)), 33)


                        OItxt = switch syminfo.type.equal("crypto")
                            true => "\nOI: " +  str.tostring(oic.get(i), format.mintick)
                            => ""

                        dotMat.Circle.unshift( 
                            
                             label.new(
                                         time, clo.get(i), "⬤",
                                         tooltip   =  "VOL: " + (math.sign(clocalc.get(i)).floatEqual(-1).determine("-" , "")) + 
                                         str.tostring(vol.get(i), format.volume)  +  OItxt, 
                                         xloc      = xloc.bar_time, 
                                         color     = #000000, 
                                         textcolor = col,
                                         size      = size.tiny,
                                         style     = label.style_text_outline
                                         ))

                        dotMat.Zone.unshift(
                                             line.new(time, clo.get(i), time, clo.get(i), 
                                                             color = col, 
                                                             xloc = xloc.bar_time
                                                             ))

                        dotMat.perBar.unshift(data.determine(vol.get(i) , oic.get(i)))               


    if vol.size().intEqual(0)
        dotMat.Start := time
    

var grid     = matrix.new<box>(5, 20)

if barstate.islast and action.notEqual("Off")
    
    if action.notEqual("Show The Highest Vol./OI Per Bar")
        
        if dotMat.Circle.size().intGreatEqual(1) 
            
            for i = 0 to dotMat.Circle.size() - 1
                dotMat.Circle.shift().delete()
        
        if dotMat.Zone.size()  .intGreatEqual(1)
            
            for i = 0 to dotMat.Zone.size() - 1
                dotMat.Zone.shift().delete()
                          
        if ti
            
            line.new(            ti2, high, ti2, low, 
                                 xloc = xloc.bar_time  , extend = extend.both, 
                                 color = chart.fg_color, width  = 2   
                                  )    

        var count = 1, vcopy = dotMat.Volume.copy(), ocopy = dotMat.OI.copy(), var SM = matrix.new<sortedMat>(8, 0), var tan3 = array.new_float()

        switch data
        
            false => vcopy.sort(order.descending)
            =>       ocopy.sort(order.descending)
        
        for i = 0 to 249

            [bool1, bool2, index] = switch data

                false => [dotMat.Volume.includes(vcopy.get(i)), action.equal(stringBool).determine( 
                         vcopy.percentrank(i).floatGreatEqual(agg) , i.intLessEqual(actint - 2)), dotMat.Volume.indexof(vcopy.get(i))]
                
                =>       [dotMat.OI.includes(ocopy.get(i))    , action.equal(stringBool).determine( 
                         ocopy.percentrank(i).floatGreatEqual(agg) , i.intLessEqual(actint - 2)),     dotMat.OI.indexof(ocopy.get(i))]


            if bool1
                if bool2
                    if dotMat.Close.indexof(dotMat.Close.get(index)).intNotEqual(-1)
                    
                        append = switch data
                        
                            false         => vcopy.get(i)
                            true          => ocopy.get(i)


                        [coloR, strinG] = if not data

                            switch math.sign(dotMat.Difference.get(index))

                                -1 => [dncol, "-"]
                                =>    [upcol, "" ]

                        else 

                            switch math.sign(dotMat.Difference.get(index))

                                -1 => [math.sign(dotMat.OI2.get(index)).floatEqual(-1).determine(dncoloi , upcoloi2) ,  "-"]
                                =>    [math.sign(dotMat.OI2.get(index)).floatEqual(-1).determine(upcoloi , dncoloi2) ,  "" ]


                        SM.add_col(SM.columns(), 

                                         array.from(

                                                     sortedMat.new(volM =  dotMat.Volume    .get(index))  , 
                                                     sortedMat.new(oicM =  dotMat.OI        .get(index))  , 
                                                     sortedMat.new(timM =  dotMat.Time      .get(index))  , 
                                                     sortedMat.new(cloM =  dotMat.Close     .get(index))  , 
                                                     sortedMat.new(clcM =  dotMat.Difference.get(index))  ,
                                                     sortedMat.new(toiM =  dotMat.OI2       .get(index))  , 
                                                     sortedMat.new(colM =  coloR                       )  , 
                                                     sortedMat.new(valM =  strinG                      )
                                                    
                                                     ))
                        
                        count += 1, dotMat.Rank.push(append), 
                       
                        tan3.push(sort.equal("Occurrence")
                                             .determine(dotMat.Time.get(index), data
                                             .determine(dotMat.OI.get(index)  , dotMat.Volume.get(index)
                                             )))
                
                else 
                    
                    break

        var uniArr   = array.from("❶","❷","❸","❹","❺","❻","❼","❽","❾","❿","⓫","⓬","⓭","⓮","⓯","⓰","⓱","⓲","⓳","⓴")
        colorr       = array.new_color(), var tan2 = array.new_float(), var tan4 = array.new_int()

        for i = 0 to SM.columns() - 1 

            condition = switch action

                "Find As Many Vol/OI Extremities As Possible" => data.determine(ocopy.percentrank(i).floatGreatEqual(agg),
                                                                 vcopy.percentrank(i).floatGreatEqual               (agg))
                
                => i.intNotEqual(-1)

            if condition

                rank = dotMat.Rank.percentrank(i)

                SIZE = switch rank.floatNotEqual(-1)

                    rank <= 10 => size.tiny
                    rank <= 25 => size.small
                    rank <= 50 => size.normal
                    rank <= 75 => size.large
                    =>            size.huge

                OItxt = switch syminfo.type.equal("crypto")
                    
                    true => "\nOI: " +  str.tostring(SM.row(5).get(i).toiM, format.mintick)
                    =>      ""
                    

                dotMat.Circle.push(label.new(int(SM.row(2).get(i).timM), SM.row(3).get(i).cloM, 
                                                 
                                                 text      = action.equal(stringBool) or i.intGreatEqual(uniArr.size() - 1) ? "⬤" : uniArr.get(i),
                                                 tooltip   = "VOL: " + (math.sign(SM.row(4).get(i).clcM).floatEqual(-1).determine("-" , ""))     + 
                                                 str.tostring(SM.row(0).get(i).volM, format.volume) + OItxt,
                                                 
                                                 xloc      = xloc.bar_time, 
                                                 color     = #000000, 
                                                 textcolor = color.new(SM.row(6).get(i).colM, 33),
                                                 size      = action.equal(stringBool) ? SIZE : size.normal,
                                                 style     = label.style_text_outline
                                                 ))

                colorr.push(color.new(SM.row(6).get(i).colM, 33)), tan4.push(SM.row(2).get(i).timM)
                tan2.HeWhoSort(sort.equal("Occurrence").determine(SM.row(2).get(i).timM, data.determine(SM.row(1).get(i).oicM, SM.row(0).get(i).volM)), -1)

        if not nake
            
            if showl.intNotEqual(0)
                
                countLab = 0
                
                for i = 0 to dotMat.Circle.size() - 1
                    
                    if dotMat.Circle.get(i).get_x().intGreatEqual(tan4.max(math.min(showl, tan4.size()-1)))
                        
                        if linebool  and dotMat.Circle.get(i).get_y().floatGreatEqual(close * (1 - linedist)) 
                                     and dotMat.Circle.get(i).get_y().floatLessEqual (close * (1 + linedist))
                                                             or not linebool

                            finCol = switch srcol
                                
                                true => dotMat.Circle.get(i).get_y().floatGreatEqual(close).determine(dncol , upcol) 
                                =>      colorr.get(i)

                            dotMat.Zone.push(line.new(
                                             
                                     dotMat.Circle.get(i).get_x(), dotMat.Circle.get(i).get_y(), pct.timeFrom("close", 40, "chart"),  dotMat.Circle.get(i).get_y(),
                                                 color = finCol,
                                                 xloc = xloc.bar_time
                                                 ))
                            countLab += 1
                            if countLab.intEqual(showl)
                                break


        else 
            
            if action.equal(stringBool) or action.equal("Show Extremities For The Data On My Screen")
                
                if dotMat.Circle.size().intGreatEqual(1) 
                    
                    for i = 0 to dotMat.Circle.size() - 1
                        
                        if linebool  and dotMat.Circle.get(i).get_y().floatGreatEqual(close * (1 - linedist)) 
                                     and dotMat.Circle.get(i).get_y().floatGreatEqual(close * (1 + linedist))
                                                     or not linebool
                            
                            dotMat.Zone.push(line.new(
                                         
                                         dotMat.Circle.get(i).get_x(),     dotMat.Circle.get(i).get_y(), 
                                         pct.timeFrom("bar", 40, "chart"), dotMat.Circle.get(i).get_y(), 
                                         xloc  = xloc.bar_time, color = color.new(SM.row(6).get(i).colM, 33)
                                         ))

        sz = switch siz
        
            "Auto"   =>  size.auto
            "Tiny"   =>  size.tiny
            "Small"  =>  size.small
            "Normal" =>  size.normal
            "Large"  =>  size.large
            "Huge"   =>  size.huge


        if float(dt).floatGreatEqual(1)
        
            var tab    = table.new(position.top_right, 4, dt+2, frame_width = 1, 
                                                         frame_color  = color.white , 
                                                         border_width = 1, 
                                                         border_color = color.white), 
                                                         nakeCount    = 0
    
            for i = 0 to nake.determine(dotMat.Circle.size() - 1, math.min(dt - 1, SM.columns() - 1))

                occCond = tan3.indexof(tan2.get(i)) 
                
                if sort.equal("Occurrence")
                    tan3.set(occCond, 0)
                
                if SM.row(0).get(i).volM.floatNotEqual(0)

                    tab.cell(0, i + 1, text = SM.row(7).get(occCond).valM + str.tostring(SM.row(0).get(occCond).volM, format.volume), 
                                                         bgcolor          = color.new(#000000, 50), 
                                                         text_color       = SM.row(6).get(occCond).colM, 
                                                         text_size        = sz, 
                                                         text_font_family = font.family_monospace
                                                         )

                    tab.cell(1, i + 1, text = str.tostring(SM.row(3).get(occCond).cloM, format.mintick), 
                                                         bgcolor          = color.new(#000000, 50), 
                                                         text_color       = SM.row(6).get(occCond).colM, 
                                                         text_size        = sz, 
                                                         text_font_family = font.family_monospace
                                                         )

                    if not na(oic.sum()) and syminfo.type.equal("crypto")
                        
                        tab.cell(2, i + 1, text = str.tostring(SM.row(5).get(occCond).toiM, format.mintick), 
                                                             bgcolor           = color.new(#000000, 50), 
                                                             text_color        = data.determine(SM.row(6).get(occCond).colM , 
                                                                                 math.sign(SM.row(5).get(occCond).toiM).floatEqual(-1).determine(dncol , upcol)),
                                                             text_size         = sz, 
                                                             text_font_family  = font.family_monospace
                                                             )
                    nakeCount += 1

                    if nakeCount.intEqual(dt)
                        break

            tab.cell(0, 0, "Vol." , text_color = color.white, bgcolor = color.new(#000000, 50), text_size = sz, text_font_family  = font.family_monospace)
            tab.cell(1, 0, "Price", text_color = color.white, bgcolor = color.new(#000000, 50), text_size = sz, text_font_family  = font.family_monospace)

            if not na(oic.sum()) and syminfo.type.equal("crypto")
                tab.cell(2, 0, "OI", text_color = color.white, bgcolor = color.new(#000000, 50), text_size = sz, text_font_family = font.family_monospace)

            if dotMat.Circle.size().intEqual(0) and nake
                
                tab.cell(0, 1, "No Naked Levels Detected", text_color = color.white, text_font_family = font.family_monospace, bgcolor = #000000)
                tab.merge_cells(0, 1, 2, 1)


            if action.notEqual(stringBool)
                
                line.new(dotMat.Start, high, dotMat.Start, low, 
                                             extend = extend.both, 
                                             color  = color.white, 
                                             width  = 4, 
                                             xloc   = xloc.bar_time
                                             )
                
                label.new(dotMat.Start, high * 1.01, 
                                     style     = label.style_label_right, 
                                     color     = #000000,
                                     xloc      = xloc.bar_time, 
                                     textcolor = color.white, 
                                     size      = size.small, 
                                     text      = "Earliest Start Date"
                                     )

    else 
        
        if dotMat.Circle.size().intGreatEqual(1) 
            
            for i = 0 to dotMat.Circle.size() - 1
                
                dotMat.perBar.set(i, math.abs(dotMat.perBar.get(i)))
            
            for i = 0 to dotMat.Circle.size() - 1

                rank = dotMat.perBar.percentrank(i)
                
                SIZE = switch rank.floatNotEqual(-1)

                    rank <= 10 => size.tiny
                    rank <= 25 => size.small
                    rank <= 50 => size.normal
                    rank <= 75 => size.large
                    =>            size.huge

                dotMat.Circle.get(i).set_size(SIZE)
            

                if i.intLessEqual(showl - 2)
                    
                    if linebool
                        if dotMat.Circle.get(i).get_y().floatGreatEqual(close * (1 - linedist)) 
                       and dotMat.Circle.get(i).get_y().floatLessEqual (close * (1 + linedist))
                        
                            dotMat.Zone.get(i).set_x2(pct.timeFrom("bar", 40, "chart"))
                    
                    else 
                        
                        dotMat.Zone.get(i).set_x2    (pct.timeFrom("bar", 40, "chart"))
                    
                    switch srcol

                        true =>  dotMat.Zone.get(i).set_color(dotMat.Circle.get(i).get_y().
                                 floatGreatEqual(close).determine(dncol , upcol))
                        
                        =>      continue



// Start
// Thank you Donovan Wall for the great range filter code!! 

Cond_EMA(x, cond, n)=>
    var val     = array.new_float(0)
    var ema_val = array.new_float(1)
    if cond
        val.push(x)
        if val.size( )> 1
            val.remove(0)
        if na(ema_val.get(0))
            ema_val.fill(val.get(0))
        ema_val.set(0, (val.get(0) - ema_val.get(0))*(2/(n + 1)) + ema_val.get(0))
    EMA = ema_val.get(0)
    EMA

rng_size(x, scale, qty, n)=> 
    ATR      = Cond_EMA(ta.tr(true), 1, n)
    AC       = Cond_EMA(math.abs(x - x[1]), 1, n)
    rng_size = qty*AC  

rng_filt(h, l, rng_, n, type, smooth, sn, av_rf, av_n)=>
    rng_smooth = Cond_EMA(rng_, 1, sn)
    r          = smooth ? rng_smooth : rng_
    var rfilt  = array.new_float(2, (h + l)/2)
    rfilt.set(1, rfilt.get(0))
    
    if h - r > rfilt.get(1)
        rfilt.set(0, h - r)
    if l + r < rfilt.get(1)
        rfilt.set(0, l + r)

    rng_filt1 = rfilt.get(0)
    
    hi_band1  = rng_filt1 + r, lo_band1  = rng_filt1 - r
    rng_filt2 = Cond_EMA(rng_filt1, rng_filt1 != rng_filt1[1], av_n)
    hi_band2  = Cond_EMA(hi_band1,  rng_filt1 != rng_filt1[1], av_n)
    lo_band2  = Cond_EMA(lo_band1,  rng_filt1 != rng_filt1[1], av_n)
    
    [rng_filt, hi_band, lo_band] = switch av_rf 
     
        true => [rng_filt2, hi_band2, lo_band2]               
        =>      [rng_filt1, hi_band1, lo_band1]
   
    [hi_band, lo_band, rng_filt]


[h_band, l_band, filt] = rng_filt(close, close, rng_size((close + close)/2, "Average Change", 20.618, 500), 500, "Type 1", true, 500, 0,0)

// Thank you Donovan Wall for great range filter code!! 
// End

var int boxCount = 0

type liqValues

    matrix <float> Average
    matrix <int>   Violations
    matrix <float> TickVol
    matrix <float> TickOI
    float []       Levels
    line  []       boxLines

    line           rightUp
    line           rightDn
    line           leftUp
    line           leftDn
    line           startU
    line           startD

var liquidation = liqValues.new(
                                 
                                 matrix.new<float>(5 , 0   ), matrix.new<int>  (2 , 11, 0),
                                 matrix.new<float>(21, 1000), matrix.new<float>(21, 1000 ),
                                             array.new_float(), array.new_line()), 
                                             orientation = matrix.new<float>(2, 5)

method expCalc(array <float> id)                   => 
    math.exp(id.avg())

method multiply(float id, string PM, float )       =>
    
    switch PM
       
        "+"  => id * (1 + ((1./( float ))  + 0.004))
        "-"  => id * (1 - ((1./( float ))  + 0.004))

method reduced(array <float> id, float , string )  => 

    switch string 
    
        "P" => id.expCalc().multiply("+", float )
        "N" => id.expCalc().multiply("-", float )

method divSubtract(array<float> id, float, float2) =>

    (id.reduced(float , "P") - id.reduced(float2, "N")) / 5


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

    n  = id.binary_search_leftmost (orientation.get(0, column))
    n1 = id.binary_search_leftmost (orientation.get(1, column))

    [n, n1]

method finSetVol(matrix <float> id, int i, int row, int start, int end)       =>
    
    for x = start to end 
        id.set (row, i, id.get(row, i) + liquidation.TickVol.get(i, x))


method finSetOI (matrix <float> id, int i, int row, int start, int end)       =>
    
    for x = start to end 
        id.set (row, i, id.get(row, i) + liquidation.TickOI.get(i, x))


method tickSet(matrix<float> id, float value, int column, int loop, int calc) => 
    
    id.set(math.max(boxCount, 0), column, nz(nz(id.get(math.max(boxCount, 0), column)) + (value / math.max(1, (calc)))))



method netAdjust(array <float> id) => 

    for i = 0 to id.size() - 1
        if na(id.get(i))
            id.set(i, 0)

    for i = id.size() - 2 to 0
        id.set(i, id.get(i) + id.get(i + 1))

    if id.size().intGreatEqual(201)
        for i = id.size() - 1 to 200
            id.pop()


if action2 and syminfo.type.equal("crypto")

    var oiclab  = matrix.new<label>(2)

    OIgrid     = input.bool (defval = true ,         title = "Use OI For Grid Color (Instead of Volume) (Crypto Only)", group = "Grid Settings") 
    heatmap    = input.bool (defval = true ,         title = "Show Heatmap (Grid)",       group = "Grid Settings")
    ext        = input.bool (defval = false,         title = "Extend Grid Boxes",  group = "Grid Settings")
    gridWidth  = input.int  (defval = 0,             title = "Grid Width",         group = "Grid Settings")
    gridCol    = input.color(defval = color.white, title = "Border Color",       group = "Grid Settings", inline = "Grid")
    gridUp     = input.color(defval = color.lime,  title = '"Up" Color',         group = "Grid Settings", inline = "Grid")
    gridDn     = input.color(defval = color.red,   title = '"Down" Color',       group = "Grid Settings", inline = "Grid")


    var float div = 0

    if action.equal("Off") and not userDefinedTime 
        bx = box.all, la = label.all, li = line.all, lf = linefill.all
    
        if bx.size().intGreatEqual(1) 
            
            row = grid.rows(), col = grid.columns()
            grid.reshape(grid.elements_count(), 1)
            
            for i = 0 to bx.size() - 1
                if not grid.col(0).includes(bx.get(i))
                    bx.get(i).delete()

            grid.reshape(row, col) 

        if la.size().intGreatEqual(1) 
            for i = 0 to la.size() - 1
                
                if not oiclab.row(0).includes(la.get(i)) 
               and not oiclab.row(1).includes(la.get(i))
                    
                    la.get(i).delete()
        
        if li.size().intGreatEqual(1) 
            for i = 0 to li.size() - 1  
                li.get(i).delete()
        
        if lf.size().intGreatEqual(1) 
            for i = 0 to lf.size() - 1
                lf.shift().delete()
    
    var oicsum    = matrix.new<float>              (2, 0)
    var int stime = 0, var int sbar = 0
    

    if obj.size().intGreatEqual(1) and clocalc.size().intGreatEqual(1)

        if sbar.intEqual(0) 
            
            sbar := bar_index, stime := time

        cond = switch userDefinedTime 
            
            false => filt.floatGreatEqual(filt[1] - atr) and filt.floatLessEqual(filt[1] + atr)
            =>       time >= timtest and time <= timtest2

        if cond

            liquidation.Average.add_col(0, array.from(high, low, math.log(close), close > open ? volume : volume * -1, time))
            
            for i = 0 to math.min(obj.size(), clocalc.size()) - 1

                if syminfo.type.equal("crypto") and OIgrid

                    if math.sign(clocalc.get(i)).floatEqual(1) 

                        switch math.sign(oic.get(i))

                            1  => oicsum.add_col(oicsum.columns(), array.from(oic.get(i), float(na)))
                            -1 => oicsum.add_col(oicsum.columns(), array.from(float(na), oic.get(i)))

                    else

                        switch math.sign(oic.get(i))

                            -1  => oicsum.add_col(oicsum.columns(), array.from(oic.get(i), float(na)))
                            1   => oicsum.add_col(oicsum.columns(), array.from(float(na), oic.get(i)))
                    
                else 


                    switch math.sign(clocalc.get(i))
                       
                        1  => oicsum.add_col(oicsum.columns(), array.from(vol.get(i), float(na)))
                        -1 => oicsum.add_col(oicsum.columns(), array.from(float(na), vol.get(i)))

                    
 
            if liquidation.Levels.size().intGreatEqual(1)

                for i = 0 to math.min(obj.size(), clocalc.size()) - 1

                    highest =        liquidation.Levels.binary_search_leftmost (hi.get(i))
                    lowest  =        liquidation.Levels.binary_search_leftmost (lo.get(i))

                    for x = lowest to highest
                        
                        volx = switch math.sign(clocalc.get(i))
                            
                            1 => vol.get(i)
                            =>   vol.get(i) * -1

                        liquidation.TickVol.tickSet(volx      , x, i, highest - lowest)
                        liquidation.TickOI .tickSet(obj.get(i), x, i, highest - lowest)


            for i = 0 to 19
                if not barstate.islast

                    con = div.floatGreatEqual(500)

                    [index, pIndex, startIndex] = switch con
                        
                        true => [   time    ,  time  [1], stime]
                        =>       [bar_index, bar_index[1], sbar]


                    if index >= math.round(startIndex + (div * (i + 1))) and pIndex < math.round(startIndex + (div * (i + 1))) 

                        boxCount += 1
                        for z = 0 to 4

                            liquidation.TickVol.set(math.max(boxCount, 0), z, liquidation.TickVol.get(math.max(boxCount - 1, 0), z))
                            liquidation.TickOI .set(math.max(boxCount, 0), z, liquidation.TickOI .get(math.max(boxCount - 1, 0), z))


                        for x = 0 to 4

                            grid.set(x, boxCount,
                                     box.new(
                                                     grid.get(x, boxCount - 1).get_right(),
                                                     liquidation.Average.row(2).reduced(100, "N") + (liquidation.Average.row(2).divSubtract(100, 100) * (x + 1)), 
                                                     math.round(index + div), 
                                                     liquidation.Average.row(2).reduced(100, "N") + (liquidation.Average.row(2).divSubtract(100, 100) *     (x)),
                                                     xloc         = div.floatGreatEqual(500).determine(xloc.bar_time, xloc.bar_index),  
                                                     border_color = gridCol, 
                                                     border_width = gridWidth, 
                                                     bgcolor      = color.white

                                                 ))


                        break
                       
            if oicsum.elements_count().intGreatEqual(90001)
                for i = 0 to 10000
                    oicsum.remove_col(i)
        
        else    

            if filt < filt[1] - atr and not userDefinedTime or filt > filt[1] + atr and not userDefinedTime or userDefinedTime and time < timtest

                liquidation.TickVol.fill(0, 0, liquidation.TickVol.rows(), 0, liquidation.TickVol.columns())
                liquidation.TickOI .fill(0, 0, liquidation.TickOI .rows(), 0, liquidation.TickOI .columns())
                liquidation.Levels.clear()
                        

                for i = 0 to grid.rows() - 1
                    for x = 0 to grid.columns() - 1
                        grid.get(i, x).delete()
                
                if oicsum.columns().intGreatEqual(1) 
                    for i = 0 to oicsum.columns() - 1
                        oicsum.remove_col()
                
                if oiclab.columns().intGreatEqual(1) 
                    
                    for i = 0 to oiclab.columns() - 1
                        oiclab.get(0, i).delete()
                        oiclab.get(1, i).delete()
                    
                    for i = 0 to oiclab.columns() - 1
                        oiclab.remove_col()

                stime := time, sbar := bar_index, div := switch (last_bar_index - sbar) / 20 >= 500
                    
                    false => (last_bar_index - sbar) / 20
                    =>       (last_bar_time - stime) / 20

                startIndex = div.floatGreatEqual(500).determine(time, bar_index)

                for x = 0 to 4
                                            
                    grid.set(x, 0,
                             box.new(
                                             startIndex,
                                             liquidation.Average.row(2).reduced(100, "N") + (liquidation.Average.row(2).divSubtract(100, 100) * (x + 1)), 
                                             math.round(startIndex + div), 
                                             liquidation.Average.row(2).reduced(100, "N") + (liquidation.Average.row(2).divSubtract(100, 100) *     (x)),
                                             xloc         = div.floatGreatEqual(500).determine(xloc.bar_time, xloc.bar_index),  
                                             border_color = gridCol, 
                                             border_width = gridWidth, 
                                             bgcolor      = color.white

                                         ))
    



                if liquidation.Average.columns().intGreatEqual(1) 
                    for i = 0 to liquidation.Average.columns() - 1
                        liquidation.Average.remove_col()
                    
                    liquidation.Average.add_col(0 ,  array.from(
                                                     high, 
                                                     low, 
                                                     math.log(close), 
                                                     close > open ? volume : volume * -1, 
                                                     time
                                                     
                                                     ))

                for i = 0 to 499
                    
                    liquidation.Levels.HeWhoSort(close * (1 + (i/1000)), 1)
                    liquidation.Levels.HeWhoSort(close * (1 - (i/1000)), 1)

                boxCount := 0


    if barstate.islast and not userDefinedTime or time[1] < timtest2 and time >= timtest2 and userDefinedTime 

        [endTime, endIndex] = switch userDefinedTime
            
            false => [last_bar_time, last_bar_index]
            true  => [timtest2, bar_index          ]


        if userDefinedTime  
            
            x = timeMat.Time.get(timeMat.Time.indexof(timtest) + 1)
            
            line.new(x, high, x, low,    xloc = xloc.bar_time,   extend = extend.both,   color = color.new(color.white, 50)  ,  width = 2)
            line.new(timtest2, high, timtest2, low, xloc = xloc.bar_time, extend = extend.both, color = color.new(#000000, 50), width = 2)
            

        posSum = oicsum.row(0).sum()
        negSum = oicsum.row(1).sum()
        
        minlvlu = 50, minlvld = 50,  minlvl = 50, var corners = matrix.new<liqValues>(6, 1)

        if minlevl.notEqual("Auto")
            
            minlvlu := int(str.tonumber(minlevl))
            minlvld := int(str.tonumber(minlevl))
        
        else 
            
            for i = 50 to 20 by 10
                
                if liquidation.Average.row(0).max().floatGreatEqual(liquidation.Average.row(2).reduced(i, "P"))
                    minlvlu := i + 10
                
                if liquidation.Average.row(1).min().floatLessEqual (liquidation.Average.row(2).reduced(i, "N"))
                    minlvld := i - 10
        
        minlvl    := math.min(minlvlu, minlvld)    


        if syminfo.type.equal("crypto")
            
            for i = 0 to liquidation.Average.columns() - 1
                for x = 0 to 10
                    if liquidation.Average.get(0, i).floatGreatEqual(liquidation.Average.row(2).reduced(x * 10, "P"))
                        liquidation.Violations.set(0, x, nz(liquidation.Violations.get(0, x) + 1))

            for i = 0 to liquidation.Average.columns() - 1
                for x = 0 to 10
                    if liquidation.Average.get(1, i).floatLessEqual(liquidation.Average.row(2).reduced(x * 10, "N"))
                        liquidation.Violations.set(1, x, nz(liquidation.Violations.get(1, x) + 1))


            if showcir

                uCalc = liquidation.Average.row(2).reduced(100, "P")
                lCalc = liquidation.Average.row(2).reduced(100, "N")

                for i = liquidation.Average.columns() - 1 to 1

                    if liquidation.Average.get(0, i - 1).floatGreatEqual(uCalc) 
                             and liquidation.Average.get(0, i) < uCalc

                        oiclab.add_col(oiclab.columns())

                        oiclab.set(0, oiclab.columns() - 1, label.new(math.round(liquidation.Average.get(4, i - 1)), 
                                                 liquidation.Average.get(0, i - 1) , "⬤", 
                                     textcolor = color.new(gridUp, 50), 
                                     color     = #000000,  
                                     style     = label.style_text_outline, 
                                     xloc      = xloc.bar_time, 
                                     size      = size.tiny
                                     ))

                    if liquidation.Average.get(1, i - 1).floatLessEqual(lCalc) 
                             and liquidation.Average.get(1, i).floatGreatEqual(lCalc)

                        oiclab.add_col(oiclab.columns())

                        oiclab.set(1, oiclab.columns() - 1, label.new(math.round(liquidation.Average.get(4, i - 1)),
                                                 liquidation.Average.get(1, i - 1) , "⬤", 
                                     textcolor = color.new(gridDn, 50), 
                                     color     = #000000, 
                                     style     = label.style_text_outline, xloc = xloc.bar_time, 
                                     size      = size.tiny
                                     ))


            for i = minlvl to 90 by 10 

                transp = array.from(45, 50, 55, 60, 65, 70, 75, 80, 85, 90)

                txt = switch i.intNotEqual(90)

                    true => str.tostring(i, "###x")
                    =>      box2Line ? "90x" : "90 - 100x" 

                switch box2Line

                    false => 
                    
                     box.new(
                             stime, liquidation.Average.row(2).expCalc().multiply("-", i + 10), endTime, liquidation.Average.row(2).expCalc().multiply("-", i), 
                                                         xloc         = xloc.bar_time, 
                                                         bgcolor      = color.new( gridUp, transp.get((i - minlvl) / 10)),  
                                                         text_color   = color.white, 
                                                         text         = txt, 
                                                         border_color = color.new( gridUp, transp.get((i - minlvl) / 10)),  
                                                         text_halign  = text.align_left, 
                                                         text_size    = size.auto

                                                         ),

                     box.new(
                             stime, liquidation.Average.row(2).expCalc().multiply("+", i + 10), endTime, liquidation.Average.row(2).expCalc().multiply("+", i),
                                                         xloc         = xloc.bar_time, 
                                                         bgcolor      = color.new( gridDn, transp.get((i - minlvl) / 10)),  
                                                         text_color   = color.white, 
                                                         text         = txt, 
                                                         border_color = color.new( gridDn, transp.get((i - minlvl) / 10)), 
                                                         text_halign  = text.align_left,
                                                         text_size    = size.auto
                                                         )

                    =>
                     line.new(
                             stime, liquidation.Average.row(2).expCalc().multiply("-", i), endTime + (time - time[3]), 
                                                         liquidation.Average.row(2).expCalc().multiply("-", i), 
                                                         xloc         = xloc.bar_time, 
                                                         color        = color.new( gridUp, transp.get((i - minlvl) / 10))

                                                         ),

                     line.new(
                             stime, liquidation.Average.row(2).expCalc().multiply("+", i), endTime + (time - time[3]), 
                                                         liquidation.Average.row(2).expCalc().multiply("+", i),
                                                         xloc          = xloc.bar_time, 
                                                         color         = color.new( gridDn, transp.get((i - minlvl) / 10)) 
                                                         )
                
                if box2Line

                    label.new(bar_index + 7, liquidation.Average.row(2).expCalc().multiply("+", i), 
                                         style     = label.style_label_left, 
                                         textcolor = gridDn, 
                                         color = #00000000,
                                         text = txt
                                         )

                    label.new(bar_index + 7, liquidation.Average.row(2).expCalc().multiply("-", i), 
                                         style     = label.style_label_left,
                                         textcolor = gridUp, 
                                         color = #00000000,
                                         text = txt
                                         )
                    if i.intEqual(90)
                     
                        line.new(
                                 stime, liquidation.Average.row(2).expCalc().multiply("-", i + 10), endTime + (time - time[3]), 
                                                             liquidation.Average.row(2).expCalc().multiply("-", i + 10), 
                                                             xloc         = xloc.bar_time, 
                                                             color        = color.new( gridUp, transp.get((i - minlvl) / 10))

                                                             )

                        line.new(
                                 stime, liquidation.Average.row(2).expCalc().multiply("+", i + 10), endTime + (time - time[3]), 
                                                             liquidation.Average.row(2).expCalc().multiply("+", i + 10),
                                                             xloc          = xloc.bar_time, 
                                                             color         = color.new( gridDn, transp.get((i - minlvl) / 10)) 
                                                             )
                
                        label.new(bar_index + 7, liquidation.Average.row(2).expCalc().multiply("+", i + 10), 
                                             style     = label.style_label_left, 
                                             textcolor = gridDn, 
                                             text = str.tostring(i + 10, "###x"),
                                             color = #00000000
                                             )

                        label.new(bar_index + 7, liquidation.Average.row(2).expCalc().multiply("-", i + 10), 
                                             style     = label.style_label_left,
                                             textcolor = gridUp, 
                                             text = str.tostring(i + 10, "###x"),
                                             color = #00000000
                                             )


                y1     = (liquidation.Average.row(2).divSubtract(minlvl, 100) / ((90 - minlvl) / 10) * ((i - minlvl) / 10))

                colarr = array.from(11, 11, 22, 22, 33, 33, 44, 44, 55, 66, 66)

                txtc   = switch liquidation.Average.row(2).expCalc().multiply("+", i + 10).floatGreatEqual(liquidation.Average.row(0).max())

                    true => #ffffff50
                    =>      color.new(gridDn, colarr.get((i - minlvl) / 10)) 

                if not box2Line
                    
                    label.new(endIndex + 25, liquidation.Average.row(2).reduced(minlvl, "P") - y1,

                                     "▰", 

                                     textcolor = txtc,
                                     size      = size.tiny, 
                                     color     = #000000, 
                                     style     = label.style_text_outline
                                     )

                txtc2 = switch liquidation.Average.row(2).expCalc().multiply("-", i + 10).floatLessEqual(liquidation.Average.row(1).min())

                    true => #ffffff50
                    =>        color.new(gridUp, colarr.get((i - minlvl) / 10))
                
                if not box2Line
                    
                    label.new(endIndex + 25, liquidation.Average.row(2).reduced(minlvl, "N") + y1, 
                                     "▰", 
                                     textcolor = txtc2 ,
                                     size      = size.tiny, 
                                     color     = #000000, 
                                     style     = label.style_text_outline
                                     )
                            
        [mult, mult2, mult3] = switch minlvl
           
            50 => [35  , 40, 30    ]
            40 => [30  , 35, 25    ]
            30 => [23  , 25.5, 20.5]
            20 => [15  , 17, 13    ]
            10 => [8   , 9 , 7     ]

        liqd  = math.avg(liquidation.Average.row(2).reduced(100, "N"), liquidation.Average.row(2).reduced(minlvl, "N"))
        liqu  = math.avg(liquidation.Average.row(2).reduced(100, "P"), liquidation.Average.row(2).reduced(minlvl, "P"))
        
        liqd2 = liquidation.Average.row(2).reduced(mult, "N")
        liqu2 = liquidation.Average.row(2).reduced(mult, "P")


        sbartime = timeMat.Time.indexof(stime)

        switchCond = syminfo.type.equal("crypto")

        [longText, shortText, totCalc] = switch switchCond
            
            true => [OIgrid.determine("\nNet Longs In Range",  "\nBuying Vol. In Range" ), 
                     OIgrid.determine("\nNet Shorts In Range", "\nSelling Vol. In Range"),
                     OIgrid.determine          (posSum+negSum, posSum-negSum)]
            
            =>      ["\nBuying Vol. In Range", "\nSelling Vol. In Range", posSum-negSum]


        label.new(bar_index + 15, liquidation.Average.row(2).expCalc(), str.tostring(totCalc, "###,###,###,###.00"), 
                                         color     = color.white, 
                                         textcolor = color.rgb(0, 0, 0), 
                                         style     = label.style_text_outline, 
                                         size      = size.small
                                         )


        b = box.new(
                    
                     int(
                             math.avg(stime, stime, endTime)), 
                             liquidation.Average.row(2).reduced(mult2, "N"), 
                        
                                 int(
                                             math.avg(stime, endTime, endTime)), 
                                             liquidation.Average.row(2).reduced(mult3, "N"),
                                             bgcolor      = #00000050, 
                                             border_color = #ffffff, 
                                             text         = str.tostring(posSum, "###,###,###,###,###,###.00") 
                                                                                   + longText , 
                                             text_color   = color.white, 
                                             text_size    = size.auto, 
                                             xloc         = xloc.bar_time
                                             )


        o = box.new(
                    
                     int(
                             math.avg(stime, stime, endTime)), 
                             liquidation.Average.row(2).reduced(mult2, "P"), 
                        
                                 int(
                                         math.avg(stime, endTime, endTime)), 
                                             liquidation.Average.row(2).reduced(mult3, "P"),
                                             bgcolor      = #00000050, 
                                             border_color = #ffffff, 
                                             text         = str.tostring(negSum, "###,###,###,###,###,###.00") +
                                                                                     + shortText , 
                                             text_color   = color.white, 
                                             text_size    = size.auto, 
                                             xloc         = xloc.bar_time
                                             )

        

        if switchCond


            liquidation.boxLines.push(line.new(timeMat.Time.get(sbartime), liqd, timeMat.Time.get(sbartime + 10), 
                                                     liqd, 
                                                     color = gridUp, 
                                                     style = line.style_dashed, 
                                                     xloc  = xloc.bar_time
                                                     ))

            corners.set(2, 0, 
                         liqValues.new(
                                 leftUp = line.new(timeMat.Time.get(sbartime + 10), liqd2, timeMat.Time.get(sbartime + 10), 
                                                         liqd, 
                                                         color = gridUp, 
                                                         style = line.style_dashed, 
                                                         xloc  = xloc.bar_time
                                                         )))


            liquidation.boxLines.push(line.new(timeMat.Time.get(sbartime + 10),  liqd2, b.get_left(),liqd2, 
                                                 color = gridUp, 
                                                 style = line.style_dashed, 
                                                 xloc  = xloc.bar_time
                                                 ))


            corners.set(0, 0, 
                             liqValues.new(
                                     rightUp = line.new(endIndex + 10,  liqd2, endIndex + 10, liqd, 
                                                 color = gridUp, 
                                                 style = line.style_dashed
                                                 )))


            liquidation.boxLines.push(line.new(int(math.avg(sbar, endIndex, endIndex)),  liqd2, endIndex + 10, liqd2, 
                                                 color = gridUp, 
                                                 style = line.style_dashed
                                                 ))


            liquidation.boxLines.push(line.new(endIndex, liqd, endIndex + 10, 
                                                 liqd, 
                                                 color = gridUp, 
                                                 style = line.style_dashed
                                                 ))


            liquidation.boxLines.push(line.new(stime, liqu, timeMat.Time.get(sbartime + 10), 
                                                 liqu, 
                                                 color = gridDn, 
                                                 style = line.style_dashed, 
                                                 xloc  = xloc.bar_time
                                                 ))


            corners.set(3, 0, 

                         liqValues.new(

                                 leftDn = line.new(timeMat.Time.get(sbartime + 10), liqu, timeMat.Time.get(sbartime + 10), 
                                                 liqu2, 
                                                 color = gridDn, 
                                                 style = line.style_dashed, 
                                                 xloc  = xloc.bar_time
                                                 )))

            liquidation.boxLines.push(line.new(timeMat.Time.get(sbartime + 10),  liqu2, o.get_left(),liqu2, 
                                                 color = gridDn, 
                                                 style = line.style_dashed, 
                                                 xloc  = xloc.bar_time
                                                 ))


            corners.set(1, 0, 
                         liqValues.new(
                                 rightDn = line.new(endIndex + 10,  liqu, endIndex + 10, liqu2, 
                                                 color = gridDn, 
                                                 style = line.style_dashed
                                                 )))


            liquidation.boxLines.push(line.new(
                     int(
                         math.avg(sbar, endIndex, endIndex)),  liqu2, endIndex + 10, liqu2, 
                                                 color = gridDn, 
                                                 style = line.style_dashed
                                                 ))



            liquidation.boxLines.push(line.new(endIndex, liqu, endIndex + 10, 
                                                 liqu, 
                                                 color = gridDn, 
                                                 style = line.style_dashed
                                                 ))
    
            var table liqtab = table.new(
                                                 position.bottom_right, 20, 20, 
                                                 bgcolor      = na, 
                                                 frame_color  = color.white, 
                                                 border_color = color.white, 
                                                 frame_width  = 1, 
                                                 border_width = 1
                                                 )

            liqtab.cell(0, 0, "Violations", text_color = color.white), liqtab.cell(0, 1, "Positive", text_color = gridDn), 
            liqtab.cell(2, 1, "Negative"  , text_color = gridUp), liqtab.merge_cells(0, 0, 3, 0), 
            
            liqtab.merge_cells(0, 1, 1, 1)
            liqtab.merge_cells(2, 1, 3, 1)

            strArr  = array.from("100x: ", "90x: ", "80x: ", "70x: ", "60x: ", "50x: ", "40x: ", "30x: ", "20x: ", "10x: " )
            strArr2 = array.from("100x: ", "90x: ", "80x: ", "70x: ", "60x: ", "50x: ", "40x: ", "30x: ", "20x: ", "10x: " )

            intMat = matrix.new<int>(0, 10)

            dnRow = liquidation.Violations.row(0), dnRow.reverse()    
            upRow = liquidation.Violations.row(1), upRow.reverse()    

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

                strArr .set(i, strArr.get(i)  + str.tostring(dnRow.get(i)))
                strArr2.set(i, strArr2.get(i) + str.tostring(upRow.get(i)))

            intMat.add_row(0, array.from(0, 1, 0, 1, 0, 1, 0, 1, 0, 1))
            intMat.add_row(1, array.from(2, 3, 2, 3, 2, 3, 2, 3, 2, 3))
            intMat.add_row(2, array.from(2, 2, 3, 3, 4, 4, 5, 5, 6, 6))

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

                liqtab.cell(intMat.get(0, i), intMat.get(2, i), strArr.get (i), text_color = gridDn  )
                liqtab.cell(intMat.get(1, i), intMat.get(2, i), strArr2.get(i), text_color = gridUp)

        if move 

            netLong  = oicsum.row(0), netShort = oicsum.row(1)


            for i = bar_index - sbar to 0
                
                if timeMat.Close.get(i).floatGreatEqual(timeMat.Close.get(i + 1))
                    
                    switch math.sign(timeMat.Difference.get(i)).floatEqual(1)
                        
                        true =>  netLong .set(i, timeMat.Difference.get(i)), 
                                 netShort.set(i, 0)
                        
                        =>       netLong .set(i, 0), 
                                 netShort.set(i, timeMat.Difference.get(i))

                else 
                    
                    switch math.sign(timeMat.Difference.get(i)).floatEqual(1)
                        
                        true =>  netLong .set(i, 0),
                                 netShort.set(i, timeMat.Difference.get(i))
                        
                        =>       netLong .set(i, timeMat.Difference.get(i)),
                                 netShort.set(i, 0)
          
            netLong.netAdjust(), netShort.netAdjust()

            b.set_top(liquidation.Average.row(2).reduced(mult, "N")) 
            o.set_top(liquidation.Average.row(2).reduced(mult, "P"))
            
            if switchCond

                linefill.new(corners.get(2, 0).leftUp, corners.get(0, 0).rightUp, #00000050) 
                linefill.new(corners.get(3, 0).leftDn, corners.get(1, 0).rightDn, #00000050)

                avgN = (math.avg(liquidation.Average.row(2).reduced(mult + 1, "N"), liquidation.Average.row(2).reduced(minlvl - 1, "N")))
                avgP = (math.avg(liquidation.Average.row(2).reduced(mult + 1, "P"), liquidation.Average.row(2).reduced(minlvl - 1, "P")))

                for i = 1 to math.min(bar_index - sbar, netLong.size() - 1)


                    netCalc   = (liquidation.Average.row(2).reduced(mult + 1, "N")) + ((liquidation.Average.row(2).reduced(minlvl - 1, "N")) 
                                                         - (liquidation.Average.row(2).reduced(mult + 1, "N"      ))) 
                                                         * (netLong.get(i) - netLong.min())  / (netLong.range     ())

                    snetCalc  = (liquidation.Average.row(2).reduced(minlvl - 1, "P"))   -   ((liquidation.Average.row(2).reduced(minlvl - 1, "P")) 
                                                         - (liquidation.Average.row(2).reduced(mult + 1, "P"      ))) 
                                                         * (netShort.get(i) - netShort.min())  / (netShort.range  ())

                    netCalc2  =   (liquidation.Average.row(2) .reduced(mult + 1, "N"))  + ((liquidation.Average.row(2) .reduced  (minlvl - 1, "N")) 
                                                         - (liquidation.Average.row(2).reduced(mult + 1, "N"       ))) 
                                                         * (netLong.get(i - 1) - netLong.min())  / (netLong.range  ()), 

                    snetCalc2 =   (liquidation.Average.row(2).reduced(minlvl-1, "P"))  - ((liquidation.Average.row(2)   .reduced(minlvl - 1, "P"  )) 
                                                         - (liquidation.Average.row(2).reduced(mult + 1, "P"       ))) 
                                                         * (netShort.get(i - 1) - netShort.min()) / (netShort.range())




                    line.new(timeMat.Time.get(i + 1), snetCalc, timeMat.Time.get(i), 
                                     snetCalc2,
                                     color = gridDn,
                                     xloc  = xloc.bar_time, 
                                     width = 2
                                     )

                    line.new(timeMat.Time.get(i + 1), netCalc, timeMat.Time.get(i), 
                                     netCalc2, 
                                     color = gridUp,
                                     xloc  = xloc.bar_time, 
                                     width = 2
                                     )
                    
                       

        if not move and switchCond

            
            if liquidation.boxLines.size().intGreatEqual(1) 
                for i = 0 to liquidation.boxLines.size() - 1
                    liquidation.boxLines.shift().delete()   
            
            for i = 0 to 3
                
                if not na(corners.get(i, 0))
                    
                    switch i % 4
                        
                        0 => corners.get(0, 0).rightUp.delete()
                        1 => corners.get(1, 0).rightDn.delete()
                        2 => corners.get(2, 0).leftUp .delete()
                        3 => corners.get(3, 0).leftDn .delete()

            if linefill.all.size().intGreatEqual(1) 
                for i = 0 to linefill.all.size() - 1
                    linefill.all.shift().delete()
        
        if heatmap
            
            count = 0
            for i = 0 to grid.rows() - 1
                for x = 0 to grid.columns() - 1

                    grid.get(i, x).set_bottom(liquidation.Average.row(2).reduced(100, "N") + (liquidation.Average.row(2).divSubtract(100, 100) * i))
                    grid.get(i, x).set_top   (liquidation.Average.row(2).reduced(100, "N") + (liquidation.Average.row(2).divSubtract(100, 100) * (i + 1)))


            for i = 0 to 4

                orientation.set(0, i, grid.get(i, 0).get_top   ())
                orientation.set(1, i, grid.get(i, 0).get_bottom())


            [up1, dn1] = liquidation.Levels.double_binary_search_leftmost (0), [up2, dn2] = liquidation.Levels.double_binary_search_leftmost (1),
            [up3, dn3] = liquidation.Levels.double_binary_search_leftmost (2), [up4, dn4] = liquidation.Levels.double_binary_search_leftmost (3),

                                         [up5, dn5] = liquidation.Levels.double_binary_search_leftmost (4)

            var finTick = matrix.new<float>(5, 1, 0), var finTick2 = matrix.new<float>(5, 1, 0)

            for i = 0 to 20

                finTick .finSetVol(i, 0, dn1, up1), finTick .finSetVol(i, 1, dn2, up2)
                finTick2.finSetOI (i, 0, dn1, up1), finTick2.finSetOI (i, 1, dn2, up2)

                finTick .finSetVol(i, 2, dn3, up3), finTick .finSetVol(i, 3, dn4, up4)
                finTick2.finSetOI (i, 2, dn3, up3), finTick2.finSetOI (i, 3, dn4, up4),

                                     finTick .finSetVol(i, 4, dn5, up5),
                                     finTick2.finSetOI (i, 4, dn5, up5)

                finTick .add_col(finTick .columns(), finTick .col(finTick .columns() - 1))
                finTick2.add_col(finTick2.columns(), finTick2.col(finTick2.columns() - 1))

            for i = 0 to grid.rows() - 1
                for x = 0 to grid.columns() - 1

                    [datax, datamin, datamax] = switch OIgrid

                        false                                    =>          [finTick .get(i, x), finTick .min(), finTick .max()]
                        true and syminfo.type.notEqual("crypto") =>          [finTick .get(i, x), finTick .min(), finTick .max()]
                        =>                                                   [finTick2.get(i, x), finTick2.min(), finTick2.max()] 

                    col = switch math.sign(datax)

                        0  => color.new(color.gray, 80)
                        1  =>   color.from_gradient(datax, 0, datamax, color.new(gridUp, 90), color.new(gridUp, 50))
                        -1 =>   color.from_gradient(datax, datamin, 0, color.new(gridDn, 50), color.new(gridDn, 90))

                    grid.get(i, x).set_bgcolor(col)

                    if showValues

                        oiTxt = switch switchCond
                            true => "\n\nOI: " +
                                             (finTick2.get(i, x).floatGreatEqual(0).determine("+" , "")) + str.tostring(finTick2.get(i, x), "###,###,###.##")
                            =>      ""

                        grid.get(i, x).set_text( 

                                                 "VOL: " + str.tostring(finTick.get(i, x), format.volume) + oiTxt)

                        grid.get(i, x).set_text_color(color.white)


            if ext
                for i = 0 to grid.rows() - 1
                    for x = 1 to grid.columns() - 1

                        [dataCur, dataPrev] = switch OIgrid

                            false                                    => [finTick .get(i, x), finTick .get(i, x - 1)]
                            true and syminfo.type.notEqual("crypto") => [finTick .get(i, x), finTick .get(i, x - 1)]
                            =>                                          [finTick2.get(i, x), finTick2.get(i, x - 1)]

                        if dataCur.floatEqual(dataPrev)

                            grid.get(i, x).set_left(grid.get(i, x - 1).get_left())
                            grid.get(i, x - 1).delete()

            if not switchCond

                distanceTop = o.get_bottom() - o.get_top()
                distanceBot = b.get_top() - b.get_bottom()

                o.set_bottom(grid.get(4, 0) .get_top())   , o.set_top(o.get_bottom() + distanceTop)
                b.set_top   (grid.get(0, 0) .get_bottom()), b.set_bottom(b.get_top() - distanceBot)


        else 
            
            for i = 0 to grid.rows() - 1
                for x = 0 to grid.columns() - 1
                    grid.get(i, x).delete()