Imb finder
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/

//@version=5
indicator('Imb finder', overlay=true, max_boxes_count=500)

var box[] bulishFvgs = array.new_box()
var box[] bearFvgs = array.new_box()

var penetrationRatio = input.float(defval=0.5, minval=0, maxval=1, step=0.1, title="Penetration Ratio")
var string ig_info = '=== Design ==='
var string ig_extend = '=== Extended ==='

var color color1 = input.color(color.new(color.yellow, 50), 'Imbalance Color', group=ig_info)
var color color2 = input.color(color.new(color.purple, 50), 'Mitigated Color', group=ig_info)


var bool isExtend = input.bool(true, 'Show last imabalance', group=ig_extend)
var bool hideFilledBoxes = input.bool(true, "Show fullfilled blocks", group=ig_extend)

var lookback = input.int(1, "Lookback", 1,  group=ig_extend, tooltip="Number of last shown imbalances")
var projection = input.int(5, "Projection", 0,  group=ig_extend, tooltip="Extends previous imbalances in the future.")

t = math.abs(time[2] - time[1])

getMetrix (boxName) =>
    top = box.get_top(boxName)
    bottom = box.get_bottom(boxName)
    left = box.get_left(boxName)
    [top, bottom, left]    

dropNa (arr) =>
    for [i, item] in arr
        if na(item)
            array.remove(arr, i)

drawFigure (left, top, right, bottom, color1) =>
    imbBox = box.new(left, top, right, bottom, xloc=xloc.bar_time)
    box.set_bgcolor(imbBox, color1)
    box.set_border_color(imbBox, color1)
    imbBox
    
processCalcBox (topBox, bottomBox, h) =>
    box.set_top(topBox, h)
    box.set_bottom(bottomBox, h)
    
paintBox (tbox, imbColor) =>
    box.set_bgcolor(tbox, imbColor)
    box.set_border_color(tbox, imbColor)
    if not hideFilledBoxes
        box.delete(tbox)
    
drawLastFvgBoxes (arrayType) =>
    var box[] fvgs = array.new_box()
        
    for [i, item] in fvgs
        box.delete(item)
    
    array.clear(fvgs)

    for [i, item] in arrayType
        if i > array.size(arrayType) - 1 - lookback 
            [top, bottom, left] = getMetrix(item)
            tbox = drawFigure(left, top, last_bar_time + t * projection, bottom, color1)
            array.push(fvgs, tbox)
            

if barstate.isconfirmed
    if high < low[2]
        tbox = drawFigure(time[1], low[2], time[0], high, color1)
        array.push(bulishFvgs, tbox)    
    
    if low > high[2]
        tbox = drawFigure(time[1], low, time[0], high[2], color1)
        array.push(bearFvgs, tbox)    

        
if array.size(bulishFvgs) > 0
    for i = array.size(bulishFvgs) - 1 to 0 by 1
        boxName = array.get(bulishFvgs, i)
        [top, bottom, left] = getMetrix(boxName)
        invalidationLimit = (top - bottom) * penetrationRatio
        
        if high > bottom + invalidationLimit
            box.set_bgcolor(boxName, color2)   
            box.set_border_color(boxName, color2)   
            if not hideFilledBoxes
                box.delete(boxName)
            array.remove(bulishFvgs, i)
        
if array.size(bearFvgs) > 0
    for i = array.size(bearFvgs) - 1 to 0 by 1
        boxName = array.get(bearFvgs, i)
        [top, bottom, left] = getMetrix(boxName)
        invalidationLimit = (top - bottom) * penetrationRatio
     
            
        if low < top - invalidationLimit
            box.set_bgcolor(boxName, color2)   
            box.set_border_color(boxName, color2)
            if not hideFilledBoxes
                box.delete(boxName)
            array.remove(bearFvgs, i)
    
if isExtend
    drawLastFvgBoxes(bulishFvgs)
    drawLastFvgBoxes(bearFvgs)

        
// label.new(bar_index, high, str.tostring(array.size(bulishFvgs) + array.size(bearFvgs)))