feat: add new indicators (Decay, Edecay, MinusDi, MinusDm, PlusDi, PlusDm, Maxindex, Minindex, Sarext) and update pine scripts, core libs, validation tests, and python bindings
2026-03-09 13:45:46 -07:00
|
|
|
// Licensed under the Apache License, Version 2.0
|
2026-01-18 19:02:03 -08:00
|
|
|
// © mihakralj
|
|
|
|
|
//@version=6
|
|
|
|
|
indicator("Triple Exponential Moving Average (TEMA)", "TEMA", overlay=true)
|
|
|
|
|
|
|
|
|
|
//@function Calculates TEMA using triple exponential smoothing with compensator
|
|
|
|
|
//@param source Series to calculate TEMA from
|
|
|
|
|
//@param period Lookback period for TEMA calculation
|
|
|
|
|
//@param alpha Optional smoothing factor (overrides period if provided)
|
|
|
|
|
//@param corrected Use diminishing alpha factors for each stage
|
|
|
|
|
//@returns TEMA value from first bar with proper compensation
|
|
|
|
|
//@optimized Uses exponential warmup compensator on all three EMA stages for O(1) complexity
|
|
|
|
|
tema(series float source, simple int period=0, simple float alpha=0.0, simple bool corrected=false) =>
|
|
|
|
|
float a1 = alpha > 0 ? alpha : (period > 0 ? 2.0 / (period + 1) : 0.1)
|
|
|
|
|
float r = math.pow(1.0 / a1, 1.0 / 3.0)
|
|
|
|
|
float a2 = corrected ? a1 * r : a1
|
|
|
|
|
float a3 = corrected ? a2 * r : a1
|
|
|
|
|
float beta1 = 1.0 - a1
|
|
|
|
|
float beta2 = 1.0 - a2
|
|
|
|
|
float beta3 = 1.0 - a3
|
|
|
|
|
var float e1 = 1.0
|
|
|
|
|
var float e2 = 1.0
|
|
|
|
|
var float e3 = 1.0
|
|
|
|
|
var bool warmup = true
|
|
|
|
|
var float rema1 = 0.0
|
|
|
|
|
var float rema2 = 0.0
|
|
|
|
|
var float rema3 = 0.0
|
|
|
|
|
var float ema1 = source
|
|
|
|
|
var float ema2 = source
|
|
|
|
|
var float ema3 = source
|
|
|
|
|
rema1 := a1 * (source - rema1) + rema1
|
|
|
|
|
if warmup
|
|
|
|
|
e1 *= beta1
|
|
|
|
|
e2 *= beta2
|
|
|
|
|
e3 *= beta3
|
|
|
|
|
float c1 = 1.0 / (1.0 - e1)
|
|
|
|
|
float c2 = 1.0 / (1.0 - e2)
|
|
|
|
|
float c3 = 1.0 / (1.0 - e3)
|
|
|
|
|
ema1 := rema1 * c1
|
|
|
|
|
rema2 := a2 * (ema1 - rema2) + rema2
|
|
|
|
|
ema2 := rema2 * c2
|
|
|
|
|
rema3 := a3 * (ema2 - rema3) + rema3
|
|
|
|
|
ema3 := rema3 * c3
|
|
|
|
|
warmup := e1 > 1e-10
|
|
|
|
|
else
|
|
|
|
|
ema1 := rema1
|
|
|
|
|
rema2 := a2 * (ema1 - rema2) + rema2
|
|
|
|
|
ema2 := rema2
|
|
|
|
|
rema3 := a3 * (ema2 - rema3) + rema3
|
|
|
|
|
ema3 := rema3
|
|
|
|
|
3 * ema1 - 3 * ema2 + ema3
|
|
|
|
|
|
|
|
|
|
// ---------- Main loop ----------
|
|
|
|
|
|
|
|
|
|
// Inputs
|
|
|
|
|
i_period = input.int(10, "Period", minval=1)
|
|
|
|
|
i_source = input.source(close, "Source")
|
|
|
|
|
|
|
|
|
|
// Calculation
|
|
|
|
|
tema_value = tema(i_source, period=i_period)
|
|
|
|
|
|
|
|
|
|
// Plot
|
|
|
|
|
plot(tema_value, "TEMA", color=color.yellow, linewidth=2)
|