Smoothed Repulse w/ Floating Levels [Loxx]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © loxx

//@version=5
indicator("Smoothed Repulse w/ Floating Levels [Loxx]", 
     shorttitle = "SRFL [Loxx]", 
     overlay = false, 
     timeframe="", 
     timeframe_gaps = true)

variant(type, src, len) =>
    sig = 0.0
    if type == "SMA"
        sig := ta.sma(src, len) 
    else if type == "EMA"
        sig := ta.ema(src, len) 
    else if type == "WMA"
        sig := ta.wma(src, len)   
    else if type == "RMA"
        sig := ta.rma(src, len)  
    sig
    
greencolor = #2DD204
redcolor = #D2042D 

per = input.int(14, 'Period', group = "Basic Settings")
type = input.string("EMA", "Smoothing Type", options = ["EMA", "WMA", "RMA", "SMA"], group = "Basic Settings")

avgmult = input.int(5, 'Average Multiplier', group = "Floating Levels Settings")
lvlper = input.int(50, 'Level Period', group = "Floating Levels Settings")
upper = input.float(90, 'Upper Level %', group = "Floating Levels Settings")
dnper = input.float(10, 'Lower Level %', group = "Floating Levels Settings")

colortype = input.string("Middle Cross", "Signal Type", options = ["Level Cross", "Middle Cross", "Slope"], group = "Signal Settings")

colorbars = input.bool(false, "Color bars?", group = "UI Options")
showfloat = input.bool(true, "Show Floating Levels?", group = "UI Options")
showfill = input.bool(true, "Fil Floating Levels?", group = "UI Options")
showSigs = input.bool(false, "Show signals?", group= "UI Options")

min   = ta.lowest(low, per)
max   = ta.highest(high, per)
bull  = variant(type, 100 * (3.0 * close - 2.0 * min- nz(open[per]))/close, per * avgmult)
bear  = variant(type, 100 * (nz(open[per]) + 2.0 * max - 3.0 * close)/close, per * avgmult)

rep = bull - bear

minf = ta.lowest(rep, lvlper)
maxf = ta.highest(rep, lvlper)

rn = maxf - minf
fup  = minf + rn * upper / 100.0
fdn  = minf + rn * dnper / 100.0
mid  = (fup + fdn) / 2.0

repc = 0.

if colortype == 'Level Cross' 
    repc := (rep > fup) ? 1 : (rep < fdn) ? 2 : (rep < fup and rep > fdn) ? 0 : nz(repc[1])  
else if colortype == 'Middle Cross' 
    repc := (rep > mid) ? 1 : (rep < mid) ? 2 : nz(repc[1])  
else 
    repc := (rep > rep[1]) ? 1 : (rep < rep[1]) ? 2 : repc[1] 

colorout = repc == 1 ? greencolor : repc == 2 ? redcolor : color.gray

plot(rep, "Smoothed Repulse", color = colorout, linewidth=2)

uppl = plot(fup, "Float Upper Level", color= color.gray)
dnpl = plot(fdn, "Float Lower Level", color=  color.gray)
midpl = plot(mid, "Float Middle", color = bar_index % 2 ? color.gray : na)

fill(uppl, midpl, title = "Top fill color", color = showfill ? color.new(greencolor, 95) : na)
fill(dnpl, midpl, title = "Bottom fill color",  color = showfill ?  color.new(redcolor, 95) : na)

barcolor(colorbars ? colorout : na)

goLong = repc == 1 and repc[1] !=1
goShort = repc == 2 and repc[1] !=2

plotshape(showSigs and goLong, title = "Long", color = greencolor, textcolor = greencolor, text = "L", style = shape.triangleup, location = location.bottom, size = size.auto)
plotshape(showSigs and goShort, title = "Short", color = redcolor, textcolor = redcolor, text = "S", style = shape.triangledown, location = location.top, size = size.auto)

alertcondition(goLong, title="Long", message='Smoothed Repulse w/ Floating Levels [Loxx]: Long\nSymbol: {{ticker}}\nPrice: {{close}}')
alertcondition(goShort, title="Short", message='Smoothed Repulse w/ Floating Levels [Loxx]: Short\nSymbol: {{ticker}}\nPrice: {{close}}')










