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

//@version=5
indicator("Momentum Detector", overlay = true)

upCandle = close > open ? true : false

range1 = input.int(1, minval=1, title="Range 1")
range2 = input.int(3, minval=1, title="Range 2")
range3 = input.int(6, minval=1, title="Range 3")
range4 = input.int(10, minval=1, title="Range 4")
range5 = input.int(15, minval=1, title="Range 5")
range6 = input.int(21, minval=1, title="Range 6")
range7 = input.int(28, minval=1, title="Range 7")
range8 = input.int(36, minval=1, title="Range 8")
range9 = input.int(45, minval=1, title="Range 9")
range10 = input.int(55, minval=1, title="Range 10")
maType = input.string("EMA", options=["EMA", "SMA", "WMA"], title="MA Base")
doRsiCandles = input.bool(false, "RSI candles?")
doRsiDev = input.bool(false, "RSI deviations?")
doSymbols = input.bool(false, "Momentum Symbols?")

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

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

hr1 = get_highest(range1, high)
hr2 = get_highest(range2, high)
hr3 = get_highest(range3, high)
hr4 = get_highest(range4, high)
hr5 = get_highest(range5, high)
hr6 = get_highest(range6, high)
hr7 = get_highest(range7, high)
hr8 = get_highest(range8, high)
hr9 = get_highest(range9, high)
hr10 = get_highest(range10, high)

lr1 = get_lowest(range1, low)
lr2 = get_lowest(range2, low)
lr3 = get_lowest(range3, low)
lr4 = get_lowest(range4, low)
lr5 = get_lowest(range5, low)
lr6 = get_lowest(range6, low)
lr7 = get_lowest(range7, low)
lr8 = get_lowest(range8, low)
lr9 = get_lowest(range9, low)
lr10 = get_lowest(range10, low)

get_crosses (emaA, emaB) =>
    cOver = ta.crossover(emaA, emaB)
    cUnder = ta.crossover(emaB, emaA)
    returnVal = 0
    if cOver
        returnVal += 1
    else if cUnder
        returnVal -= 1
    returnVal

count_crosses(Hsource, Lsource) =>
    Hcount = 0
    Lcount = 0

    if Hsource > hr1
        Hcount += 1
    if Hsource > hr2
        Hcount += 1
    if Hsource > hr3
        Hcount += 1
    if Hsource > hr4
        Hcount += 1
    if Hsource > hr5
        Hcount += 1
    if Hsource > hr6
        Hcount += 1
    if Hsource > hr7
        Hcount += 1
    if Hsource > hr8
        Hcount += 1
    if Hsource > hr9
        Hcount += 1
    if Hsource > hr10
        Hcount += 1

    if Lsource < lr1
        Lcount += 1
    if Lsource < lr2
        Lcount += 1
    if Lsource < lr3
        Lcount += 1
    if Lsource < lr4
        Lcount += 1
    if Lsource < lr5
        Lcount += 1
    if Lsource < lr6
        Lcount += 1
    if Lsource < lr7
        Lcount += 1
    if Lsource < lr8
        Lcount += 1
    if Lsource < lr9
        Lcount += 1
    if Lsource < lr10
        Lcount += 1

    plotval = Hcount - Lcount
    ema1 = ta.ema(plotval, range2)
    ema2 = ta.ema(plotval, range4)
    ema3 = ta.ema(plotval, range6)
    ema4 = ta.ema(plotval, range8)
    ema5 = ta.ema(plotval, range10)
    if maType == "SMA"
        ema1 := ta.sma(plotval, range2)
        ema2 := ta.sma(plotval, range4)
        ema3 := ta.sma(plotval, range6)
        ema4 := ta.sma(plotval, range8)
        ema5 := ta.sma(plotval, range10)
    else if maType == "WMA"
        ema1 := ta.wma(plotval, range2)
        ema2 := ta.wma(plotval, range4)
        ema3 := ta.wma(plotval, range6)
        ema4 := ta.wma(plotval, range8)
        ema5 := ta.wma(plotval, range10)
    

    crossCount = 0
    crossCount += get_crosses(ema1, ema2)
    crossCount += get_crosses(ema1, ema3)
    crossCount += get_crosses(ema1, ema4)
    crossCount += get_crosses(ema1, ema5)
    crossCount += get_crosses(ema2, ema3)
    crossCount += get_crosses(ema2, ema4)
    crossCount += get_crosses(ema2, ema5)
    crossCount += get_crosses(ema3, ema4)
    crossCount += get_crosses(ema3, ema5)
    crossCount += get_crosses(ema4, ema5)

    plotDirection = 0
    if ema1 > ema2 and ema2 > ema3 and ema3 > ema4 and ema4 > ema5
        plotDirection += 1
    if ema1 < ema2 and ema2 < ema3 and ema3 < ema4 and ema4 < ema5
        plotDirection -= 1

    [crossCount, plotDirection]

[crossCount, direction] = count_crosses(close, close)
crossColor = color(na)

strongUpColor = color.new(color.blue, 67)
strongDownColor = color.new(color.orange, 67)
sBackUpColor = color.new(color.green, 67)
sBackDownColor = color.new(color.red, 67)

if crossCount > 0
    crossColor := strongUpColor
else 
    crossColor := strongDownColor

pH = plot(ta.sma(high, 5), color=na)
pL = plot(ta.sma(low, 5), color=na)

plotHighest = (crossCount[1] == 5 or crossCount[1] == -5) and upCandle
plotshape(doSymbols and plotHighest, style = shape.labelup, location=location.abovebar, color=crossColor)
plotshape(doSymbols and (((crossCount[1] == 3 or crossCount[1] == -3) and upCandle) or ((crossCount[1] == 4 or crossCount[1] == -4) and upCandle)), style = shape.triangleup, location=location.abovebar, color=crossColor)
plotshape(doSymbols and ((crossCount[1] == 2 or crossCount[1] == -2) and upCandle), style = shape.arrowup, location=location.abovebar, color=crossColor)
plotshape(doSymbols and (((crossCount[1] == 5 or crossCount[1] == -5) and not upCandle)), style = shape.labeldown, location=location.belowbar, color=crossColor)
plotshape(doSymbols and (((crossCount[1] == 3 or crossCount[1] == -3) and not upCandle) or ((crossCount[1] == 4 or crossCount[1] == -4)) and not upCandle), style = shape.triangledown, location=location.belowbar, color=crossColor)
plotshape(doSymbols and (((crossCount[1] == 2 or crossCount[1] == -2) and not upCandle)), style = shape.arrowdown, location=location.belowbar, color=crossColor)
backColor = if(true)
    switch
        direction > 0 => sBackUpColor
        direction < 0 => sBackDownColor
        => color(na)   
fill(pH, pL, backColor)

paleUpColor = color.new(color.blue, 33)
paleDownColor = color.new(color.orange, 33)
pBackUpColor = color.new(color.green, 33)
pBackDownColor = color.new(color.red, 33)

[crossCount2, direction2] = count_crosses(high, low)
crossColor := color(color.new(color.gray, 50))

if crossCount2 > 0
    crossColor := paleUpColor
else 
    crossColor := paleDownColor

plotshape(doSymbols and ((crossCount2[1] == 5 or crossCount2[1] == -5) and upCandle), style = shape.labelup, location=location.abovebar, color=crossColor)
plotshape(doSymbols and (((crossCount2[1] == 3 or crossCount2[1] == -3) and upCandle) or ((crossCount2[1] == 4 or crossCount2[1] == -4) and upCandle)), style = shape.triangleup, location=location.abovebar, color=crossColor)
plotshape(doSymbols and ((crossCount2[1] == 2 or crossCount2[1] == -2) and upCandle), style = shape.arrowup, location=location.abovebar, color=crossColor)
plotshape(doSymbols and (((crossCount2[1] == 5 or crossCount2[1] == -5) and not upCandle)), style = shape.labeldown, location=location.belowbar, color=crossColor)
plotshape(doSymbols and (((crossCount2[1] == 3 or crossCount2[1] == -3) and not upCandle) or ((crossCount2[1] == 4 or crossCount2[1] == -4) and not upCandle)), style = shape.triangledown, location=location.belowbar, color=crossColor)
plotshape(doSymbols and (((crossCount2[1] == 2 or crossCount2[1] == -2) and not upCandle)), style = shape.arrowdown, location=location.belowbar, color=crossColor)
backColor2 = if(true)
    switch
        direction2 > 0 => pBackUpColor
        direction2 < 0 => pBackDownColor
        => color(color.new(color.gray, 75))
fill(pL, pH, backColor2)


//Optional rsi strength candles
trsi = ta.rsi(close, 14)
rsiMA = ta.sma(trsi, 14)

hitrsi = false
if trsi >= rsiMA
    hitrsi := true

newHi = false
newLo = false
hRsi = get_highest(14, trsi)    
if trsi > hRsi
    newHi := true
lRsi = get_lowest(14, trsi)
if trsi < lRsi
    newLo := true
    
spikeHi = (get_highest(5, trsi) < trsi) and not newHi
spikeLo = (get_lowest(5, trsi) > trsi) and not newLo

plotchar(spikeHi and doRsiDev, char="+", location=location.belowbar, color=color.green)
plotchar(spikeLo and doRsiDev, char="x", location=location.abovebar, color=color.red)

barColor = color.new(color.white, 100)
if hitrsi
    if newHi
        barColor := color.new(color.green, 0)
    else
        barColor := color.new(color.green, 50)
else
    if newLo
        barColor := color.new(color.red, 0)
    else
        barColor := color.new(color.red, 50)

barcolor(doRsiCandles ? barColor : na)

test_peak (source, isHi) =>
    isPeak = false
    if isHi 
        if (source[0] < source[2]) and (source[1] < source[2]) and (source[2] > source[3]) and (source[2] > source[4])
            isPeak := true
    else 
        if (source[0] > source[2]) and (source[1] > source[2]) and (source[2] < source[3]) and (source[2] < source[4])
            isPeak := true
    isPeak

hiDev = test_peak(high, true)
hiRDev = false
rhiRDev = false
rhiRDev := test_peak(trsi, true)
if (rhiRDev or rhiRDev[1] or rhiRDev[2] or rhiRDev[3] or trsi < trsi[2]) and trsi[2] > 50 and hitrsi
    hiRDev := true
if hiDev and hiRDev
    hiDev := true
else
    hiDev := false

loDev = test_peak(low, false)
loRDev = false
rloRDev = false
rloRDev := test_peak(trsi, false)
if (rloRDev or rloRDev[1] or rloRDev[2] or rloRDev[3] or trsi > trsi[2]) and trsi[2] < 50 and not hitrsi 
    loRDev := true
if loDev and loRDev
    loDev := true
else
    loDev := false

hiColor = color.new(color.red, 50)
loColor = color.new(color.green, 50)
if (trsi[4] > 70 or trsi[4] < 30) or (trsi[3] > 70 or trsi[3] < 30) or (trsi[2] > 70 or trsi[2] < 30) or (trsi[1] > 70 or trsi[1] < 30) or (trsi > 70 or trsi < 30)
    hiColor := color.red
    loColor := color.green

plotchar(hiDev and doRsiDev, "H", color=hiColor, location=location.abovebar, offset = -2)
plotchar(loDev and doRsiDev, "L", color=loColor, location=location.belowbar, offset = -2)

isPivotHigh = ta.pivothigh(high, 5, 5)
isPivotLow = ta.pivotlow(low, 5, 5)
isPivot = isPivotHigh or isPivotLow

plotThisHigh = isPivotHigh > 0
sameDirection = ta.valuewhen(isPivot, isPivotHigh, 0)  // check if the previous pivot was also a high
if isPivotHigh
    plotThisHigh := not sameDirection  // reassign our plotting var if its not the same direction

plotThisLow = isPivotLow > 0
sameDirection := ta.valuewhen(isPivot, isPivotLow, 0)  // check if the previous pivot was also a high
if isPivotLow
    plotThisLow := not sameDirection  // reassign our plotting var if its not the same direction

plotshape(doSymbols and plotThisHigh, style=shape.cross, color = color.green, location=location.abovebar)
plotshape(doSymbols and plotThisLow, style=shape.xcross, color = color.red, location=location.belowbar)