mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-25 05:48:06 +00:00
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.
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
# CRMA: Cubic Regression Moving Average
|
||||
|
||||
> "Linear regression tells you where the trend is going. Quadratic regression tells you it's curving. Cubic regression tells you the curve is changing its mind."
|
||||
|
||||
CRMA fits a degree-3 polynomial $y = a_0 + a_1 x + a_2 x^2 + a_3 x^3$ to the most recent $N$ bars via ordinary least squares, then returns the fitted endpoint value $a_0$. By capturing inflection and curvature that linear and quadratic models miss, CRMA tracks S-shaped reversals and accelerating trends with measurably lower endpoint error than LSMA or QRMA on non-stationary price series. The cost is a 4x4 linear system solve per bar, which is O(1) once power sums are accumulated in O(N).
|
||||
|
||||
## Historical Context
|
||||
|
||||
Polynomial regression as a smoothing technique dates to Legendre (1805) and Gauss (1809), who independently developed the method of least squares. The specific application of cubic (degree-3) polynomial fitting to financial time series emerged from the broader Savitzky-Golay filtering framework published in 1964, which showed that polynomial regression over a sliding window produces FIR filter coefficients with desirable frequency-domain properties.
|
||||
|
||||
CRMA occupies the sweet spot in the polynomial hierarchy. Degree-1 (LSMA) captures only linear trends. Degree-2 (QRMA) adds curvature but misses inflection points. Degree-3 (CRMA) captures inflection, the point where acceleration changes sign, which is precisely where trend reversals begin. Degree-4 and above risk Runge's phenomenon: oscillatory artifacts near window edges that amplify noise rather than suppress it.
|
||||
|
||||
The key implementation difference from textbook polynomial regression is the x-indexing convention. CRMA uses $x = 0$ for the newest bar and $x = N-1$ for the oldest. This means the fitted endpoint is simply $a_0$, the intercept, avoiding the numerical instability of evaluating $a_0 + a_1(N-1) + a_2(N-1)^2 + a_3(N-1)^3$ with large $N$.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Normal Equations Assembly
|
||||
|
||||
The polynomial fit requires solving $\mathbf{M} \cdot \mathbf{a} = \mathbf{r}$ where:
|
||||
|
||||
$$
|
||||
M_{ij} = \sum_{k=0}^{N-1} x_k^{i+j}, \quad r_i = \sum_{k=0}^{N-1} x_k^i \cdot y_k, \quad i,j \in \{0,1,2,3\}
|
||||
$$
|
||||
|
||||
Seven power sums ($S_0$ through $S_6$) and four cross-products ($r_0$ through $r_3$) are accumulated in a single O(N) pass over the circular buffer.
|
||||
|
||||
### 2. Gaussian Elimination with Partial Pivoting
|
||||
|
||||
The 4x4 augmented matrix is solved via Gaussian elimination with partial pivoting. Partial pivoting prevents division-by-zero and minimizes round-off amplification. The pivot search, row swap, and elimination are all O(1) operations on a fixed 4x4 system (64 element accesses, 48 multiply-adds).
|
||||
|
||||
### 3. Back-Substitution
|
||||
|
||||
After elimination produces an upper-triangular system, back-substitution extracts $a_3, a_2, a_1, a_0$ in four steps. The result $a_0$ is the fitted value at $x = 0$ (newest bar).
|
||||
|
||||
### 4. Singular Matrix Guard
|
||||
|
||||
If the pivot magnitude falls below $10^{-12}$, the system is treated as singular and the raw price is returned. This handles degenerate cases (e.g., all identical prices, $N < 4$ effective points).
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
The cubic regression minimizes the sum of squared residuals:
|
||||
|
||||
$$
|
||||
\min_{a_0, a_1, a_2, a_3} \sum_{k=0}^{N-1} \left( y_k - a_0 - a_1 x_k - a_2 x_k^2 - a_3 x_k^3 \right)^2
|
||||
$$
|
||||
|
||||
Setting partial derivatives to zero yields the 4x4 normal equation system:
|
||||
|
||||
$$
|
||||
\begin{bmatrix} S_0 & S_1 & S_2 & S_3 \\ S_1 & S_2 & S_3 & S_4 \\ S_2 & S_3 & S_4 & S_5 \\ S_3 & S_4 & S_5 & S_6 \end{bmatrix} \begin{bmatrix} a_0 \\ a_1 \\ a_2 \\ a_3 \end{bmatrix} = \begin{bmatrix} r_0 \\ r_1 \\ r_2 \\ r_3 \end{bmatrix}
|
||||
$$
|
||||
|
||||
Where:
|
||||
|
||||
$$
|
||||
S_m = \sum_{k=0}^{N-1} k^m, \quad r_m = \sum_{k=0}^{N-1} k^m \cdot y_k
|
||||
$$
|
||||
|
||||
The power sums $S_m$ have closed-form expressions (Faulhaber's formulas), but accumulating them in the data loop adds negligible cost and avoids large intermediate products.
|
||||
|
||||
**Default parameters:** `period = 14`, `minPeriod = 4` (minimum for degree-3 fit).
|
||||
|
||||
**Pseudo-code (streaming):**
|
||||
|
||||
```
|
||||
buffer ← circular_buffer(period)
|
||||
buffer.push(price)
|
||||
n ← min(bar_count, period)
|
||||
if n < 4: return price
|
||||
|
||||
// Accumulate sums in O(n)
|
||||
for i = 0 to n-1:
|
||||
x = i; x2 = x*x; x3 = x2*x
|
||||
S0 += 1; S1 += x; S2 += x2; S3 += x3
|
||||
S4 += x2*x2; S5 += x2*x3; S6 += x3*x3
|
||||
r0 += y[i]; r1 += x*y[i]; r2 += x2*y[i]; r3 += x3*y[i]
|
||||
|
||||
// Build 4×5 augmented matrix, solve via Gaussian elimination
|
||||
M = [[S0,S1,S2,S3,r0], [S1,S2,S3,S4,r1], [S2,S3,S4,S5,r2], [S3,S4,S5,S6,r3]]
|
||||
gaussian_eliminate_partial_pivot(M)
|
||||
a = back_substitute(M)
|
||||
return a[0] // fitted value at x=0 (newest bar)
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- Legendre, A.-M. (1805). *Nouvelles méthodes pour la détermination des orbites des comètes*. Firmin Didot.
|
||||
- Gauss, C.F. (1809). *Theoria motus corporum coelestium*. Perthes et Besser.
|
||||
- Savitzky, A. & Golay, M.J.E. (1964). "Smoothing and Differentiation of Data by Simplified Least Squares Procedures." *Analytical Chemistry*, 36(8), 1627-1639.
|
||||
- Press, W.H. et al. (2007). *Numerical Recipes*, 3rd ed. Cambridge University Press. Chapter 15: Modeling of Data.
|
||||
@@ -0,0 +1,78 @@
|
||||
# HEND: Henderson Moving Average
|
||||
|
||||
> "Robert Henderson designed a filter so good that the Australian Bureau of Statistics still uses it a century later. When your smoothing algorithm outlasts empires, you did something right."
|
||||
|
||||
HEND is a symmetric FIR filter derived from the Henderson (1916) closed-form weight formula, designed to pass cubic polynomial trends without distortion while maximally suppressing irregular noise. Used as the core smoother in the X-11 and X-13ARIMA-SEATS seasonal adjustment frameworks by statistical agencies worldwide, HEND achieves the theoretically optimal trade-off between smoothness (measured by the sum of squared third differences of the weights) and fidelity for cubic trends. Weights can be negative at the edges, giving the filter a bandpass-like property that sharpens trend-cycle extraction.
|
||||
|
||||
## Historical Context
|
||||
|
||||
Robert Henderson published the weight formula in 1916 in the *Transactions of the Actuarial Society of America*, motivated by the need to graduate mortality tables without distorting underlying polynomial trends. The U.S. Census Bureau adopted Henderson filters as the trend-cycle component of the X-11 method (Shiskin, Young, and Musgrave, 1967), where 5, 9, 13, and 23-point Henderson filters became standard choices. The Australian Bureau of Statistics (ABS) uses the 13-point Henderson as its default trend estimator for quarterly national accounts.
|
||||
|
||||
Henderson's filter has a unique property among polynomial-preserving smoothers: it minimizes the sum of squared third differences of the filter weights subject to the constraint that polynomials up to degree 3 pass through unchanged. This optimality criterion produces smoother weight sequences than Savitzky-Golay filters of the same polynomial order, at the cost of a fixed (non-configurable) smoothness-fidelity balance.
|
||||
|
||||
The requirement for odd period length ($N \geq 5$) stems from the symmetric weight structure. Even-length Henderson filters are mathematically possible but break the centered-symmetry property that guarantees zero phase distortion.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Weight Computation (One-Time)
|
||||
|
||||
Weights are computed from Henderson's closed-form formula:
|
||||
|
||||
$$
|
||||
w(k) = \frac{315 \left[(n-1)^2 - k^2\right]\left[n^2 - k^2\right]\left[(n+1)^2 - k^2\right]\left[3n^2 - 16 - 11k^2\right]}{8n(n^2-1)(4n^2-1)(4n^2-9)(4n^2-25)}
|
||||
$$
|
||||
|
||||
where $n = (N+3)/2$ and $k$ ranges from $-(N-1)/2$ to $(N-1)/2$. Weights are normalized to sum to 1.0 after computation.
|
||||
|
||||
### 2. Symmetric Convolution
|
||||
|
||||
The filter applies as a standard FIR convolution over the circular buffer. Because weights are symmetric ($w(k) = w(-k)$), the implementation can exploit symmetry to halve multiplications, though the normalization step makes this optional.
|
||||
|
||||
### 3. Negative Edge Weights
|
||||
|
||||
Unlike most window-based averages, Henderson weights are negative at the extremes of the window. This is not a bug; it is the mechanism by which the filter suppresses low-frequency drift that would distort cubic trends. The negative wings act as a gentle high-pass correction.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
The Henderson filter minimizes:
|
||||
|
||||
$$
|
||||
\min_{\{w_k\}} \sum_{k} (\Delta^3 w_k)^2 \quad \text{subject to} \quad \sum_{k} k^j w_k = \delta_{j0}, \quad j = 0, 1, 2, 3
|
||||
$$
|
||||
|
||||
where $\Delta^3$ is the third-difference operator. The constraints ensure that constant, linear, quadratic, and cubic polynomials are reproduced exactly.
|
||||
|
||||
The closed-form solution with $n = (N+3)/2$, $k \in [-(N-1)/2, (N-1)/2]$:
|
||||
|
||||
$$
|
||||
w(k) = \frac{315 \cdot \left[(n-1)^2 - k^2\right]\left[n^2 - k^2\right]\left[(n+1)^2 - k^2\right]\left[3n^2 - 16 - 11k^2\right]}{8n(n^2-1)(4n^2-1)(4n^2-9)(4n^2-25)}
|
||||
$$
|
||||
|
||||
**Frequency response:** The Henderson filter has zeros at specific frequencies determined by the polynomial-preservation constraints. For the 13-point filter, sidelobe attenuation exceeds $-40$ dB.
|
||||
|
||||
**Default parameters:** `period = 7` (must be odd, $\geq 5$).
|
||||
|
||||
**Pseudo-code (streaming):**
|
||||
|
||||
```
|
||||
// One-time weight computation
|
||||
half = (period - 1) / 2
|
||||
n = (period + 3) / 2
|
||||
for k = -half to half:
|
||||
w[k] = 315 * ((n-1)²-k²) * (n²-k²) * ((n+1)²-k²) * (3n²-16-11k²)
|
||||
/ [8n(n²-1)(4n²-1)(4n²-9)(4n²-25)]
|
||||
normalize(w)
|
||||
|
||||
// Per-bar convolution
|
||||
buffer.push(price)
|
||||
if count < period: return price
|
||||
result = Σ buffer[j] * w[j] for j = 0..period-1
|
||||
return result
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- Henderson, R. (1916). "Note on Graduation by Adjusted Average." *Transactions of the Actuarial Society of America*, 17, 43-48.
|
||||
- Shiskin, J., Young, A.H., & Musgrave, J.C. (1967). "The X-11 Variant of the Census Method II Seasonal Adjustment Program." Technical Paper 15, U.S. Bureau of the Census.
|
||||
- Hyndman, R.J. (2011). "Moving Averages." In *International Encyclopedia of Statistical Science*. Springer.
|
||||
- Kenny, P.B. & Durbin, J. (1982). "Local Trend Estimation and Seasonal Adjustment of Economic and Social Time Series." *JRSS Series A*, 145(1), 1-41.
|
||||
@@ -0,0 +1,99 @@
|
||||
# ILRS: Integral of Linear Regression Slope
|
||||
|
||||
> "John Ehlers took the slope of a regression line, integrated it, and got a smoother trend follower. Differentiate to find direction, integrate to find position. Calculus: still useful after 300 years."
|
||||
|
||||
ILRS computes the linear regression slope over a rolling window, then accumulates it via discrete integration (running sum) to reconstruct a smoothed price-level signal. By differentiating (slope extraction) and reintegrating, ILRS acts as a low-pass filter that preserves trend direction while suppressing high-frequency noise more aggressively than LSMA. The integration step introduces a natural momentum quality: the output continues rising even as slope magnitude diminishes, making ILRS particularly effective for trend-following systems that need early exit signals based on slope deceleration.
|
||||
|
||||
## Historical Context
|
||||
|
||||
John Ehlers introduced ILRS in *Rocket Science for Traders* (Wiley, 2001) as part of his signal-processing approach to technical analysis. Ehlers recognized that most moving averages are essentially low-pass filters applied directly to price, but the differentiate-then-integrate approach offers a different noise profile. The linear regression slope acts as a first-derivative estimator, and the running sum reconstructs the original signal minus the high-frequency components that the regression window cannot track.
|
||||
|
||||
The concept has deep roots in control theory and signal processing. The "differentiate and integrate" technique is standard in PID controllers and phase-locked loops, where it provides better noise rejection than direct filtering when the signal's derivative is smoother than the signal itself. In financial time series, this condition holds when price changes are more persistent than price levels, a reasonable assumption during trending regimes.
|
||||
|
||||
ILRS differs from LSMA (which evaluates the regression line at the endpoint) in a crucial way: LSMA's output is bounded by the regression window, while ILRS accumulates indefinitely. This makes ILRS a non-stationary filter whose output drifts with the integrated slope, requiring periodic resynchronization to avoid floating-point drift over very long series.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Rolling Linear Regression Slope
|
||||
|
||||
The slope is computed via the standard least-squares formula over the circular buffer:
|
||||
|
||||
$$
|
||||
\text{slope} = \frac{N \sum x_i y_i - \sum x_i \sum y_i}{N \sum x_i^2 - \left(\sum x_i\right)^2}
|
||||
$$
|
||||
|
||||
The x-index sums ($\sum x$, $\sum x^2$) are computed analytically (Faulhaber's formulas), reducing the per-bar cost to a single O(N) pass for the y-dependent sums.
|
||||
|
||||
### 2. Discrete Integration
|
||||
|
||||
The integral is a simple running sum:
|
||||
|
||||
$$
|
||||
\text{ILRS}_t = \text{ILRS}_{t-1} + \text{slope}_t
|
||||
$$
|
||||
|
||||
This is O(1) per bar after the slope is computed.
|
||||
|
||||
### 3. Initialization
|
||||
|
||||
The integral is initialized to the first price value, ensuring the output starts at a reasonable level rather than zero.
|
||||
|
||||
### 4. Drift Management
|
||||
|
||||
Because ILRS accumulates slope indefinitely, floating-point precision degrades over millions of bars. A periodic resynchronization (e.g., every 1000 bars, re-anchor to slope-implied price) prevents meaningful drift.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
Given a window of $N$ prices $y_0, y_1, \ldots, y_{N-1}$ (oldest to newest), the regression slope is:
|
||||
|
||||
$$
|
||||
b = \frac{N \sum_{i=0}^{N-1} i \cdot y_i - \left(\sum_{i=0}^{N-1} i\right)\left(\sum_{i=0}^{N-1} y_i\right)}{N \sum_{i=0}^{N-1} i^2 - \left(\sum_{i=0}^{N-1} i\right)^2}
|
||||
$$
|
||||
|
||||
With analytical x-sums:
|
||||
|
||||
$$
|
||||
\sum i = \frac{N(N-1)}{2}, \quad \sum i^2 = \frac{N(N-1)(2N-1)}{6}
|
||||
$$
|
||||
|
||||
The ILRS output:
|
||||
|
||||
$$
|
||||
\text{ILRS}_t = \text{ILRS}_{t-1} + b_t, \quad \text{ILRS}_0 = y_0
|
||||
$$
|
||||
|
||||
**Default parameters:** `period = 14`, `minPeriod = 2`.
|
||||
|
||||
**Pseudo-code (streaming):**
|
||||
|
||||
```
|
||||
buffer ← circular_buffer(period)
|
||||
buffer.push(price)
|
||||
n ← min(bar_count, period)
|
||||
|
||||
if n < 2:
|
||||
integral ← price
|
||||
return integral
|
||||
|
||||
// Analytical x-sums
|
||||
sumX = n*(n-1)/2
|
||||
sumX2 = n*(n-1)*(2n-1)/6
|
||||
|
||||
// Data-dependent y-sums (O(n) pass)
|
||||
sumY = 0; sumXY = 0
|
||||
for i = 0 to n-1:
|
||||
sumY += buffer[i]
|
||||
sumXY += i * buffer[i]
|
||||
|
||||
denomX = n * sumX2 - sumX * sumX
|
||||
slope = (n * sumXY - sumX * sumY) / denomX
|
||||
|
||||
integral += slope
|
||||
return integral
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- Ehlers, J.F. (2001). *Rocket Science for Traders: Digital Signal Processing Applications*. John Wiley & Sons.
|
||||
- Ehlers, J.F. (2004). *Cybernetic Analysis for Stocks and Futures*. John Wiley & Sons.
|
||||
- Kendall, M.G. & Stuart, A. (1979). *The Advanced Theory of Statistics*, Vol. 2. Griffin. Chapter 29: Regression.
|
||||
@@ -0,0 +1,94 @@
|
||||
# KAISER: Kaiser Window Moving Average
|
||||
|
||||
> "James Kaiser gave signal processing a knob. Turn beta up, sidelobes go down, transition band widens. Turn it down, you get an SMA. One parameter to rule them all."
|
||||
|
||||
KAISER applies the Kaiser-Bessel window function as FIR filter weights, providing a single parameter ($\beta$) that continuously controls the trade-off between main lobe width (transition band sharpness) and sidelobe attenuation (stopband rejection). At $\beta = 0$ it degenerates to a rectangular window (SMA); at $\beta \approx 5.65$ it approximates the Blackman window; at $\beta \approx 8.6$ it matches the Hamming window's sidelobe profile. This makes KAISER the most flexible single-parameter window-based moving average, allowing traders to tune frequency selectivity without changing the window length.
|
||||
|
||||
## Historical Context
|
||||
|
||||
James F. Kaiser and Ronald W. Schafer published the Kaiser window in 1980, building on Kaiser's earlier work at Bell Labs in the 1960s. The window was motivated by a practical problem: given a desired sidelobe attenuation level, what is the shortest FIR filter that achieves it? Kaiser showed that the modified Bessel function of the first kind, $I_0$, produces near-optimal windows that closely approximate the prolate spheroidal wave functions (the theoretically optimal windows derived by Slepian in 1964) while being far simpler to compute.
|
||||
|
||||
The Kaiser window became the default design tool in DSP textbooks (Oppenheim & Schafer, Parks & Burrus) because of its parametric flexibility. In financial applications, this flexibility maps directly to a smoothness-responsiveness knob: low $\beta$ preserves fast price movements (less smoothing, sharper transitions), while high $\beta$ produces smoother output with greater lag (more attenuation of high-frequency price noise).
|
||||
|
||||
The $I_0$ Bessel function is computed via power series: $I_0(x) = \sum_{m=0}^{M} \left[\frac{(x/2)^m}{m!}\right]^2$. Twenty-five terms provide double-precision convergence for $\beta \leq 20$.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Bessel Function Approximation
|
||||
|
||||
The zeroth-order modified Bessel function $I_0(x)$ is evaluated via its power series with 25 terms. The series converges rapidly because the terms are squared factorials, guaranteeing monotonic decrease after the peak term.
|
||||
|
||||
### 2. Weight Computation (One-Time)
|
||||
|
||||
For each position $k \in [0, N-1]$, the normalized coordinate $t = 2k/(N-1) - 1$ maps to $[-1, 1]$. The Kaiser window value is:
|
||||
|
||||
$$
|
||||
w(k) = \frac{I_0\left(\beta \sqrt{1 - t^2}\right)}{I_0(\beta)}
|
||||
$$
|
||||
|
||||
Weights are normalized to sum to 1.0. The $\sqrt{1-t^2}$ argument is clamped to non-negative to handle floating-point edge cases.
|
||||
|
||||
### 3. FIR Convolution
|
||||
|
||||
Standard weighted sum over the circular buffer using precomputed weights. O(N) per bar.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
The Kaiser window function for a filter of length $N$:
|
||||
|
||||
$$
|
||||
w[k] = \frac{I_0\left(\beta\sqrt{1 - \left(\frac{2k}{N-1} - 1\right)^2}\right)}{I_0(\beta)}, \quad k = 0, 1, \ldots, N-1
|
||||
$$
|
||||
|
||||
where $I_0(x)$ is the zeroth-order modified Bessel function of the first kind:
|
||||
|
||||
$$
|
||||
I_0(x) = \sum_{m=0}^{\infty} \left[\frac{(x/2)^m}{m!}\right]^2
|
||||
$$
|
||||
|
||||
**Key $\beta$ values and their equivalences:**
|
||||
|
||||
| $\beta$ | Equivalent Window | Sidelobe (dB) | Transition BW |
|
||||
| :---: | :--- | :---: | :---: |
|
||||
| 0 | Rectangular (SMA) | $-13$ | $0.92/N$ |
|
||||
| 3.0 | General-purpose | $-33$ | $2.4/N$ |
|
||||
| 5.65 | Blackman-like | $-57$ | $3.6/N$ |
|
||||
| 8.6 | Hamming-like | $-90$ | $5.0/N$ |
|
||||
|
||||
**Kaiser's empirical formulas** (for filter design):
|
||||
|
||||
$$
|
||||
\beta = \begin{cases} 0.1102(A - 8.7) & A > 50 \\ 0.5842(A-21)^{0.4} + 0.07886(A-21) & 21 \leq A \leq 50 \\ 0 & A < 21 \end{cases}
|
||||
$$
|
||||
|
||||
where $A = -20\log_{10}(\delta)$ is the desired stopband attenuation in dB.
|
||||
|
||||
**Default parameters:** `period = 14`, `beta = 3.0`, `minPeriod = 2`.
|
||||
|
||||
**Pseudo-code (streaming):**
|
||||
|
||||
```
|
||||
// One-time: compute I0 and weights
|
||||
bessel_i0(x):
|
||||
sum = 1.0; term = 1.0; hx = x/2
|
||||
for m = 1 to 25: term *= hx/m; sum += term²
|
||||
return sum
|
||||
|
||||
i0_beta = bessel_i0(beta)
|
||||
for k = 0 to period-1:
|
||||
t = 2k/(N-1) - 1
|
||||
arg = sqrt(max(0, 1 - t²))
|
||||
w[k] = bessel_i0(beta * arg) / i0_beta
|
||||
normalize(w)
|
||||
|
||||
// Per-bar convolution
|
||||
buffer.push(price)
|
||||
if count < period: return price
|
||||
return Σ buffer[j] * w[j]
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- Kaiser, J.F. & Schafer, R.W. (1980). "On the Use of the I0-Sinh Window for Spectrum Analysis." *IEEE Trans. Acoust., Speech, Signal Process.*, ASSP-28(1), 105-107.
|
||||
- Oppenheim, A.V. & Schafer, R.W. (2009). *Discrete-Time Signal Processing*, 3rd ed. Prentice Hall. Section 7.4.
|
||||
- Slepian, D. (1964). "Prolate Spheroidal Wave Functions, Fourier Analysis and Uncertainty." *Bell System Technical Journal*, 43(6), 3009-3057.
|
||||
@@ -0,0 +1,82 @@
|
||||
# LANCZOS: Lanczos (Sinc) Window Moving Average
|
||||
|
||||
> "Cornelius Lanczos used the sinc function to reconstruct band-limited signals from discrete samples. Apply it to price data and you get a moving average that respects the Nyquist limit while your competitors are still using SMAs."
|
||||
|
||||
LANCZOS applies the normalized sinc function $\text{sinc}(x) = \sin(\pi x)/(\pi x)$ as a symmetric FIR window, producing a moving average with near-ideal low-pass frequency characteristics. The sinc function is the impulse response of the perfect brick-wall low-pass filter; windowing it to finite length trades sharp cutoff for practical realizability. The result is a smoother with minimal Gibbs phenomenon ringing and excellent passband flatness, at the cost of small negative sidelobe weights that can cause minor overshooting on sharp price discontinuities.
|
||||
|
||||
## Historical Context
|
||||
|
||||
Cornelius Lanczos (1893-1974) was a Hungarian-American mathematician and physicist who made foundational contributions to applied mathematics, including the Lanczos algorithm for eigenvalue computation, the Lanczos tau method for differential equations, and the Lanczos sigma factor for reducing Gibbs phenomenon in Fourier series. His 1956 book *Applied Analysis* introduced the sinc-based window that bears his name.
|
||||
|
||||
The Lanczos window is the simplest sinc-kernel window: a single lobe of the sinc function, truncated to the filter length. Higher-order Lanczos kernels (Lanczos-2, Lanczos-3) multiply $\text{sinc}(x) \cdot \text{sinc}(x/a)$ for sharper cutoff and are widely used in image resampling (e.g., the default resizer in FFmpeg and ImageMagick). For financial time series, the first-order Lanczos window provides a good balance between frequency selectivity and computational simplicity.
|
||||
|
||||
The key property distinguishing Lanczos from other window-based MAs is the sinc function's direct relationship to the ideal low-pass filter. While Hann, Hamming, and Blackman windows are ad-hoc designs optimized for sidelobe suppression, the Lanczos window starts from the theoretically optimal impulse response and truncates it, preserving the passband flatness that other windows sacrifice for sidelobe control.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Weight Computation (One-Time)
|
||||
|
||||
For each position $k \in [0, N-1]$, the normalized coordinate $x = 2k/(N-1) - 1$ maps to $[-1, 1]$. The Lanczos window value is:
|
||||
|
||||
$$
|
||||
w(k) = \text{sinc}(x) = \frac{\sin(\pi x)}{\pi x}, \quad w(0) = 1
|
||||
$$
|
||||
|
||||
The sinc function produces negative values for $|x| > 1$ in the general case, but within the $[-1, 1]$ window, negative weights appear only near the edges where $|x|$ approaches 1. These negative weights are retained (not clamped) for frequency-domain fidelity.
|
||||
|
||||
### 2. Normalization
|
||||
|
||||
Weights are normalized to sum to 1.0, ensuring the filter preserves constant (DC) signals exactly.
|
||||
|
||||
### 3. FIR Convolution
|
||||
|
||||
Standard weighted convolution over the circular buffer. O(N) per bar. The symmetric weight structure enables potential paired-multiplication optimization (summing symmetric buffer pairs before multiplying by the shared weight).
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
The Lanczos window for a filter of length $N$:
|
||||
|
||||
$$
|
||||
w[k] = \text{sinc}\!\left(\frac{2k}{N-1} - 1\right), \quad k = 0, 1, \ldots, N-1
|
||||
$$
|
||||
|
||||
where:
|
||||
|
||||
$$
|
||||
\text{sinc}(x) = \begin{cases} 1 & x = 0 \\ \frac{\sin(\pi x)}{\pi x} & x \neq 0 \end{cases}
|
||||
$$
|
||||
|
||||
**Frequency response:** The continuous sinc function has an ideal rectangular frequency response (brick-wall low-pass). Truncation introduces sidelobes at approximately $-13$ dB for the first sidelobe (comparable to the rectangular window), with subsequent sidelobes decaying as $1/f$. The passband flatness is superior to most other windows of the same length.
|
||||
|
||||
**Normalized output:**
|
||||
|
||||
$$
|
||||
\text{LANCZOS}_t = \frac{\sum_{k=0}^{N-1} w[k] \cdot x_{t-k}}{\sum_{k=0}^{N-1} w[k]}
|
||||
$$
|
||||
|
||||
**Default parameters:** `period = 14`, `minPeriod = 2`.
|
||||
|
||||
**Pseudo-code (streaming):**
|
||||
|
||||
```
|
||||
// One-time weight computation
|
||||
for k = 0 to period-1:
|
||||
x = 2k/(N-1) - 1
|
||||
if |x| < 1e-10:
|
||||
w[k] = 1.0
|
||||
else:
|
||||
w[k] = sin(π·x) / (π·x)
|
||||
normalize(w)
|
||||
|
||||
// Per-bar convolution
|
||||
buffer.push(price)
|
||||
if count < period: return price
|
||||
return Σ buffer[j] * w[j]
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- Lanczos, C. (1956). *Applied Analysis*. Prentice-Hall. Reprinted by Dover, 1988.
|
||||
- Duchon, C.E. (1979). "Lanczos Filtering in One and Two Dimensions." *Journal of Applied Meteorology*, 18(8), 1016-1022.
|
||||
- Oppenheim, A.V. & Schafer, R.W. (2009). *Discrete-Time Signal Processing*, 3rd ed. Prentice Hall. Section 7.2: Properties of Commonly Used Windows.
|
||||
- Turkowski, K. (1990). "Filters for Common Resampling Tasks." In *Graphics Gems I*, Academic Press. pp. 147-165.
|
||||
@@ -0,0 +1,93 @@
|
||||
# PARZEN: Parzen (de la Vallée-Poussin) Window Moving Average
|
||||
|
||||
> "Emanuel Parzen convolved two triangular windows and got a piecewise cubic with zero sidelobe discontinuity. When your window function is its own proof of smoothness, the spectral leakage has nowhere to hide."
|
||||
|
||||
PARZEN applies the Parzen (de la Vallée-Poussin) window function as FIR filter weights, producing a moving average with exceptional sidelobe suppression ($-24$ dB/octave rolloff) and a smooth bell-shaped kernel. The Parzen window is the self-convolution of two triangular (Bartlett) windows at half-length, which guarantees continuous first and second derivatives at all points. This makes it one of the few windows whose frequency response has no discontinuities in its first three derivatives, yielding the fastest sidelobe decay rate among common windows without requiring the computational cost of Bessel functions (Kaiser) or specialized polynomials (Henderson).
|
||||
|
||||
## Historical Context
|
||||
|
||||
Emanuel Parzen (1929-2016) introduced the window in a 1961 paper on spectral estimation in *Technometrics*, though the underlying function was studied earlier by de la Vallée-Poussin in the context of Fourier series summability. Parzen's contribution was to recognize the window's optimality properties for spectral density estimation: among all non-negative windows with continuous derivatives up to order 2, the Parzen window minimizes the integrated squared bias of the spectral estimate.
|
||||
|
||||
The Parzen window's construction as a convolution of two Bartlett windows gives it a natural interpretation: it is equivalent to computing the SMA of an SMA of half the period, twice. This "double triangular smoothing" produces the piecewise cubic shape without explicit polynomial computation. In the spectral domain, the convolution translates to multiplication: the Parzen frequency response is the square of the Bartlett frequency response, which explains the doubled sidelobe rolloff rate ($-24$ dB/octave vs. $-12$ dB/octave for Bartlett).
|
||||
|
||||
Compared to competing windows, Parzen trades main-lobe width for sidelobe suppression. Its main lobe is wider than Hann or Hamming (meaning more lag in the time domain), but its sidelobes decay faster than any other polynomial-based window. For financial applications where smooth trend extraction matters more than sharp frequency cutoff, this trade-off favors Parzen.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Piecewise Cubic Weight Function
|
||||
|
||||
The Parzen window is defined in two regions based on the normalized coordinate $|u| = |k - (N-1)/2| / ((N-1)/2)$:
|
||||
|
||||
- **Inner region** ($|u| \leq 0.5$): Cubic spline with positive curvature tapering from the peak.
|
||||
- **Outer region** ($0.5 < |u| \leq 1.0$): Cubic taper to zero at the window edge.
|
||||
|
||||
The two pieces join with continuous first and second derivatives at $|u| = 0.5$, ensuring no spectral artifacts from weight discontinuities.
|
||||
|
||||
### 2. Weight Normalization
|
||||
|
||||
Weights are normalized to sum to 1.0. Because all Parzen weights are non-negative, the filter output is always a convex combination of input prices (no overshoot possible from negative weights).
|
||||
|
||||
### 3. FIR Convolution
|
||||
|
||||
Standard weighted convolution over the circular buffer. O(N) per bar. The symmetric structure allows paired-element optimization for SIMD.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
For a window of length $N$, with normalized coordinate $u = (k - (N-1)/2) / ((N-1)/2)$, $k = 0, \ldots, N-1$:
|
||||
|
||||
$$
|
||||
w(k) = \begin{cases} 1 - 6u^2 + 6|u|^3 & |u| \leq 0.5 \\ 2(1 - |u|)^3 & 0.5 < |u| \leq 1.0 \\ 0 & |u| > 1.0 \end{cases}
|
||||
$$
|
||||
|
||||
**Frequency response properties:**
|
||||
|
||||
| Property | Value |
|
||||
| :--- | :--- |
|
||||
| Main lobe width ($-3$ dB) | $\approx 2.0/N$ |
|
||||
| First sidelobe | $-53$ dB |
|
||||
| Sidelobe rolloff | $-24$ dB/octave |
|
||||
| All weights non-negative | Yes |
|
||||
|
||||
**Equivalence to double convolution:**
|
||||
|
||||
$$
|
||||
w_{\text{Parzen}}[n] = w_{\text{Bartlett}}[n] * w_{\text{Bartlett}}[n]
|
||||
$$
|
||||
|
||||
where $*$ denotes discrete convolution and the Bartlett windows are of length $N/2$.
|
||||
|
||||
**Normalized output:**
|
||||
|
||||
$$
|
||||
\text{PARZEN}_t = \frac{\sum_{k=0}^{N-1} w[k] \cdot x_{t-k}}{\sum_{k=0}^{N-1} w[k]}
|
||||
$$
|
||||
|
||||
**Default parameters:** `period = 14`, `minPeriod = 2`.
|
||||
|
||||
**Pseudo-code (streaming):**
|
||||
|
||||
```
|
||||
// One-time weight computation
|
||||
half_N = (period - 1) / 2
|
||||
for k = 0 to period-1:
|
||||
u = (k - half_N) / half_N
|
||||
abs_u = |u|
|
||||
if abs_u <= 0.5:
|
||||
w[k] = 1 - 6*abs_u² + 6*abs_u³
|
||||
else if abs_u <= 1.0:
|
||||
w[k] = 2*(1 - abs_u)³
|
||||
else:
|
||||
w[k] = 0
|
||||
normalize(w)
|
||||
|
||||
// Per-bar convolution
|
||||
buffer.push(price)
|
||||
if count < period: return price
|
||||
return Σ buffer[j] * w[j]
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- Parzen, E. (1961). "Mathematical Considerations in the Estimation of Spectra." *Technometrics*, 3(2), 167-190.
|
||||
- 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 Trans. Acoust., Speech, Signal Process.*, 29(1), 84-91.
|
||||
@@ -0,0 +1,98 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,78 @@
|
||||
# RWMA: Range Weighted Moving Average
|
||||
|
||||
> "Most averages weight by position: recent bars matter more. RWMA weights by volatility: volatile bars matter more. The market spoke loudest when the range was widest, so listen to those bars."
|
||||
|
||||
RWMA weights each bar's contribution to the average by its price range (high minus low), giving greater influence to volatile bars and less to narrow-range, indecisive bars. The logic: a bar with a large range represents stronger price discovery and carries more informational content than a low-range doji. This produces a moving average that gravitates toward prices established during high-activity periods, naturally incorporating volatility as a relevance signal without requiring a separate volatility indicator.
|
||||
|
||||
## Historical Context
|
||||
|
||||
Range-weighted averaging is a practical adaptation of the general concept of precision-weighted means from statistics, where observations are weighted by the inverse of their variance (or, equivalently, by their "importance" or precision). In financial applications, bar range serves as a real-time proxy for intra-bar volatility, available without the computational overhead of standard deviation or ATR calculations.
|
||||
|
||||
The concept appears informally in trading literature from the 1990s, often attributed to floor-trader heuristics: "wide-range bars lead price," meaning that the closing prices of high-range bars tend to be more predictive of subsequent direction than those of narrow-range bars. RWMA formalizes this heuristic into a weighted average.
|
||||
|
||||
Unlike position-weighted averages (WMA, EMA) where the weighting scheme is fixed by the period, RWMA's weights are data-adaptive. The weight vector changes every bar based on the range profile of the lookback window. This makes RWMA inherently non-stationary: two windows with identical closing prices but different range profiles produce different RWMA values. The data-adaptive property also means RWMA cannot be expressed as a fixed-coefficient FIR filter, though its computation is structurally similar.
|
||||
|
||||
RWMA requires high and low price data (TBar inputs), making it inapplicable to single-valued series. When all bars have zero range (constant price), the denominator collapses to zero and the filter falls back to the raw source price.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Weight Computation
|
||||
|
||||
For each bar $i$ in the lookback window:
|
||||
|
||||
$$
|
||||
w_i = \max(\text{High}_i - \text{Low}_i, 0)
|
||||
$$
|
||||
|
||||
The $\max$ clamp ensures non-negative weights (relevant for synthetic data where high $<$ low might occur due to data errors).
|
||||
|
||||
### 2. Weighted Average
|
||||
|
||||
$$
|
||||
\text{RWMA} = \frac{\sum_{i=0}^{N-1} \text{Close}_i \cdot w_i}{\sum_{i=0}^{N-1} w_i}
|
||||
$$
|
||||
|
||||
If $\sum w_i = 0$ (all bars have zero range), the output degenerates to the current source price.
|
||||
|
||||
### 3. TBar Requirement
|
||||
|
||||
RWMA consumes TBar data (OHLC), not single-valued TValue. The C# implementation should accept `TBar` inputs and route `High`, `Low`, `Close` appropriately.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
Given a window of $N$ bars with close prices $c_i$, highs $h_i$, and lows $l_i$ (where $i = 0$ is newest):
|
||||
|
||||
$$
|
||||
\text{RWMA}_t = \frac{\sum_{i=0}^{N-1} c_{t-i} \cdot (h_{t-i} - l_{t-i})}{\sum_{i=0}^{N-1} (h_{t-i} - l_{t-i})}
|
||||
$$
|
||||
|
||||
**Properties:**
|
||||
|
||||
- **Convex combination:** All weights are non-negative, so the output is bounded by $[\min(c_i), \max(c_i)]$ within the window. No overshoot possible.
|
||||
- **Adaptive lag:** Lag shifts toward the position of the highest-range bars. If the most volatile bar is recent, lag decreases; if it is old, lag increases.
|
||||
- **Degeneracy:** When all ranges are zero, $\text{RWMA} = c_t$ (current close).
|
||||
|
||||
**Complexity:** O(N) per bar (single pass over the window).
|
||||
|
||||
**Default parameters:** `period = 14`, `minPeriod = 1`.
|
||||
|
||||
**Pseudo-code (streaming):**
|
||||
|
||||
```
|
||||
sumWV = 0; sumW = 0
|
||||
for i = 0 to period-1:
|
||||
range = max(high[i] - low[i], 0)
|
||||
sumWV += close[i] * range
|
||||
sumW += range
|
||||
|
||||
if sumW > 0:
|
||||
return sumWV / sumW
|
||||
else:
|
||||
return close[0]
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- Bollinger, J. (2001). *Bollinger on Bollinger Bands*. McGraw-Hill. (Discusses range-based volatility measures in the context of band-width indicators.)
|
||||
- Achelis, S.B. (2000). *Technical Analysis from A to Z*, 2nd ed. McGraw-Hill.
|
||||
- Garman, M.B. & Klass, M.J. (1980). "On the Estimation of Security Price Volatilities from Historical Data." *Journal of Business*, 53(1), 67-78. (Range-based volatility estimation from OHLC data.)
|
||||
@@ -0,0 +1,89 @@
|
||||
# SP15: Spencer 15-Point Moving Average
|
||||
|
||||
> "John Spencer designed 15 weights that zero out quarterly and quintile seasonality from economic data. Eighty years later, statisticians still reach for them when they need a quick seasonal adjustment that does not require the German engineering of X-13ARIMA."
|
||||
|
||||
SP15 is a fixed-coefficient symmetric FIR filter with 15 weights: $[-3, -6, -5, 3, 21, 46, 67, 74, 67, 46, 21, 3, -5, -6, -3]$ divided by 320. The weights were designed by John Spencer to have zero frequency response at periods 4 and 5 (frequencies $2\pi/4$ and $2\pi/5$), making the filter effective at removing quarterly and quintile seasonal components from economic time series. The negative edge weights provide bandpass-like characteristics, and the fixed design requires no parameters beyond the source series.
|
||||
|
||||
## Historical Context
|
||||
|
||||
John Spencer published the 15-point and 21-point weighted moving averages in 1904 for use in actuarial graduation (smoothing mortality tables). The weights were constructed to satisfy two constraints simultaneously: (1) preserve polynomial trends up to degree 3 (cubic), and (2) have zero response at specific seasonal frequencies. The 15-point variant zeros out periods 4 and 5; the 21-point variant zeros out periods 4, 5, and 7.
|
||||
|
||||
Spencer's filters predated Henderson's (1916) by twelve years and were widely used in actuarial science and economic statistics before the X-11 method standardized on Henderson filters. The Spencer 15-point filter was the default seasonal adjustment tool at the U.K. Office for National Statistics until the adoption of X-11 in the 1960s. In modern practice, it remains useful as a quick-and-dirty seasonal smoother when full X-13ARIMA decomposition is overkill.
|
||||
|
||||
The fixed 15-bar length creates a natural centered lag of 7 bars, which is appropriate for quarterly data (4 observations per year, so a 15-point filter spans nearly 4 quarters). For financial time series, the filter useful for removing intra-week (5-bar) and intra-month patterns from daily data.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Fixed Weight Vector
|
||||
|
||||
The 15 weights are hardcoded constants, symmetric around the center:
|
||||
|
||||
$$
|
||||
\mathbf{w} = \frac{1}{320}[-3, -6, -5, 3, 21, 46, 67, 74, 67, 46, 21, 3, -5, -6, -3]
|
||||
$$
|
||||
|
||||
No weight computation is needed; the coefficients are compile-time constants.
|
||||
|
||||
### 2. Symmetric Convolution
|
||||
|
||||
The symmetric structure allows folded computation: pair the $i$-th and $(14-i)$-th bars (which share the same weight), sum them, then multiply by the weight once. This halves the multiplication count from 15 to 8.
|
||||
|
||||
### 3. Negative Edge Weights
|
||||
|
||||
Three weights at each edge are negative ($-3, -6, -5$), giving the filter its seasonal-nulling property. The output can exceed the input range when edge bars have extreme values relative to the center.
|
||||
|
||||
### 4. Zero-Parameter Design
|
||||
|
||||
SP15 takes no period parameter. The filter length is always 15, and the weights are always Spencer's original values. This is both a strength (no tuning required) and a limitation (no adaptation to different data characteristics).
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
The Spencer 15-point filter output:
|
||||
|
||||
$$
|
||||
\text{SP15}_t = \frac{1}{320}\sum_{j=0}^{14} w_j \cdot x_{t-j}
|
||||
$$
|
||||
|
||||
Exploiting symmetry ($w_j = w_{14-j}$):
|
||||
|
||||
$$
|
||||
\text{SP15}_t = \frac{1}{320}\left[w_7 \cdot x_{t-7} + \sum_{j=0}^{6} w_j \left(x_{t-j} + x_{t-14+j}\right)\right]
|
||||
$$
|
||||
|
||||
**Frequency response zeros:**
|
||||
|
||||
$$
|
||||
H\left(e^{j2\pi/4}\right) = 0, \quad H\left(e^{j2\pi/5}\right) = 0
|
||||
$$
|
||||
|
||||
These zeros ensure complete suppression of periodicities at 4 and 5 bars.
|
||||
|
||||
**Weight sum:** $-3-6-5+3+21+46+67+74+67+46+21+3-5-6-3 = 320$
|
||||
|
||||
**Polynomial preservation:** The filter preserves polynomials up to degree 3:
|
||||
|
||||
$$
|
||||
\sum_{j=0}^{14} w_j \cdot (j-7)^k = 320 \cdot \delta_{k0}, \quad k = 0, 1, 2, 3
|
||||
$$
|
||||
|
||||
**Default parameters:** None (fixed 15-point filter).
|
||||
|
||||
**Pseudo-code (streaming):**
|
||||
|
||||
```
|
||||
// Fixed symmetric weights (compile-time constants)
|
||||
w = [-3, -6, -5, 3, 21, 46, 67, 74, 67, 46, 21, 3, -5, -6, -3]
|
||||
|
||||
// Symmetric folded computation
|
||||
total = w[7] * src[7]
|
||||
for j = 0 to 6:
|
||||
total += w[j] * (src[j] + src[14-j])
|
||||
return total / 320
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- Spencer, J. (1904). "On the Graduation of the Rates of Sickness and Mortality." *Journal of the Institute of Actuaries*, 38, 334-343.
|
||||
- Macaulay, F.R. (1931). *The Smoothing of Time Series.* NBER. Chapter 4: Spencer-Type Formulas.
|
||||
- Kendall, M.G. & Stuart, A. (1976). *The Advanced Theory of Statistics*, Vol. 3, 3rd ed. Griffin. Section 46.13: Spencer's Formulae.
|
||||
- Kenny, P.B. & Durbin, J. (1982). "Local Trend Estimation and Seasonal Adjustment of Economic and Social Time Series." *JRSS Series A*, 145(1).
|
||||
@@ -0,0 +1,88 @@
|
||||
# SWMA: Symmetric Weighted Moving Average
|
||||
|
||||
> "Take the SMA of an SMA and you get a triangular filter. It is the simplest possible smoothing kernel that has zero phase distortion and no frequency-domain discontinuities. Sometimes simple is exactly what you need."
|
||||
|
||||
SWMA applies triangular (symmetric) weights that peak at the center of the window and taper linearly to the edges. For period $N$, the weight at position $i$ is $w(i) = (N/2 + 1) - |i - N/2|$, producing a tent-shaped kernel. This is mathematically equivalent to convolving two rectangular windows (SMA of SMA), giving SWMA a frequency response that is the square of the SMA's sinc-like response. The result is smoother than SMA with better sidelobe suppression, at the cost of slightly more lag.
|
||||
|
||||
## Historical Context
|
||||
|
||||
The symmetric (triangular) weighted average is one of the oldest smoothing methods in statistics, predating modern signal processing by centuries. Its equivalence to the double-application of the simple moving average was recognized by Macaulay (1931) in his NBER monograph on time-series smoothing. The TRIMA (Triangular Moving Average) implemented elsewhere in QuanTAlib is the same mathematical operation computed via double SMA composition.
|
||||
|
||||
In PineScript, `ta.swma` refers specifically to the 4-point variant with weights $[1, 2, 2, 1]/6$, which is a special case of the general symmetric weighted average. QuanTAlib's SWMA generalizes this to arbitrary periods.
|
||||
|
||||
The triangular kernel has a natural Bayesian interpretation: if you believe the "true" signal is equally likely to be any value in a window of width $N/2$, and your observation window is also $N/2$, the posterior belief about the signal value is triangular. This makes SWMA the optimal Bayesian filter under uniform prior and uniform observation noise assumptions.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Weight Computation
|
||||
|
||||
For a window of length $N$ with half-width $h = (N-1)/2$:
|
||||
|
||||
$$
|
||||
w(i) = h + 1 - |i - h|, \quad i = 0, 1, \ldots, N-1
|
||||
$$
|
||||
|
||||
Weights form a triangle peaking at the center. For even $N$, the peak is a plateau of two equal values.
|
||||
|
||||
### 2. Normalized Weighted Sum
|
||||
|
||||
$$
|
||||
\text{SWMA} = \frac{\sum_{i=0}^{N-1} w(i) \cdot x_{t-i}}{\sum_{i=0}^{N-1} w(i)}
|
||||
$$
|
||||
|
||||
The weight sum equals $(h+1)^2$ for odd $N$ and $h(h+2)+1$ for even $N$.
|
||||
|
||||
### 3. Equivalence to Double SMA
|
||||
|
||||
SWMA(N) produces the same output as SMA(M) applied to SMA(M) where $M = \lceil N/2 \rceil$. This means the streaming implementation can compose two SMA instances for O(1) updates, rather than O(N) convolution.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
The triangular window for length $N$, with $h = (N-1)/2$:
|
||||
|
||||
$$
|
||||
w[i] = h + 1 - |i - h|, \quad i = 0, \ldots, N-1
|
||||
$$
|
||||
|
||||
**Frequency response:**
|
||||
|
||||
$$
|
||||
H_{\text{SWMA}}(f) = H_{\text{SMA}}^2(f) = \left[\frac{\sin(\pi f M)}{\pi f M}\right]^2
|
||||
$$
|
||||
|
||||
where $M = \lceil N/2 \rceil$. The squared sinc provides:
|
||||
|
||||
| Property | SMA | SWMA |
|
||||
| :--- | :---: | :---: |
|
||||
| First zero | $1/N$ | $2/N$ |
|
||||
| First sidelobe | $-13$ dB | $-26$ dB |
|
||||
| Rolloff rate | $-6$ dB/octave | $-12$ dB/octave |
|
||||
| Passband ripple | Moderate | Low |
|
||||
|
||||
**Weight sum (closed form):**
|
||||
|
||||
For odd $N = 2m+1$: $\sum w = (m+1)^2$
|
||||
|
||||
For even $N = 2m$: $\sum w = m(m+1)$
|
||||
|
||||
**PineScript special case:** `ta.swma` uses $N = 4$, $h = 1.5$, weights $= [1, 2, 2, 1]$, $\sum w = 6$.
|
||||
|
||||
**Default parameters:** `period = 4`, `minPeriod = 2`.
|
||||
|
||||
**Pseudo-code (streaming):**
|
||||
|
||||
```
|
||||
half = (period - 1) / 2.0
|
||||
sumWV = 0; sumW = 0
|
||||
for i = 0 to period-1:
|
||||
w = half + 1 - |i - half|
|
||||
sumWV += src[i] * w
|
||||
sumW += w
|
||||
return sumWV / sumW
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- Macaulay, F.R. (1931). *The Smoothing of Time Series.* National Bureau of Economic Research. Chapter 3: Moving Averages and Their Properties.
|
||||
- Oppenheim, A.V. & Schafer, R.W. (2009). *Discrete-Time Signal Processing*, 3rd ed. Prentice Hall. Section 5.6: The Bartlett (Triangular) Window.
|
||||
- Murphy, J.J. (1999). *Technical Analysis of the Financial Markets*. New York Institute of Finance. Chapter 9: Moving Averages.
|
||||
@@ -0,0 +1,96 @@
|
||||
# TUKEY_W: Tukey (Tapered Cosine) Window Moving Average
|
||||
|
||||
> "John Tukey designed a window with a knob that goes from 'do nothing' to 'full Hann' in one parameter. Set alpha to 0.5 and you get the pragmatist's compromise: flat where it matters, tapered where it would otherwise ring."
|
||||
|
||||
TUKEY_W applies the Tukey (tapered cosine) window as FIR filter weights, offering a single parameter $\alpha$ that controls the fraction of the window that is cosine-tapered. At $\alpha = 0$, the window is rectangular (SMA). At $\alpha = 1$, it becomes the Hann window. The default $\alpha = 0.5$ tapers 25% at each edge while keeping the central 50% flat at unity, combining the passband efficiency of the rectangular window with the sidelobe suppression of cosine tapering. This makes Tukey the default "when in doubt" window in spectral analysis, and by extension, a sensible default for window-based moving averages.
|
||||
|
||||
## Historical Context
|
||||
|
||||
John Wilder Tukey (1915-2000) introduced the tapered cosine window as part of his extensive work on spectral analysis, culminating in the landmark *Power Spectral Analysis and Its Applications* textbook with Blackman (1958). Tukey recognized that the rectangular window's sharp edges cause spectral leakage (Gibbs phenomenon), while fully tapered windows like Hann sacrifice too much effective window length. The tapered cosine compromise preserves most of the rectangular window's frequency resolution (through the flat center) while controlling leakage through the cosine-tapered edges.
|
||||
|
||||
The Tukey window is also known as the "cosine-tapered window" or "split-cosine-bell window" in the spectral analysis literature. The parameter $\alpha$ is sometimes called the "taper ratio" or "rolloff fraction." In the acoustics and seismology communities, it is standard practice to start with $\alpha = 0.5$ and adjust based on the leakage characteristics of the specific data.
|
||||
|
||||
For financial applications, the Tukey window's parametric nature offers a practical advantage over fixed windows: a trader can adjust $\alpha$ to control how much edge attenuation is applied. Low $\alpha$ (near 0) prioritizes responsiveness (less lag), while high $\alpha$ (near 1) prioritizes smoothness (less noise).
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
### 1. Piecewise Weight Function
|
||||
|
||||
The Tukey window divides the $N$-point window into three regions:
|
||||
|
||||
- **Left taper** ($0 \leq n < \alpha(N-1)/2$): Raised-cosine ramp from 0 to 1.
|
||||
- **Flat center** ($\alpha(N-1)/2 \leq n \leq (N-1)(1-\alpha/2)$): Constant weight of 1.
|
||||
- **Right taper** ($(N-1)(1-\alpha/2) < n \leq N-1$): Raised-cosine ramp from 1 to 0.
|
||||
|
||||
### 2. Normalization
|
||||
|
||||
Weights are normalized by their sum, which depends on $\alpha$:
|
||||
|
||||
$$
|
||||
\sum w = N - \alpha(N-1)/2 \cdot (1-2/\pi)
|
||||
$$
|
||||
|
||||
(approximately, for large $N$).
|
||||
|
||||
### 3. FIR Convolution
|
||||
|
||||
Standard weighted convolution. O(N) per bar. The flat center section allows paired SIMD processing of constant-weight elements.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
For a window of length $N$, sample index $n \in [0, N-1]$, and taper fraction $\alpha \in [0, 1]$:
|
||||
|
||||
$$
|
||||
w[n] = \begin{cases} \frac{1}{2}\left(1 - \cos\!\left(\frac{2\pi n}{\alpha(N-1)}\right)\right) & 0 \leq n < \frac{\alpha(N-1)}{2} \\ 1 & \frac{\alpha(N-1)}{2} \leq n \leq (N-1)\left(1 - \frac{\alpha}{2}\right) \\ \frac{1}{2}\left(1 - \cos\!\left(\frac{2\pi(N-1-n)}{\alpha(N-1)}\right)\right) & (N-1)\left(1 - \frac{\alpha}{2}\right) < n \leq N-1 \end{cases}
|
||||
$$
|
||||
|
||||
**Special cases:**
|
||||
|
||||
| $\alpha$ | Window | Properties |
|
||||
| :---: | :--- | :--- |
|
||||
| 0 | Rectangular (SMA) | Max resolution, worst leakage |
|
||||
| 0.5 | Half-tapered (default) | Good compromise |
|
||||
| 1.0 | Hann | Best leakage suppression, widest main lobe |
|
||||
|
||||
**Frequency response properties (approximate for $N \gg 1$):**
|
||||
|
||||
| $\alpha$ | Main lobe width | First sidelobe (dB) |
|
||||
| :---: | :---: | :---: |
|
||||
| 0 | $2/N$ | $-13$ |
|
||||
| 0.25 | $2.2/N$ | $-19$ |
|
||||
| 0.5 | $2.5/N$ | $-26$ |
|
||||
| 0.75 | $2.8/N$ | $-29$ |
|
||||
| 1.0 | $3.2/N$ | $-32$ |
|
||||
|
||||
**Normalized output:**
|
||||
|
||||
$$
|
||||
\text{TUKEY\_W}_t = \frac{\sum_{n=0}^{N-1} w[n] \cdot x_{t-n}}{\sum_{n=0}^{N-1} w[n]}
|
||||
$$
|
||||
|
||||
**Default parameters:** `period = 20`, `alpha = 0.5`, `minPeriod = 2`.
|
||||
|
||||
**Pseudo-code (streaming):**
|
||||
|
||||
```
|
||||
N = period - 1
|
||||
aN = alpha * N
|
||||
sumWV = 0; sumW = 0
|
||||
|
||||
for i = 0 to N:
|
||||
w = 1.0
|
||||
if aN > 0:
|
||||
if i < aN/2:
|
||||
w = 0.5 * (1 - cos(2π*i / aN))
|
||||
else if i > N - aN/2:
|
||||
w = 0.5 * (1 - cos(2π*(N-i) / aN))
|
||||
sumWV += src[i] * w
|
||||
sumW += w
|
||||
return sumWV / sumW
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- Tukey, J.W. (1967). "An Introduction to the Calculations of Numerical Spectrum Analysis." In *Spectral Analysis of Time Series*, ed. B. Harris. Wiley. pp. 25-46.
|
||||
- Blackman, R.B. & Tukey, J.W. (1958). *The Measurement of Power Spectra from the Point of View of Communications Engineering*. Dover.
|
||||
- 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.
|
||||
Reference in New Issue
Block a user