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:
Applies Hilbert Transform to create InPhase and Quadrature components
Calculates the period from the phase relationship
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:
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
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:
Separates trend from cycle components
Identifies the dominant cycle period
Calculates cycle phase and amplitude
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