Files

8.9 KiB
Raw Permalink Blame History

AFIRMA: Autoregressive FIR Moving Average

Standard Moving Averages assume linear or exponential weights. AFIRMA asks: what if we used signal processing window functions instead?

Property Value
Category Forecast
Inputs Source (close)
Parameters period, window (default WindowType.BlackmanHarris), leastSquares (default false)
Outputs Single series (Afirma)
Output range Tracks input
Warmup period bars
PineScript afirma.pine
  • AFIRMA is a Windowed Weighted Moving Average that replaces standard linear weighting with weights derived from signal processing window functions (...
  • Similar: TSF, LinReg | Complementary: Error metrics for accuracy | Trading note: Adaptive FIR Moving Average for forecasting; projects price using optimized FIR coefficients.
  • Validated against TA-Lib, Skender, and Tulip reference implementations where available.

AFIRMA is a Windowed Weighted Moving Average that replaces standard linear weighting with weights derived from signal processing window functions (Hanning, Hamming, Blackman, Blackman-Harris). This approach achieves specific frequency response characteristics tailored to noise reduction.

The optional Least Squares mode fits a linear regression to recent bars and blends the fitted values with original data, producing a hybrid smoothed-predicted output.

Historical Context

Moving averages traditionally use Simple (rectangular window), Weighted (triangular window), or Exponential (recursive) forms. The DSP community solved finite filter design decades ago using window functions to minimize spectral leakage (ringing artifacts at discontinuities).

AFIRMA applies these well-understood coefficients directly to price series. It is effectively an FIR filter where coefficients are determined solely by the chosen window function—no manual coefficient calculation required.

Architecture & Physics

AFIRMA maintains a sliding window of the last P prices and computes a weighted average using pre-calculated window coefficients.

Window Functions

Instead of linear weights (1, 2, 3...), AFIRMA generates weights using cosine-sum series:


w_k = a_0 + a_1 \cos\left(\frac{2\pi k}{P}\right) + a_2 \cos\left(\frac{4\pi k}{P}\right) + a_3 \cos\left(\frac{6\pi k}{P}\right)

where P is the period and k is the index from 0 to P-1.

Window Coefficients Main Lobe Side Lobe
Rectangular a_0=1 Narrowest 13 dB
Hanning a_0=0.5, a_1=-0.5 Medium 32 dB
Hamming a_0=0.54, a_1=-0.46 Medium 43 dB
Blackman a_0=0.42, a_1=-0.5, a_2=0.08 Wide 58 dB
Blackman-Harris a_0=0.35875, a_1=-0.48829, a_2=0.14128, a_3=-0.01168 Widest 92 dB

The default Blackman-Harris provides maximum side-lobe suppression (92 dB), ideal for financial data with non-Gaussian noise spikes.

Least Squares Mode

When leastSquares=true, AFIRMA performs an additional step after the base weighted average:

  1. Determine regression window: n = \min\left(\lfloor(P-1)/2\rfloor, 50\right)
  2. Fit linear regression to the most recent n bars (lags 0 to n-1)
  3. Create hybrid buffer: Use fitted values for lags 0 to n-1, original values for lags n to P-1
  4. Average the hybrid buffer: Simple mean of all P values

This produces a smoothed estimate that incorporates short-term trend extrapolation. The fitted portion projects recent momentum while the original portion anchors to historical context.

Note: Despite some references calling this "cubic polynomial fitting," the actual implementation uses linear regression (first-degree polynomial: y = \text{intercept} + \text{slope} \times x).

Mathematical Foundation

Base Filter Equation


\text{AFIRMA}_t = \frac{\sum_{k=0}^{P-1} w_k \cdot x_{t-k}}{\sum_{k=0}^{P-1} w_k}

where x is the input series and w_k are the window weights.

Window Coefficient Formulas

Hanning:


w_k = 0.5 - 0.5 \cos\left(\frac{2\pi k}{P}\right)

Hamming:


w_k = 0.54 - 0.46 \cos\left(\frac{2\pi k}{P}\right)

Blackman:


w_k = 0.42 - 0.5 \cos\left(\frac{2\pi k}{P}\right) + 0.08 \cos\left(\frac{4\pi k}{P}\right)

Blackman-Harris:


w_k = 0.35875 - 0.48829 \cos\left(\frac{2\pi k}{P}\right) + 0.14128 \cos\left(\frac{4\pi k}{P}\right) - 0.01168 \cos\left(\frac{6\pi k}{P}\right)

Least Squares Regression

Given regression window size n:


S_x = \frac{(n-1)n}{2}, \quad S_{x^2} = \frac{(n-1)n(2n-1)}{6}

S_y = \sum_{i=0}^{n-1} x_{t-i}, \quad S_{xy} = \sum_{i=0}^{n-1} i \cdot x_{t-i}

\text{slope} = \frac{n \cdot S_{xy} - S_x \cdot S_y}{n \cdot S_{x^2} - S_x^2}

\text{intercept} = \frac{S_y - \text{slope} \cdot S_x}{n}

Fitted value at lag i: \hat{x}_i = \text{intercept} + \text{slope} \cdot i

Final LS output:


\text{AFIRMA}_{LS} = \frac{1}{P} \left( \sum_{i=0}^{n-1} \hat{x}_i + \sum_{i=n}^{P-1} x_{t-i} \right)

Parameters

Parameter Default Range Description
Period ≥ 1 Window length (number of taps)
Window BlackmanHarris Enum Window function for weight generation
LeastSquares false bool Enable linear regression blending

Performance Profile

Operation Count (Streaming Mode)

Windowed FIR convolution — O(P) per bar where P = period (window length).

Operation Count Cost (cycles) Subtotal
RingBuffer write 1 ~2 cy ~2 cy
FIR convolution (P FMA ops) P ~1 cy ~P cy
Weight normalization 1 ~1 cy ~1 cy
LS regression (if enabled) n ~2 cy ~2n cy
NaN guard + state update 1 ~2 cy ~2 cy
Total (P=20) O(P) ~25 cy

O(P) per bar where P = window length. FMA-fused dot product dominates; LS regression adds O(n) where n = min(⌊(P1)/2⌋, 50).

Metric Value Notes
Complexity O(P) Convolution per bar
Allocations 0 Zero-allocation in Update and Batch spans
Warmup P bars WarmupPeriod = period

Quality Metrics

Metric Score Notes
Accuracy 9/10 Excellent noise suppression
Timeliness 6/10 Inherent FIR lag (~P/2 bars)
Overshoot 2/10 Minimal; no recursive amplification
Smoothness 10/10 Exceptional with Blackman-Harris

Validation

Library Status Notes
Pine Script Matches afirma.pine reference
Internal Batch, Streaming, Span modes consistent
TA-Lib N/A Not implemented
Skender N/A Not implemented

Window Comparison

For identical period, different windows trade smoothness for responsiveness:

Window Smoothness Lag Best For
Rectangular Low Lowest Equivalent to SMA
Hanning Medium Medium Balanced general use
Hamming Medium-High Medium Better spectral properties than Hanning
Blackman High Higher Noisy trending markets
BlackmanHarris Highest Highest Maximum noise rejection

Common Pitfalls

  1. Lag Increases with Smoothness: Blackman-Harris has the best noise rejection but also the most lag. For fast signals, consider Hanning or even Rectangular (which degrades to SMA).

  2. Least Squares Is Not Magic: LS mode adds trend extrapolation but can overshoot during reversals. It works best in trending markets, not choppy conditions.

  3. Large Periods Amplify Lag: FIR filters have inherent delay of approximately P/2 bars. Period 50 means ~25 bars of lag regardless of window choice.

  4. isNew Parameter Matters: When processing live ticks within the same bar, use Update(value, isNew: false). When a new bar opens, use isNew: true (default). Incorrect usage corrupts internal state.

  5. NaN Handling: Non-finite inputs (NaN, ±Infinity) are replaced with the last valid value. Consecutive NaN inputs maintain the last known good value. After Reset(), the first valid input establishes the baseline.

  6. Warmup Period: AFIRMA requires period bars before IsHot becomes true. During warmup, it uses available data with proportionally adjusted weights.

References

  • Harris, F. J. (1978). "On the use of windows for harmonic analysis with the discrete Fourier transform." Proceedings of the IEEE, 66(1), 51-83.
  • Nuttall, A. H. (1981). "Some windows with very good sidelobe behavior." IEEE Transactions on Acoustics, Speech, and Signal Processing, 29(1), 84-91.