- Implemented ChopIndicator for Quantower with configurable period and cold value display. - Created Chop class for calculating the Choppiness Index with detailed documentation. - Added comprehensive unit tests for Chop functionality, covering various market conditions and edge cases. - Developed markdown documentation for CHOP, detailing its historical context, mathematical foundation, and usage examples. - Established a remediation plan for channel indicators documentation, identifying gaps and prioritizing updates.
8.6 KiB
REGCHANNEL: Linear Regression Channel
"Linear regression isn't about predicting the future—it's about understanding where price should be given recent history, and measuring how far it's strayed."
The Linear Regression Channel (REGCHANNEL) plots a best-fit line through price data over a specified period, with parallel bands at a configurable standard deviation distance. This implementation uses ordinary least squares (OLS) regression with population standard deviation of residuals, providing a statistically grounded view of trend direction and price deviation.
Historical Context
Linear regression channels emerged from basic statistical analysis applied to financial markets. The concept combines two fundamental statistical tools: linear regression (fitting a line to minimize squared errors) and standard deviation (measuring dispersion around that line).
Unlike moving average envelopes that simply offset from a smoothed price, regression channels adapt their slope to the underlying trend and their width to actual price volatility around that trend. This makes them particularly useful for identifying when prices have deviated significantly from their recent trajectory.
The indicator is functionally identical to SDCHANNEL but uses "Regchannel" naming convention, which may be preferred in some trading platforms and literature.
Architecture & Physics
1. Sliding Window Buffer
The indicator maintains a rolling window of the most recent period price values:
W_t = \{P_{t-n+1}, P_{t-n+2}, \ldots, P_t\}
where n = \min(t+1, \text{period}). During warmup (t < \text{period}), all available values are used.
2. Linear Regression via Least Squares
For each update, the indicator computes the best-fit line y = mx + b using the normal equations:
m = \frac{n \sum_{i=0}^{n-1} x_i y_i - \sum_{i=0}^{n-1} x_i \sum_{i=0}^{n-1} y_i}{n \sum_{i=0}^{n-1} x_i^2 - \left(\sum_{i=0}^{n-1} x_i\right)^2}
b = \frac{\sum_{i=0}^{n-1} y_i - m \sum_{i=0}^{n-1} x_i}{n}
where x_i = i (time index) and y_i = P_i (price at that index).
3. Regression Value Calculation
The middle line value at the current bar (rightmost point of the regression line):
\text{Middle}_t = m \cdot (n-1) + b
This represents the expected price based on the linear trend through the window.
4. Standard Deviation of Residuals
The indicator computes population standard deviation of the residuals (differences between actual and predicted values):
\sigma_t = \sqrt{\frac{\sum_{i=0}^{n-1} (y_i - \hat{y}_i)^2}{n}}
where \hat{y}_i = m \cdot i + b is the predicted value at position i.
5. Channel Bands
Upper and lower bands are placed at a configurable multiple of the standard deviation:
\text{Upper}_t = \text{Middle}_t + k \cdot \sigma_t
\text{Lower}_t = \text{Middle}_t - k \cdot \sigma_t
where k is the multiplier parameter (default 2.0).
Mathematical Foundation
Efficient Computation Using Running Sums
Rather than recalculating sums from scratch each bar, the implementation maintains running sums and adjusts them incrementally. For a sliding window of size n:
\sum x = 0 + 1 + \ldots + (n-1) = \frac{n(n-1)}{2}\sum x^2 = 0^2 + 1^2 + \ldots + (n-1)^2 = \frac{n(n-1)(2n-1)}{6}
These are constants for a fixed period, computed once at construction.
Denominator and Numerical Stability
The denominator in the slope calculation:
D = n \sum x^2 - \left(\sum x\right)^2
For n \geq 2, this is always positive, ensuring numerical stability. The implementation guards against D = 0 (which can only occur for n = 1).
Residual Calculation
For each point in the window:
r_i = y_i - (m \cdot i + b)
The sum of squared residuals:
\text{SSR} = \sum_{i=0}^{n-1} r_i^2
Performance Profile
Operation Count (Streaming Mode, Scalar)
| Operation | Count | Cost (cycles) | Subtotal |
|---|---|---|---|
| ADD/SUB | ~3n+15 | 1 | ~3n+15 |
| MUL | ~2n+10 | 3 | ~6n+30 |
| DIV | 4 | 15 | 60 |
| SQRT | 1 | 15 | 15 |
| Ring buffer ops | 2 | 5 | 10 |
| Total | — | — | ~9n+130 |
For period=20: approximately 310 cycles per bar.
Quality Metrics
| Metric | Score | Notes |
|---|---|---|
| Accuracy | 9/10 | Exact OLS regression; population σ |
| Timeliness | 7/10 | Inherent lag from lookback window |
| Smoothness | 8/10 | Regression naturally smooths |
| Responsiveness | 6/10 | Slower to react than EMA-based channels |
Validation
| Library | Status | Notes |
|---|---|---|
| TA-Lib | N/A | No direct equivalent |
| Skender | N/A | No direct equivalent |
| Tulip | N/A | No direct equivalent |
| Manual | ✅ | Verified against hand calculations |
Linear regression channels are not commonly found in standard TA libraries with this exact specification. Validation relies on mathematical verification against known formulas.
Usage & Pitfalls
- Warmup Period: The indicator requires
periodbars to reach full accuracy. During warmup, it uses all available data but may produce different results than post-warmup. - Slope Interpretation: A positive slope indicates uptrend within the window; negative indicates downtrend. The magnitude indicates trend strength.
- Band Width = 0: When prices fall perfectly on a line (zero residuals), bands collapse to the middle line. This is mathematically correct but visually unexpected.
- Standard Deviation Choice: This implementation uses population σ (dividing by n), not sample σ (dividing by n-1). Some implementations differ.
- Memory Footprint: Each instance requires a RingBuffer of
perioddoubles (~8 bytes each) plus state structs (~80 bytes). For period=20: ~240 bytes per instance. - isNew Parameter: When
isNew=false, the indicator rolls back to the previous state before incorporating the update. This enables bar correction without state accumulation errors.
API
classDiagram
class Regchannel {
+string Name
+int WarmupPeriod
+TValue Last
+TValue Upper
+TValue Lower
+double Slope
+double StdDev
+bool IsHot
+Regchannel(int period, double multiplier)
+Regchannel(TSeries source, int period, double multiplier)
+TValue Update(TValue input, bool isNew)
+Tuple~TSeries,TSeries,TSeries~ Update(TSeries source)
+void Prime(TSeries source)
+void Reset()
+static void Batch(ReadOnlySpan~double~ source, Span~double~ middle, Span~double~ upper, Span~double~ lower, int period, double multiplier)
+static Tuple~TSeries,TSeries,TSeries~ Batch(TSeries source, int period, double multiplier)
+static Tuple~Tuple~TSeries,TSeries,TSeries~,Regchannel~ Calculate(TSeries source, int period, double multiplier)
}
Class: Regchannel
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
period |
int |
20 |
>1 |
Lookback period for linear regression calculation. |
multiplier |
double |
2.0 |
>0 |
Standard deviation multiplier for band width. |
Properties
Last(TValue): The current linear regression value (middle line).Upper(TValue): The upper band (regression + multiplier × σ).Lower(TValue): The lower band (regression - multiplier × σ).Slope(double): The slope of the linear regression line.StdDev(double): The standard deviation of residuals.IsHot(bool): Returnstruewhen warmup period is complete.
Methods
Update(TValue input, bool isNew): Updates the indicator with a new value and returns the result.Update(TSeries source): Processes an entire series and returns (Middle, Upper, Lower) tuple of TSeries.Prime(TSeries source): Initializes internal state from historical data.Reset(): Resets the indicator to its initial state.Batch(...): Static method for span-based batch processing.Calculate(TSeries source, int period, double multiplier): Static factory that returns results and indicator instance.
C# Example
using QuanTAlib;
// Initialize
var regchannel = new Regchannel(period: 20, multiplier: 2.0);
// Update Loop
foreach (var bar in quotes)
{
var result = regchannel.Update(bar.Close);
// Use valid results
if (regchannel.IsHot)
{
Console.WriteLine($"{bar.Time}: Mid={result.Value:F2}, Upper={regchannel.Upper.Value:F2}, Lower={regchannel.Lower.Value:F2}, Slope={regchannel.Slope:F4}");
}
}
References
- Draper, N.R. & Smith, H. (1998). "Applied Regression Analysis." Wiley.
- Murphy, J.J. (1999). "Technical Analysis of the Financial Markets." New York Institute of Finance.
- PineScript Reference: Linear Regression implementation patterns.