4.1 KiB
CFB: Jurik Composite Fractal Behavior
Mark Jurik's CFB is not a momentum indicator. It is a stopwatch for chaos.
The Jurik Composite Fractal Behavior (CFB) index measures the duration of a trend by analyzing the "fractal efficiency" of price movement across multiple time scales. It answers the question: "How long has the market been moving in a straight line?"
Most indicators assume a fixed period (e.g., RSI-14). CFB rejects this rigidity. It scans a massive array of lookback periods simultaneously (by default, from 2 to 192 bars) to find which timeframes are exhibiting efficient trending behavior. It then composites these valid timeframes into a single index representing the current trend's maturity.
Historical Context
Mark Jurik is the quiet giant of signal processing in finance. His work focuses on low-lag, adaptive algorithms that treat price series as noisy signals rather than accounting ledgers. CFB is designed to be a "modulator"—a signal used to tune other indicators.
Architecture & Physics
CFB is a massive parallel processor. It doesn't just look at one timeframe; it looks at all of them.
- Fractal Efficiency: For every length
Lin the scan set, the ratio of net price movement to total path length (volatility) is calculated. - Filtering: Any timeframe where the efficiency is below a threshold (0.25) is discarded. This filters out "meandering" or choppy periods.
- Compositing: A weighted average of the qualifying lengths is taken, with the efficiency ratio itself used as the weight.
- Decay: If no timeframes qualify, the index decays exponentially, reflecting the loss of trend memory.
The Computational Challenge
A naive implementation of CFB is O(N \times M), where M is the number of lengths scanned (often ~100). This is prohibitively slow for real-time systems.
The QuanTAlib implementation uses a running-sum algorithm to maintain O(1) complexity per update. Ninety-six parallel running sums of volatility are maintained, updating incrementally as new bars arrive and old bars drop off.
Mathematical Foundation
The core concept is the Fractal Efficiency Ratio.
1. Efficiency Ratio (R_L)
For each length L:
R_L = \frac{|P_t - P_{t-L}|}{\sum_{i=0}^{L-1} |P_{t-i} - P_{t-i-1}|}
2. Weighting (w_L)
w_L = \begin{cases} R_L & \text{if } R_L \ge 0.25 \\ 0 & \text{if } R_L < 0.25 \end{cases}
3. Composite Index
CFB = \frac{\sum (L \times w_L)}{\sum w_L}
4. Decay
If \sum w_L \le 0.25:
CFB_t = \max(1, CFB_{t-1} \times 0.5)
Performance Profile
Memory is traded for speed. The state object is large (~2KB), but the update loop is extremely fast due to the running-sum optimization.
Zero-Allocation Design
The implementation uses a fixed-size array for the running sums, allocated on the stack or as part of the object state. No dynamic memory allocation occurs during updates.
| Metric | Score | Notes |
|---|---|---|
| Throughput | 50ns | Updates 96 parallel sums. |
| Allocations | 0 | Hot path is allocation-free. |
| Complexity | O(1) | Constant time relative to history length. |
| Accuracy | 10/10 | Matches Jurik's methodology. |
| Timeliness | 8/10 | Adaptive to trend changes. |
| Overshoot | 0/10 | Bounded by design. |
| Smoothness | 6/10 | Can jump when trends break. |
Validation
Validation is performed against internal consistency checks and Jurik's published methodology.
| Library | Status | Notes |
|---|---|---|
| QuanTAlib | ✅ | Internal consistency (Batch vs Streaming). |
| TA-Lib | N/A | Not implemented in TA-Lib. |
| Skender | N/A | Not implemented in Skender. |
| Tulip | N/A | Not implemented in Tulip. |
| Ooples | N/A | Not implemented. |
Common Pitfalls
- Not a Directional Signal: CFB tells you how long a trend has lasted, not which way it is going. A high CFB can occur in a crash or a rally.
- Modulation: Its best use is to dynamically adjust the period of other indicators (e.g.,
RSI(Period = CFB)). Using it as a standalone crossover signal is usually a mistake.