Cycle Indicators

Cycle indicators use the Hilbert Transform to identify dominant cycles in price data. These indicators are based on the work of John Ehlers and are useful for identifying cyclical patterns and trend vs. cycle modes.


HT_DCPERIOD - Dominant Cycle Period

The Dominant Cycle Period identifies the length (in bars) of the dominant cycle in the price data using the Hilbert Transform.

Formula

The Hilbert Transform is applied to price data to extract the dominant cycle period. The algorithm:

  1. Applies Hilbert Transform to create InPhase and Quadrature components

  2. Calculates the period from the phase relationship

  3. Smooths the period estimate

Characteristics

Property

Value

Input

Close price

Output

Single value (period in bars)

Lookback

63

Memory

O(1)

API Usage

from techkit import HT_DCPERIOD

dcperiod = HT_DCPERIOD()
result = dcperiod.update(close_price)
if result.valid:
    print(f"Dominant Cycle Period: {result.value:.1f} bars")
const tk = require('techkit');

const dcperiod = tk.htDcperiod();
const result = dcperiod.update(close);
#include <techkit/techkit.hpp>

techkit::HT_DCPERIOD dcperiod;
auto result = dcperiod.update(close);
tk_indicator dcperiod = tk_ht_dcperiod_new();
tk_result r = tk_update(dcperiod, close);
tk_free(dcperiod);

Trading Usage

  • Cycle Length: Typical values range from 10-50 bars

  • Adaptive Indicators: Use period to set adaptive moving average periods

  • Entry Timing: Enter trades at cycle extremes

  • Trend vs. Cycle: Combine with HT_TRENDMODE to determine market state


HT_DCPHASE - Dominant Cycle Phase

The Dominant Cycle Phase returns the current phase of the dominant cycle in degrees (0-360).

Formula

The phase is calculated from the InPhase and Quadrature components:

\[\text{phase} = \arctan2(\text{Quadrature}, \text{InPhase}) \times \frac{180}{\pi}\]

Phase is normalized to 0-360 degrees.

Characteristics

Property

Value

Input

Close price

Output

Single value (phase in degrees, 0-360)

Lookback

63

Memory

O(1)

API Usage

from techkit import HT_DCPHASE

dcphase = HT_DCPHASE()
result = dcphase.update(close_price)
if result.valid:
    phase = result.value
    if phase < 90:
        print("Early cycle")
    elif phase < 180:
        print("Mid cycle up")
    elif phase < 270:
        print("Late cycle")
    else:
        print("Mid cycle down")

Trading Usage

  • Cycle Position:

    • 0-90°: Early cycle (potential buy)

    • 90-180°: Mid cycle up

    • 180-270°: Late cycle (potential sell)

    • 270-360°: Mid cycle down

  • Entry/Exit Timing: Use phase extremes for entries

  • Cycle Confirmation: Combine with HT_SINE for cycle confirmation


HT_PHASOR - Phasor Components

The HT_PHASOR returns the InPhase and Quadrature components of the Hilbert Transform, which represent the cycle in complex number form.

Formula

The Hilbert Transform extracts:

  • InPhase (I1): Real component of the cycle

  • Quadrature (Q1): Imaginary component of the cycle

These components are 90 degrees out of phase.

Characteristics

Property

Value

Input

Close price

Output

Two values (inphase, quadrature)

Lookback

63

Memory

O(1)

API Usage

from techkit import HT_PHASOR

phasor = HT_PHASOR()
result = phasor.update(close_price)
if result.valid:
    print(f"InPhase: {result.inphase:.4f}")
    print(f"Quadrature: {result.quadrature:.4f}")
    
    # Calculate amplitude
    amplitude = (result.inphase**2 + result.quadrature**2)**0.5
    print(f"Amplitude: {amplitude:.4f}")

Trading Usage

  • Cycle Amplitude: Calculate from I1² + Q1²

  • Cycle Phase: Calculate from atan2(Q1, I1)

  • Advanced Analysis: Use for custom cycle indicators

  • Filtering: Use to filter noise from price data


HT_SINE - SineWave

The HT_SINE returns the Sine and LeadSine of the dominant cycle phase. LeadSine is 45 degrees ahead of Sine.

Formula

\[\text{Sine} = \sin(\text{phase})\]
\[\text{LeadSine} = \sin(\text{phase} + 45°)\]

where phase is calculated from HT_PHASOR components.

Characteristics

Property

Value

Input

Close price

Output

Two values (sine, leadsine)

Lookback

63

Memory

O(1)

API Usage

from techkit import HT_SINE

sine = HT_SINE()
result = sine.update(close_price)
if result.valid:
    print(f"Sine: {result.sine:.4f}")
    print(f"LeadSine: {result.leadsine:.4f}")
    
    # Buy signal: Sine crosses above LeadSine
    if result.sine > result.leadsine:
        print("Bullish signal")
    # Sell signal: Sine crosses below LeadSine
    elif result.sine < result.leadsine:
        print("Bearish signal")

Trading Usage

  • Buy Signal: Sine crosses above LeadSine

  • Sell Signal: Sine crosses below LeadSine

  • Cycle Extremes:

    • Sine near +1: Cycle peak (potential sell)

    • Sine near -1: Cycle trough (potential buy)

  • Trend Following: Use in trending markets (confirmed by HT_TRENDMODE)

Common Strategy

# Combined cycle strategy
sine = HT_SINE()
trendmode = HT_TRENDMODE()

for price in prices:
    sine_result = sine.update(price)
    trend_result = trendmode.update(price)
    
    if sine_result.valid and trend_result.valid:
        # Only trade in cycle mode (not trending)
        if trend_result.value == 0:  # Cycle mode
            if sine_result.sine > sine_result.leadsine:
                # Buy signal
                pass
            elif sine_result.sine < sine_result.leadsine:
                # Sell signal
                pass

HT_TRENDLINE - Instantaneous Trendline

The HT_TRENDLINE returns the instantaneous trendline based on the dominant cycle. It’s smoother than a simple moving average and adapts to the cycle.

Formula

The trendline is calculated from the InPhase component, filtered to remove cycle components and leave only the trend.

Characteristics

Property

Value

Input

Close price

Output

Single value (trendline price)

Lookback

63

Memory

O(1)

API Usage

from techkit import HT_TRENDLINE

trendline = HT_TRENDLINE()
result = trendline.update(close_price)
if result.valid:
    print(f"Trendline: {result.value:.2f}")
    
    # Price above trendline = uptrend
    if close_price > result.value:
        print("Uptrend")
    else:
        print("Downtrend")

Trading Usage

  • Trend Identification: Price above trendline = uptrend

  • Support/Resistance: Trendline acts as dynamic S/R

  • Entry Signals: Buy when price crosses above trendline

  • Comparison: Smoother than EMA, adapts to cycles


HT_TRENDMODE - Trend vs. Cycle Mode

The HT_TRENDMODE determines whether the market is in trending mode (1) or cycling mode (0).

Formula

The indicator compares the strength of the trend component to the cycle component. If trend dominates, returns 1; if cycle dominates, returns 0.

Characteristics

Property

Value

Input

Close price

Output

Single value (1 = trending, 0 = cycling)

Lookback

63

Memory

O(1)

API Usage

from techkit import HT_TRENDMODE

trendmode = HT_TRENDMODE()
result = trendmode.update(close_price)
if result.valid:
    if result.value == 1:
        print("Market is trending - use trend-following indicators")
    else:
        print("Market is cycling - use cycle indicators")

Trading Usage

  • Indicator Selection:

    • Trending (1): Use trend-following indicators (MA, ADX)

    • Cycling (0): Use cycle indicators (HT_SINE, oscillators)

  • Strategy Adaptation: Switch strategies based on mode

  • Filter: Filter cycle signals when in trending mode

Combined Strategy Example

from techkit import HT_TRENDMODE, HT_SINE, HT_TRENDLINE, ADX

trendmode = HT_TRENDMODE()
sine = HT_SINE()
trendline = HT_TRENDLINE()
adx = ADX(period=14)

for bar in bars:
    mode = trendmode.update(bar.close)
    sine_result = sine.update(bar.close)
    trend_result = trendline.update(bar.close)
    adx_result = adx.update_ohlcv(bar)
    
    if all results valid:
        if mode.value == 1:  # Trending
            # Use trend-following logic
            if bar.close > trend_result.value and adx_result.adx > 25:
                # Strong uptrend
                pass
        else:  # Cycling
            # Use cycle logic
            if sine_result.sine > sine_result.leadsine:
                # Cycle buy signal
                pass

Hilbert Transform Overview

The Hilbert Transform is a mathematical technique that:

  1. Separates trend from cycle components

  2. Identifies the dominant cycle period

  3. Calculates cycle phase and amplitude

  4. Determines market mode (trending vs. cycling)

Advantages

  • Adaptive: Automatically adapts to changing cycle lengths

  • No Lag: Instantaneous calculation (no look-ahead bias)

  • Mode Detection: Identifies when to use trend vs. cycle strategies

Limitations

  • Requires Warmup: Needs 63 bars before valid output

  • Noise Sensitivity: Can be affected by market noise

  • Complex: Requires understanding of cycle analysis



Further Reading

  • Ehlers, J. F. (2001). Rocket Science for Traders: Digital Signal Processing Applications

  • Ehlers, J. F. (2004). Cybernetic Analysis for Stocks and Futures