Files
QuanTAlib/lib/cycles/ht_dcperiod/HtDcperiod.md
T
Miha Kralj 26280ce80b Add Choppiness Index (CHOP) implementation and tests
- 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.
2026-02-05 19:42:49 -08:00

4.0 KiB
Raw Blame History

HT_DCPERIOD: Hilbert Transform - Dominant Cycle Period

"Knowing the cycle period is the master key—it calibrates other indicators to the market's current rhythm."

HT_DCPERIOD estimates the period of the dominant market cycle using Ehlers' Hilbert Transform cascade. The indicator measures the instantaneous period based on the rate of change of the phase angle, providing a variable period length (typically 6-50 bars) that dynamically tunes other indicators.

Historical Context

John Ehlers introduced the Hilbert Transform Dominant Cycle Period in Rocket Science for Traders (2001). The goal was to overcome the limitations of fixed-period indicators by measuring the actual cycle length present in the data.

TA-Lib implements HT_DCPERIOD using Ehlers' specific coefficients (A = 0.0962, B = 0.5769) and smoothing algorithms. QuanTAlib matches the TA-Lib implementation within floating-point tolerance.

Architecture & Physics

The algorithm follows a complex pipeline to extract cycle period from phase information.

1. WMA Price Smoothing


SmoothPrice_t = \frac{4P_t + 3P_{t-1} + 2P_{t-2} + P_{t-3}}{10}

2. Hilbert Transform Components

The Hilbert Transform generates In-Phase (I) and Quadrature (Q) components:

  • Detrender: Removes DC component and trend
  • Q1: Quadrature component of detrender
  • I1: In-Phase component (delayed detrender)
  • jI, jQ: Hilbert transforms of I1 and Q1

3. Phasor Components


I2_t = I1_t - jQ_t

Q2_t = Q1_t + jI_t

Smoothed with EMA (α = 0.2).

4. Period Extraction


Period_t = \frac{2\pi}{\arctan(Im_t / Re_t)}

Clamped to [6, 50] and smoothed with EMA (α = 0.33).

Performance Profile

Operation Count (Streaming Mode, per Bar)

Operation Count Cost (cycles) Subtotal
MUL (Hilbert taps) 28 3 84
MUL (homodyne mix) 4 3 12
ADD/SUB 40 1 40
ATAN2 1 25 25
DIV 3 15 45
Total 76 ~206 cycles

Complexity Analysis

  • Streaming: O(1) per bar—fixed Hilbert cascade
  • Memory: ~1.2 KB per instance (circular buffers + state)
  • Warmup: 32 bars (TA-Lib lookback)

Validation

Library Status Notes
TA-Lib Matches TALib.Functions.HtDcPeriod()
Skender N/A Not implemented
PineScript Matches ht_dcperiod.pine reference

Usage & Pitfalls

  • Output is period in bars (6-50 range)—not an oscillator
  • 32-bar warmup required—ignore early values
  • Trending markets cause period to drift to upper limit (50)
  • High noise causes jitter—internal smoothing helps
  • Use for adaptive tuning: RSI(period: htDcperiod.Value / 2)
  • Stable periods indicate rhythmic market suitable for oscillators

API

classDiagram
    class HtDcperiod {
        +double Value
        +bool IsHot
        +HtDcperiod()
        +HtDcperiod(ITValuePublisher source)
        +TValue Update(TValue input, bool isNew)
        +void Reset()
    }

Class: HtDcperiod

Parameter Type Default Range Description
(none) No constructor parameters

Properties

  • Value (double): Dominant cycle period in bars (6-50)
  • IsHot (bool): Returns true when warmup (32 bars) is complete

Methods

  • Update(TValue input, bool isNew): Updates the indicator with a new data point

C# Example

using QuanTAlib;

// Create HT_DCPERIOD
var htPeriod = new HtDcperiod();

// Update with streaming data
foreach (var bar in quotes)
{
    var result = htPeriod.Update(new TValue(bar.Date, bar.Close));
    
    if (htPeriod.IsHot)
    {
        double period = result.Value;
        Console.WriteLine($"{bar.Date}: Dominant Cycle = {period:F2} bars");
        
        // Use cycle to tune RSI adaptively
        int adaptivePeriod = (int)(period / 2);
        var adaptiveRsi = new Rsi(adaptivePeriod);
    }
}

// Batch calculation
var output = HtDcperiod.Calculate(sourceSeries);