[FFriZz]Priceline/Ticks
// This source code is subject to the terms of the Mozilla PublicBull License 2.0 at https://mozilla.org/MPL/2.0/
// © FFriZz

//@version=5
indicator('[FFriZz]Priceline/Ticks',overlay = true,max_labels_count = 500,max_lines_count = 500)
import FFriZz/BoxLine_Lib/8 as XY

//inputs//
bool          usePriceLine = input.bool(true ,'Price Line?',group = 'On/Off')         
bool         usePriceLabel = input.bool(true ,'Chart Label?',group = 'On/Off')  
bool          usePriceTick = input.bool(true ,'Ticks?',group = 'On/Off')  
bool              useTable = input.bool(true ,'Table?',group = 'On/Off')
bool            useReverse = input.bool(false ,'Reverse Table?',group = 'On/Off')
bool              useBoxes = input.bool(true ,'S/R Boxes?',group = 'On/Off')  
// debug = input.bool(true ,'Table?',group = 'On/Off')  

bool       lineColorChange = input.bool(false ,'Change Price Line Colors?',group = 'Price line',inline = 'f',tooltip = 'Defaults to Up Color') 
color              colorUp = input.color(#000000,'Up',group = 'Price line',inline = 'f')           
color            colorDown = input.color(#ff0000,'Down',group = 'Price line',inline = 'f') 
string              extend = input.string('Extend Both','Extend Price line',options = ['Extend Both','Extend None','Extend Right','Extend Left'],group = 'Price line', inline = 'a')
int             pLineWidth = input.int(1,'Width',group = 'Price line',inline = 'b')
string           lineStyle = input.string('Dashed','Price line Style',options = ['Solid','Dashed','Dotted','Arrow Right','Arrow Left','Arrow Both'],group = 'Price line', inline = 'c')

bool labelPriceColorChange = input.bool(false ,'Change Label Price Colors?',group = 'Price label',inline = 'g',tooltip = 'Defaults to Up Color') 
color          textColorUp = input.color(#000000,'Up',group = 'Price label',inline = 'g')           
color        textColorDown = input.color(#ff0000,'Down',group = 'Price label',inline = 'g') 
string           labelSize = input.string('Normal','label Size',options = ['Auto','Tiny','Small','Normal','Large','Huge'],group = 'Price label', inline = 'e')

bool  labelTickColorChange = input.bool(true ,'Change  Tick Colors?',group = 'Ticks',inline = 'c',tooltip = 'Defaults to Up Color') 
color     priceTickColorUp = input.color(#008000,'Up',group = 'Ticks',inline = 'c')           
color   priceTickColorDown = input.color(#ff0000,'Down',group = 'Ticks',inline = 'c')
color           boxColorUp = input.color(#00800062,'Up',group = 'Ticks',inline = 'c')           
color         boxColorDown = input.color(#ff00004f,'Down',group = 'Ticks',inline = 'c')

int                 offset = input.int(0,'Offset',group = 'Adjustments', inline = '') 
int                  count = input.int(30,'Tick Display Count',group = 'Adjustments',inline = '',minval = 0) 
int            displayBull = input.int(30,'Bull Box Count',group = 'Adjustments',inline = '',minval = 0) 
int            displayBear = input.int(30,'Bear Box Count',group = 'Adjustments',inline = '',minval = 0) 

//Single Colors//
if labelTickColorChange == false
    priceTickColorDown := priceTickColorUp
if labelPriceColorChange == false
    textColorDown := textColorUp
if lineColorChange == false
    colorDown := colorUp

//Switches//{
LineStyle = switch lineStyle
    'Solid'       => line.style_solid
    'Dashed'      => line.style_dashed
    'Dotted'      => line.style_dotted
    'Arrow Right' => line.style_arrow_right
    'Arrow Left'  => line.style_arrow_left
    'Arrow Both'  => line.style_arrow_both
    => na
    
Extend = switch extend
    'Extend Both'  => extend.both
    'Extend None'  => extend.none
    'Extend Right' => extend.right
    'Extend Left'  => extend.left
    => na  

LabelSize = size.large
TickSize = size.small
switch labelSize
    'Tiny'   => LabelSize := size.tiny,   
                 TickSize := size.tiny
    'Small'  => LabelSize := size.small,  
                 TickSize := size.tiny
    'Normal' => LabelSize := size.normal, 
                 TickSize := size.small
    'Large'  => LabelSize := size.large,  
                 TickSize := size.normal
    'Huge'   => LabelSize := size.huge,   
                 TickSize := size.normal
    'Auto'   => LabelSize := size.auto,   
                 TickSize := size.auto
    => na
//}

//Vars//
string mt = str.tostring(syminfo.mintick)
string zeros = '0.'
while str.length(zeros) < str.length(mt)
    zeros += '0'

varip string[] aTrackUp = array.new_string()
varip string[] aTrackDn = array.new_string()

int                 bt = time_close - time
varip bool         vIP = na
varip int           ip = 0
varip float    ipClose = na 
bool           upcBull = close > open
varip        aSizeBull = 0
varip        aSizeBear = 0
varip trackMovementsUp = 0.0
varip trackMovementsDn = 0.0
// varip debuggerBull = '', varip debuggerBear = ''

//ifs//
if barstate.islast

    varip float[]  aFVGbullTop = array.new<float>() 
    varip float[]  aFVGbullBot = array.new<float>() 
    varip float[]  aFVGbearTop = array.new<float>()
    varip float[]  aFVGbearBot = array.new<float>()
    var     box[]     aBullBox = array.new<box>() 
    var     box[]     aBearBox = array.new<box>()
    varip float[]     aOrderUp = array.new<float>()
    varip float[]     aOrderDn = array.new<float>()
    
    varip   volUp = 0.0
    varip   volDn = 0.0
    varip volDiff = 0.0
    varip float volSave = na
    if volume < volSave 
        volSave := 0
        volDn   := 0
        volUp   := 0
    
    varip  cBull = 0.0
    varip cBull2 = 0.0
    varip cBull3 = 0.0
    varip  BullS = 0

    varip  cBear = 0.0
    varip cBear2 = 0.0
    varip cBear3 = 0.0
    varip  BearS = 0
 
    if na(volSave)
        volSave := volume

    if ipClose != close 
        if ipClose > close
            array.push(aTrackDn,str.tostring(close - ipClose,zeros) + '\n')
            array.push(aTrackUp,'\n')

            trackMovementsDn += math.abs(close - ipClose)
            volDn += volume - volSave
            
            if array.size(aTrackUp) > count
                array.shift(aTrackUp)
            if array.size(aTrackDn) > count
                array.shift(aTrackDn)
            ip := -1
       
        if ipClose < close
            array.push(aTrackUp,'+' + str.tostring(close - ipClose,zeros) + '\n')
            array.push(aTrackDn,'\n')
            
            trackMovementsUp += math.abs(close - ipClose)
            volUp += volume - volSave
            
            if array.size(aTrackUp) > count
                array.shift(aTrackUp)
            if array.size(aTrackDn) > count
                array.shift(aTrackDn)
            ip := 1

    if volume > volSave
        if close == ipClose
            
            if ip < 0
                array.push(aTrackDn,'▼\n')
                array.push(aTrackUp,'\n')
                volDn += volume - volSave
                
            if ip > 0
                array.push(aTrackUp,'▲\n')
                array.push(aTrackDn,'\n')
                volUp += volume - volSave
                       
            if array.size(aTrackUp) > count
                array.shift(aTrackUp)
            if array.size(aTrackDn) > count
                array.shift(aTrackDn) 

        if useBoxes


            //Bull Tick FVGs{
            if close > ipClose and BullS == 0
                cBull  := close
                cBull2 := ipClose
                BullS  := 1
            if close < cBull and BullS == 1
                cBull3 := cBull2
                cBull2 := cBull
                cBull  := close
                BullS  := 2
            else if close > cBull and BullS == 1
                BullS := 0
            if close < cBull2 and close > cBull3 and BullS == 2
                cBull := close
            if close < cBull3 and BullS == 2
                BullS := 0
            if close > cBull2 and BullS == 2
                cBull3 := cBull2
                cBull2 := cBull
                cBull  := close
                BullS  := 3
            if close > cBull3 and BullS == 3
                if close < cBull and close > cBull3 
                    cBull2 := cBull
                    cBull  := close
                    BullS  := 4
                else
                    cBull := close
            if close < cBull3 and (BullS == 4 or BullS == 3)
                BullS := 0
            if close > cBull3 and close < cBull and BullS == 4
                cBull := close
            if close > cBull and BullS == 4
                array.unshift(aFVGbullTop,cBull)
                array.unshift(aFVGbullBot,cBull3)
                array.unshift(aOrderUp,volUp)
                // oLabelBull = label.new(time, math.avg(cBull2,array.get(aFVGbull,0)),text = str.tostring(volUp-array.get(aOrderUp,0),'0.000'),xloc = xloc.bar_time,
                //  color = color(na), style = label.style_label_center, textcolor = priceTickColorUp, size = size.auto)
                BullS := 0
                //}

            //Bear Tick FVGs{
            if close < ipClose and BearS == 0
                cBear  := close
                cBear2 := ipClose
                BearS  := 1
            if close > cBear and BearS == 1
                cBear3 := cBear2
                cBear2 := cBear
                cBear  := close
                BearS  := 2
            else if close < cBear and BearS == 1
                BearS := 0
            if close > cBear2 and close < cBear3 and BearS == 2
                cBear := close
            if close > cBear3 and BearS == 2
                BearS := 0
            if close < cBear2 and BearS == 2
                cBear3 := cBear2
                cBear2 := cBear
                cBear  := close
                BearS  := 3
            if close < cBear3 and BearS == 3
                if close > cBear and close < cBear3 
                    cBear2 := cBear
                    cBear  := close
                    BearS  := 4
                else
                    cBear := close
            if close > cBear3 and (BearS == 4 or BearS == 3)
                BearS := 0
            if close < cBear3 and close > cBear and BearS == 4
                cBear := close
            if close < cBear and BearS == 4
                array.unshift(aFVGbearTop,cBear3)
                array.unshift(aFVGbearBot,cBear)
                array.unshift(aOrderDn,volDn)
                // oLabelBear = label.new(time, math.avg(cBear2,array.get(aFVGbear,0)),text = '\n' + str.tostring(volDn-array.get(aOrderDn,0),'0.000'),xloc = xloc.bar_time,
                //  color = color(na), style = label.style_label_center, textcolor = priceTickColorDown, size = size.auto)
                BearS := 0

    // atr = ta.atr(1000)
    // if barstate.islast
    
    //     var label lbl = na, label.delete(lbl)
    //     lbl := label.new(bar_index + 50, high,'Bear:'+str.tostring(BearS)+'\nBull:'+str.tostring(BullS))        
                //}

        volSave := volume

    //Line Edits  

    if array.size(aFVGbullTop) > displayBull
        array.pop(aFVGbullTop), array.pop(aFVGbullBot)
    if array.size(aFVGbearTop) > displayBear
        array.pop(aFVGbearTop), array.pop(aFVGbearBot)

    if array.size(aBullBox) > 0
        for i = array.size(aBullBox) - 1 to 0 
            box.delete(array.remove(aBullBox,i))

    if array.size(aFVGbullTop) > 0
        for i = array.size(aFVGbullTop) - 1 to 0 
            top = array.get(aFVGbullTop,i)
            bot = array.get(aFVGbullBot,i)
            BullBox = box.new(time - bt,top,last_bar_time + bt + bt,bot,xloc = xloc.bar_time,border_color = boxColorUp,bgcolor = boxColorUp)
            array.unshift(aBullBox,BullBox)
            // BullBox = line.new(time - bt,y,last_bar_time + bt + bt,y,xloc = xloc.bar_time,color = priceTickColorUp, width = 1)
            // array.unshift(aBullBox,BullLine)

    aSizeBull := array.size(aBullBox)
    if aSizeBull > 0 
        for i = aSizeBull - 1 to  0 
            BullBox = array.get(aBullBox,i)
            [_,top,_,bottom] = XY.BoxXY(BullBox)  
            if close < top
                box.set_top(BullBox,close)
                if array.size(aFVGbullTop) > 0
                    array.set(aFVGbullTop,i,close)
            if close < bottom
                box.delete(array.get(aBullBox,i))
                array.remove(aFVGbullTop,i), array.remove(aFVGbullBot,i)

    
    if array.size(aBearBox) > 0
        for i = array.size(aBearBox) - 1 to 0 
            box.delete(array.remove(aBearBox,i))

    if array.size(aFVGbearTop) > 0
        for i = array.size(aFVGbearTop) - 1 to 0 
            top = array.get(aFVGbearTop,i)
            bot = array.get(aFVGbearBot,i)
            BearBox = box.new(time - bt,top,last_bar_time + bt + bt,bot,xloc = xloc.bar_time,border_color = boxColorDown,bgcolor = boxColorDown)
            array.unshift(aBearBox,BearBox)
            // BullBox = line.new(time - bt,y,last_bar_time + bt + bt,y,xloc = xloc.bar_time,color = priceTickColorUp, width = 1)
            // array.unshift(aBearBox,BullLine)

    aSizeBear := array.size(aBearBox)
    if aSizeBear > 0 
        for i = aSizeBear - 1 to  0 
            BearBox = array.get(aBearBox,i)
            [_,top,_,bottom] = XY.BoxXY(BearBox)  
            if close > bottom
                box.set_bottom(BearBox,close)
                if array.size(aFVGbearBot) > 0
                    array.set(aFVGbearBot,i,close)
            if close > top
                box.delete(array.get(aBearBox,i))
                array.remove(aFVGbearTop,i), array.remove(aFVGbearBot,i)

    //Debuggers{
    // debuggerBear := str.tostring(array.size(aBearBox))
    // debuggerBear += ' ' + str.tostring(array.size(aFVGbear))

    // debuggerBull := str.tostring(array.size(aBullBox))
    // debuggerBull += ' ' + str.tostring(array.size(aFVGbull))
    //}
//}
    ipClose := close

    priceCount = close - open 
    pricePerc = math.abs(100 - ((close / open) * 100)) 

    //Color Switches//{
    if labelPriceColorChange or lineColorChange
        vIP := ip > 0
    color lineColor = lineColorChange ? vIP ? colorUp : colorDown : upcBull ? colorUp : colorDown
    color priceColor = labelPriceColorChange ? vIP ? textColorUp : textColorDown : upcBull ? textColorUp : textColorDown
//}

    int x = last_bar_time + ((10 + offset) * bt)

//Lines and Labels//
    if usePriceLabel
        var label label = na, label.delete(label)  
        label := label.new(x, close,xloc = xloc.bar_time, text = str.tostring(close,zeros), 
         color = chart.bg_color, style = label.style_text_outline, textcolor = priceColor, size = LabelSize)
        
        var label labelVUp = na, label.delete(labelVUp)  
        labelVUp := label.new(x, close, xloc = xloc.bar_time, text = (volUp > volDn and close < open ? 'D ' : '') + '+' + str.tostring(volUp) + 
         ' | +'+str.tostring(trackMovementsUp),
         color = color(na), style = label.style_label_up, textcolor = priceTickColorUp, size = TickSize)
        
        var label labelC = na, label.delete(labelC)  
        labelC := label.new(x, close, xloc = xloc.bar_time, text = (priceCount > 0 ? '\n+' : '\n') + str.tostring(priceCount) + ' | ' + (priceCount > 0 ? '+' : '-') + str.tostring(pricePerc,'0.00') + '%', 
         color = color(na), style = label.style_label_up, textcolor = priceCount > 0 ? priceTickColorUp : priceCount < 0 ? priceTickColorDown : #000000, size = TickSize)
        
        var label labelVDn = na, label.delete(labelVDn)  
        labelVDn := label.new(x, close, xloc = xloc.bar_time, text = (volUp < volDn and close > open ? '\n\nD -' : '\n\n-') + str.tostring(volDn) + 
         ' | -' + str.tostring(trackMovementsDn), 
         color = color(na), style = label.style_label_up, textcolor = priceTickColorDown, size = TickSize)

    if usePriceTick
        var label labelUP = na, label.delete(labelUP)
        labelUP := label.new(x, close,xloc = xloc.bar_time, text = '' + array.join(aTrackUp,''), color = color(na), 
         style = label.style_none, textcolor = priceTickColorUp, size = TickSize)
        
        var label labelDN = na, label.delete(labelDN)
        labelDN := label.new(x, close,xloc = xloc.bar_time, text = '' + array.join(aTrackDn,''), color = color(na), 
         style = label.style_none, textcolor = priceTickColorDown, size = TickSize) 

    if usePriceLine
        var line line = na, line.delete(line)
        line := line.new(bar_index, close, 10 + bar_index + offset, close, extend = Extend, color = lineColor, style = LineStyle, width = pLineWidth)

    if useTable
        var table Tbl = table.new(position.middle_right,columns = 1,rows = 5, bgcolor = color(na),
         frame_color = #00000000, frame_width = 1,border_color = #00000000,border_width = 1)
        
        strDN = str.replace_all(array.join(str.split(str.replace_all(array.join(useReverse ? aTrackUp : aTrackDn,''),'\n',' '),' '),'\n'),' ','')
        DN = str.length(strDN)
        
        table.cell(Tbl,0,0,strDN,0,0,text_color = useReverse ? priceTickColorUp : priceTickColorDown,
                     bgcolor = color(na),text_size = TickSize)    
        
        table.cell(Tbl,0,useReverse ? 3 : 1,(volUp < volDn and close > open ? 'D -' : '-') + str.tostring(volDn),0,2,
                     text_color = priceTickColorDown,bgcolor = color(na),text_size = TickSize)    
        
        table.cell(Tbl,0,2,str.tostring(close,zeros),0,2,text_color = chart.fg_color,
                     bgcolor = color(na),text_size = TickSize)        
        
        table.cell(Tbl,0,useReverse ? 1 : 3,(volUp > volDn and close < open ? 'D +' : '+') + str.tostring(volUp),0,2,
                     text_color =   priceTickColorUp,bgcolor = color(na),text_size = TickSize)
        
        array.reverse(useReverse ? aTrackDn : aTrackUp)
        strUP = str.replace_all(array.join(str.split(str.replace_all(array.join(useReverse ? aTrackDn : aTrackUp,''),'\n',' '),' '),'\n'),' ','')
        UP = str.length(strUP)
        
        table.cell(Tbl,0,4,strUP,0,0,text_color = useReverse ? priceTickColorDown : priceTickColorUp,
                     bgcolor = color(na),text_size = TickSize)
        array.reverse(useReverse ? aTrackDn : aTrackUp)





        //DebuggerTable{
            // if debug
            //     table.cell(Tbl,0,1,
                 
            //      'LineAll = ' + str.tostring(array.size(line.all)) + '\n' +
            //      'BullS = ' + str.tostring(BullS) + 
            //      '\ncBull = ' + str.tostring(cBull) + 
            //      '\ncBull2 = ' + str.tostring(cBull2) + 
            //      '\ncBull3 = ' + str.tostring(cBull3) + '\n' + 
            //      BullCon + 
            //      '\nBull FVG Confirm = ' + str.tostring(BullBoxCount) +
            //      '\naSizeBull = ' + str.tostring(aSizeBull) +
            //      '\n-------------------\n' + 
            //      debuggerBull + 
            //      '\n-------------------\nBearS = ' + str.tostring(BearS)  +
            //      '\ncBear = ' + str.tostring(cBear) + 
            //      '\ncBear2 = ' + str.tostring(cBear2) + 
            //      '\ncBear3 = ' + str.tostring(cBear3) + '\n' +
            //       BearCon + '\nBear FVG Confirm = ' + str.tostring(BearBoxCount) +
            //      '\naSizeBear = ' + str.tostring(aSizeBear) + 
            //      '\n-------------------\n' + 
            //      debuggerBear,
             
            //      text_halign = text.align_left,text_color = #00ff00,bgcolor = lColor,text_size = size.small)
            //}