mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-17 10:08: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.
175 lines
6.9 KiB
Markdown
175 lines
6.9 KiB
Markdown
# PCHANNEL: Price Channel
|
||
|
||
> "The Turtles didn't need complex math. They needed to know when price broke out of its cage."
|
||
|
||
Price Channel (PC) tracks the highest high and lowest low over a lookback period, creating a price envelope that defines where the market has been. Functionally identical to Donchian Channels—same algorithm, different name. Unlike volatility-based bands (Bollinger, Keltner), Price Channel uses actual price extremes—no standard deviations, no averages of true range. The result: bands that represent real support and resistance levels traders actually watch. This implementation uses monotonic deques for O(1) amortized updates rather than the naive O(n) rescan that plagues most implementations.
|
||
|
||
## Historical Context
|
||
|
||
Price Channel is the generic name for what **Richard Donchian** formalized in the 1960s while managing one of the first publicly held commodity funds. The indicator is also known as Donchian Channels, N-period high/low channels, or simply "breakout bands."
|
||
|
||
The "4-week rule" (buy on 20-day high, sell on 20-day low) became the foundation for systematic trend-following. The indicator gained fame through the **Turtle Trading** experiment in 1983. Richard Dennis and William Eckhardt recruited novice traders and taught them a mechanical system built on channel breakouts. The Turtles reportedly made over $100 million. Curtis Faith's book and subsequent leaks revealed the core: enter on 20-day breakouts, exit on 10-day counter-breakouts.
|
||
|
||
Most implementations compute max/min by scanning the entire lookback window on every bar—O(n) per update, O(n²) for a series. This works for period=20 but becomes painful for longer windows or real-time feeds. QuanTAlib uses monotonic deques that maintain running max/min in O(1) amortized time, enabling period=500+ without performance degradation.
|
||
|
||
## Architecture & Physics
|
||
|
||
Price Channel consists of three components: upper band (highest high), lower band (lowest low), and middle band (their average).
|
||
|
||
### 1. Upper Band (Highest High)
|
||
|
||
Tracks the maximum high price over the lookback window:
|
||
|
||
$$
|
||
U_t = \max_{i=0}^{n-1}(H_{t-i})
|
||
$$
|
||
|
||
where $H$ is the high price and $n$ is the period. The upper band moves up immediately when a new high occurs, but only drops when the previous highest high exits the lookback window.
|
||
|
||
### 2. Lower Band (Lowest Low)
|
||
|
||
Tracks the minimum low price over the lookback window:
|
||
|
||
$$
|
||
L_t = \min_{i=0}^{n-1}(L_{t-i})
|
||
$$
|
||
|
||
where $L$ is the low price. The lower band drops immediately on new lows but only rises when the previous lowest low exits the window.
|
||
|
||
### 3. Middle Band
|
||
|
||
The arithmetic mean of the upper and lower bands:
|
||
|
||
$$
|
||
M_t = \frac{U_t + L_t}{2}
|
||
$$
|
||
|
||
This represents the "equilibrium" price over the lookback period.
|
||
|
||
### Monotonic Deque Algorithm
|
||
|
||
Instead of rescanning the window on each bar, the implementation maintains two monotonic deques:
|
||
|
||
1. **Deque (Max):** Valid indices of decreasing values. Front is always the Max.
|
||
2. **Deque (Min):** Valid indices of increasing values. Front is always the Min.
|
||
3. **Update:**
|
||
- Remove old indices from front (expired).
|
||
- Remove values from back that are superseded by new value.
|
||
- Add new value to back.
|
||
|
||
**Complexity:** Each element is added once and removed at most once. Total work for $N$ bars is $O(N)$, averaging $O(1)$ per bar.
|
||
|
||
## Performance Profile
|
||
|
||
### Operation Count (Streaming Mode, Scalar)
|
||
|
||
Per-bar cost using monotonic deque optimization:
|
||
|
||
| Operation | Count | Cost (cycles) | Subtotal |
|
||
| :--- | :---: | :---: | :---: |
|
||
| CMP (Bound checks) | 4 | 1 | 4 |
|
||
| ADD (Index update) | 1 | 1 | 1 |
|
||
| MUL (Average) | 1 | 3 | 3 |
|
||
| Deque Maint. | ~2 | 1 | ~2 |
|
||
| **Total** | **8** | — | **~10 cycles** |
|
||
|
||
**Complexity**: O(1) amortized.
|
||
|
||
### Batch Mode (512 values, SIMD/FMA)
|
||
|
||
Finding max/min over sliding windows has limited SIMD benefit due to sequential dependency and the efficiency of the scalar deque algorithm.
|
||
|
||
| Operation | Scalar Ops | SIMD Benefit | Notes |
|
||
| :--- | :---: | :---: | :--- |
|
||
| Max/Min update | 4 | 1× | Deque-based, sequential |
|
||
| Middle band | 2 | 2× | ADD + MUL parallelizable |
|
||
|
||
| Mode | Cycles/bar | Total (512 bars) | Improvement |
|
||
| :--- | :---: | :---: | :---: |
|
||
| Scalar streaming | 10 | 5,120 | — |
|
||
| Partial SIMD | ~8 | ~4,096 | **~20%** |
|
||
|
||
## Validation
|
||
|
||
| Library | Status | Notes |
|
||
| :--- | :---: | :--- |
|
||
| **TA-Lib** | - | No implementation |
|
||
| **Skender** | - | No implementation (uses Donchian) |
|
||
| **Tulip** | - | No implementation |
|
||
| **Ooples** | ✅ | Cross-validated via Donchian equivalence |
|
||
| **Dchannel** | ✅ | Exact match—identical algorithm |
|
||
|
||
## Usage & Pitfalls
|
||
|
||
- **Stale Extremes**: Price Channel bands stay flat until a new extreme occurs or the old extreme exits the window. This is feature, not a bug.
|
||
- **O(n) Trap**: Naive implementations rescan the full window every bar. QuanTAlib's solution is O(1).
|
||
- **Breakout vs. Touch**: Price touching the upper band is not the same as breaking out. True breakouts close above/below the band.
|
||
- **Asymmetric Exit**: Consider different periods for long/short entries and exits (e.g., Turtle 20/10 rule).
|
||
|
||
## API
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class Pchannel {
|
||
+Name : string
|
||
+WarmupPeriod : int
|
||
+Upper : TValue
|
||
+Lower : TValue
|
||
+Last : TValue
|
||
+IsHot : bool
|
||
+Update(TBar bar) TValue
|
||
+Update(TBarSeries source) TSeries
|
||
+Prime(TBarSeries source) void
|
||
}
|
||
```
|
||
|
||
### Class: `Pchannel`
|
||
|
||
| Parameter | Type | Default | Range | Description |
|
||
| :--- | :--- | :--- | :--- | :--- |
|
||
| `period` | `int` | — | `>0` | Lookback window size. |
|
||
| `source` | `TBarSeries` | — | `any` | Initial input source (optional). |
|
||
|
||
### Properties
|
||
|
||
- `Name` (`string`): The indicator name (e.g., "Pchannel(20)").
|
||
- `WarmupPeriod` (`int`): The number of samples needed for full validity.
|
||
- `Upper` (`TValue`): The current highest high.
|
||
- `Lower` (`TValue`): The current lowest low.
|
||
- `Last` (`TValue`): The current middle line value ((Upper + Lower) / 2).
|
||
- `IsHot` (`bool`): Returns `true` if we have processed `period` samples.
|
||
|
||
### Methods
|
||
|
||
- `Update(TBar bar)`: Updates the indicator with a new bar (High/Low) and returns the Middle band value.
|
||
- `Update(TBarSeries source)`: Batch processes a series and returns (Middle, Upper, Lower) tuple.
|
||
- `Prime(TBarSeries source)`: Pre-loads the indicator with history without returning results.
|
||
|
||
## C# Example
|
||
|
||
```csharp
|
||
using QuanTAlib;
|
||
|
||
// Initialize
|
||
var channel = new Pchannel(period: 20);
|
||
|
||
// Update Loop
|
||
foreach (var bar in bars)
|
||
{
|
||
var result = channel.Update(bar);
|
||
|
||
if (channel.IsHot)
|
||
{
|
||
Console.WriteLine($"{bar.Time}: Mid={result.Value:F2} Upper={channel.Upper.Value:F2} Lower={channel.Lower.Value:F2}");
|
||
}
|
||
}
|
||
|
||
// Batch Processing
|
||
var (mid, upper, lower) = channel.Update(bars);
|
||
```
|
||
|
||
## References
|
||
|
||
- Donchian, R. (1960). "High Finance in Copper." *Financial Analysts Journal*.
|
||
- Faith, C. (2007). *Way of the Turtle: The Secret Methods that Turned Ordinary People into Legendary Traders*.
|