On-Chart QQE of RSI on Variety MA [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("On-Chart QQE of RSI on Variety MA [Loxx]", 
     overlay = true, 
     timeframe="", 
     timeframe_gaps = true)

import loxx/loxxexpandedsourcetypes/4
import loxx/loxxmas/1

greencolor = #2DD204
redcolor = #D2042D 
bluecolor = #042dd2

cchange_onLevels = "Change on Levels"
cchange_onSlope = "Change on Slope"
cchange_onZero = "Change on Zero"
cchange_onOriginal = "Change on Original"

lightgreencolor = #96E881 
lightredcolor =  #DF4F6C
lightbluecolor =  #4f6cdf

darkGreenColor =  #1B7E02 
darkRedColor = #93021F
darkBlueColor = #021f93

smthtype = input.string("Kaufman", "HAB Calc Type", options = ["AMA", "T3", "Kaufman"], group='Source Settings')
srcin = input.string("Close", "Source", 
	 options = 
	 ["Close", "Open", "High", "Low", "Median", "Typical", "Weighted", "Average", "Average Median Body", "Trend Biased", "Trend Biased (Extreme)", 
	 "HA Close", "HA Open", "HA High", "HA Low", "HA Median", "HA Typical", "HA Weighted", "HA Average", "HA Average Median Body", "HA Trend Biased", "HA Trend Biased (Extreme)",
	 "HAB Close", "HAB Open", "HAB High", "HAB Low", "HAB Median", "HAB Typical", "HAB Weighted", "HAB Average", "HAB Average Median Body", "HAB Trend Biased", "HAB Trend Biased (Extreme)"], 
	 group='Source Settings')

inpRsiPeriod = input.int(14, "RSI Period", group = "Basic Settings")  
inpMaPeriod = input.int(32, "Average Period", group = "Basic Settings")  

typeout= input.string("Exponential Moving Average - EMA", "Filter Type", options = ["ADXvma - Average Directional Volatility Moving Average",  "Ahrens Moving Average"
     , "Alexander Moving Average - ALXMA", "Double Exponential Moving Average - DEMA", "Double Smoothed Exponential Moving Average - DSEMA"
     , "Exponential Moving Average - EMA", "Fast Exponential Moving Average - FEMA", "Fractal Adaptive Moving Average - FRAMA"
     , "Hull Moving Average - HMA", "IE/2 - Early T3 by Tim Tilson", "Integral of Linear Regression Slope - ILRS"
     , "Instantaneous Trendline", "Laguerre filt", "Leader Exponential Moving Average", "Linear Regression Value - LSMA (Least Squares Moving Average)"
     , "Linear Weighted Moving Average - LWMA", "McGinley Dynamic", "McNicholl EMA", "Non-Lag Moving Average", "Parabolic Weighted Moving Average"
     , "Recursive Moving Trendline", "Simple Moving Average - SMA", "Sine Weighted Moving Average", "Smoothed Moving Average - SMMA"
     , "Smoother", "Super Smoother", "Three-pole Ehlers Butterworth", "Three-pole Ehlers Smoother"
     , "Triangular Moving Average - TMA", "Triple Exponential Moving Average - TEMA", "Two-pole Ehlers Butterworth", "Two-pole Ehlers smoother"
     , "Volume Weighted EMA - VEMA", "Zero-Lag DEMA - Zero Lag Double Exponential Moving Average", "Zero-Lag Moving Average"
     , "Zero Lag TEMA - Zero Lag Triple Exponential Moving Average"],
     group = "Basic Settings")
     
inpRsiSmoothingFactor = input.int(5, "RSI Smoothing Factor", group = "Basic Settings")  
inpWPFast = input.float(2.618, "Fast Period", group = "Basic Settings")    
inpWPSlow = input.float(4.236, "Slow Period", group = "Basic Settings")  

inpHlPeriod = input.int(25, "Highest High/Lowest Low Period", group = "Basic Settings")   
inpHlLevelUp = input.int(70, "Overbought Level", group = "Basic Settings")  
inpHlLevelDn = input.int(30, "Oversold Level", group = "Basic Settings")   

inpColorChange = input.string(cchange_onLevels, "Change", options = [cchange_onLevels, cchange_onSlope, cchange_onZero, cchange_onOriginal], group = "Basic Settings")

showSigs = input.bool(true, "Show Signals?", group = "UI Options")


frama_FC = input.int(defval=1, title="* Fractal Adjusted (FRAMA) Only - FC", group = "Moving Average Inputs")
frama_SC = input.int(defval=200, title="* Fractal Adjusted (FRAMA) Only - SC", group = "Moving Average Inputs")
instantaneous_alpha = input.float(defval=0.07, minval = 0, title="* Instantaneous Trendline (INSTANT) Only - Alpha", group = "Moving Average Inputs")
_laguerre_alpha = input.float(title="* Laguerre filt (LF) Only - Alpha", minval=0, maxval=1, step=0.1, defval=0.7, group = "Moving Average Inputs")
lsma_offset = input.int(defval=0, title="* Least Squares Moving Average (LSMA) Only - Offset", group = "Moving Average Inputs")
_pwma_pwr = input.int(2, "* Parabolic Weighted Moving Average (PWMA) Only - Power", minval=0, group = "Moving Average Inputs")
kfl=input.float(0.666, title="* Kaufman's Adaptive MA (KAMA) Only - Fast End", group = "Moving Average Inputs")
ksl=input.float(0.0645, title="* Kaufman's Adaptive MA (KAMA) Only - Slow End", group = "Moving Average Inputs")
amafl = input.int(2, title="* Adaptive Moving Average (AMA) Only - Fast", group = "Moving Average Inputs")
amasl = input.int(30, title="* Adaptive Moving Average (AMA) Only - Slow", group = "Moving Average Inputs")

variant(type, src, len) =>
    sig = 0.0
    trig = 0.0
    special = false
    if type == "ADXvma - Average Directional Volatility Moving Average"
        [t, s, b] = loxxmas.adxvma(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Ahrens Moving Average"
        [t, s, b] = loxxmas.ahrma(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Alexander Moving Average - ALXMA"
        [t, s, b] = loxxmas.alxma(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Double Exponential Moving Average - DEMA"
        [t, s, b] = loxxmas.dema(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Double Smoothed Exponential Moving Average - DSEMA"
        [t, s, b] = loxxmas.dsema(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Exponential Moving Average - EMA"
        [t, s, b] = loxxmas.ema(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Fast Exponential Moving Average - FEMA"
        [t, s, b] = loxxmas.fema(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Fractal Adaptive Moving Average - FRAMA"
        [t, s, b] = loxxmas.frama(src, len, frama_FC, frama_SC)
        sig := s
        trig := t
        special := b
    else if type == "Hull Moving Average - HMA"
        [t, s, b] = loxxmas.hma(src, len)
        sig := s
        trig := t
        special := b
    else if type == "IE/2 - Early T3 by Tim Tilson"
        [t, s, b] = loxxmas.ie2(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Integral of Linear Regression Slope - ILRS"
        [t, s, b] = loxxmas.ilrs(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Instantaneous Trendline"
        [t, s, b] = loxxmas.instant(src, instantaneous_alpha)
        sig := s
        trig := t
        special := b
    else if type == "Laguerre filt"
        [t, s, b] = loxxmas.laguerre(src, _laguerre_alpha)
        sig := s
        trig := t
        special := b
    else if type == "Leader Exponential Moving Average"
        [t, s, b] = loxxmas.leader(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Linear Regression Value - LSMA (Least Squares Moving Average)"
        [t, s, b] = loxxmas.lsma(src, len, lsma_offset)
        sig := s
        trig := t
        special := b
    else if type == "Linear Weighted Moving Average - LWMA"
        [t, s, b] = loxxmas.lwma(src, len)
        sig := s
        trig := t
        special := b
    else if type == "McGinley Dynamic"
        [t, s, b] = loxxmas.mcginley(src, len)
        sig := s
        trig := t
        special := b
    else if type == "McNicholl EMA"
        [t, s, b] = loxxmas.mcNicholl(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Non-Lag Moving Average"
        [t, s, b] = loxxmas.nonlagma(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Parabolic Weighted Moving Average"
        [t, s, b] = loxxmas.pwma(src, len, _pwma_pwr)
        sig := s
        trig := t
        special := b
    else if type == "Recursive Moving Trendline"
        [t, s, b] = loxxmas.rmta(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Simple Moving Average - SMA"
        [t, s, b] = loxxmas.sma(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Sine Weighted Moving Average"
        [t, s, b] = loxxmas.swma(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Smoothed Moving Average - SMMA"
        [t, s, b] = loxxmas.smma(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Smoother"
        [t, s, b] = loxxmas.smoother(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Super Smoother"
        [t, s, b] = loxxmas.super(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Three-pole Ehlers Butterworth"
        [t, s, b] = loxxmas.threepolebuttfilt(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Three-pole Ehlers Smoother"
        [t, s, b] = loxxmas.threepolesss(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Triangular Moving Average - TMA"
        [t, s, b] = loxxmas.tma(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Triple Exponential Moving Average - TEMA"
        [t, s, b] = loxxmas.tema(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Two-pole Ehlers Butterworth"
        [t, s, b] = loxxmas.twopolebutter(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Two-pole Ehlers smoother"
        [t, s, b] = loxxmas.twopoless(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Volume Weighted EMA - VEMA"
        [t, s, b] = loxxmas.vwema(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Zero-Lag DEMA - Zero Lag Double Exponential Moving Average"
        [t, s, b] = loxxmas.zlagdema(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Zero-Lag Moving Average"
        [t, s, b] = loxxmas.zlagma(src, len)
        sig := s
        trig := t
        special := b
    else if type == "Zero Lag TEMA - Zero Lag Triple Exponential Moving Average"
        [t, s, b] = loxxmas.zlagtema(src, len)
        sig := s
        trig := t
        special := b
    trig

haclose  =  ohlc4
haopen   = float(na)
haopen  := na(haopen[1]) ? (open + close) / 2 : (nz(haopen[1]) + nz(haclose[1])) / 2
hahigh   =math.max(high, math.max(haopen, haclose))
halow    = math.min(low,  math.min(haopen, haclose))
hamedian = (hahigh + halow) / 2
hatypical = (hahigh + halow + haclose) / 3
haweighted =  (hahigh + halow + haclose + haclose)/4 
haaverage =  (haopen + hahigh + halow + haclose)/4

sourceout(smthtype, srcin)=>
	src = switch srcin
		"Close" => close
		"Open" => open
		"High" => high
		"Low" => low
		"Median" => hl2
		"Typical" => hlc3
		"Weighted" => hlcc4
		"Average" => ohlc4
		"Average Median Body" => (open + close)/2
		"Trend Biased" => loxxexpandedsourcetypes.rtrendb()
		"Trend Biased (Extreme)" => loxxexpandedsourcetypes.rtrendbext()
		"HA Close" => loxxexpandedsourcetypes.haclose(haclose)
		"HA Open" => loxxexpandedsourcetypes.haopen(haopen)
		"HA High" => loxxexpandedsourcetypes.hahigh(hahigh)
		"HA Low" => loxxexpandedsourcetypes.halow(halow)
		"HA Median" => loxxexpandedsourcetypes.hamedian(hamedian)
		"HA Typical" => loxxexpandedsourcetypes.hatypical(hatypical)
		"HA Weighted" => loxxexpandedsourcetypes.haweighted(haweighted)
		"HA Average" => loxxexpandedsourcetypes.haaverage(haaverage)
		"HA Average Median Body" => loxxexpandedsourcetypes.haavemedbody(haclose, haopen)
		"HA Trend Biased" => loxxexpandedsourcetypes.hatrendb(haclose, haopen, hahigh, halow)
		"HA Trend Biased (Extreme)" => loxxexpandedsourcetypes.hatrendbext(haclose, haopen, hahigh, halow)
		"HAB Close" => loxxexpandedsourcetypes.habclose(smthtype, amafl, amasl, kfl, ksl)
		"HAB Open" => loxxexpandedsourcetypes.habopen(smthtype, amafl, amasl, kfl, ksl)
		"HAB High" => loxxexpandedsourcetypes.habhigh(smthtype, amafl, amasl, kfl, ksl)
		"HAB Low" => loxxexpandedsourcetypes.hablow(smthtype, amafl, amasl, kfl, ksl)
		"HAB Median" => loxxexpandedsourcetypes.habmedian(smthtype, amafl, amasl, kfl, ksl)
		"HAB Typical" => loxxexpandedsourcetypes.habtypical(smthtype, amafl, amasl, kfl, ksl)
		"HAB Weighted" => loxxexpandedsourcetypes.habweighted(smthtype, amafl, amasl, kfl, ksl)
		"HAB Average" => loxxexpandedsourcetypes.habaverage(smthtype, amafl, amasl, kfl, ksl)
		"HAB Average Median Body" => loxxexpandedsourcetypes.habavemedbody(smthtype, amafl, amasl, kfl, ksl)
		"HAB Trend Biased" => loxxexpandedsourcetypes.habtrendb(smthtype, amafl, amasl, kfl, ksl)
		"HAB Trend Biased (Extreme)" => loxxexpandedsourcetypes.habtrendbext(smthtype, amafl, amasl, kfl, ksl)
		=> close

_alphaS = 2.0 / (1.0 + (inpRsiSmoothingFactor > 1 ? inpRsiSmoothingFactor : 1))
_alphaR = 2.0 / (1.0 + inpRsiPeriod)
work = 0.
ema = 0.
emm = 0.
wlevs = 0.
wlevf = 0.
dv = 0.
tr = 0.

maHandle = variant(typeout, sourceout(smthtype, srcin), inpMaPeriod)

rsi = ta.rsi(maHandle, inpRsiPeriod)

work := nz(work[1]) + _alphaS * (rsi - nz(work[1]))

_diff = nz(work[1]) - work

if _diff < 0
    _diff := -_diff

ema := nz(ema[1]) + _alphaR * (_diff - nz(ema[1]))
emm := nz(emm[1]) + _alphaR * (ema - nz(emm[1]))

_iEmf = emm * inpWPFast
_iEms = emm * inpWPSlow

tr := nz(wlevs[1])
dv := tr

if work < tr
    tr := work + _iEms
    if nz(work[1]) < dv and tr > dv 
        tr := dv

if work > tr
    tr := work - _iEms
    if nz(work[1]) > dv and tr < dv
        tr := dv

wlevs := tr

tr := nz(wlevf[1])
dv := tr

if work < tr
    tr := work + _iEmf
    if nz(work[1]) < dv and tr > dv
        tr := dv

if (work > tr) 
    tr := work - _iEmf
    if nz(work[1]) > dv and tr < dv
        tr := dv

wlevf := tr

prev_max = ta.highest(high, inpHlPeriod - 1)
prev_min = ta.lowest(low, inpHlPeriod - 1)

fmax = (high > prev_max) ? high : prev_max
fmin = (low < prev_min) ? low : prev_min
rng = (fmax - fmin) / 100.0

levu = fmin + inpHlLevelUp * rng
levd = fmin + inpHlLevelDn * rng
levm = fmin + 50 * rng

val = fmin + work * rng

fillud = fmin + work * rng
filldu = fmin + work * rng

levf = fmin + wlevf * rng
levs = fmin + wlevs * rng

filluu = fmax
filldd = fmin

valc = 0.
switch inpColorChange
    cchange_onLevels =>   valc := val > levu ? 1 : val < levd ? 2 : 0
    cchange_onSlope =>    valc := val > nz(val[1]) ? 1 :val < nz(val[1]) ? 2 : nz(valc[1])
    cchange_onZero  =>    valc := val > levm ? 1 : val < levm ? 2 : 0
    cchange_onOriginal => valc := work > wlevf and work > wlevs ? 1 : work < wlevf and work < wlevs ? 2 : nz(valc[1])

fillu = plot(filluu, color = color.new(color.white, 100))
filld = plot(filldd, color = color.new(color.white, 100))

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

fill(fillu, filld, color = color.new(colorout, 80))

plot(levu, "Upper Level", color = lightgreencolor, linewidth = 1)
plot(levd, "Lower Level", color = lightredcolor, linewidth = 1)
plot(levm, "Middle Level", color = color.gray, linewidth = 1)

plot(val, "QQE", color = colorout, linewidth = 5)

plot(levs, "QQE Slow", color = color.yellow, linewidth = 2)
plot(levf, "QQE Fast", color = color.white, linewidth = 1)

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

plotshape(showSigs and goLong, title = "Long", color = color.yellow, textcolor = color.yellow, text = "L", style = shape.triangleup, location = location.belowbar, size = size.small)
plotshape(showSigs and goShort, title = "Short", color = color.fuchsia, textcolor = color.fuchsia, text = "S", style = shape.triangledown, location = location.abovebar, size = size.small)

alertcondition(goLong, title="Long", message="On-Chart QQE of RSI on Variety MA [Loxx]: Long\nSymbol: {{ticker}}\nPrice: {{close}}")
alertcondition(goShort, title="Short", message="On-Chart QQE of RSI on Variety MA [Loxx]: Short\nSymbol: {{ticker}}\nPrice: {{close}}")