Momentum Deviation Bands [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("Momentum Deviation Bands [Loxx]",
     overlay = true, 
     timeframe="", 
     timeframe_gaps = true)

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

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

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

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

_kalman(src, per, K, Sharpness)=>
    velocity = 0.0
    kfilt = 0.0
    Distance = src - nz(kfilt[1], src)
    Error = nz(kfilt[1], src) + Distance * math.sqrt(Sharpness*K/ 100)
    velocity := nz(velocity[1], 0) + Distance*K / 100
    kfilt := Error + velocity
    kfilt

_vidya(src, per, histPer)=>
    k = ta.stdev(src, per) / ta.stdev(src, histPer)
    sc = 2 / (per + 1)
    vidya = 0.0
    vidya := nz(k * sc * src + (1 - k * sc) * vidya[1], 0)
    vidya

_kama(src, len, kama_fastend, kama_slowend) =>
    xvnoise = math.abs(src - src[1])
    nfastend = kama_fastend
    nslowend = kama_slowend
    nsignal = math.abs(src - src[len])
    nnoise = math.sum(xvnoise, len)
    nefratio = nnoise != 0 ? nsignal / nnoise : 0
    nsmooth = math.pow(nefratio * (nfastend - nslowend) + nslowend, 2)
    nAMA = 0.0
    nAMA := nz(nAMA[1]) + nsmooth * (src - nz(nAMA[1]))
    nAMA

_ama(src, len, fl, sl)=>
    flout = 2/(fl + 1)
    slout = 2/(sl + 1)
    hh = ta.highest(len + 1)
    ll = ta.lowest(len + 1)
    mltp = hh - ll != 0 ? math.abs(2 * src - ll - hh) / (hh - ll) : 0
    ssc = mltp * (flout - slout) + slout
    ama = 0.
    ama := nz(ama[1]) + math.pow(ssc, 2) * (src - nz(ama[1]))
    ama
    
t3filter(float src, float per, float hot, string clean)=>
    float a = hot
    float _c1 = -a * a * a
    float _c2 = 3 * a * a + 3 * a * a * a
    float _c3 = -6 * a * a - 3 * a - 3 * a * a * a
    float _c4 = 1 + 3 * a + a * a * a + 3 * a * a
    
    float alpha = 0.
    
    if (clean == "T3 New")
        alpha := 2.0 / (2.0 + (per - 1.0) / 2.0)
    else 
        alpha := 2.0 / (1.0 + per)

    float _t30 = src, _t31 = src
    float _t32 = src, _t33 = src
    float _t34 = src, _t35 = src
    
    _t30 := nz(_t30[1]) + alpha * (src -  nz(_t30[1]))
    _t31 := nz(_t31[1]) + alpha * (_t30 - nz(_t31[1]))
    _t32 := nz(_t32[1]) + alpha * (_t31 - nz(_t32[1]))
    _t33 := nz(_t33[1]) + alpha * (_t32 - nz(_t33[1]))
    _t34 := nz(_t34[1]) + alpha * (_t33 - nz(_t34[1]))
    _t35 := nz(_t35[1]) + alpha * (_t34 - nz(_t35[1]))
    float out =
         _c1 * _t35 + _c2 * _t34 +
         _c3 * _t33 +  _c4 * _t32
    out

smthtype = input.string("Kaufman", "Heikin-Ashi Better Caculation Type", options = ["AMA", "T3", "Kaufman"], group = "Source Settings")

srcin = input.string("Close", "Source", group= "Source Settings", 
     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)"])

inpPeriod = input.int(60, "Period", group = "Basic Settings")

inpMomPeriod = input.int(2, "Momentum Period", group = "Basic Settings")

bl2_type = input.string("Hull Moving Average - HMA", "Moving Average Type",
     options = [
     "Adaptive Moving Average - AMA",
     "ADXvma - Average Directional Volatility Moving Average",
     "Ahrens Moving Average", 
     "Alexander Moving Average - ALXMA", 
     "Donchian",
     "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 maout by Tim Tilson", 
     "Integral of Linear Regression Slope - ILRS", 
     "Instantaneous Trendline",
     "Kalman Filter",
     "Kaufman Adaptive Moving Average - KAMA",
     "Laguerre Filter", 
     "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", 
     "T3", 
     "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",
     "Variable Index Dynamic Average - VIDYA", 
     "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")


inpMultiplier1 = input.float(1.0, "Multiplier 1", group = "Basic Settings")
inpMultiplier2 = input.float(2.0, "Multiplier 2", group = "Basic Settings")
inpMultiplier3 = input.float(3.0, "Multiplier 3", group = "Basic Settings")
inpMultiplier4 = input.float(4.0, "Multiplier 4", group = "Basic Settings")
inpMultiplier5 = input.float(5.0, "Multiplier 5", group = "Basic Settings")

show1 = input.bool(true, "Show Level 1", group = "UI Options")
show2 = input.bool(true, "Show Level 2", group = "UI Options")
show3 = input.bool(true, "Show Level 3", group = "UI Options")
show4 = input.bool(true, "Show Level 4", group = "UI Options")
show5 = input.bool(true, "Show Level 5", 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 Filter (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")
t3hot = input.float(.7, "* T3 Only - T3 Hot", group = "Moving Average Inputs") 
t3swt = input.string("T3 New", "* T3 Only - T3 Type", options = ["T3 New", "T3 Original"], group = "Moving Average Inputs")
histPer = input.int(30, "* Variable Index Dynamic Average (VIDYA) Only - Hist Period", group = "Moving Average Inputs")
Sharpness = input.float(1.0, "* Kalman Filter only - Sharpness", group = "Moving Average Inputs")
K = input.float(1.0,  "* Kalman Filter only - K", group = "Moving Average Inputs")

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

inpMomPrice = switch srcin
	"Close" => loxxexpandedsourcetypes.rclose()
	"Open" => loxxexpandedsourcetypes.ropen()
	"High" => loxxexpandedsourcetypes.rhigh()
	"Low" => loxxexpandedsourcetypes.rlow()
	"Median" => loxxexpandedsourcetypes.rmedian()
	"Typical" => loxxexpandedsourcetypes.rtypical()
	"Weighted" => loxxexpandedsourcetypes.rweighted()
	"Average" => loxxexpandedsourcetypes.raverage()
    "Average Median Body" => loxxexpandedsourcetypes.ravemedbody()
	"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)
	=> haclose

variant(type, src, len) =>
    sig = 0.0
    trig = 0.0
    special = false

    if type == "Donchian" 
        out = math.avg(ta.lowest(len), ta.highest(len))
        trig := out
        sig := out[1]

    if type == "Adaptive Moving Average - AMA"
        out = _ama(src, len, amafl, amasl)
        trig := out
        sig := out[1]

    else if type == "Kaufman Adaptive Moving Average - KAMA"
        t = _kama(src, len, kfl, ksl)
        trig := t
        sig := t[1]

    else if type == "T3"
        t = t3filter(src, len, t3hot, t3swt)
        trig := t
        sig := t[1]

    else if type == "Kalman Filter"
        t = _kalman(src, len, K, Sharpness)
        trig := t
        sig := t[1]

    else if type == "Variable Index Dynamic Average - VIDYA"
        t = _vidya(src, len, histPer)
        sig := t
        trig := t[1]

    else 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 maout 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 Filter"
        [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, close]

sum = 0.
sum := nz(sum[1])
sum := sum + nz(sum[1]) + inpMomPrice - nz(inpMomPrice[inpPeriod])

momentumSum = 0.
momentumSum := nz(momentumSum[1])
momentumSum := momentumSum + math.pow(ta.mom(inpMomPrice, inpMomPeriod), 2) - math.pow(nz(ta.mom(inpMomPrice, inpMomPeriod)[inpPeriod]), 2)

deviation = math.sqrt(momentumSum / inpPeriod)

[val, _] = variant(bl2_type, inpMomPrice, inpPeriod)

colorout = val > val[1] ? greencolor : redcolor

bandup1 = val + deviation * inpMultiplier1
banddn1 = val - deviation * inpMultiplier1

bandup2 = val + deviation * inpMultiplier2
banddn2 = val - deviation * inpMultiplier2

bandup3 = val + deviation * inpMultiplier3
banddn3 = val - deviation * inpMultiplier3

bandup4 = val + deviation * inpMultiplier4
banddn4 = val - deviation * inpMultiplier4

bandup5 = val + deviation * inpMultiplier5
banddn5 = val - deviation * inpMultiplier5

plot(val, "Moving Average", color = colorout, linewidth = 3)

plot(show1 ? bandup1 : na, "Level 1 Up", color = color.gray)
plot(show1 ? banddn1 : na, "Level 1 Down",color = color.gray)

plot(show2 ? bandup2 : na, "Level 2 Up",color = darkRedColor)
plot(show2 ? banddn2 : na, "Level 2 Down",color = darkGreenColor)

plot(show3 ? bandup3 : na, "Level 3 Up",color = redcolor, linewidth = 1)
plot(show3 ? banddn3 : na, "Level 3 Down",color = greencolor, linewidth = 1)

plot(show4 ? bandup4 : na, "Level 4 Up",color = lightredcolor, linewidth = 1)
plot(show4 ? banddn4 : na, "Level 4 Down",color = lightgreencolor, linewidth = 1)

plot(show5 ? bandup5 : na, "Level 5 Up",color = color.new(color.white, 50), linewidth = 1)
plot(show5 ? banddn5 : na, "Level 5 Down",color = color.new(color.white, 50), linewidth = 1)
