Pips-Stepped, R-squared Adaptive T3 [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("Pips-Stepped, R-squared Adaptive T3 [Loxx]",
     shorttitle='PSRSAT3 [Loxx]', 
     overlay = true, 
     timeframe="", 
     timeframe_gaps = true)

greencolor = #2DD204
redcolor = #D2042D

_t3rSqrdAdapt(float src, float period, bool original, bool trendFollow, bool adapt, float factor)=>
    alpha = original ? 
         2.0 / (1.0 + period) : 
         2.0 / (2.0 + (period - 1.0) / 2.0)
    
    len = 0., SumX = 0., SumX2 = 0.
    SumY = 0., SumY2 = 0., SumXY = 0.
    
    if (len != period)
        len := period, SumX := 0
        for k = 0 to period - 1 
            SumX += k + 1
        SumX2 := 0
        for k = 0 to period - 1 
            SumX2 += (k + 1) * (k + 1)
   
    for k = 0 to period - 1 
        tprice = nz(src[k])
        SumY += tprice
        SumY2 += math.pow(tprice, 2)
        SumXY += (k + 1) * tprice
        
    Q1 = SumXY - SumX * SumY / period
    Q2 = SumX2 - SumX * SumX / period
    Q3 = SumY2 - SumY * SumY / period
    hot = factor
    if adapt
        hot := Q2 * Q3 != 0 ? 
                 trendFollow ? 
                     math.max(1.0 - (Q1 * Q1 / (Q2 * Q3)), 0.01) : 
                     math.max((Q1 * Q1 / (Q2 * Q3)), 0.01) : 0.
    t31 = src, t32 = src, t33 = src
    t34 = src, t35 = src, t36 = src
    price = 0.
    
    t31 := nz(t31[1]) + alpha * (src - nz(t31[1]))
    t32 := nz(t32[1]) + alpha * (t31 - nz(t32[1]))

    price := (1.0 + hot) * t31 - hot * t32
    t33 := nz(t33[1]) + alpha * (price - nz(t33[1]))
    t34 := nz(t34[1]) + alpha * (t33 - nz(t34[1]))

    price := (1.0 + hot) * t33 - hot * t34
    t35 := nz(t35[1]) + alpha * (price - nz(t35[1]))
    t36 := nz(t36[1]) + alpha * (t35 - nz(t36[1]))
    out = ((1.0 + hot) * t35 - hot * t36)
    out
    
_calcBaseUnit() =>
    bool isForexSymbol = syminfo.type == "forex"
    bool isYenPair = syminfo.currency == "JPY"
    float out = isForexSymbol ? isYenPair ? 0.01 : 0.0001 : syminfo.mintick
    out
    
_stepSizeCalc(type, per, sense, size)=>
    float stma = 0.
    float ATR0 = 0.
    float ATRmax = 0.
    float ATRmin = 0.
    float out = 0
    float alfa = 0
    if (size == 0) 
        float avgrng = 0
        float Weight = 0
        for i = per-1 to 0 
            if (type == "SMA")
                alfa := 1.0
            else
                alfa := 1.0 * (per - i) / per
            avgrng += alfa * (nz(high[i]) - nz(low[i]))
            Weight += alfa
        ATR0 := avgrng / Weight
        if (ATR0 > ATRmax) 
            ATRmax := ATR0
        if (ATR0 < ATRmin) 
            ATRmin := ATR0
        out := math.round(0.5 * sense * (ATRmax + ATRmin) / _calcBaseUnit())
    else
        out := sense * size
    out

per = input.int(14, "Period", group = "T3 Settings")
t3hot = input.float(0.7, "T3 Factor (non-adaptive only)", step = 0.01, maxval = 1, minval = 0, group = "T3 Settings")

orig = input.bool(false, "Original?", group = "T3 Settings")
fllwtrnd = input.bool(true, "Trend follow? (adaptive only)", group = "T3 Settings")
adapt = input.bool(true, "Make it Adaptive?", group = "T3 Settings")

MA_Mode = input.string("SMA", "MA Type", options = ["SMA", "LWMA"], group = "Stepping Settings")
Percentage = input.float(0, "Percentage", step = 0.1, group = "Stepping Settings", tooltip = "Percentage of Up/Down Moving")
stepsize = input.int(20, "Step size", group = "Stepping Settings") 
sense = input.float(5, "Sensivity", step = 0.1, minval = 0.1, group = "Stepping Settings") 
HighLow = input.bool(false, "High/Low mode?", group = "Stepping Settings") 

colorbars = input.bool(false, "Color bars?", group= "UI Options")
flat = input.bool(false, "Flat-level colroing?", group= "UI Options")
showSigs = input.bool(false, "Show signals?", group= "UI Options")

size = _stepSizeCalc(MA_Mode, per, sense, stepsize)
smax = 0., smin = 0.

if HighLow
    smax := _t3rSqrdAdapt(low, per, orig, fllwtrnd, adapt, t3hot)  + 2.0 * size * _calcBaseUnit()
    smin := _t3rSqrdAdapt(high, per, orig, fllwtrnd, adapt, t3hot)  - 2.0 * size * _calcBaseUnit()
else 
    smax := _t3rSqrdAdapt(low, per, orig, fllwtrnd, adapt, t3hot) + 2.0 * size * _calcBaseUnit()
    smin := _t3rSqrdAdapt(low, per, orig, fllwtrnd, adapt, t3hot)  - 2.0 * size * _calcBaseUnit()

trend = 0., out = 0.

trend := trend[1]

if (close > smax[1]) 
    trend := 1
if (close < smin[1]) 
    trend := -1

if (trend > 0) 
    if (smin < smin[1]) 
        smin := smin[1]
    out := smin + size * _calcBaseUnit()
else 
    if (smax > smax[1])
        smax := smax[1]
    out := smax - size * _calcBaseUnit()

val = out + Percentage / 100.0 * stepsize * _calcBaseUnit()
colorout = val > val[1] ? greencolor : val < val[1] ? redcolor : color.gray

goLong_pre = ta.crossover(val, val[1])
goShort_pre = ta.crossunder(val, val[1])

contSwitch = 0
contSwitch := nz(contSwitch[1])
contSwitch := goLong_pre ? 1 : goShort_pre ? -1 : contSwitch

goLong = goLong_pre and ta.change(contSwitch)
goShort = goShort_pre and ta.change(contSwitch)

plot(val,"Pips-Stepped, R-squared Adaptive T3", color = flat ? colorout : (contSwitch == 1  ? greencolor : redcolor), linewidth = 3)

barcolor(colorbars ? flat ? colorout : (contSwitch == 1  ? greencolor : redcolor) : na)

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

alertcondition(goLong, title="Long", message="Pips-Stepped, R-squared Adaptive T3 [Loxx]: Long\nSymbol: {{ticker}}\nPrice: {{close}}")
alertcondition(goShort, title="Short", message="Pips-Stepped, R-squared Adaptive T3 [Loxx]: Short\nSymbol: {{ticker}}\nPrice: {{close}}")


