Mandelbrot Ch. 3: The Hurst Exponent & Long Memory
阅读中文版The rescaled range (R/S) method for measuring long memory, mean-reversion vs. trend persistence, and computing the Hurst exponent in Python.
🔊 Listen to Article (Chinese Audio)
Mandelbrot Fractal Ch. 3: The Hurst Exponent & Long Memory
"The flood records of the Nile told me a secret about financial markets: natural and market systems both have memory — past events continue to influence the future, rather than being instantly forgotten as random walk theory assumes." — Benoit Mandelbrot
An Accidental Discovery in Nile Hydrology
Harold Edwin Hurst, studying millennia of Nile flood records in the 1950s, found that high-flood years clustered with more high-flood years, and low years with more low years — evidence of long memory, not independent randomness.
Mandelbrot recognized this hydrological tool as the perfect test of the Efficient Market Hypothesis's core claim that price changes are independent and unpredictable.
Rescaled Range (R/S) Analysis
$$Y_k = \sum_{t=1}^{k}(X_t - \bar{X}), \quad R(n) = \max_k Y_k - \min_k Y_k$$
$$\frac{R(n)}{S(n)} \sim c \cdot n^H \implies \log\left(\frac{R(n)}{S(n)}\right) = \log(c) + H\log(n)$$
Interpreting the Hurst Exponent
| Range | Behavior | Trading Implication |
|---|---|---|
| $H = 0.5$ | Pure random walk | No memory; technical analysis has no edge |
| $0.5 < H < 1.0$ | Persistent trend | Trend-following has mathematical grounding |
| $0 < H < 0.5$ | Anti-persistent / mean-reverting | Mean-reversion has mathematical grounding |
Mandelbrot's empirical work on cotton, gold, and equity indices found most series cluster between $H = 0.5$ and $0.7$ — directly falsifying the pure random walk premise of EMH.
import numpy as np
def hurst_exponent(price_series, min_window=10, max_window=None):
n = len(price_series)
max_window = max_window or n // 2
window_sizes = np.unique(np.logspace(np.log10(min_window), np.log10(max_window), 20).astype(int))
rs_values = []
for window in window_sizes:
n_chunks = n // window
if n_chunks < 1:
continue
rs_chunk = []
for i in range(n_chunks):
chunk = price_series[i*window:(i+1)*window]
cumulative = np.cumsum(chunk - np.mean(chunk))
s = np.std(chunk)
if s > 0:
rs_chunk.append((np.max(cumulative) - np.min(cumulative)) / s)
if rs_chunk:
rs_values.append(np.mean(rs_chunk))
hurst, _ = np.polyfit(np.log(window_sizes[:len(rs_values)]), np.log(rs_values), 1)
return hurst
Practical Execution Rules
- Measure the Hurst exponent before deploying trend or mean-reversion strategies — favor trend-following above $H = 0.55$, mean-reversion below $H = 0.45$.
- Re-estimate on a rolling window — $H$ drifts across regimes; do not rely on a single historical estimate.
- Treat $H$ as a framework filter, not a timing signal — combine with independent momentum or band signals for entries/exits.