ES S/R Levels
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © daniel49193

//@version=5
indicator(title="ES SR Levels", overlay=true)

// Define your price levels input
supportLevels = input.string("4240-45 (major), 4224, 4220 (major), 4206 (major), 4195, 4185 (major), 4175",title="Support Levels")
resistanceLevels =  input.string("4260, 4267 (major), 4275, 4283, 4289, 4297-4300 (major), 4310-15, 4325-30", title="Resistance Levels")
res_col = input(defval = color.new(color.red, 50), title = "Resistance Color", group = "Colors 🟡🟢🟣")
sup_col = input(defval = color.new(color.lime, 50), title = "Support Color", group = "Colors 🟡🟢🟣")
size_labels = input.string(title='Label font size', defval=size.normal, options=[size.large, size.normal, size.small])
color_labels = input(title='Label font color', defval=color.white)
label_position = input.int(title='Label Position', defval=20, minval=0, maxval=50, tooltip='When increasing number, labels move right')

IsHourlyTF() =>
	timeframe.in_seconds() >= timeframe.in_seconds("60")

// Function to check if a level is a range
isRange(level) =>
    str.contains(level, "-")

// Function to extract the range values
getRangeValues(level) =>
    removeMajor = str.replace(level, "(major)", "")
    removeSpace = str.replace(removeMajor, " ", "")
    values = str.split(removeSpace, "-")
    if array.size(values) == 2
        lowValStr = array.get(values, 0)
        highValStr = array.get(values, 1)
        if str.length(highValStr) == 2
            lowValArray = str.split(lowValStr,'')
            highValPrice = array.get(lowValArray,0)+array.get(lowValArray,1)+highValStr
            lowVal = str.tonumber(lowValStr)
            highVal = str.tonumber(highValPrice)
            [lowVal, highVal]
        else if str.length(highValStr) == 4
            lowVal = str.tonumber(lowValStr)
            highVal = str.tonumber(highValStr)
            [lowVal, highVal]
    else
        [0, 0]

// Split the inputLevels string into individual levels
var slevels_input = str.split(supportLevels, ", ")
var rlevels_input = str.split(resistanceLevels, ", ")

var s_boxes = array.new_box()
var s_labels = array.new_label()
var s_lines = array.new_line()

var r_boxes = array.new_box()
var r_labels = array.new_label()
var r_lines = array.new_line()

// Function to create lines from user-defined price levels
f_setSLevels(_input_array,_input_boxes,_input_labels,_input_lines,_color) =>
    for i = 0 to array.size(_input_array) - 1
        price_level = str.replace(array.get(_input_array, i),"(major)","")
        isMajor = str.contains(array.get(_input_array, i), "(major)")

        if isRange(price_level)
            [lowVal, highVal] = getRangeValues(price_level)
            array.push(_input_boxes, box.new(left=bar_index, bottom=lowVal, right=bar_index + 1, top=highVal, bgcolor=_color, border_width=1, border_color=_color, extend=extend.both))
            array.push(_input_labels, label.new(bar_index + label_position, highVal, isMajor ? str.tostring(lowVal)+"-"+str.tostring(highVal)+" (Major)" : str.tostring(lowVal)+"-"+str.tostring(highVal), style=label.style_none, textcolor=color_labels, size=size_labels))
        else
            price = str.tonumber(price_level)
            array.push(_input_lines, line.new(x1=bar_index, y1=price, x2=bar_index+1, y2=price, color=_color, width=1, extend=extend.both))
            array.push(_input_labels, label.new(bar_index + label_position, price, isMajor ? str.tostring(price)+" (Major)" : str.tostring(price), style=label.style_none, textcolor=color_labels, size=size_labels))

f_clearLabels(_array) =>
    if array.size(_array) > 0
        for i = 0 to array.size(_array) - 1
            label.delete(array.shift(_array))

if barstate.islast
    f_clearLabels(s_labels)
    f_clearLabels(r_labels)
    f_setSLevels(slevels_input,s_boxes,s_labels,s_lines,sup_col)
    f_setSLevels(rlevels_input,r_boxes,r_labels,r_lines,res_col)
