Customizable Pivot Support/Resistance Zones [JacobMagleby]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ExoMaven

//@version=5
indicator(title = "Customizable Pivot Support/Resistance Zones + Custom Filter Compatibility[ExoMaven]", shorttitle = "Customizable Pivot Support/Resistance Zones [V1]", overlay = true, max_lines_count = 500)


//PIVOT HIGH/LOW
left_bars = input.int(title = "Left Bars", defval = 25, group = "Pivot Settings", tooltip = "Amount of consecutive closing prices to the left of the point that must be above/below the point for a valid zone | DOES NOT AFFECT DELAY OF ZONE")
right_bars = input.int(title = "Right Bars", defval = 25, group = "Pivot Settings", tooltip = "Amount of consecutive closing prices to the right of the point that must be above/below the point for a valid zone | THE AMOUNT OF BARS IT TAKES FOR THE ZONE TO APPEAR OFF OF THE POINT IS DEPENDENT ON THIS SETTING. (i.e. if the right bars is set to 5, it will take 5 candles into the future before it will print in real-time)")

pivot_high = fixnan(ta.pivothigh(high, left_bars, right_bars))
pivot_low  = fixnan(ta.pivotlow(low, left_bars, right_bars))

pivot_high_change = pivot_high != pivot_high[1] and barstate.isconfirmed
pivot_low_change  = pivot_low != pivot_low[1] and barstate.isconfirmed


//CUSTOM SOURCES/CONDITIONS
use_custom_source1 = input.bool(title = "Enable Custom Source #1", defval = false, group = "Custom Indicator Filter", tooltip = "Check the box to enable this filter. If the box is unchecked, the filter will not apply and the indicator will calculate based only on the pivot points")
custom_source1 = input.source(title = "Custom Indicator Source #1", defval = ohlc4, group = "Custom Indicator Filter", tooltip = "You can select one of these built-in sources, or you can put any 1 indicator of your choice onto the chart alongside this indicator and will have the ability to select one of the external indicators values/outputs as the source, therefore allowing you to create your own custom filter")
binary_long1 = input.string(title = "Value Must Be (Above/Below/Equal) For Support", defval = "Above", options = ["Above", "Below", "Equal"], group = "Custom Indicator Filter", tooltip = "Choose if the Custom Indicator Value above must be above, below, or equal to the required value below for a 'Support Zone'")
required_long1 = input.float(title = "Value Requirement For Support", defval = 100, group = "Custom Indicator Filter", tooltip = "This is the value that the Custom Source above must be above or below for a zone to be valid for the creation of a 'Support Zone'")
use_close_for_required_long = input.bool(title = "Use Closing Price For Requirement For Support", defval = false, group = "Custom Indicator Filter", tooltip = "This will override the 'Value Requirement For Support' input in the above setting, allowing you to use indicators like 'Moving Average' for example. You can attach the 'Moving Average' indicator onto the indicator rather than something like an rsi and make a filter that requires the closing price to be above/below the 'Moving Average' for the zone")
binary_short1 = input.string(title = "Value Must Be (Above/Below/Equal) For Resistance", defval = "Below", options = ["Above", "Below", "Equal"], group = "Custom Indicator Filter", tooltip = "Choose if the Custom Indicator Value above must be above, below, or equal to the required value below for a 'Resistance Zone'")
required_short1 = input.float(title = "Value Requirement For Resistance", defval = 100, group = "Custom Indicator Filter", tooltip = "This is the value that the Custom Source above must be above or below for a zone to be valid for the creation of a 'Resistance Zone'")
use_close_for_required_short = input.bool(title = "Use Closing Price For Requirement For Resistance", defval = false, group = "Custom Indicator Filter", tooltip = "This will override the 'Value Requirement For Resistance' input in the above setting, allowing you to use indicators like 'Moving Average' for example. You can attach the 'Moving Average' indicator onto the indicator rather than something like an rsi and make a filter that requires the closing price to be above/below the 'Moving Average' for the zone")

final_required_long1 = use_close_for_required_long ? close[right_bars] : required_long1[right_bars]
final_required_short1 = use_close_for_required_short ? close[right_bars] : required_short1[right_bars]

custom1_long_is_true  = use_custom_source1 ? (binary_long1 == "Above" ? custom_source1[right_bars] > final_required_long1 : binary_long1 == "Below" ? custom_source1[right_bars] < final_required_long1 : custom_source1[right_bars] == final_required_long1) : true
custom1_short_is_true = use_custom_source1 ? (binary_short1 == "Above" ? custom_source1[right_bars] > final_required_short1 : binary_short1 == "Below" ? custom_source1[right_bars] < final_required_short1 : custom_source1[right_bars] == final_required_short1) : true


//COLOR SETTINGS
support_line_color = input.color(title = "Support Edge Color", defval = color.green, group = "Color Settings")
support_linefill_color = input.color(title = "Support Background Color", defval = color.new(color.green, 50), group = "Color Settings")

resistance_line_color = input.color(title = "Resistance Edge Color", defval = color.red, group = "Color Settings")
resistance_linefill_color = input.color(title = "Resistance Background Color", defval = color.new(color.red, 50), group = "Color Settings")

change_colors_based_on_price = input.bool(title = "Change Colors According To Price", defval = true, group = "Color Settings", tooltip = "If enabled, when price is above a zone, the color will change to a support color, vise versa for when the price is below a zone.")

//NEW ZONE CONDITIONS
var line support_top_line = na
var line support_bot_line = na
var linefill support_line_fill = na

var line resistance_top_line = na
var line resistance_bot_line = na
var linefill resistance_line_fill = na

new_support = pivot_low_change and custom1_long_is_true
new_resistance = pivot_high_change and custom1_short_is_true


//MAIN-OP
support_top_value = close[right_bars] < open[right_bars] ? close[right_bars] : open[right_bars]
resistance_bot_value = close[right_bars] > open[right_bars] ? close[right_bars] : open[right_bars]

if new_support
    support_top_line := line.new(x1 = bar_index[right_bars], y1 = support_top_value, x2 = bar_index, y2 = support_top_value, xloc = xloc.bar_index, color = support_line_color, extend = extend.none, style = line.style_solid, width = 2)
    support_bot_line := line.new(x1 = bar_index[right_bars], y1 = low[right_bars], x2 = bar_index, y2 = low[right_bars], xloc = xloc.bar_index, color = support_line_color, extend = extend.none, style = line.style_solid, width = 2)
    
    support_line_fill := linefill.new(line1 = support_top_line, line2 = support_bot_line, color = support_linefill_color)
    
if new_resistance
    resistance_top_line := line.new(x1 = bar_index[right_bars], y1 = resistance_bot_value, x2 = bar_index, y2 = resistance_bot_value, xloc = xloc.bar_index, color = resistance_line_color, extend = extend.none, style = line.style_solid, width = 2)
    resistance_bot_line := line.new(x1 = bar_index[right_bars], y1 = high[right_bars], x2 = bar_index, y2 = high[right_bars], xloc = xloc.bar_index, color = resistance_line_color, extend = extend.none, style = line.style_solid, width = 2)

    resistance_line_fill := linefill.new(line1 = resistance_top_line, line2 = resistance_bot_line, color = resistance_linefill_color)
    
if barstate.isconfirmed
    line.set_x2(support_top_line, bar_index)
    line.set_x2(support_bot_line, bar_index)
    line.set_x2(resistance_top_line, bar_index)
    line.set_x2(resistance_bot_line, bar_index)
    
    if change_colors_based_on_price
    
        if close > line.get_y1(support_top_line)
            line.set_color(support_top_line, support_line_color)
            line.set_color(support_bot_line, support_line_color)
            
            linefill.set_color(support_line_fill, support_linefill_color)
            
        if close < line.get_y1(support_bot_line)
            line.set_color(support_top_line, resistance_line_color)
            line.set_color(support_bot_line, resistance_line_color)
            
            linefill.set_color(support_line_fill, resistance_linefill_color)
            
        if close > line.get_y1(resistance_top_line)
            line.set_color(resistance_top_line, support_line_color)
            line.set_color(resistance_bot_line, support_line_color)
            
            linefill.set_color(resistance_line_fill, support_linefill_color)
            
        if close < line.get_y1(resistance_bot_line)
            line.set_color(resistance_top_line, resistance_line_color)
            line.set_color(resistance_bot_line, resistance_line_color)
            
            linefill.set_color(resistance_line_fill, resistance_linefill_color)
        
        
//ALERT CONDITIONS
new_support_created = new_support
new_resistance_created = new_resistance

support_top_line_value = line.get_y1(support_top_line)
support_bot_line_value = line.get_y1(support_bot_line)

resistance_top_line_value = line.get_y1(resistance_top_line)
resistance_bot_line_value = line.get_y1(resistance_bot_line)

close_crosses_below_top_zone = close < support_top_line_value and close[1] >= support_top_line_value and barstate.isconfirmed or close < resistance_top_line_value and close[1] >= resistance_top_line_value and barstate.isconfirmed
close_crosses_above_bot_zone = close > support_bot_line_value and close[1] <= support_bot_line_value and barstate.isconfirmed or close > resistance_bot_line_value and close[1] <= resistance_bot_line_value and barstate.isconfirmed

low_crosses_below_top_zone = low < support_top_line_value and low[1] >= support_top_line_value and barstate.isconfirmed or low < resistance_top_line_value and low[1] >= resistance_top_line_value and barstate.isconfirmed
high_crosses_above_bot_zone = high > support_bot_line_value and high[1] <= support_bot_line_value and barstate.isconfirmed or high > resistance_bot_line_value and high[1] <= resistance_bot_line_value and barstate.isconfirmed

close_is_inside_zone = close < support_top_line_value and close > support_bot_line_value and barstate.isconfirmed or close < resistance_top_line_value and close > resistance_bot_line_value and barstate.isconfirmed
close_is_touching_zone = close <= support_top_line_value and close >= support_bot_line_value and barstate.isconfirmed or close <= resistance_top_line_value and close >= resistance_bot_line_value and barstate.isconfirmed

breakout_to_upside = close > support_top_line_value and close[1] < support_top_line_value and barstate.isconfirmed or close > resistance_top_line_value and close[1] < resistance_top_line_value and barstate.isconfirmed
breakout_to_downside = close < support_bot_line_value and close[1] > support_bot_line_value and barstate.isconfirmed or close < resistance_bot_line_value and close[1] > resistance_bot_line_value and barstate.isconfirmed

alertcondition(condition = new_support_created, title = "New Support Created")
alertcondition(condition = new_resistance_created, title = "New Resistance Created")

alertcondition(condition = close_crosses_below_top_zone, title = "Close Crosses Below Top Of Zone")
alertcondition(condition = close_crosses_above_bot_zone, title = "Close Crosses Above Bottom Of Zone")

alertcondition(condition = low_crosses_below_top_zone, title = "Low Crosses Below Top Of Zone")
alertcondition(condition = high_crosses_above_bot_zone, title = "High Crosses Above Bottom Of Zone")

alertcondition(condition = close_is_inside_zone, title = "Close Is Inside Of Zone")
alertcondition(condition = close_is_touching_zone, title = "Close Is Touching Any Part Of The Zone")

alertcondition(condition = breakout_to_upside, title = "Close Breakout To The Upside")
alertcondition(condition = breakout_to_downside, title = "Close Breakout To The Downside")
