mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-24 13:38:05 +00:00
61 lines
2.0 KiB
Plaintext
61 lines
2.0 KiB
Plaintext
// The MIT License (MIT)
|
||||
|
|
// © mihakralj
|
|||
|
|
//@version=6
|
|||
|
|
indicator("Linear Trend Moving Average (LTMA)", "LTMA", overlay=true)
|
|||
|
|
|
|||
|
|
//@function Calculates Linear Trend MA using dual EMA with linear extrapolation
|
|||
|
|
//@param source Series to smooth
|
|||
|
|
//@param period Lookback period (determines alpha = 2/(period+1))
|
|||
|
|
//@returns LTMA value: EMA-based linear trend projection from first bar
|
|||
|
|
//@description LTMA tracks both level and slope using two cascaded EMAs,
|
|||
|
|
// then extrapolates the linear trend forward. Unlike DEMA (which cancels
|
|||
|
|
// first-order lag via 2×EMA1 − EMA2), LTMA estimates the instantaneous
|
|||
|
|
// slope from the EMA difference and projects it forward by the full period:
|
|||
|
|
// slope = (EMA1 − EMA2) / (decay − 1)
|
|||
|
|
// LTMA = EMA1 + slope × period
|
|||
|
|
// where decay = (1 − alpha). This produces a predictive moving average
|
|||
|
|
// that follows linear trends with zero steady-state error.
|
|||
|
|
// Uses §2 exponential warmup compensator on both EMAs (e*=beta,
|
|||
|
|
// c=1/(1-e)) for valid output from bar 1.
|
|||
|
|
ltma(series float source, simple int period) =>
|
|||
|
|
if period <= 0
|
|||
|
|
runtime.error("Period must be greater than 0")
|
|||
|
|
float alpha = 2.0 / (period + 1)
|
|||
|
|
float beta = 1.0 - alpha
|
|||
|
|
|
|||
|
|
var bool warmup = true
|
|||
|
|
var float e = 1.0
|
|||
|
|
var float ema1 = 0.0
|
|||
|
|
var float ema2 = 0.0
|
|||
|
|
var float result = source
|
|||
|
|
|
|||
|
|
float src = nz(source)
|
|||
|
|
|
|||
|
|
ema1 := alpha * (src - ema1) + ema1
|
|||
|
|
ema2 := alpha * (ema1 - ema2) + ema2
|
|||
|
|
|
|||
|
|
if warmup
|
|||
|
|
e *= beta
|
|||
|
|
float c = 1.0 / (1.0 - e)
|
|||
|
|
float comp1 = c * ema1
|
|||
|
|
float comp2 = c * ema2
|
|||
|
|
float slope = comp1 - comp2
|
|||
|
|
result := comp1 + slope * period
|
|||
|
|
warmup := e > 1e-10
|
|||
|
|
else
|
|||
|
|
float slope = ema1 - ema2
|
|||
|
|
result := ema1 + slope * period
|
|||
|
|
result
|
|||
|
|
|
|||
|
|
// ---------- Main loop ----------
|
|||
|
|
|
|||
|
|
// Inputs
|
|||
|
|
i_period = input.int(14, "Period", minval=1)
|
|||
|
|
i_source = input.source(close, "Source")
|
|||
|
|
|
|||
|
|
// Calculation
|
|||
|
|
ltma_value = ltma(i_source, period=i_period)
|
|||
|
|
|
|||
|
|
// Plot
|
|||
|
|
plot(ltma_value, "LTMA", color=color.yellow, linewidth=2)
|