← Back to Home
Enhancing Trading Strategies With a Hurst-Based Regime Filter

Enhancing Trading Strategies With a Hurst-Based Regime Filter

Trend-following systems often fail during sideways markets. A common solution is to apply a regime filter that activates the strategy only when the market shows persistent directional behavior. One useful statistical measure for this purpose is the Hurst exponent.

This article explains how to combine the Hurst exponent with a simple moving average crossover to build a trend-following strategy and implement it in Python using vectorbt.

Concept

The strategy trades only when the market demonstrates persistent trending behavior.

The logic combines two components.

A trend signal

Fast moving average above slow moving average indicates bullish momentum.

A market regime filter

The Hurst exponent measures whether price movements behave like a trend, random walk, or mean-reverting process.

Trades are only taken when the regime suggests trending conditions.

The Hurst Exponent

The Hurst exponent (H) quantifies the persistence of a time series.

Interpretation

The classical estimation method is the Rescaled Range (R/S) method.

\[ \frac{R(n)}{S(n)} \propto n^H \]

Taking logs gives an estimate of (H)

\[ H = \frac{\log(R(n)/S(n))}{\log(n)} \]

Where

Values above roughly 0.6 often indicate strong trend persistence.

Strategy Logic

Entry conditions

Exit conditions

The filter prevents trades during noisy or mean-reverting periods.

Data Download

The following code downloads historical data using yfinance.

import numpy as np
import pandas as pd
import yfinance as yf
import vectorbt as vbt
from hurst import compute_Hc
import matplotlib.pyplot as plt
import matplotlib
matplotlib.use("inline")

ticker = "ETH-USD"
start = "2022-01-01"
end = "2025-12-31"

df = yf.download(ticker, start=start, end=end, auto_adjust=True).droplevel(1, 1)

close = df["Close"].dropna()

The .droplevel(1, 1) removes the multi-index created by yfinance so the dataframe is easier to work with.

Log Returns

The Hurst exponent is estimated from log returns, not prices.

log_ret = np.log(close / close.shift(1)).dropna()

Log returns stabilize variance and make statistical analysis more reliable.

Rolling Hurst Calculation

A rolling window allows the regime to adapt over time.

hurst_window = 120

hurst_values = []

for i in range(len(log_ret)):
    if i < hurst_window:
        hurst_values.append(np.nan)
    else:
        window = log_ret.iloc[i-hurst_window:i]
        H, _, _ = compute_Hc(window, kind="price", simplified=True)
        hurst_values.append(H)

hurst = pd.Series(hurst_values, index=log_ret.index)

This produces a time series representing the local persistence of the market.

Moving Averages

Simple moving averages provide the trend signal.

fast_sma = 10
slow_sma = 30

fast = close.rolling(fast_sma).mean()
slow = close.rolling(slow_sma).mean()

Short windows respond quickly to price changes while longer windows define the broader trend.

Regime Filter

The regime filter activates trading only in trending conditions.

hurst_trending = 0.6

trending = hurst > hurst_trending

When the Hurst value exceeds the threshold the market is treated as persistent.

Entry and Exit Signals

Signals combine the trend signal with the regime filter.

entries = (fast > slow) & trending
exits = (fast < slow) | (~trending)

Entries require both trend confirmation and favorable market structure.

Backtesting With Vectorbt

vectorbt makes it straightforward to simulate the strategy.

fee = 0.001

pf = vbt.Portfolio.from_signals(
    close,
    entries,
    exits,
    fees=fee
)

The framework automatically handles position management, transaction costs, and performance metrics.

Performance Evaluation

A quick performance overview can be produced with:

print(pf.stats())
pf.total_return().vbt.plot()
Pasted image 20260306071914.png

Extensions

The approach can be improved in several ways.

Adaptive thresholds

Instead of a fixed Hurst threshold, use quantiles of historical values.

Multi-timeframe confirmation

Combine Hurst estimates from different windows.

Volatility filtering

Trade only when both volatility and persistence support trend continuation.

Asset diversification

Apply the same regime filter across multiple markets.

Summary

The Hurst-Filtered SMA Trend Strategy enhances a classic moving average crossover by incorporating statistical market structure. The Hurst exponent acts as a regime filter that allows trades only during persistent trending conditions.

Combining simple indicators with statistical measures often produces strategies that are both robust and interpretable, making them useful foundations for more advanced systematic trading systems.