Customizable Gap Finder++
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ProfessorZoom

//@version=5
indicator('Gap Finder++', overlay=true, max_bars_back=4000)

// Inputs
var barsBack = input.int(title='Bars to Check For', defval=4000, group='Main Settings', minval=50, maxval=4000, step=1)
var extendUnFilled = input.bool(title='Extend Unfilled Gap Boxes', defval=true, group='Main Settings')
var showFilledBoxes = input.bool(title='Show Filled Gap Boxes', defval=true, group='Main Settings')
var gapFilledLabelColor = input.color(title='Gap Filled Label Color', defval=color.white, group='Main Settings')
var hideAllFilledStuff = input.bool(title='Hide All Filled Gap Stuff', defval=true, group='Main Settings')
var showLabels = input.bool(title='Show Gap Notification Labels', defval=false, group='Main Settings')

var gapUpLabelColor = input.color(title='Gap Up Label Color', defval=color.rgb(255, 255, 255, 10), group='Gap Up')
var gapUpBackgroundColor = input.color(title='Gap Up Border Color', defval=color.rgb(255, 128, 128, 90), group='Gap Up')
var gapUpBorderColor = input.color(title='Gap Up Background Color', defval=color.rgb(255, 255, 255, 100), group='Gap Up')

var gapDownLabelColor = input.color(title='Gap Down Label Color', defval=color.rgb(255, 255, 255, 10), group='Gap Down')
var gapDownBackgroundColor = input.color(title='Gap Down Border Color', defval=color.rgb(64, 255, 200, 94), group='Gap Down')
var gapDownBorderColor = input.color(title='Gap Down Background Color', defval=color.rgb(255, 255, 255, 100), group='Gap Down')

// Really wish we could write classes

// Gap Ups
var gapUpBarsAgo = array.new_int()
var gapUpRight = array.new_int()
var gapUpLeft = array.new_int()
var gapUpHighs = array.new_float()
var gapUpLows = array.new_float()
var gapUpClosed = array.new_int()

// Gap Downs
var gapDownBarsAgo = array.new_int()
var gapDownRight = array.new_int()
var gapDownLeft = array.new_int()
var gapDownHighs = array.new_float()
var gapDownLows = array.new_float()
var gapDownClosed = array.new_int()

// We take the current bar and look back
// what we do here is to go back back back back
if barstate.islast

    // Check for gaps
    for i = 0 to barsBack by 1

        // Gap Ups
        if low[i] > high[i + 1]
            if showLabels
                label.new(bar_index[i], high[i], 'Gap Up', color=gapUpLabelColor)
            array.push(gapUpBarsAgo, i)
            array.push(gapUpRight, bar_index[i])
            array.push(gapUpLeft, bar_index[i + 1])
            array.push(gapUpHighs, low[i])
            array.push(gapUpLows, high[i + 1])

        // Gap Downs
        if high[i] < low[i + 1]
            if showLabels
                label.new(bar_index[i], high[i], 'Gap Down', color=gapUpLabelColor)
            array.push(gapDownBarsAgo, i)
            array.push(gapDownRight, bar_index[i])
            array.push(gapDownLeft, bar_index[i + 1])
            array.push(gapDownHighs, low[i + 1])
            array.push(gapDownLows, high[i])

    // [GAP UP] Check if any gaps are filled
    if array.size(gapUpBarsAgo) > 0
        for i = 0 to array.size(gapUpRight) - 1 by 1
            for j = array.get(gapUpBarsAgo, i) to 0 by 1
                if low[j] <= array.get(gapUpLows, i)
                    if showFilledBoxes and hideAllFilledStuff == false
                        box.new(left=array.get(gapUpLeft, i), top=array.get(gapUpHighs, i), right=bar_index[j], bottom=array.get(gapUpLows, i), border_width=1, border_style=line.style_solid, bgcolor=gapUpBackgroundColor, border_color=gapUpBorderColor)
                    //if hideAllFilledStuff == false and showLabels
                        //label.new(bar_index[j], low[j], "Gap Filled", color=gapFilledLabelColor, style=label.style_label_up)
                    array.push(gapUpClosed, array.get(gapUpRight, i))
                    break
        for i = 0 to array.size(gapUpRight) - 1 by 1
            for j = array.get(gapUpBarsAgo, i) to 0 by 1
                if array.includes(gapUpClosed, array.get(gapUpRight, i)) == false
                    if low[j] <= array.get(gapUpHighs, i)
                        array.set(gapUpHighs, i, low[j])

        // [GAP UP] Draw unfilled gap boxes
        for i = 0 to array.size(gapUpRight) - 1 by 1
            if array.includes(gapUpClosed, array.get(gapUpRight, i)) == false
                box.new(left=array.get(gapUpLeft, i), top=array.get(gapUpHighs, i), right=bar_index, bottom=array.get(gapUpLows, i), border_width=1, border_style=line.style_solid, bgcolor=gapUpBackgroundColor, border_color=gapUpBorderColor, extend=extendUnFilled ? extend.right : extend.none)

    // [GAP DOWN] Check if any gaps are filled
    if array.size(gapDownBarsAgo) > 0
        for i = 0 to array.size(gapDownRight) - 1 by 1
            for j = array.get(gapDownBarsAgo, i) to 0 by 1
                if high[j] >= array.get(gapDownHighs, i)
                    if showFilledBoxes and hideAllFilledStuff == false
                        box.new(left=array.get(gapDownLeft, i), top=array.get(gapDownHighs, i), right=bar_index[j], bottom=array.get(gapDownLows, i), border_width=1, border_style=line.style_solid, bgcolor=gapDownBackgroundColor, border_color=gapDownBorderColor)
                    if hideAllFilledStuff == false and showLabels
                        label.new(bar_index[j], high[j], 'Gap Filled', color=gapFilledLabelColor, style=label.style_label_down)
                    array.push(gapDownClosed, array.get(gapDownRight, i))
                    break
        for i = 0 to array.size(gapDownRight) - 1 by 1
            for j = array.get(gapDownBarsAgo, i) to 0 by 1
                if array.includes(gapDownClosed, array.get(gapDownRight, i)) == false
                    if high[j] >= array.get(gapDownLows, i)
                        array.set(gapDownLows, i, high[j])

        // [GAP DOWN] Draw unfilled gap boxes
        for i = 0 to array.size(gapDownRight) - 1 by 1
            if array.includes(gapDownClosed, array.get(gapDownRight, i)) == false
                box.new(left=array.get(gapDownLeft, i), top=array.get(gapDownHighs, i), right=bar_index, bottom=array.get(gapDownLows, i), border_width=1, border_style=line.style_solid, bgcolor=gapDownBackgroundColor, border_color=gapDownBorderColor, extend=extendUnFilled ? extend.right : extend.none)

