Bull Flag Detection
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © xfuturesgod

//@version=5
indicator("Bull Flag Detection", overlay = true)

// Get user input
lookback      = input.int(title="Percentage Gain Lookback", defval=20, step=1, tooltip="Lookback period for determining percentage gain threshold")
emaMainLength = input.int(title="Longterm EMA Length", defval=200, minval=1)
emaDSR1Length = input.int(title="DSR 1 EMA Length", defval=50, minval=1)
emaDSR2Length = input.int(title="DSR 2 EMA Length", defval=20, minval=1)
percentThreshold = input.float(title="Percentage Treshold", defval = 1.0, tooltip = "Percent gain for determining valid flag pole")
swingHighLookback = input.int(title ="Swing High Lookback", defval = 10, tooltip = "Lookback period for determining swing highs")
swingLowLookback = input.int(title ="Swing Low Lookback", defval = 10, tooltip = "Lookback period for determining swing lows")

// Get moving averages
ema200 = ta.ema(close, emaMainLength)
ema100 = ta.ema(close,100)
ema50 = ta.ema(close, emaDSR1Length)
ema20 = ta.ema(close, emaDSR2Length)

// Declare variables to detect swing highs and swing lows
swingHigh = high[1] == ta.highest(high, 10) and high < high[1]
swingLow = low[1] == ta.lowest(low, 10) and low > low[1]

// Are we in a short term bull trend or bear trend?
bearTrend = ema200 > ema50 and ema50 > ema20  // Bearish trend
bullTrend = ema200 < ema50 and ema50 < ema20 // Bullish trend


// Draw invisible plot lines required for zone color fill.
zone1 = plot(ema20, color=na)
zone2 = plot(ema50, color=na)

// Fill zone
fill(zone1, zone2, color=bullTrend ? color.new(color.blue, 75) : na)

// Draw long-term EMA
plot(ema200, color=bullTrend ? color.blue : na, linewidth=2)


flagPole = (((close - low[lookback]) / low[lookback]) * 100 > percentThreshold)
flagPoleStart = not flagPole[1] and flagPole
flagPoleEnd = flagPole[1] and not flagPole


var x1Array = array.new_int(5, math.round(close))
var x2Array = array.new_int(5, math.round(close))
var y1Array = array.new_float(5, close)
var y2Array = array.new_float(5, close)
var searchingForLow = false
var float highestHigh = na  // Initialize the highest high tracker
var bool searchingforHigh1 = na
var searchingForHigh2 = false
var float flagResistance1 = na
var float flagResistance2 = na
var bool flagComplete = false
barsSincePoleStart = ta.barssince(flagPoleStart)
barsSincePoleEnd = ta.barssince(flagPoleEnd)
polePeriod =  barsSincePoleEnd - barsSincePoleStart
flagLowDetected = searchingForLow and swingLow
flagHighDetected = searchingForHigh2 and swingHigh
flagFinished = flagComplete and not flagComplete[1]



if flagPoleStart
    label.new(bar_index, high, text="Flag Pole", style=label.style_label_down, color=color.rgb(192, 238, 194), yloc=yloc.abovebar)
    searchingForLow := false
    searchingforHigh1 := true
    highestHigh := high  // Reset the highest high at the start of the flagpole

if searchingforHigh1
    if high > highestHigh
        highestHigh := high

if flagPoleEnd
    searchingForLow := true
    searchingforHigh1 := false
    array.push(y1Array, highestHigh)
    array.push(x1Array, bar_index)
    
if flagLowDetected
    searchingForLow := false

if flagLowDetected
    searchingForHigh2 := true

if flagHighDetected and searchingForHigh2
    searchingForHigh2 := false


flag = searchingforHigh1 or searchingForLow or searchingForHigh2


bgcolor(flag ? color.new(color.green, 90) : na, title="Flag Highlight")
plotshape(flagPoleStart, "FP", style = shape.triangledown, location = location.abovebar, color = color.rgb(192, 238, 194))

