Breakout Accumulation/Distribution
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Austimize

//Custom swing fail detector with levels, breakouts, and colored candles.

//@version=5
indicator("Breakout Accumulation/Distribution", "Breakout A/D", overlay = true)

lbL = input.int(4, "Left Lookback")
lbR = input.int(3, "Right Lookback")
colorCandles = input.bool(true, "Color Candles?")
timeframe1 = input.timeframe("", "Timeframe")

sourceHigh = request.security(syminfo.tickerid, timeframe1, high, barmerge.gaps_off, barmerge.lookahead_on)
sourceLow = request.security(syminfo.tickerid, timeframe1, low, barmerge.gaps_off, barmerge.lookahead_on)
sourceClose = request.security(syminfo.tickerid, timeframe1, close, barmerge.gaps_off, barmerge.lookahead_on)


anchorR = math.round(lbL * 1.5)
anchorL = lbR * 2

get_lowest (source, num) =>
    lowval = 99999999.9
    for i = 1 to num
        if source[i] < lowval
            lowval := source[i]
    lowval

get_highest (source, num) =>
    highval = 0.0
    for i = 1 to num
        if source[i] > highval
            highval := source[i]
    highval



isHighAnchor = ta.pivothigh(sourceHigh, anchorL, anchorR)
isLowAnchor = ta.pivotlow(sourceLow, anchorL, anchorR)

lastAnchor = 0
lastAnchor := isHighAnchor and not isLowAnchor ? 1 : isLowAnchor and not isHighAnchor ? -1 : lastAnchor[1]

barsSinceHigh = 0
barsSinceLow = 0
barsSinceHigh := barsSinceHigh[1] + 1
barsSinceLow := barsSinceLow[1] + 1

lowSwing = sourceLow[barsSinceLow]
highSwing = sourceHigh[barsSinceHigh]

pivotHigh = ta.pivothigh(sourceHigh, lbL, lbR)
pivotLow = ta.pivotlow(sourceLow, lbL, lbR)

lastPivot = 0
lastPivot := pivotHigh and not pivotLow ? 1 : pivotLow and not pivotHigh ? -1 : lastPivot[1]

barsSinceHighPivot = 0
barsSinceLowPivot = 0
barsSinceHighPivot := barsSinceHighPivot[1] + 1
barsSinceLowPivot := barsSinceLowPivot[1] + 1

pivotHighline = sourceHigh[barsSinceHighPivot]
pivotLowline = sourceLow[barsSinceLowPivot]

swingFailHigh = pivotHigh and sourceClose[lbR] < highSwing ? true : false
swingFailLow = pivotLow and sourceClose[lbR] > lowSwing ? true : false

swingFailHighMinor = pivotHigh and sourceClose[lbR] < pivotHighline ? true : false
swingFailLowMinor = pivotLow and sourceClose[lbR] > pivotLowline ? true : false

lastMinorFail = 0
lastMinorFail := swingFailHighMinor and not swingFailLowMinor ? 1 : swingFailLowMinor and not swingFailHighMinor ? -1 : lastMinorFail[1]

plotHighFail = swingFailHighMinor and not swingFailHigh 
plotLowFail = swingFailLowMinor and not swingFailLow

lastFail = 0
lastFail := swingFailHigh and not swingFailLow ? 1 : swingFailLow and not swingFailHigh ? -1 : lastFail[1]

highBreakout = sourceClose > highSwing and sourceClose > get_highest(sourceClose, anchorR - 1)
lowBreakout = sourceClose < lowSwing and sourceClose < get_lowest(sourceClose, anchorR - 1)

lastBreakout = 0
prevBreakout = lastBreakout[1]
lastBreakout := highBreakout ? 1 : lowBreakout? -1 : prevBreakout

accum = highBreakout and prevBreakout == -1
dist = lowBreakout and prevBreakout == 1

lastBreakout := lastBreakout >= 1 and isHighAnchor ? -1 : lastBreakout
lastBreakout := lastBreakout <= 1 and isLowAnchor ? 1 : lastBreakout

minorHighBreakout = sourceClose > pivotHighline and sourceClose > get_highest(sourceClose, lbR - 1)
minorLowBreakout = sourceClose < pivotLowline and sourceClose < get_lowest(sourceClose, lbR - 1)

lastMinorBreakout = 0
prevMinorBreakout = lastMinorBreakout[1]
lastMinorBreakout := minorHighBreakout ? 1 : minorLowBreakout? -1 : prevMinorBreakout

accumM = minorHighBreakout and prevMinorBreakout == -1
distM = minorLowBreakout and prevMinorBreakout == 1

accumV1 = minorHighBreakout and prevBreakout == -1
distV1 = minorLowBreakout and prevBreakout == 1

accumV2 = highBreakout and prevMinorBreakout == -1
distV2 = lowBreakout and prevMinorBreakout == 1

isAccum = accum or accumM or accumV1 or accumV2
isDist = dist or distM or distV1 or distV2
currentAD = 0
lastAD = currentAD[1]
currentAD := isAccum ? 1 : isDist ? -1 : lastAD

plotchar(isAccum, "Accumulation", char = "A", location = location.belowbar, color = color.green)
plotchar(isDist, "Distribution", char = "D", location = location.abovebar, color = color.red)

lastMinorBreakout := lastMinorBreakout >= 1 and pivotHigh ? -1 : lastMinorBreakout
lastMinorBreakout := lastMinorBreakout <= 1 and pivotLow ? 1 : lastMinorBreakout

isMinorBreakHigh = minorHighBreakout and not highBreakout
isMinorBreakLow = minorLowBreakout and not lowBreakout

barsSinceHigh := isHighAnchor ? anchorR : barsSinceHigh
barsSinceLow := isLowAnchor ? anchorR : barsSinceLow

barsSinceHighPivot := pivotHigh ? lbR : barsSinceHighPivot
barsSinceLowPivot := pivotLow ? lbR : barsSinceLowPivot

barsSinceHigh := isHighAnchor ? anchorR : barsSinceHigh
barsSinceLow := isLowAnchor ? anchorR : barsSinceLow

plotColor = color.orange
plotColor := isAccum ? color.green : isDist ? color.red : na //color.red : lastAD == 1 ? color.green : lastAD == -1 ?
barcolor(colorCandles ? plotColor : na, title = "Bar Color")