Files
QuanTAlib/lib/trends_FIR/qrma/Qrma.md
T
Miha Kralj 90d5638008 Add new moving average implementations: LTMA, MCNMA, NLMA, NMA, NYQMA, RAIN, and TRAMA
- LTMA (Linear Trend Moving Average): Introduces a predictive moving average using dual cascaded EMAs for trend estimation.
- MCNMA (McNicholl EMA): Implements a zero-lag TEMA using a cascaded EMA structure for enhanced responsiveness.
- NLMA (Non-Lag Moving Average): Utilizes a damped cosine kernel to achieve reduced lag in moving averages.
- NMA (Natural Moving Average): Adapts smoothing based on volatility profiles using a square-root kernel.
- NYQMA (Nyquist Moving Average): Applies the Nyquist-Shannon theorem to prevent aliasing in cascaded moving averages.
- RAIN (Rainbow Moving Average): Combines multiple SMA layers with weighted averages for multi-scale smoothing.
- TRAMA (Trend Regularity Adaptive Moving Average): Adapts smoothing based on the frequency of new highs and lows in price data.
2026-02-20 21:40:32 -08:00

4.7 KiB
Raw Blame History

QRMA: Quadratic Regression Moving Average

"Linear regression assumes the world is a straight line. Quadratic regression admits it might curve. For parabolic price moves, that admission turns out to be worth 40% less endpoint error."

QRMA fits a second-degree polynomial y = a + bx + cx^2 to the most recent N bars via ordinary least squares, then returns the fitted value at the endpoint (newest bar). By capturing curvature that LSMA (degree-1) misses, QRMA provides meaningfully better tracking of accelerating or decelerating price trends. The 3x3 normal-equation system is solved via Cramer's rule in O(1) after an O(N) data accumulation pass, making it computationally efficient and suitable for streaming applications.

Historical Context

Quadratic regression applied to time-series smoothing is a special case of the Savitzky-Golay filter (1964) with polynomial degree 2. Savitzky and Golay showed that polynomial least-squares fitting over a sliding window produces FIR filter coefficients equivalent to convolution, and that these coefficients preserve polynomial trends of degree \leq d while suppressing higher-order components.

QRMA sits between LSMA (degree-1, captures slope only) and CRMA (degree-3, captures inflection). The degree-2 model adds one parameter (curvature c) relative to linear regression, which is sufficient to track parabolic moves, acceleration phases, and the initial curvature of trend reversals. For most financial time series, degree-2 captures the dominant non-linearity without the fitting instability that arises with higher degrees on noisy data.

The x-indexing convention matters for numerical stability. QRMA uses x = 0 for the oldest bar and x = N-1 for the newest, evaluating the polynomial at x = N-1 (the endpoint). This avoids the large-exponent cancellation errors that arise when evaluating at x = 0 with the "newest=0" convention (where the polynomial coefficients must reconstruct the signal from high powers of N-1).

Architecture & Physics

1. Analytical X-Sums

The x-index power sums (\sum x, \sum x^2, \sum x^3, \sum x^4) are computed from Faulhaber's closed-form formulas, depending only on N. These are effectively constants for fixed period.

2. Data-Dependent Y-Sums

A single O(N) pass over the circular buffer accumulates \sum y, \sum xy, and \sum x^2 y.

3. Cramer's Rule Solution

The 3x3 normal-equation system is solved via Cramer's rule (determinant ratios), which is numerically stable for well-conditioned systems and avoids the overhead of Gaussian elimination. A singularity guard (determinant < 10^{-20}) returns the raw price for degenerate inputs.

4. Endpoint Evaluation

The fitted polynomial a + b(N-1) + c(N-1)^2 is evaluated at the newest bar.

Mathematical Foundation

The quadratic regression minimizes:


\min_{a, b, c} \sum_{k=0}^{N-1} \left( y_k - a - bk - ck^2 \right)^2

The normal equations form a 3x3 system:


\begin{bmatrix} N & S_1 & S_2 \\ S_1 & S_2 & S_3 \\ S_2 & S_3 & S_4 \end{bmatrix} \begin{bmatrix} a \\ b \\ c \end{bmatrix} = \begin{bmatrix} \sum y \\ \sum ky \\ \sum k^2 y \end{bmatrix}

where S_m = \sum_{k=0}^{N-1} k^m has closed forms:


S_1 = \frac{N(N-1)}{2}, \quad S_2 = \frac{N(N-1)(2N-1)}{6}

S_3 = \left[\frac{N(N-1)}{2}\right]^2, \quad S_4 = \frac{N(N-1)(2N-1)(3N^2-3N-1)}{30}

Cramer's rule: With coefficient matrix \mathbf{D} and right-hand side \mathbf{r}:


a = \frac{\det(\mathbf{D}_a)}{\det(\mathbf{D})}, \quad b = \frac{\det(\mathbf{D}_b)}{\det(\mathbf{D})}, \quad c = \frac{\det(\mathbf{D}_c)}{\det(\mathbf{D})}

Endpoint value: \text{QRMA} = a + b(N-1) + c(N-1)^2

Default parameters: period = 14, minPeriod = 3 (minimum for degree-2 fit).

Pseudo-code (streaming):

buffer ← circular_buffer(period)
buffer.push(price)
if count < period: return price

// Analytical x-sums (constants for fixed N)
S1 = N*(N-1)/2;  S2 = N*(N-1)*(2N-1)/6
S3 = S1²;        S4 = N*(N-1)*(2N-1)*(3N²-3N-1)/30

// Data sums (O(N) pass)
sy = 0; sxy = 0; sx2y = 0
for j = 0 to N-1:
    val = buffer[j]  // oldest to newest
    sy += val; sxy += j*val; sx2y += j²*val

// 3×3 Cramer's rule
det = N*(S2*S4 - S3²) - S1*(S1*S4 - S3*S2) + S2*(S1*S3 - S2²)
if |det| < 1e-20: return price
a = cramer_a(det, sy, sxy, sx2y, ...)
b = cramer_b(det, ...)
c = cramer_c(det, ...)

return a + b*(N-1) + c*(N-1)²

Resources

  • Savitzky, A. & Golay, M.J.E. (1964). "Smoothing and Differentiation of Data by Simplified Least Squares Procedures." Analytical Chemistry, 36(8), 1627-1639.
  • Schafer, R.W. (2011). "What Is a Savitzky-Golay Filter?" IEEE Signal Processing Magazine, 28(4), 111-117.
  • Press, W.H. et al. (2007). Numerical Recipes, 3rd ed. Cambridge University Press. Section 3.5: Least-Squares Fitting.