Balance Zone Extension
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © mcthatsme

//@version=5
indicator("Balance Zone Extension", overlay=true, max_lines_count=500)

//Inputs
balance_High    = input.float (defval=3900, title="Top of Balance Zone")
balance_Low     = input.float (defval=3790, title="Bottom of Balance Zone")
numLines        = input.string(defval="8" , title="Number of Sections per Balance Zone", options=["2", "4", "8", "16", "32"], tooltip="How many times the box is halved. Warning: Max line limit is 500")
num_Boxes_Above = input.int   (defval=2   , title="Number of Boxes Above Balance Zone")
num_Boxes_Below = input.int   (defval=2   , title="Number of Boxes Below Balance Zone")

//Balance Zone Colors
balance_zone_color = input.color(defval=color.new(color.gray, 90)  , title="Balance Zone Background Color", group="Balance Zone Colors")
even_zone_color    = input.color(defval=color.new(color.blue, 90)  , title="Even Zone Color"              , group="Balance Zone Colors")
odd_zone_color     = input.color(defval=color.new(color.yellow, 90), title="Odd Zone Color"               , group="Balance Zone Colors")

HL_lineColor    = input.color (defval=color.new(color.white, 50), title="Balance High/Low Line Color"    , group="Line Colors")
HL_linewidth    = input.int   (defval=2                           , title="Balance High/Low Line Thickness", group="Line Colors")
HL_styleOption  = input.string( defval="solid (─)"                , title='Balance High/Low Line Style'    , group="Line Colors", options=["solid (─)", "dashed (╌)", "dotted (┈)"])
HL_lineStyle    = (HL_styleOption == "dotted (┈)") ? line.style_dotted : 
                   (HL_styleOption == "dashed (╌)") ? line.style_dashed :
                   line.style_solid

Half_lineColor    = input.color (defval=color.new(color.yellow, 50), title="50% Line Color"    , group="Line Colors")
Half_linewidth    = input.int   (defval=1                            , title="50% Line Thickness", group="Line Colors")
Half_styleOption  = input.string(defval="dashed (╌)"                 , title='50% Line Style'    , group="Line Colors", options=["solid (─)", "dashed (╌)", "dotted (┈)"])
Half_lineStyle    = (Half_styleOption == "dotted (┈)") ? line.style_dotted : 
                   (Half_styleOption == "dashed (╌)") ? line.style_dashed :
                   line.style_solid

Bal_lineColor    = input.color (defval=color.new(color.blue, 50), title="Other Balance Line Color"    , group="Line Colors")
Bal_linewidth    = input.int   (defval=1                          , title="Other Balance Line Thickness", group="Line Colors")
Bal_styleOption  = input.string(defval="dotted (┈)"               , title='Other Balance Line Style'    , group="Line Colors", options=["solid (─)", "dashed (╌)", "dotted (┈)"])
Bal_lineStyle    = (Bal_styleOption == "dotted (┈)") ? line.style_dotted : 
                   (Bal_styleOption == "dashed (╌)") ? line.style_dashed :
                   line.style_solid

lines_Per_Box = str.tonumber(numLines)
sectionSize    = 1/lines_Per_Box
balance_Vals   = array.new_float(0)

var BALANCE_HIGH_LINES = array.new_line(0)
var BALANCE_LOW_LINES  = array.new_line(0)
var BALANCE_50_LINES   = array.new_line(0)
var BALANCE_LINES      = array.new_line(0)
var LINE_FILLS         = array.new_linefill(0)

//Value Calculations
balance_Range = balance_High - balance_Low
balance_50    = balance_Range / 2

if lines_Per_Box > 1
    for i = 1 to lines_Per_Box - 1
        if sectionSize * i != 0.5
            array.push(balance_Vals, balance_Low + balance_Range * (i * 1/lines_Per_Box))

//Delete Lines before creating new ones
if array.size(BALANCE_HIGH_LINES) > 0
    sizeArrHigh  = array.size(BALANCE_HIGH_LINES) - 1

    for i = sizeArrHigh to 0
        line.delete(array.get(BALANCE_HIGH_LINES, i))
        array.remove(BALANCE_HIGH_LINES, i)

if array.size(BALANCE_LOW_LINES) > 0
    sizeArrLow  = array.size(BALANCE_LOW_LINES) - 1

    for i = sizeArrLow to 0
        line.delete(array.get(BALANCE_LOW_LINES, i))
        array.remove(BALANCE_LOW_LINES, i)

if array.size(BALANCE_LINES) > 0
    sizeArrBal = array.size(BALANCE_LINES) - 1

    for i = sizeArrBal to 0
        line.delete(array.get(BALANCE_LINES, i))
        array.remove(BALANCE_LINES, i)

if array.size(BALANCE_50_LINES) > 0
    sizeArr50  = array.size(BALANCE_50_LINES) - 1

    for i = sizeArr50 to 0
        line.delete(array.get(BALANCE_50_LINES, i))
        array.remove(BALANCE_50_LINES, i)

if array.size(LINE_FILLS) > 0
    sizeArrLineFill  = array.size(LINE_FILLS) - 1

    for i = sizeArrLineFill to 0
        linefill.delete(array.get(LINE_FILLS, i))
        array.remove(LINE_FILLS, i)

//Add lines to chart based on user inputs
//Original Balance Zone lines
array.push(BALANCE_HIGH_LINES, line.new(bar_index, balance_High, bar_index[1], balance_High, color=HL_lineColor, style=HL_lineStyle,width=HL_linewidth, extend=extend.both))
array.push(BALANCE_LOW_LINES, line.new(bar_index, balance_Low , bar_index[1], balance_Low, color=HL_lineColor, style=HL_lineStyle,width=HL_linewidth, extend=extend.both))
array.push(BALANCE_50_LINES, line.new(bar_index, balance_Low + balance_50, bar_index[1], balance_Low + balance_50, color=Half_lineColor, style=Half_lineStyle, width=Half_linewidth, extend=extend.both))

if lines_Per_Box > 2
    for j = 0 to array.size(balance_Vals) - 1
        array.push(BALANCE_LINES   , line.new(bar_index, array.get(balance_Vals, j), bar_index[1], array.get(balance_Vals, j), color=Bal_lineColor, style=Bal_lineStyle,width=Bal_linewidth, extend=extend.both))

//Balance zone color fill
array.push(LINE_FILLS, linefill.new(array.get(BALANCE_HIGH_LINES, 0), array.get(BALANCE_LOW_LINES, 0), balance_zone_color))

//For loops to cycle through balance zone extensions
if num_Boxes_Above > 0
    for i = 1 to num_Boxes_Above
        array.push(BALANCE_HIGH_LINES, line.new(bar_index, balance_High + balance_Range * i, bar_index[1], balance_High + balance_Range * i, color=HL_lineColor, style=HL_lineStyle,width=HL_linewidth, extend=extend.both))
        array.push(BALANCE_50_LINES, line.new(bar_index, balance_Low + (balance_Range * i + balance_50), bar_index[1], balance_Low + (balance_Range * i + balance_50), color=Half_lineColor, style=Half_lineStyle, width=Half_linewidth, extend=extend.both))
        
        if lines_Per_Box > 2
            for j = 0 to array.size(balance_Vals) - 1
                array.push(BALANCE_LINES, line.new(bar_index, array.get(balance_Vals, j) + balance_Range * i, bar_index[1], array.get(balance_Vals, j) + balance_Range * i, color=Bal_lineColor, style=Bal_lineStyle,width=Bal_linewidth, extend=extend.both))

        if i % 2 == 1
            array.push(LINE_FILLS, linefill.new(array.get(BALANCE_HIGH_LINES, i - 1), array.get(BALANCE_HIGH_LINES, i), odd_zone_color))
        else
            array.push(LINE_FILLS, linefill.new(array.get(BALANCE_HIGH_LINES, i - 1), array.get(BALANCE_HIGH_LINES, i), even_zone_color))

if num_Boxes_Below > 0
    for i = 1 to num_Boxes_Below
        array.push(BALANCE_LOW_LINES, line.new(bar_index, balance_Low  - balance_Range * i, bar_index[1], balance_Low  - balance_Range * i, color=HL_lineColor, style=HL_lineStyle,width=HL_linewidth, extend=extend.both))
        array.push(BALANCE_50_LINES, line.new(bar_index, balance_Low - (balance_Range * i - balance_50), bar_index[1], balance_Low - (balance_Range * i - balance_50), color=Half_lineColor, style=Half_lineStyle, width=Half_linewidth, extend=extend.both))
    
        if lines_Per_Box > 2
            for j = 0 to array.size(balance_Vals) - 1
                array.push(BALANCE_LINES, line.new(bar_index, array.get(balance_Vals, j) - balance_Range * i, bar_index[1], array.get(balance_Vals, j) - balance_Range * i, color=Bal_lineColor, style=Bal_lineStyle,width=Bal_linewidth, extend=extend.both))

        if i % 2 == 1
            array.push(LINE_FILLS, linefill.new(array.get(BALANCE_LOW_LINES, i - 1), array.get(BALANCE_LOW_LINES, i), odd_zone_color))
        else
            array.push(LINE_FILLS, linefill.new(array.get(BALANCE_LOW_LINES, i - 1), array.get(BALANCE_LOW_LINES, i), even_zone_color))       
        