Volume Based Support & Resistance
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © noafarin

//@version=5
indicator("Volume Based Support & Resistance","VBSR",overlay = true,max_lines_count =500,max_labels_count = 500)
var sr_diff_input = input.float(10,"Major Supp/Res Lines difference %",tooltip = "Major S/R Lines percent difference",group = "Easy Settings")

var variable_line_distance_from_main = input.float(0.382,"Variable S/R Distance From Main",group = "Pro Settings") // 1 - 0.618
var variable_line_distance_from_eachother = input.float(0.236,"Variable S/R Distance From Eachother",group = "Pro Settings") // 0.618 - 0.382
var len = input.int(52,"Volume Hgihest Length",tooltip = "Number of candles for lookback of the highest function",group = "Volume Settings")
var devider = input.float(0.5,"Volume Devider",tooltip = "highest(volume,len) * devider ",group = "Volume Settings")

var show_variable_line_change_point_label = input.bool(false,"Show variable lines change point label",group = "Labels (Debug)")
var show_lines_nuber_label = input.bool(false,"Show lines number label",group = "Labels (Debug)")

var show_diff_input = sr_diff_input * 2

var line_array = array.new_line()
var variable_line_array = array.new_line()
var sr_prices = array.new_float()
var major_sr_prices = array.new_float()

var major_cross_counter = 0

compare_src = hlcc4 //input(hlcc4)
vol_src = volume
the_price = close
if close > open // green
    if close[1] < open[1]  // red
        the_price := low // pull back
    else
        the_price := high // reverse
else // red                        
    if close[1] < open[1] // throw back
        the_price := low
    else
        the_price := high

contrast_color = chart.bg_color == color.white ? color.yellow : color.orange

vol_cond = vol_src > ta.highest(vol_src,len) * devider
if vol_cond
    if array.size(line_array) == 0
        array.push(line_array,line.new(bar_index,the_price,bar_index+10,the_price))
    else
        is_sr_new = true
        for i = 0 to array.size(line_array) - 1
            the_line = array.get(line_array,i)
            the_lines_price = line.get_y1(the_line)
            the_difference = math.abs(the_lines_price - the_price) * 100 / the_price
            if  the_difference < sr_diff_input // there is a line near previous lines
                //method 3
                if the_difference > sr_diff_input * variable_line_distance_from_main and the_difference < sr_diff_input * (1-variable_line_distance_from_main)
                    if array.size(variable_line_array) == 0
                        array.push(variable_line_array,line.new(bar_index,the_price,bar_index+90,the_price,color = color.purple))
                    else
                        is_var_sr_new = true
                        for j = 0 to array.size(variable_line_array) - 1
                            the_var_line = array.get(variable_line_array,j)
                            the_var_lines_price = line.get_y1(the_var_line)
                            the_var_difference = math.abs(the_var_lines_price - the_price) * 100 / the_price
                            if the_var_difference <  sr_diff_input * variable_line_distance_from_eachother
                                line.set_y1(the_var_line,the_price)
                                line.set_y2(the_var_line,the_price)
                                line.set_x2(the_var_line,bar_index)
                                line.set_color(the_var_line,contrast_color)

                                sr_i = array.binary_search(sr_prices,the_var_lines_price)
                                if sr_i != -1
                                    array.set(sr_prices,sr_i,the_price)

                                if show_variable_line_change_point_label
                                    label.new(bar_index,high)
                                is_var_sr_new := false
                                break
                        if is_var_sr_new
                            array.push(variable_line_array,line.new(bar_index,the_price,bar_index+90,the_price,color = color.purple))

                is_sr_new := false
                break
        if is_sr_new
            array.push(line_array,line.new(bar_index,the_price,bar_index+10,the_price))


// majors
for i = 0 to array.size(line_array)? array.size(line_array) - 1 : na
    the_line = array.get(line_array,i)
    the_lines_price = line.get_y1(the_line)
    line.set_color(the_line,close > the_lines_price?color.green:color.red)         
    if math.abs((the_lines_price - compare_src)) * 100 / compare_src > show_diff_input
        line.set_extend(the_line,extend.none)
        line.set_style(the_line,line.style_dashed)
        line.set_color(the_line,color=color.blue)
    else
        line.set_style(the_line,line.style_solid)
    if math.abs((the_lines_price - high)) * 100 / high < sr_diff_input or math.abs((the_lines_price - low)) * 100 / low < sr_diff_input
        line.set_x2(the_line,bar_index)
    
    if array.size(sr_prices) == 0 or not array.includes(sr_prices,the_lines_price)
        array.push(sr_prices,the_lines_price)
    
    if array.size(major_sr_prices) == 0 or not array.includes(major_sr_prices,the_lines_price)
        array.push(major_sr_prices,the_lines_price)

// minors
for j = 0 to array.size(variable_line_array) ? array.size(variable_line_array) - 1 : na
    the_line = array.get(variable_line_array,j)
    the_lines_price = line.get_y1(the_line)
    line.set_color(the_line,contrast_color)
    line.set_style(the_line,line.style_dashed)

    if math.abs((the_lines_price - high)) * 100 / high < sr_diff_input or math.abs((the_lines_price - low)) * 100 / low < sr_diff_input * variable_line_distance_from_eachother
        line.set_x2(the_line,bar_index)
    
    if array.size(sr_prices) == 0 or not array.includes(sr_prices,the_lines_price)
        array.push(sr_prices,the_lines_price)

array.sort(sr_prices)

if bar_index == last_bar_index and show_lines_nuber_label
    label.new(bar_index+10,high,str.tostring(array.size(line_array))+" main lines\n" + str.tostring(array.size(variable_line_array)) + " var lines\n" + str.tostring(array.size(sr_prices)) + " all\n" + str.tostring(array.size(major_sr_prices)) + " majors" ,textcolor = color.white)

            
