7.8 KiB
POLYFIT: Polynomial Fitting
Polynomial fitting bends a curve through price data, capturing nonlinear trends that a straight line cannot.
| Property | Value |
|---|---|
| Category | Statistic |
| Inputs | Source (close) |
| Parameters | period, degree (default 2) |
| Outputs | Single series (Polyfit) |
| Output range | Varies (see docs) |
| Warmup | period bars |
| PineScript | polyfit.pine |
- Polynomial Fitting computes a rolling polynomial regression of configurable degree over a lookback window, returning the fitted value at the curren...
- Similar: LinReg, TSF | Trading note: Polynomial curve fitting; captures non-linear trends. Higher order = more responsive but risk of overfitting.
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
Polynomial Fitting computes a rolling polynomial regression of configurable degree over a lookback window, returning the fitted value at the current bar. Degree 1 produces a linear regression endpoint (identical to LSQR), degree 2 produces a quadratic fit that captures curvature, and degree 3 produces a cubic fit that captures inflection points. The implementation solves the normal equations \mathbf{X}^T\mathbf{X}\mathbf{a} = \mathbf{X}^T\mathbf{y} via Gauss-Jordan elimination with partial pivoting, evaluating the resulting polynomial at x = 1 (the current bar position). With O(Nd + d^3) complexity per bar where N is the period and d is the degree, POLYFIT provides a general-purpose curve-fitting tool that subsumes linear regression and extends it to arbitrary polynomial order.
Historical Context
Polynomial regression traces to Adrien-Marie Legendre (1805) and Carl Friedrich Gauss (1809), who independently developed the method of least squares. The normal equations formulation provides the minimum-sum-of-squares solution in closed form, though numerical stability requires careful implementation. Gauss-Jordan elimination with partial pivoting (Jordan, 1873) is the standard approach for small systems like those arising in polynomial fitting with degrees 1-6.
In technical analysis, linear regression (degree 1) is well established via the Linear Regression Channel and LSQR indicators. Higher-degree fits are less common due to overfitting concerns, but degree 2 (quadratic) is useful for detecting acceleration/deceleration in trends, and degree 3 (cubic) can capture reversal patterns. The key insight is that higher degrees track price more closely but also amplify noise; the optimal degree depends on the signal-to-noise ratio and the lookback period.
The x-normalization step (mapping time indices to [0, 1]) is critical for numerical stability: without it, the Vandermonde matrix entries x^d would span many orders of magnitude for typical lookback periods, causing catastrophic cancellation in the normal equations. With normalization, the matrix condition number remains manageable up to degree 6.
Architecture and Physics
The implementation uses a circular buffer to maintain the last period values, with NaN substitution via last-valid-value tracking.
Matrix assembly: Constructs the (d+1) \times (d+1) Gram matrix \mathbf{G} = \mathbf{X}^T\mathbf{X} and right-hand side \mathbf{r} = \mathbf{X}^T\mathbf{y} in a single pass over the data. The Vandermonde basis vectors are [1, x, x^2, \ldots, x^d] where x_i = i/(n-1) is the normalized time position. The matrix is symmetric so only the upper triangle needs explicit computation (mirrored to lower).
Solver: Gauss-Jordan elimination with partial pivoting transforms the augmented matrix [\mathbf{G} | \mathbf{r}] into [\mathbf{I} | \mathbf{a}]. Partial pivoting selects the row with the largest absolute value in the current column to minimize round-off error. Singular or near-singular matrices (pivot < 10^{-30}) abort gracefully.
Evaluation: The polynomial P(x) = a_0 + a_1 x + a_2 x^2 + \cdots + a_d x^d is evaluated at x = 1.0 (current bar, since time is normalized to [0, 1]). This gives the fitted value at the most recent observation.
Degree clamping: If degree exceeds period - 1, it is automatically reduced to prevent underdetermined systems.
Mathematical Foundation
The polynomial model:
P(x) = \sum_{j=0}^{d} a_j x^j = a_0 + a_1 x + a_2 x^2 + \cdots + a_d x^d
The normal equations for least-squares fitting:
\mathbf{X}^T\mathbf{X}\,\mathbf{a} = \mathbf{X}^T\mathbf{y}
where \mathbf{X} is the n \times (d+1) Vandermonde matrix:
X_{ij} = x_i^j, \quad x_i = \frac{i}{n-1} \in [0, 1]
The Gram matrix elements:
G_{jk} = \sum_{i=0}^{n-1} x_i^{j+k}
The right-hand side:
r_j = \sum_{i=0}^{n-1} x_i^j \cdot y_i
Gauss-Jordan with partial pivoting reduces [\mathbf{G} | \mathbf{r}] to [\mathbf{I} | \mathbf{a}]:
- For each column
c: find the rowpin[c, d]with maximum|G_{pc}| - Swap rows
candp - Scale row
cso the pivot becomes 1 - Subtract multiples of row
cfrom all other rows
Output: \hat{y}_{\text{current}} = P(1.0) = \sum_{j=0}^{d} a_j
Parameter constraints: period \ge 2, degree \ge 1 (clamped to period - 1). Computational complexity: O(nd + d^3).
POLYFIT(source, period, degree):
d = min(degree, period - 1)
m = d + 1
normalize x_i = i / (n-1) for i in [0, n-1]
// Build normal equations
G = (m x m) matrix of zeros
r = m-vector of zeros
for each (x_i, y_i) in window:
for j = 0 to d:
r[j] += x_i^j * y_i
for k = j to d:
G[j][k] += x_i^(j+k)
G[k][j] = G[j][k] // symmetric
// Gauss-Jordan with partial pivoting
for col = 0 to d:
pivot_row = argmax |G[row][col]| for row in [col, d]
swap rows col and pivot_row in G and r
scale row col by 1/G[col][col]
eliminate col from all other rows
// Evaluate at x = 1.0 (current bar)
return sum(r[j] for j = 0 to d)
Performance Profile
Operation Count (Streaming Mode)
Polyfit uses a running-sum approach via Vandermonde normal equations for degree-1 (linear) regression, updated O(1) per bar with a sliding window ring buffer.
| Operation | Count | Cost (cycles) | Subtotal |
|---|---|---|---|
| Ring buffer add/evict | 1 | 3 cy | ~3 cy |
| Update running sums (Sx, Sy, Sxx, Sxy) | 4 | 2 cy | ~8 cy |
| Solve 2x2 normal system | 1 | 6 cy | ~6 cy |
| FMA for slope/intercept | 2 | 1 cy | ~2 cy |
| NaN guard + state update | 1 | 2 cy | ~2 cy |
| Total | O(1) | — | ~21 cy |
O(1) per update for linear (degree-1) fit using online normal equations. Higher-degree fits require O(degree^2) matrix solve per bar.
Batch Mode (SIMD Analysis)
| Operation | Vectorizable? | Notes |
|---|---|---|
| Running sum accumulation | Yes | Vector reduces 4 sums in parallel |
| Normal equation solve | Partial | 2×2 system trivially unrolled |
| Output projection | Yes | FMA for y = a*x + b across output span |
Batch span path can vectorize sum accumulation and output projection. Inner loop SIMD-friendly for degree-1 case.
Resources
- Legendre, A.M. "Nouvelles methodes pour la determination des orbites des cometes." 1805.
- Gauss, C.F. "Theoria Motus Corporum Coelestium." 1809.
- Golub, G. & Van Loan, C. "Matrix Computations." 4th edition, Johns Hopkins University Press, 2013.
- Press, W.H. et al. "Numerical Recipes: The Art of Scientific Computing." 3rd edition, Cambridge University Press, 2007. Chapter 15 (Modeling of Data).
- Draper, N. & Smith, H. "Applied Regression Analysis." 3rd edition, Wiley, 1998.