loxxmas - moving averages used in Loxx's indis & strats
// 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

// @description TODO:loxx moving averages used in indicators
library("loxxmas", overlay = true)

// @function KAMA Kaufman adaptive moving average
// @param src float
// @param len int
// @param kamafastend int
// @param kamaslowend int
// @returns array
export kama(float src, int len, int kamafastend, int kamaslowend) =>
    xvnoise = math.abs(src - src[1])
    nfastend = kamafastend
    nslowend = kamaslowend
    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

// @function AMA, adaptive moving average
// @param src float
// @param len int
// @param fl int
// @param sl int
// @returns array
export ama(float src, int len, int fl, int 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

// @function T3 moving average, adaptive moving average
// @param src float
// @param len int
// @returns array
export t3(float src, int len) =>
    xe11 = ta.ema(src, len)
    xe21 = ta.ema(xe11, len)
    xe31 = ta.ema(xe21, len)
    xe41 = ta.ema(xe31, len)
    xe51 = ta.ema(xe41, len)
    xe61 = ta.ema(xe51, len)
    b1 = 0.7
    c11 = -b1 * b1 * b1
    c21 = 3 * b1 * b1 + 3 * b1 * b1 * b1
    c31 = -6 * b1 * b1 - 3 * b1 - 3 * b1 * b1 * b1
    c41 = 1 + 3 * b1 + b1 * b1 * b1 + 3 * b1 * b1
    nT3Average = c11 * xe61 + c21 * xe51 + c31 * xe41 + c41 * xe31
    nT3Average
    
// @function ADXvma - Average Directional Volatility Moving Average
// @param src float
// @param len int
// @returns array
export adxvma(float src, int len)=>
    tpdm = 0., tmdm = 0.
    pdm = 0., mdm = 0., pdi = 0., mdi = 0., out = 0., val = 0.
    tpdi = 0., tmdi = 0., thi = 0., tlo = 0., tout = 0., vi = 0.

    diff = src - nz(src[1])
    tpdm := diff > 0 ? diff : tpdm
    tmdm := diff > 0 ? tmdm : -diff
    pdm := ((len- 1.0) * nz(pdm[1]) + tpdm) / len
    mdm := ((len- 1.0) * nz(mdm[1]) + tmdm) / len
    
    trueRange = pdm + mdm
    tpdi := nz(pdm / trueRange)
    tmdi := nz(mdm / trueRange)
    pdi := ((len- 1.0) * nz(pdi[1]) + tpdi) / len
    mdi := ((len- 1.0) * nz(mdi[1]) + tmdi) / len
    
    tout := (pdi + mdi) > 0 ?  math.abs(pdi - mdi) / (pdi + mdi) : tout
    out := ((len- 1.0) * nz(out[1]) + tout) / len
    thi := math.max(out, nz(out[1]))
    tlo := math.min(out, nz(out[1]))
    for j = 2 to len 
        thi := math.max(nz(out[j]), thi)
        tlo := math.min(nz(out[j]), tlo)
    vi := (thi - tlo) > 0 ? (out - tlo) / (thi - tlo) : vi
    val := ((len- vi) * nz(val[1]) + vi * src) / len
    [val, val[1], false]
 
// @function Ahrens Moving Average
// @param src float
// @param len int
// @returns array
export ahrma(float src, int len)=>
    ahrma = 0.
    medMA = (nz(ahrma[1]) + nz(ahrma[len])) / 2.0
    ahrma := nz(ahrma[1]) + ((src - medMA) / len)
    [ahrma, ahrma[1], false]

// @function Alexander Moving Average - ALXMA
// @param src float
// @param len int
// @returns array
export alxma(float src, int len)=>
    sumw = len - 2
    sum  = sumw * src
    for k = 1 to len 
        weight = len - k - 2 
        sumw += weight
        sum += weight * nz(src[k])
    out = len < 4 ? src : sum/sumw 
    [out, out[1], false]

// @function Double Exponential Moving Average - DEMA
// @param src float
// @param len int
// @returns array
export dema(float src, simple int len)=>
    e1 = ta.ema(src, len)
    e2 = ta.ema(e1, len)
    dema = 2 * e1 - e2
    [dema, dema[1], false]
    
// @function Double Smoothed Exponential Moving Average - DSEMA
// @param src float
// @param len int
// @returns array
export dsema(float src, int len)=>
    alpha = 2.0 / (1.0 + math.sqrt(len))
    ema1 = 0., ema2 = 0.
    ema1 := nz(ema1[1]) + alpha * (src - nz(ema1[1]))
    ema2 := nz(ema2[1]) + alpha * (ema1 - nz(ema2[1]))
    [ema2, ema2[1], false]

// @function Exponential Moving Average - EMA
// @param src float
// @param len int
// @returns array
export ema(float src, simple int len)=>
    out = ta.ema(src, len)
    [out, out[1], false]

// @function Fast Exponential Moving Average - FEMA
// @param src float
// @param len int
// @returns array
export fema(float src, int len)=>
    alpha = (2.0 / (2.0 + (len - 1.0) / 2.0))
    out = 0.
    out := nz(out[1]) + alpha * (src - nz(out[1])) 
    [out, out[1], false]

// @function Hull moving averge
// @param src float
// @param len int
// @returns array
export hma(float src, simple int len)=>
    out = ta.hma(src, len)
    [out, out[1], false]
    
// @function Early T3 by Tim Tilson
// @param src float
// @param len int
// @returns array
export ie2(float src, int len)=>
    sumx=0., sumxx=0., sumxy=0., sumy=0.
    for k = 0 to len - 1   
        price = nz(src[k]) 
        sumx  += k
        sumxx += k * k
        sumxy += k * price
        sumy  += price
    slope = (len * sumxy - sumx * sumy) / (sumx * sumx - len * sumxx)
    average = sumy/len
    out = (((average + slope) + (sumy + slope * sumx) / len) / 2.0)
    [out, out[1], false]

// @function Fractal Adaptive Moving Average - FRAMA
// @param src float
// @param len int
// @param FC int
// @param SC int
// @returns array
export frama(float src, int len, int FC, int SC) =>
    len1 = len / 2
    e = math.e
    w = math.log(2 / (SC + 1)) / math.log(e)  // Natural logarithm (ln(2/(SC+1))) workaround
    H1 = ta.highest(high, len1)
    L1 = ta.lowest(low, len1)
    N1 = (H1 - L1) / len1
    H2 = ta.highest(high, len1)[len1]
    L2 = ta.lowest(low, len1)[len1]
    N2 = (H2 - L2) / len1
    H3 = ta.highest(high, len)
    L3 = ta.lowest(low, len)
    N3 = (H3 - L3) / len
    dimen1 = (math.log(N1 + N2) - math.log(N3)) / math.log(2)
    dimen = N1 > 0 and N2 > 0 and N3 > 0 ? dimen1 : nz(dimen1[1])
    alpha1 = math.exp(w * (dimen - 1))
    oldalpha = alpha1 > 1 ? 1 : alpha1 < 0.01 ? 0.01 : alpha1
    oldN = (2 - oldalpha) / oldalpha
    N = (SC - FC) * (oldN - 1) / (SC - 1) + FC
    alpha_ = 2 / (N + 1)
    alpha = alpha_ < 2 / (SC + 1) ? 2 / (SC + 1) : alpha_ > 1 ? 1 : alpha_
    out = 0.0
    out := (1 - alpha) * nz(out[1]) + alpha * src
    [out, out[1], false]

// @function Instantaneous Trendline
// @param src float
// @param float alpha
// @returns array
export instant(float src, float alpha) =>
    itrend = 0.0
    itrend := bar_index < 7 ? (src + 2 * nz(src[1]) + nz(src[2])) / 4 : 
         (alpha - math.pow(alpha, 2) / 4) * src + 0.5 * math.pow(alpha, 2) * nz(src[1]) - (alpha - 0.75 * math.pow(alpha, 2)) * nz(src[2]) +  2 * (1 - alpha) * nz(itrend[1]) - math.pow(1 - alpha, 2) * nz(itrend[2])
    trigger = 2 * itrend - nz(itrend[2])
    [trigger, itrend, false]

// @function Integral of Linear Regression Slope - ILRS
// @param src float
// @param int len
// @returns array
export ilrs(float src, int len)=> // Integral of linear regression slope
    sum = len * (len -1) * 0.5
    sum2 = (len - 1) * len * (2 * len - 1) / 6.0
    sum1 = 0., sumy = 0., slope = 0.
    for i = 0 to len - 1 
        sum1 += i * nz(src[i])
        sumy += nz(src[i])
    num1 = len * sum1 - sum * sumy
    num2 = sum * sum - len * sum2
    slope := num2 != 0. ? num1/num2 : 0.
    ilrs = slope + ta.sma(src, len)
    [ilrs, ilrs[1], false]

// @function Laguerre Filter
// @param src float
// @param float alpha
// @returns array
export laguerre(float src, float alpha)=>
    L0 = 0.0, L1 = 0.0, L2 = 0.0, L3 = 0.0
    L0 := alpha * src + (1 - alpha) * nz(L0[1])
    L1 := -(1 - alpha) * L0 + nz(L0[1]) + (1 - alpha) * nz(L1[1])
    L2 := -(1 - alpha) * L1 + nz(L1[1]) + (1 - alpha) * nz(L2[1])
    L3 := -(1 - alpha) * L2 + nz(L2[1]) + (1 - alpha) * nz(L3[1])
    lf = (L0 + 2 * L1 + 2 * L2 + L3) / 6
    [lf, lf[1], false]

// @function Leader Exponential Moving Average
// @param src float
// @param int len
// @returns array
export leader(float src, int len)=>
    alpha = 2.0/(len + 1.0)
    ldr = 0.,ldr2 = 0.
    ldr := nz(ldr[1]) + alpha * (src - nz(ldr[1]))
    ldr2 := nz(ldr2[1]) + alpha * (src - ldr - nz(ldr2[1]))
    out = ldr + ldr2
    [out, out[1], false]
    
// @function Linear Regression Value - LSMA (Least Squares Moving Average)
// @param src float
// @param int len
// @param int offset
// @returns array
export lsma(float src, simple int len, simple int offset)=>
    out = ta.linreg(src, len, offset)
    [out, out[1], false]

// @function Linear Weighted Moving Average - LWMA
// @param src float
// @param int len
// @returns array
export lwma(float src, int len)=>
    out = ta.wma(src, len)
    [out, out[1], false]

// @function McGinley Dynamic
// @param src float
// @param int len
// @returns array
export mcginley(float src, simple int len)=>
    mg = 0.0
    t = ta.ema(src, len)
    mg := na(mg[1]) ? t : mg[1] + (src - mg[1]) / (len * math.pow(src / mg[1], 4))
    [mg, mg[1], false]

// @function McNicholl EMA
// @param src float
// @param int len
// @returns array
export mcNicholl(float src, simple int len)=>
    alpha = 2 / (len + 1)
    ema1 = ta.ema(src, len)
    ema2 = ta.ema(ema1, len)
    out = ((2 - alpha) * ema1 - ema2) / (1 - alpha)
    [out, out[1], false]

// @function Non-lag moving average
// @param src float
// @param int len
// @returns array
export nonlagma(float src, int len)=>
    cycle = 4.0
    coeff = 3.0 * math.pi
    phase = len - 1.0
    _len = int(len * cycle + phase)
    weight = 0., alfa = 0., out = 0.
    alphas = array.new_float(_len, 0)
    for k = 0 to _len - 1
        t = 0.
        t := k <= phase - 1 ?  1.0 * k / (phase - 1) : 1.0 + (k - phase + 1) * (2.0 * cycle - 1.0) / (cycle * len -1.0)
        beta = math.cos(math.pi * t)
        g = 1.0/(coeff * t + 1)
        g := t <= 0.5  ? 1 : g
        array.set(alphas, k, g * beta)
        weight += array.get(alphas, k)
    if (weight > 0)  
        sum = 0.
        for k = 0 to _len - 1
            sum += array.get(alphas, k) * nz(src[k])
        out := (sum / weight)
    [out, out[1], false]

// @function Parabolic Weighted Moving Average
// @param src float
// @param int len
// @param float pwr
// @returns array
export pwma(float src, int len, float pwr)=>
    sum = 0.0, weightSum = 0.0
    for i = 0 to len - 1 by 1
        weight = math.pow(len - i, pwr)
        sum += nz(src[i]) * weight
        weightSum += weight
        weightSum
    out = sum / weightSum
    [out, out[1], false]

// @function Recursive Moving Trendline
// @param src float
// @param int len
// @returns array
export rmta(float src, int len)=>
    alpha = 2 / (len + 1)
    b = 0.0
    b := (1 - alpha) * nz(b[1], src) + src
    rmta = 0.0
    rmta := (1 - alpha) * nz(rmta[1], src) + alpha * (src + b - nz(b[1]))
    [rmta, rmta[1], false]

// @function Simple decycler - SDEC
// @param src float
// @param int len
// @returns array
export decycler(float src, int len)=>
    alphaArg = 2 * math.pi / (len * math.sqrt(2))
    alpha = 0.0
    alpha := math.cos(alphaArg) != 0 ? (math.cos(alphaArg) + math.sin(alphaArg) - 1) / math.cos(alphaArg) : nz(alpha[1])
    hp = 0.0
    hp := math.pow(1 - alpha / 2, 2) * (src - 2 * nz(src[1]) + nz(src[2])) + 2 * (1 - alpha) * nz(hp[1]) - math.pow(1 - alpha, 2) * nz(hp[2])
    decycler = src - hp
    [decycler, decycler[1], false]

// @function Simple Moving Average
// @param src float
// @param int len
// @returns array
export sma(float src, int len)=>
    out = ta.sma(src, len)
    [out, out[1], false]

// @function Sine Weighted Moving Average
// @param src float
// @param int len
// @returns array
export swma(float src, int len)=>
    sum = 0.0, weightSum = 0.0
    for i = 0 to len - 1 by 1
        weight = math.sin((i + 1) * math.pi / (len + 1))
        sum += nz(src[i]) * weight
        weightSum += weight
        weightSum
    swma = sum / weightSum
    [swma, swma[1], false]

// @function linear weighted moving average
// @param src float
// @param int len
// @returns array
export slwma(float src, int len)=>
    out = ta.wma(ta.wma(src, len), math.floor(math.sqrt(len)))
    [out, out[1], false]

// @function Smoothed Moving Average - SMMA
// @param src float
// @param int len
// @returns array
export smma(float src, simple int len)=>
    out = ta.rma(src, len)
    [out, out[1], false]

// @function Ehlers super smoother
// @param src float
// @param int len
// @returns array
export super(float src, int len) =>
    f = (1.414 * math.pi)/len
    a = math.exp(-f)
    c2 = 2 * a * math.cos(f)
    c3 = -a*a
    c1 = 1-c2-c3
    smooth = 0.0
    smooth := c1*(src+src[1])*0.5+c2*nz(smooth[1])+c3*nz(smooth[2])
    [smooth, smooth[1], false]

// @function Smoother filter
// @param src float
// @param int len
// @returns array
export smoother(float src, int len)=>
    wrk = src, wrk2 = src, wrk4 = src
    wrk0 = 0., wrk1 = 0., wrk3 = 0.
    alpha = 0.45 * (len - 1.0) / (0.45 * (len - 1.0) + 2.0)
    wrk0 := src + alpha * (nz(wrk[1]) - src)
    wrk1 := (src - wrk) * (1 - alpha) + alpha * nz(wrk1[1])
    wrk2 := wrk0 + wrk1
    wrk3 := (wrk2 - nz(wrk4[1])) * math.pow(1.0 - alpha, 2) + math.pow(alpha, 2) * nz(wrk3[1])
    wrk4 := wrk3 + nz(wrk4[1])
    [wrk4, wrk4[1], false]

// @function Triangular moving average - TMA
// @param src float
// @param int len
// @returns array
export tma(float src, int len)=>
    filt = 0.0, coef = 0.0, l2 = len / 2.0
    for i = 1 to len
        c = i < l2 ? i : i > l2 ? len + 1 - i : l2
        filt := filt + (c * nz(src[i - 1]))
        coef := coef + c
    filt := coef != 0 ? filt / coef : 0
    [filt, filt[1], false]

// @function Tripple exponential moving average - TEMA
// @param src float
// @param int len
// @returns array
export tema(float src, simple int len)=>
    ema1 = ta.ema(src, len)
    ema2 = ta.ema(ema1, len)
    ema3 = ta.ema(ema2, len)
    out = 3 * (ema1 - ema2) + ema3
    [out, out[1], false]

// @function Volume weighted ema - VEMA
// @param src float
// @param int len
// @returns array
export vwema(float src, simple int len) =>
    p = ta.ema(volume * src, len)
    v = ta.ema(volume, len)
    vwema = p / v
    [vwema, vwema[1], false]

// @function Volume weighted moving average - VWMA
// @param src float
// @param int len
// @returns array
export vwma(float src, simple int len)=>
    ma = ta.vwma(src, len)
    [ma, ma[1], false]

// @function Zero-lag dema
// @param src float
// @param int len
// @returns array
export zlagdema(float src, simple  int len)=>
    zdema1 = ta.ema(src, len) 
    zdema2 = ta.ema(zdema1, len)
    dema1 = 2 * zdema1 - zdema2
    zdema12 = ta.ema(dema1, len)
    zdema22 = ta.ema(zdema12, len)
    demaout = 2 * zdema12 - zdema22
    [demaout, demaout[1], false]

// @function Zero-lag moving average
// @param src float
// @param int len
// @returns array
export zlagma(float src, int len)=>
    alpha = 2.0/(1.0 + len)
    per = math.ceil((len - 1.0) / 2.0 )
    zlagma = 0.
    zlagma := nz(zlagma[1]) + alpha * (2.0 * src - nz(zlagma[per]) - nz(zlagma[1]))
    [zlagma, zlagma[1], false]

// @function Zero-lag tema
// @param src float
// @param int len
// @returns array
export zlagtema(float src, simple int len)=>
    ema1 = ta.ema(src, len)
    ema2 = ta.ema(ema1, len)
    ema3 = ta.ema(ema2, len)
    out = 3 * (ema1 - ema2) + ema3
    ema1a = ta.ema(out, len)
    ema2a = ta.ema(ema1a, len)
    ema3a = ta.ema(ema2a, len)
    outf = 3 * (ema1a - ema2a) + ema3a
    [outf, outf[1], false]

// @function Three-pole Ehlers Butterworth
// @param src float
// @param int len
// @returns array
export threepolebuttfilt(float src, int len)=>
    a1 = 0., b1 = 0., c1 = 0.
    coef1 = 0., coef2 = 0., coef3 = 0., coef4 = 0.
    bttr = 0., trig = 0.
    a1 := math.exp(-math.pi / len)
    b1 := 2 * a1 * math.cos(1.738 * math.pi / len)
    c1 := a1 * a1
    coef2 := b1 + c1
    coef3 := -(c1 + b1 * c1)
    coef4 := c1 * c1
    coef1 := (1 - b1 + c1) * (1 - c1) / 8
    bttr := coef1 * (src + 3 * nz(src[1]) + 3 * nz(src[2]) + nz(src[3])) + coef2 * nz(bttr[1]) + coef3 * nz(bttr[2]) + coef4 * nz(bttr[3])
    bttr := bar_index < 4 ? src : bttr
    trig := nz(bttr[1])
    [bttr, trig, true]

// @function Three-pole Ehlers smoother
// @param src float
// @param int len
// @returns array
export threepolesss(float src, int len)=>
    a1 = 0., b1 = 0., c1 = 0.
    coef1 = 0., coef2 = 0., coef3 = 0., coef4 = 0.
    filt = 0., trig = 0.
    a1 := math.exp(-math.pi / len)
    b1 := 2 * a1 * math.cos(1.738 * math.pi / len)
    c1 := a1 * a1
    coef2 := b1 + c1
    coef3 := -(c1 + b1 * c1)
    coef4 := c1 * c1
    coef1 := 1 - coef2 - coef3 - coef4
    filt := coef1 * src + coef2 * nz(filt[1]) + coef3 * nz(filt[2]) + coef4 * nz(filt[3])
    filt := bar_index < 4 ? src : filt
    trig := nz(filt[1])
    [filt, trig, true]

// @function Two-pole Ehlers Butterworth
// @param src float
// @param int len
// @returns array
export twopolebutter(float src, int len)=>
    a1 = 0., b1 = 0.
    coef1 = 0., coef2 = 0., coef3 = 0.
    bttr = 0., trig = 0.
    a1 := math.exp(-1.414 * math.pi / len)
    b1 := 2 * a1 * math.cos(1.414 * math.pi / len)
    coef2 := b1
    coef3 := -a1 * a1
    coef1 := (1 - b1 + a1 * a1) / 4
    bttr := coef1 * (src + 2 * nz(src[1]) + nz(src[2])) + coef2 * nz(bttr[1]) + coef3 * nz(bttr[2])
    bttr := bar_index < 3 ? src : bttr
    trig := nz(bttr[1])
    [bttr, trig, true]

// @function Two-pole Ehlers smoother
// @param src float
// @param int len
// @returns array
export twopoless(float src, int len)=>
    a1 = 0., b1 = 0.
    coef1 = 0., coef2 = 0., coef3 = 0.
    filt = 0., trig = 0.
    a1 := math.exp(-1.414 * math.pi / len)
    b1 := 2 * a1 * math.cos(1.414 * math.pi / len)
    coef2 := b1
    coef3 := -a1 * a1
    coef1 := 1 - coef2 - coef3
    filt := coef1 * src + coef2 * nz(filt[1]) + coef3 * nz(filt[2])
    filt := bar_index < 3 ? src : filt
    trig := nz(filt[1])
    [filt, trig, true]
    
//exmaple useage
[out, _, _] = ema(close, 25)
plot(out)
    
    
    
