MA cloud + divergence tension
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © dickymoore
//@version=5
indicator("MA cloud + divergence tension", overlay=true)

length = input.int(title="Length", defval=200, minval=0, maxval=500) // How many bars back are we using for our calculations?
sensitivity = input.int(title="Sensitivity", defval=99, minval=0, maxval=100) // How sensitive is this indicator?
showCloudProximity = input.bool(title="Show Cloud Proximity", defval=false)
simpAverage = ta.sma(close, length) // SMA
expoAverage = ta.ema(close, length) // EMA

average = math.avg(simpAverage,expoAverage) // THe midpoint between the two moving averages

distances = array.new_float(length) // declare an array called distances
for i=0 to (length - 1) // look back and set how far from the average is the close price of each candle
    array.set(distances, i, close[i]>average ? close[i]-average : 0-(close[i]-average))

topDist = array.max(distances) // find the most extreme historic divergence from the average 
tensionPct = (array.get(distances,0)/topDist)*100 // track how far each price diverges as a percentage of the most extreme case

simpLine = plot(simpAverage, color=color.navy)  // SMA plot
expoLine = plot(expoAverage, color=color.fuchsia) // EMA plot

fill(simpLine, expoLine, color.new(color.blue, (100-(((tensionPct/100))*tensionPct))),"MA spread") // fill the space between the two moving averages, and set the transparency based on how extreme is the current divergence
maxTension = tensionPct>sensitivity // If we've crossed the sensitivity threshold (the percentage divergence is more than the sensitivity)
above = close > average // if we're above the average, it's good to know or not

plot((maxTension and not(above)) ? (low*0.9) : na, color = color.new(#0E0E0E, 5), style=plot.style_circles, linewidth = 9)
plot((maxTension and not(above)) ? (low*0.9) : na, color = color.new(#FAFeFa, 5), style=plot.style_circles, linewidth = 7)
plot((maxTension and not(above)) ? (low*0.9) : na, color = color.new(#0aff0a, 5), style=plot.style_circles, linewidth = 5)
plot((maxTension and above) ? (high*1.1) : na, color = color.new(#0E0E0E, 5), style=plot.style_circles, linewidth = 9)
plot((maxTension and above) ? (high*1.1) : na, color = color.new(#FAFeFa, 5), style=plot.style_circles, linewidth = 7)
plot((maxTension and above) ? (high*1.1) : na, color = color.new(#ff000a, 5), style=plot.style_circles, linewidth = 5)

alertcondition(condition=maxTension and not(above), title='MA Extreme Tension below', message="Price at extreme levels below moving averages")
alertcondition(condition=maxTension and above, title='MA Extreme Tension above', message="Price at extreme levels above moving averages")

sensitiveCloudBottom = simpAverage>expoAverage ? ((expoAverage/100)*sensitivity):((simpAverage/100)*sensitivity) // what's the top of the cloud?
sensitiveCloudTop = simpAverage<expoAverage ? expoAverage+(expoAverage/100)*(100-sensitivity):simpAverage+(simpAverage/100)*(100-sensitivity) // what's the bottom of the cloud?

plot(not(showCloudProximity) ? na:sensitiveCloudBottom, color=color.red) // define the bottom of the cloud sensitivity range, if we want to
plot(not(showCloudProximity) ? na:sensitiveCloudTop, color=color.red) // define the top of the cloud sensitivity range, if we want to

lastExtremeCondition = ta.barssince(maxTension) // how many bars since we had max tension?
withinCloud = high >= sensitiveCloudBottom and low <= sensitiveCloudTop
tensionSet = ta.barssince(maxTension)<ta.barssince(withinCloud) // have we had max tension that's not been released by touching the cloud?
tensionReleased = false // let's set the default state of this as false
if (tensionSet[1] and withinCloud) // and if we've touched the cloud after having max tension
    tensionSet := false // unset max tension
    tensionReleased := true // and confirm we've had the tension released

plot((tensionReleased and not(above[1])) ? (sensitiveCloudBottom) : na, color = color.new(#0E0E0E, 5), style=plot.style_circles, linewidth = 9)
plot((tensionReleased and not(above[1])) ? (sensitiveCloudBottom) : na, color = color.new(#FAFeFa, 5), style=plot.style_circles, linewidth = 7)
plot((tensionReleased and not(above[1])) ? (sensitiveCloudBottom) : na, color = color.new(#30a3ff, 5), style=plot.style_circles, linewidth = 5)
plot((tensionReleased and above[1]) ? (sensitiveCloudTop) : na, color = color.new(#0E0E0E, 5), style=plot.style_circles, linewidth = 9)
plot((tensionReleased and above[1]) ? (sensitiveCloudTop) : na, color = color.new(#FAFeFa, 5), style=plot.style_circles, linewidth = 7)
plot((tensionReleased and above[1]) ? (sensitiveCloudTop) : na, color = color.new(#30a3ff, 5), style=plot.style_circles, linewidth = 5)

alertcondition(condition=tensionReleased and not(above), title='MA Extreme Tension below released', message="Price returning from extreme levels below moving averages")
alertcondition(condition=tensionReleased and above, title='MA Extreme Tension above released', message="Price returning from extreme levels above moving averages")