Note
Go to the end to download the full example code or to run this example in your browser via JupyterLite.
Hurst exponent#
To size the Aswan reservoirs, Harold Edwin Hurst (1951) studied the range of cumulative departures of the Nile’s annual flow from its mean: the storage a dam would need to deliver the average flow every year. Divided by the standard deviation, the range of independent inflows grows like \(n^{1/2}\); Hurst found \(n^{0.73}\) for the Nile and many other records. Wet years cluster with wet years. Mandelbrot later linked the exponent \(H\) to fractional Brownian motion: \(H > 1/2\) means persistence, \(H < 1/2\) mean reversion, and in markets a reliable \(H \ne 1/2\) would make returns predictable.
import matplotlib.pyplot as plt
import numpy as np
from financialkit.time_series import hurst_exponent, simulate_fgn
from financialkit.time_series.visualizers import plot_rescaled_range
Persistent, independent and anti-persistent noise#
Fractional Gaussian noise with three exponents, cumulated into “flows”.

<matplotlib.legend.Legend object at 0x1169dfa10>
Rescaled-range analysis#
The slope of \(\log(R/S)_n\) on \(\log n\) estimates \(H\). The dashed line is Anis and Lloyd’s exact expectation for independent data; its slope exceeds 1/2 in short windows, which is why the corrected estimate measures the excess over it.
fig, ax = plt.subplots()
for H, x in series.items():
res = hurst_exponent(x)
plot_rescaled_range(res, ax=ax, label=f"true {H}:")
print(f"true H = {H}: raw slope {res.hurst:.2f}, corrected {res.hurst_corrected:.2f}")
ax.legend(fontsize=8)
plt.show()

true H = 0.3: raw slope 0.38, corrected 0.34
true H = 0.5: raw slope 0.52, corrected 0.48
true H = 0.75: raw slope 0.72, corrected 0.69
The returns of a random-walk price have \(H \approx 1/2\) once the small-sample bias is removed.
returns = 0.01 * np.random.default_rng(0).standard_normal(4096)
print(f"random-walk returns: corrected H = {hurst_exponent(returns).hurst_corrected:.2f}")
random-walk returns: corrected H = 0.52
Total running time of the script: (0 minutes 0.077 seconds)