FIGARCH — long memory in volatility (from scratch)¶

Fractionally Integrated GARCH (Baillie, Bollerslev & Mikkelsen 1996)¶

Every GARCH fit in this arc reports the same near-unit-root persistence, $\alpha+\beta\approx0.997$ — volatility shocks that almost never die. Standard GARCH can only call this "nearly integrated" ($d=0$ short memory, compromised up toward 1) or IGARCH ($d=1$). FIGARCH offers the honest middle — fractional integration. It applies the fractional-differencing operator $(1-L)^d$ to the ARCH filter, $$\phi(L)(1-L)^d\,\varepsilon_t^2=\omega+(1-\beta L)\,\nu_t,\qquad \nu_t=\varepsilon_t^2-\sigma_t^2,$$ so a volatility shock decays hyperbolically ($\sim j^{\,d-1}$) rather than geometrically. $d\in(0,1)$ nests the spectrum: $d=0$ is ordinary GARCH (short memory), $d=1$ is IGARCH (infinite persistence), $0<d<1$ is genuine long memory. We estimate it from scratch (figarch.py) and read off $d$ — the answer to "how persistent is volatility, really?"

Data: daily S&P 500 log returns, sp500ret.csv (1987–2009) — the same series the GARCH arc and the MS-GARCH rival (msgarch_python.ipynb) use.

The model: fractional differencing and the ARCH($\infty$) filter¶

The whole idea lives in the operator $(1-L)^d$ for non-integer $d$. Expanded as a binomial series it is an infinite lag polynomial with slowly-decaying coefficients: $$(1-L)^d=\sum_{j=0}^{\infty}\pi_j L^j,\qquad \pi_0=1,\quad \pi_j=\pi_{j-1}\,\frac{j-1-d}{j},$$ so $\pi_j\sim j^{-d-1}$ — a hyperbolic, not geometric, tail. This is the bridge between $d=0$ (only $\pi_0=1$ survives → ordinary GARCH) and $d=1$ (the ordinary difference $1-L$ → IGARCH).

Solving the FIGARCH equation for $\sigma_t^2$ writes the conditional variance as an ARCH($\infty$) filter of past squared returns, $$\sigma_t^2=\frac{\omega}{1-\beta}+\lambda(L)\,\varepsilon_t^2,\qquad \lambda(L)=1-\frac{(1-\phi L)(1-L)^d}{1-\beta L},$$ whose weights $\lambda_j$ inherit the hyperbolic decay of $(1-L)^d$. figarch.py builds exactly these $\lambda_j$ recursively (weights) and convolves them with $\varepsilon_t^2$ (var); the plot below is that $\lambda_j$ sequence. The single parameter $d$ controls how fat the memory tail is.

In [1]:
import numpy as np, pandas as pd, matplotlib.pyplot as plt
import figarch as FI, garch_scratch as G

r = pd.read_csv("sp500ret.csv")["ret"].values
th, r2 = FI.mle(r, student=True); o, d, phi, beta, nu = th          # FIGARCH-t by ML
aic_fi = -2 * FI.loglik(th, r2, True) + 2 * 5
thg, _, _ = G.garch_mle(r, student=True); ag, bg = thg[1], thg[2]    # GARCH-t for comparison
print("FIGARCH-t:  omega %.3f  d %.3f  phi %.3f  beta %.3f  nu %.2f   AIC %.0f" % (o, d, phi, beta, nu, aic_fi))
print("GARCH-t:    alpha %.3f  beta %.3f  ->  persistence alpha+beta = %.4f (near unit root)" % (ag, bg, ag + bg))
print("d = %.3f in (0,1): genuine LONG MEMORY (d=0 -> GARCH short memory; d=1 -> IGARCH)" % d)

# ARCH(inf) shock weights: FIGARCH lambda_j (hyperbolic) vs GARCH alpha*beta^{j-1} (geometric)
J = 400; j = np.arange(1, J + 1)
lam = FI.weights(d, phi, beta, J)[1:]; psi = ag * bg ** (j - 1)
lam_n = lam / lam.sum(); psi_n = psi / psi.sum()
Rk_fi = 1 - np.cumsum(lam_n); Rk_g = 1 - np.cumsum(psi_n)            # fraction of impact beyond lag k
print("memory: %% of a shock still felt after 100 days -- FIGARCH %.0f%%  vs GARCH %.1f%%" % (100 * Rk_fi[99], 100 * Rk_g[99]))

fig, ax = plt.subplots(1, 2, figsize=(13, 4.6))
ax[0].loglog(j, lam_n, color="firebrick", lw=1.8, label="FIGARCH  ($d=%.2f$, hyperbolic)" % d)
ax[0].loglog(j, psi_n, color="seagreen", lw=1.8, label="GARCH  (geometric)")
ax[0].set_xlabel("lag  $j$ (days)"); ax[0].set_ylabel("shock weight $\\lambda_j$ (normalised)"); ax[0].legend(fontsize=8)
ax[0].set_title("How a volatility shock decays\n(FIGARCH: power-law straight line; GARCH: falls off a cliff)")
ax[1].plot(j, 100 * Rk_fi, color="firebrick", lw=1.8, label="FIGARCH")
ax[1].plot(j, 100 * Rk_g, color="seagreen", lw=1.8, label="GARCH")
ax[1].set_xlim(0, 250); ax[1].set_xlabel("days after the shock  $k$"); ax[1].set_ylabel("% of the shock's impact still ahead")
ax[1].legend(fontsize=8); ax[1].set_title("Volatility memory\n(GARCH forgets in weeks; FIGARCH remembers for a year)")
plt.tight_layout(); plt.show()
FIGARCH-t:  omega 0.021  d 0.523  phi 0.175  beta 0.667  nu 6.23   AIC 14677
GARCH-t:    alpha 0.060  beta 0.937  ->  persistence alpha+beta = 0.9968 (near unit root)
d = 0.523 in (0,1): genuine LONG MEMORY (d=0 -> GARCH short memory; d=1 -> IGARCH)
memory: % of a shock still felt after 100 days -- FIGARCH 7%  vs GARCH 0.1%
No description has been provided for this image

Reading the figure¶

  • Left — the decay is a power law, not a cliff. On log-log axes the FIGARCH shock weights $\lambda_j$ fall along a near-straight line (a power law, slope $\approx d-1$), while the GARCH weights $\alpha\beta^{\,j-1}$ curve away and collapse — geometric decay looks like falling off a cliff. By lag 100 the FIGARCH weight is thousands of times larger than GARCH's.
  • Right — volatility remembers for a year. Read as memory: GARCH has essentially forgotten a shock within ~6 weeks, but FIGARCH still carries ~7% of a shock's impact after 100 trading days (GARCH ~0.1%). The near-integrated persistence is really a long, slowly-fading memory.

Results¶

  • $d=0.52$ — genuine long memory. Well inside $(0,1)$: volatility is neither short-memory GARCH nor integrated IGARCH but fractionally integrated. And FIGARCH-$t$ fits better by AIC (14677) than GARCH-$t$ (≈14684 on the same returns, as reported in the GARCH project) — the long-memory structure is real, not a reparameterisation.
  • The same long memory HAR found — from returns instead of RV. In Phase 1 the realized-variance autocorrelation decayed hyperbolically (implying $d\approx0.4$–0.5); here FIGARCH recovers $d=0.52$ directly from daily returns. Two data sources, one conclusion — FIGARCH is the returns-side twin of HAR.

The persistence question¶

FIGARCH gives one answer to "why is volatility persistence ≈ 1?": it is genuine long memory. But there is a rival answer — that the appearance of long memory is an artifact of unmodeled regime shifts (Diebold–Inoue 2001: switching and long memory are observationally confounded). The companion MS-GARCH notebook makes that case, and the realized-volatility series is the tiebreaker.

Reference¶

  • Baillie, R. T., Bollerslev, T. & Mikkelsen, H. O. (1996). Fractionally integrated generalized autoregressive conditional heteroskedasticity. J. Econometrics 74, 3–30.

Next: msgarch_python.ipynb — Markov-switching GARCH, the regime-based rival explanation of persistence.