Files
QuanTAlib/lib/cycles/ht_sine/HtSine.md
T
Miha Kralj 3dd05f23e4 Refactor indicators to include "Ehlers" in names and descriptions for clarity
- Updated the name and description of the Hilbert Trendline (HTIT) to "Ehlers Hilbert Transform Instantaneous Trend (HTIT)".
- Changed the name and description of the MESA Adaptive Moving Average (MAMA) to "Ehlers MESA Adaptive Moving Average".
- Modified the Center of Gravity (CG) indicator to "Ehlers Center of Gravity (CG)".
- Renamed the Detrended Synthetic Price (DSP) to "Ehlers Detrended Synthetic Price (DSP)".
- Updated the Autocorrelation Periodogram (EACP) to "Ehlers Autocorrelation Periodogram (EACP)".
- Changed the Homodyne Discriminator (HOMOD) to "Ehlers Homodyne Discriminator (HOMOD)".
- Updated the Hilbert Transform Dominant Cycle Period and Phase indicators to include "Ehlers" in their names.
- Renamed the Hilbert Transform Phasor Components to "Ehlers Hilbert Transform Phasor Components (HT_PHASOR)".
- Updated the SineWave indicator to "Ehlers Hilbert Transform SineWave (HT_SINE)".
- Changed the Phasor Analysis indicator to "Ehlers Hilbert Transform Phasor Components (HT_PHASOR)".
- Updated the SSF-Based Detrended Synthetic Price to "Ehlers SSF Detrended Synthetic Price (SSFDSP)".
- Renamed the Ultimate Channel to "Ehlers Ultimate Channel (UCHANNEL)".
- Added new indicators: Moving Average Variable Period (MAVP), Ehlers Predictive Moving Average (PMA), Ehlers Reverse EMA (REVERSEEMA), and Ehlers Trendflex Indicator (TRENDFLEX).
- Updated various SVG badges to reflect changes in classes, comments, source files, lines of code, methods, and public types.
2026-02-18 19:08:15 -08:00

6.0 KiB

HT_SINE: Ehlers Hilbert Transform SineWave

"The Hilbert Transform gives us the phase of the dominant cycle—knowing when to buy and sell becomes a matter of trigonometry."

The Hilbert Transform SineWave extracts the dominant market cycle phase and outputs both sine and lead sine (45° phase advance) for cycle timing. The crossover of these two waves identifies turning points in ranging markets up to 1/8th of a cycle early.

Historical Context

John Ehlers introduced the Hilbert Transform SineWave in Rocket Science for Traders (2001) as part of his comprehensive signal processing framework for financial markets. The indicator addresses a fundamental limitation of traditional oscillators—they respond to price amplitude rather than cycle phase.

The HT_SINE builds upon David Hilbert's 1905 mathematical transform, which creates a 90° phase-shifted (quadrature) version of a signal. In signal processing, this enables instantaneous frequency and phase extraction. Ehlers recognized that market cycles, though noisy and variable, could be analyzed using these same techniques.

Unlike momentum oscillators that lag price action, the HT_SINE theoretically provides zero-lag cycle detection by measuring phase directly. This makes it particularly valuable in ranging markets where cycles are well-defined. The dual output (Sine and LeadSine) creates a built-in early warning system for cycle reversals.

Architecture & Physics

The algorithm implements a discrete approximation of the Hilbert Transform optimized for financial time series with adaptive period estimation.

Step 1: WMA Smoothing

A 4-bar weighted moving average removes Nyquist-frequency noise:

\bar{P}_t = \frac{4P_t + 3P_{t-1} + 2P_{t-2} + P_{t-3}}{10}

Step 2: Hilbert Transform FIR

The discrete Hilbert approximation generates quadrature components:

\text{Detrender}_t = 0.0962\bar{P}_t + 0.5769\bar{P}_{t-2} - 0.5769\bar{P}_{t-4} - 0.0962\bar{P}_{t-6}

Step 3: I/Q Component Smoothing

In-phase and quadrature components undergo exponential smoothing:

Q_t = 0.2(Q1_t + JI_t) + 0.8 Q_{t-1} I_t = 0.2(I1_t - JQ_t) + 0.8 I_{t-1}

Step 4: Homodyne Discriminator

Period estimation uses phase rate of change:

Re_t = 0.2(I_t \cdot I_{t-1} + Q_t \cdot Q_{t-1}) + 0.8 Re_{t-1} Im_t = 0.2(I_t \cdot Q_{t-1} - Q_t \cdot I_{t-1}) + 0.8 Im_{t-1} \text{Period}_t = \frac{2\pi}{\arctan(Im_t / Re_t)}

Step 5: DC Phase Calculation

The dominant cycle phase sums weighted contributions:

\phi_t = \arctan\left(\frac{\sum_{i=0}^{P-1} \sin(2\pi i/P) \cdot \bar{P}_{t-i}}{\sum_{i=0}^{P-1} \cos(2\pi i/P) \cdot \bar{P}_{t-i}}\right)

Step 6: Output Generation

\text{Sine}_t = \sin(\phi_t) \text{LeadSine}_t = \sin(\phi_t + 45°)

Performance Profile

Operation Count (Streaming Mode, per Bar)

Operation Count Cost (cycles) Subtotal
FMA 12 5 60
MUL 18 4 72
ADD/SUB 25 1 25
DIV 2 15 30
sin/cos 2P 40 ~80P
atan 2 50 100
Buffer access 15 3 45
Total ~370

Complexity Analysis

  • Time: O(P) per bar where P is smoothed period (typically 6-50)
  • Space: O(1) — fixed-size circular buffers (50 + 44 + 64 elements)
  • Latency: 63 bars warmup (31 + 32 for TA-Lib compatibility)

Validation

Library Status Notes
TA-Lib Match TA_HT_SINE() reference implementation
PineScript Match Custom ht_sine.pine validation script
Quantower Match HtSine.Quantower.Tests.cs adapter tests

Usage & Pitfalls

  • Trend Failure: Crossover signals whipsaw in strong trends; parallel "snake" pattern indicates trending mode
  • Warmup Period: Requires 63 bars before outputs stabilize
  • Phase Lag: Despite "zero-lag" theory, smoothing introduces 4-6 bars practical lag
  • Range-Only: Most effective in sideways/ranging markets with clear cyclical behavior
  • LeadSine First: LeadSine turns before Sine at reversals—watch for divergence

API

classDiagram
    class AbstractBase {
        <<abstract>>
        +Name string
        +WarmupPeriod int
        +IsHot bool
        +Last TValue
        +Update(TValue input, bool isNew) TValue
        +Reset() void
    }
    class HtSine {
        +LeadSine double
        +HtSine()
        +HtSine(ITValuePublisher source)
        +Update(TValue input, bool isNew) TValue
        +Update(TSeries source) TSeries
        +Prime(ReadOnlySpan~double~ source, TimeSpan? step) void
        +Reset() void
        +Calculate(TSeries source)$ TSeries
        +Batch(ReadOnlySpan~double~ source, Span~double~ sine, Span~double~ leadSine)$ void
    }
    AbstractBase <|-- HtSine

Class: HtSine

Hilbert Transform SineWave indicator with dual output.

Properties

Name Type Description
LeadSine double Current LeadSine value (45° phase lead)
IsHot bool True after 63 bars warmup
Last TValue Most recent Sine output

Methods

Name Returns Description
Update(TValue, bool) TValue Updates state with new price value
Batch(source, sine, leadSine) void Processes span with dual output spans
Calculate(TSeries) TSeries Static factory returning Sine series

C# Example

using QuanTAlib;

// Create HT_SINE indicator
var htSine = new HtSine();

// Process price data
foreach (var bar in bars)
{
    var result = htSine.Update(new TValue(bar.Time, bar.Close));
    
    if (htSine.IsHot)
    {
        double sine = result.Value;
        double leadSine = htSine.LeadSine;
        
        // Crossover detection
        // Buy: Sine crosses above LeadSine
        // Sell: Sine crosses below LeadSine
        Console.WriteLine($"Sine: {sine:F4}, LeadSine: {leadSine:F4}");
    }
}

// Batch processing with dual outputs
Span<double> sineOut = stackalloc double[prices.Length];
Span<double> leadOut = stackalloc double[prices.Length];
HtSine.Batch(prices, sineOut, leadOut);