mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-16 09:38:05 +00:00
- 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.
146 lines
4.7 KiB
Markdown
146 lines
4.7 KiB
Markdown
# EACP: Ehlers Autocorrelation Periodogram
|
||
|
||
> "The autocorrelation periodogram uses the Wiener-Khinchin theorem to transform autocorrelation into spectral density, revealing the dominant cycle hidden within price noise."
|
||
|
||
The Ehlers Autocorrelation Periodogram (EACP) is an advanced spectral analysis tool that estimates the dominant cycle period of a financial time series. It computes autocorrelation across various lags and transforms this into a power spectrum to identify the most potent frequency, enabling adaptive indicator tuning.
|
||
|
||
## Historical Context
|
||
|
||
John Ehlers introduced the Autocorrelation Periodogram to the trading community as a solution for measuring market cycles. He leveraged the **Wiener-Khinchin theorem**, which links the time domain (autocorrelation) to the frequency domain (power spectral density).
|
||
|
||
This allows traders to detect the current "heartbeat" of the market—the dominant cycle—which can then tune other indicators (like RSI or Stochastic) to the current market speed, creating truly adaptive trading systems.
|
||
|
||
## Architecture & Physics
|
||
|
||
The algorithm proceeds in three major stages: Pre-filtering, Correlation, and Spectral Analysis.
|
||
|
||
### 1. Signal Pre-processing
|
||
|
||
High-pass filter removes DC component and trends; Super-smoother attenuates aliasing noise.
|
||
|
||
$$
|
||
HP_t = (1 - \alpha_{HP}/2)^2 \cdot (P_t - 2P_{t-1} + P_{t-2}) + 2(1-\alpha_{HP}) \cdot HP_{t-1} - (1-\alpha_{HP})^2 \cdot HP_{t-2}
|
||
$$
|
||
|
||
### 2. Autocorrelation
|
||
|
||
For every lag $k$ from 0 to MaxPeriod:
|
||
|
||
$$
|
||
R_k = \frac{\sum (x_i - \bar{x})(x_{i-k} - \bar{x})}{\sqrt{\sum (x_i - \bar{x})^2 \sum (x_{i-k} - \bar{x})^2}}
|
||
$$
|
||
|
||
A high correlation at lag 20 implies a 20-bar cycle.
|
||
|
||
### 3. Dominant Cycle Extraction
|
||
|
||
Power spectrum via DFT, smoothed with exponential decay:
|
||
|
||
$$
|
||
S_p = 0.2 \cdot P_p^2 + 0.8 \cdot S_{p-1}
|
||
$$
|
||
|
||
Dominant cycle as center of gravity of spectral peaks:
|
||
|
||
$$
|
||
DC = \frac{\sum Power_i \cdot Period_i}{\sum Power_i}
|
||
$$
|
||
|
||
## Performance Profile
|
||
|
||
### Operation Count (Streaming Mode, per Bar)
|
||
|
||
| Operation | Count | Cost (cycles) | Subtotal |
|
||
| :--- | :---: | :---: | :---: |
|
||
| Correlation loop | N×M | 5 | 5NM |
|
||
| DFT inner loop | N×N | 8 | 8N² |
|
||
| Power smoothing | N | 4 | 4N |
|
||
| AGC normalization | N | 3 | 3N |
|
||
| **Total** | — | — | **O(N²)** |
|
||
|
||
### Complexity Analysis
|
||
|
||
- **Streaming:** O(N × M) where N=period range, M=averaging length
|
||
- **Memory:** O(N) for correlation and power arrays
|
||
- **Warmup:** ~2 × MaxPeriod bars
|
||
|
||
**Note:** This is one of the most computationally expensive indicators due to nested loops.
|
||
|
||
## Validation
|
||
|
||
| Library | Status | Notes |
|
||
| :--- | :---: | :--- |
|
||
| TA-Lib | N/A | Not implemented |
|
||
| Skender | N/A | Not implemented |
|
||
| PineScript | ✅ | Validated against Ehlers' reference code |
|
||
|
||
## Usage & Pitfalls
|
||
|
||
- **Primary use is tuning**—provides `period` parameter for other indicators (RSI, Stochastic)
|
||
- **Requires substantial warmup** (~2 × MaxPeriod) to stabilize spectrum
|
||
- **Struggles with rapid cycle changes**—period jumping from 10 to 40 in few bars
|
||
- **Compute on bar close only**—avoid running on every tick for many symbols
|
||
- **Enhance mode** (`enhance=true`) sharpens peaks but can cause jumpiness
|
||
- **Pure sine wave** of period 20 correctly converges to ~20.0
|
||
|
||
## API
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class Eacp {
|
||
+int MinPeriod
|
||
+int MaxPeriod
|
||
+double DominantCycle
|
||
+double NormalizedPower
|
||
+bool IsHot
|
||
+Eacp(int minPeriod, int maxPeriod, bool enhance)
|
||
+TValue Update(TValue input, bool isNew)
|
||
+void Reset()
|
||
}
|
||
```
|
||
|
||
### Class: `Eacp`
|
||
|
||
| Parameter | Type | Default | Range | Description |
|
||
| :--- | :--- | :--- | :--- | :--- |
|
||
| `minPeriod` | `int` | `8` | `≥3` | Minimum period to evaluate |
|
||
| `maxPeriod` | `int` | `48` | `>minPeriod` | Maximum period to evaluate |
|
||
| `enhance` | `bool` | `true` | — | Apply cubic emphasis to peaks |
|
||
|
||
### Properties
|
||
|
||
- `DominantCycle` (`double`): Estimated dominant cycle period in bars
|
||
- `NormalizedPower` (`double`): Power at dominant period (0-1)
|
||
- `IsHot` (`bool`): Returns `true` when warmup is complete
|
||
|
||
### Methods
|
||
|
||
- `Update(TValue input, bool isNew)`: Updates the indicator with a new data point
|
||
|
||
## C# Example
|
||
|
||
```csharp
|
||
using QuanTAlib;
|
||
|
||
// Configure for cycles between 8 and 48 bars
|
||
var eacp = new Eacp(minPeriod: 8, maxPeriod: 48, enhance: true);
|
||
|
||
// Update with streaming data
|
||
foreach (var bar in quotes)
|
||
{
|
||
var result = eacp.Update(new TValue(bar.Date, bar.Close));
|
||
|
||
if (eacp.IsHot)
|
||
{
|
||
Console.WriteLine($"{bar.Date}: Dominant Cycle = {eacp.DominantCycle:F1} bars");
|
||
|
||
// Use cycle to tune RSI
|
||
int adaptivePeriod = (int)(eacp.DominantCycle / 2);
|
||
var adaptiveRsi = new Rsi(adaptivePeriod);
|
||
}
|
||
}
|
||
|
||
// Batch calculation
|
||
var output = Eacp.Calculate(sourceSeries, minPeriod: 8, maxPeriod: 48);
|
||
```
|