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.
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%
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.