- 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.
6.4 KiB
DECAYCHANNEL: Decay Min-Max Channel
"Price extremes have a half-life—the market forgets yesterday's drama at an exponential rate."
Decay Channel is a price envelope that combines the absolute boundaries of Donchian Channels with an exponential decay mechanism. While Donchian Channels hold their width until an extreme exits the lookback window, Decay Channels allow the bands to effectively "forget" old extremes over time, converging towards the center. This creates a dynamic envelope that expands instantly on new volatility but contracts smoothly during consolidation, modeling the "half-life" of price memory.
Historical Context
The Decay Channel is a QuanTAlib innovation that applies principles from physics—specifically radioactive decay and Newton's Law of Cooling—to price channel construction. The concept emerged from the observation that standard Donchian Channels exhibit a discontinuous "cliff edge" behavior: bands remain static until an old extreme exits the lookback window, then jump abruptly.
This behavior doesn't reflect how markets actually work. Traders naturally give less weight to older price extremes as time passes. The Decay Channel formalizes this intuition using the exponential decay function, where the period parameter serves as the "half-life"—the number of bars after which an extreme's influence is reduced by 50%.
The mathematical foundation draws from the decay constant λ = ln(2)/T, the same formula used in carbon dating and thermal cooling calculations. This creates bands that behave more like a physical system with memory—instantly responsive to new extremes, but gradually relaxing during consolidation.
Architecture & Physics
The system models price extremes as energetic events that decay over time, similar to Newton's Law of Cooling or radioactive decay.
- Price Extremes: The outer boundaries are constrained by the actual Highest High and Lowest Low (Donchian Channel) over the
Period. - Exponential Decay: When a new extreme is not established, the band decays towards the midpoint.
- Radioactive Half-Life: The decay rate (
\lambda) is calibrated such that the influence of an extreme reduces by 50% over the specifiedPeriod.
Formula
The decay constant \lambda is derived from the half-life formula:
\lambda = \frac{\ln(2)}{Period}
For each bar, if a new raw extreme is not found, the band decays:
Age = \text{Bars since last extreme}
Factor = e^{-\lambda \times Age}
DecayedMax = Midpoint + Factor \times (max_{initial} - Midpoint)
The final upper/lower bands are clamped:
Upper = \min(DecayedMax, DonchianUpper)
Lower = \max(DecayedMin, DonchianLower)
Middle = \frac{Upper + Lower}{2}
Calculation Steps
- Update Extremes: Compute the raw Highest High and Lowest Low for the
Periodusing efficient Monotonic Deques. - Track Age: If the current High
\geRaw Max, reset Max Age to 0. Otherwise, increment Age. - Apply Decay: Calculate the exponential decay factor based on Age.
- Constrain: Ensure the Decayed value does not exceed the Raw Donchian bounds (e.g., Upper band cannot be higher than the highest high).
- Compute Midpoint: Average the constrained Upper and Lower bands.
Performance Profile
The implementation balances the computational cost of transcendental functions (Math.Exp) with efficient memory management for the sliding window extremes.
Operation Count (Streaming Mode, per Bar)
| Operation | Count | Cost (cycles) | Subtotal |
|---|---|---|---|
| CMP (Deque extremes) | 3 | 1 | 3 |
| EXP (Decay factor) | 2 | 15 | 30 |
| MUL | 2 | 3 | 6 |
| ADD/SUB | 2 | 1 | 2 |
| MIN/MAX | 2 | 1 | 2 |
| Total | 11 | — | ~43 cycles |
Complexity Analysis
| Mode | Complexity | Notes |
|---|---|---|
| Streaming | O(1) | Amortized via monotonic deque |
| Batch | O(n) | FMA optimization for decay |
Validation
| Library | Status | Notes |
|---|---|---|
| Donchian | ✅ | Decay bands never exceed Donchian bounds |
| Mathematical | ✅ | Value decays exactly 50% towards mean after Period bars |
| QuanTAlib | ✅ | Original implementation |
Usage & Pitfalls
- Half-Life Interpretation: The
periodparameter is the half-life, not a lookback window. Afterperiodbars without a new extreme, the band has decayed 50% towards center. - Asymmetric Behavior: Bands snap instantly to new extremes but decay gradually. This asymmetry is intentional—it models how markets accept new price levels quickly but forget old extremes slowly.
- Requires High/Low: The indicator uses bar High/Low for extremes, not close prices. Ensure your data includes these fields.
- Bar Correction: Use
isNew=falsewhen updating the current bar's value,isNew=truefor new bars. - Donchian Constraint: Decayed bands are always within Donchian bounds—useful for confirmation that bands aren't artificially extended.
- Consolidation Detection: Narrow bands (Upper ≈ Lower) indicate extended consolidation where old extremes have fully decayed.
API
classDiagram
class Decaychannel {
+Decaychannel(int period)
+TValue Last
+TValue Upper
+TValue Lower
+bool IsHot
+TValue Update(TBar bar)
+void Reset()
}
Class: Decaychannel
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
period |
int |
— | >0 |
Lookback window for extremes and half-life calculation. |
Properties
| Name | Type | Description |
|---|---|---|
Last |
TValue |
The Middle Band value. |
Upper |
TValue |
The Decayed Upper Band. |
Lower |
TValue |
The Decayed Lower Band. |
IsHot |
bool |
Returns true when the indicator has processed enough bars to cover the period. |
Methods
Update(TBar bar): Updates the indicator with a new bar (High/Low required).Reset(): Clears all historical data, deques, and decay timers.
C# Example
using QuanTAlib;
// 1. Initialize with a 20-bar half-life
var decay = new Decaychannel(period: 20);
// 2. Stream data
var bars = GetHistory();
foreach (var bar in bars)
{
decay.Update(bar);
// The Upper band will be lower than a standard 20-period Donchian
// if no new highs have occurred recently.
if (bar.Close > decay.Upper.Value)
{
Console.WriteLine("Breakout over decayed resistance");
}
}