Hull Moving Average (HMA)

Haiyue
10min

I. What is HMA

The Hull Moving Average (HMA) is a moving average that achieves both extremely low lag and high smoothness simultaneously. It was invented in 2005 by Australian mathematician and trader Alan Hull, and is widely regarded as one of the best compromise solutions in the moving average family.

Historical Background

In his trading practice, Alan Hull identified a fundamental contradiction: traditional moving averages are either smooth but laggy (like SMA) or fast but noisy (like TEMA). His goal was to design a moving average that could simultaneously:

  1. Nearly eliminate lag
  2. Maintain curve smoothness

He ingeniously achieved this through a combination of WMA (Weighted Moving Average) and square-root period smoothing. Since its introduction, HMA has quickly gained recognition from traders worldwide, often called the “Holy Grail of moving averages.”

Indicator Classification

  • Type: Overlay indicator, plotted on the price chart
  • Category: Moving Averages
  • Default Parameters: Period n=20n = 20, data source is closing price (Close)

II. Mathematical Principles and Calculation

Core Formula

HMA is calculated in three steps:

Step 1: Calculate half-period WMA and full-period WMA

WMAhalf=WMA(P,n/2)WMA_{half} = WMA(P, \lfloor n/2 \rfloor) WMAfull=WMA(P,n)WMA_{full} = WMA(P, n)

Step 2: Construct the difference series

Δ=2WMAhalfWMAfull\Delta = 2 \cdot WMA_{half} - WMA_{full}

Step 3: Apply n\sqrt{n}-period WMA to the difference series

HMA=WMA(Δ,n)HMA = WMA(\Delta, \lfloor \sqrt{n} \rfloor)

The combined formula is:

HMAn=WMA(2WMA(P,n/2)WMA(P,n), n)HMA_n = WMA\Big(2 \cdot WMA(P, \lfloor n/2 \rfloor) - WMA(P, n),\ \lfloor\sqrt{n}\rfloor\Big)

Design Rationale

Why use 2WMAhalfWMAfull2 \cdot WMA_{half} - WMA_{full}?

  • WMAhalfWMA_{half} uses half the period, responding faster but with some lag
  • WMAfullWMA_{full} uses the full period, responding slower with greater lag
  • 2WMAhalfWMAfull2 \cdot WMA_{half} - WMA_{full} acts as an “extrapolation,” overcompensating for the slower average’s lag to approximate the true price. This approach is analogous to DEMA’s 2EMAEMA(EMA)2 \cdot EMA - EMA(EMA)

Why apply a final n\sqrt{n}-period WMA?

  • The difference Δ\Delta has extremely low lag but the curve is not smooth enough (noisy)
  • Applying n\sqrt{n}-period WMA to Δ\Delta provides final smoothing. n\sqrt{n} is a carefully chosen value — sufficient to eliminate noise without introducing too much additional lag
Why WMA Instead of EMA

Alan Hull chose WMA over EMA because WMA’s linear weights perform better in combination operations. WMA’s finite window ensures that the intermediate difference Δ\Delta is computed cleanly, while EMA’s infinite memory could introduce extra lag in multi-layer nesting.

Numerical Example

Taking n=16n = 16 as an example:

  • n/2=8\lfloor n/2 \rfloor = 8
  • n=4\lfloor\sqrt{n}\rfloor = 4
  • Calculate WMA(P,8)WMA(P, 8) and WMA(P,16)WMA(P, 16)
  • Difference Δ=2WMA(P,8)WMA(P,16)\Delta = 2 \cdot WMA(P, 8) - WMA(P, 16)
  • Final result HMA=WMA(Δ,4)HMA = WMA(\Delta, 4)

III. Python Implementation

import numpy as np
import pandas as pd

def wma(close: pd.Series, period: int) -> pd.Series:
    """Calculate the Weighted Moving Average (WMA)"""
    weights = np.arange(1, period + 1, dtype=float)

    def _wma(window):
        return np.dot(window, weights) / weights.sum()

    return close.rolling(window=period, min_periods=period).apply(_wma, raw=True)


def hma(close: pd.Series, period: int = 20) -> pd.Series:
    """
    Calculate the Hull Moving Average (HMA)

    Parameters
    ----------
    close : pd.Series
        Closing price series
    period : int
        Calculation period, default is 20

    Returns
    -------
    pd.Series
        HMA value series
    """
    half_period = int(period / 2)
    sqrt_period = int(np.sqrt(period))

    # Steps 1 & 2: Construct the difference series
    wma_half = wma(close, half_period)
    wma_full = wma(close, period)
    delta = 2 * wma_half - wma_full

    # Step 3: Final smoothing
    return wma(delta, sqrt_period)


def hma_numpy(close: np.ndarray, period: int = 20) -> np.ndarray:
    """
    Manual HMA implementation using numpy
    """
    def _wma_np(src, p):
        n = len(src)
        result = np.full(n, np.nan)
        w = np.arange(1, p + 1, dtype=float)
        d = w.sum()
        for i in range(p - 1, n):
            window = src[i - p + 1 : i + 1]
            if np.any(np.isnan(window)):
                continue
            result[i] = np.dot(window, w) / d
        return result

    half_p = int(period / 2)
    sqrt_p = int(np.sqrt(period))

    wma_half = _wma_np(close, half_p)
    wma_full = _wma_np(close, period)
    delta = 2 * wma_half - wma_full

    return _wma_np(delta, sqrt_p)


# ========== Usage Example ==========
if __name__ == "__main__":
    np.random.seed(42)
    dates = pd.date_range("2024-01-01", periods=150, freq="D")
    price = 100 + np.cumsum(np.random.randn(150) * 0.8)

    df = pd.DataFrame({
        "date": dates,
        "open":  price + np.random.randn(150) * 0.3,
        "high":  price + np.abs(np.random.randn(150) * 0.6),
        "low":   price - np.abs(np.random.randn(150) * 0.6),
        "close": price,
        "volume": np.random.randint(1000, 10000, size=150),
    })
    df.set_index("date", inplace=True)

    # Compare multiple moving averages
    df["SMA_20"] = df["close"].rolling(20).mean()
    df["EMA_20"] = df["close"].ewm(span=20, adjust=False).mean()
    df["HMA_20"] = hma(df["close"], 20)

    print("=== SMA vs EMA vs HMA Comparison ===")
    print(df[["close", "SMA_20", "EMA_20", "HMA_20"]].tail(10))

    # HMA direction change signal
    df["hma_dir"] = np.where(df["HMA_20"] > df["HMA_20"].shift(1), 1, -1)
    df["dir_change"] = df["hma_dir"].diff().abs() > 0

    print("\n=== HMA Direction Change Points ===")
    print(df.loc[df["dir_change"], ["close", "HMA_20", "hma_dir"]])

IV. Problems the Indicator Solves

1. The Lag vs. Smoothness Dilemma

This is HMA’s most significant contribution. Traditionally, reducing lag means sacrificing smoothness (as with TEMA), but HMA’s unique multi-layer WMA combination achieves excellent smoothness alongside extremely low lag.

2. Trend Direction Detection

Changes in HMA’s direction (rising or falling) provide a highly reliable trend signal:

  • HMA turns upward -> Uptrend begins
  • HMA turns downward -> Downtrend begins

Due to HMA’s smoothness, direction change signals do not flip frequently, resulting in fewer false signals.

3. Precise Entry / Exit Timing

HMA’s low lag makes it especially suitable for:

  • Precise entry after trend confirmation
  • Timely exit when trends end
  • Minimizing entry lag and exit delay

4. Visual Trend Analysis

Many traders use HMA color changes (green when rising / red when falling) for visual trend assessment. HMA’s smooth curve makes this visual analysis very intuitive and reliable.

Color Coding Strategy

In charting software, set HMA to display as green when rising and red when falling. Since HMA rarely produces false direction changes, this color coding provides very clear trend signals.


V. Advantages, Disadvantages, and Use Cases

Advantages

AdvantageDescription
Low lag, high smoothnessAchieves both simultaneously; one of the best compromises in moving average design
Reliable direction signalsLow false signal rate for direction changes
Strong adaptabilityPerforms consistently across different markets and timeframes
Elegant constructionUses only simple WMA combinations; clear computational logic

Disadvantages

DisadvantageDescription
Slight overshootMay briefly overshoot during sharp reversals
Higher computationRequires three WMA operations, each O(n)O(n)
Not ideal for support/resistanceDue to overshoot, HMA is less suitable as a support/resistance level
Parameter sensitiveThe floor operation on n\sqrt{n} means different periods can produce notably different results

Use Cases

  • Trend-following strategies: HMA is one of the top choices for trend strategies
  • Swing trading: Daily-level direction assessment
  • Position trading: Capture swing start/end points using HMA direction changes

Comprehensive Moving Average Comparison

IndicatorLagSmoothnessOvershootBest Use
SMAHighHighestNoneLong-term trend / Support-resistance
EMAMediumHighNoneGeneral purpose / MACD component
DEMALowMediumSlightFast signals
TEMAVery lowLowerNotableUltra-fast signals
HMAVery lowHighSlightTrend following
Practical Notes
  1. HMA’s floor operation on n\sqrt{n} means that periods 16 and 20 both use a 4-period WMA for the final smoothing step. Consider this discretization effect when selecting periods.
  2. HMA may still produce false direction changes in extreme ranging markets (e.g., narrow consolidation). Combining with ADX is recommended.
  3. Due to its overshoot characteristic, HMA is not recommended for setting stop-loss levels. Use ATR or smoother moving averages for stop-loss placement.