Realized GARCH — the bridge between GARCH and realized volatility¶

Phase 3: Hansen, Huang & Shek (2012)¶

The arc has run two separate tracks: GARCH/SV infer a latent variance $h_t$ from daily returns, while HAR models the observed realized variance $RV_t$ directly. Realized GARCH joins them. It keeps GARCH's latent $h_t$ but (i) lets the informative $RV$ drive the variance recursion instead of the noisy squared return, and (ii) adds a measurement equation tying the observed $RV_t$ to the latent $h_t$: $$r_t=\sqrt{h_t}\,z_t,\qquad \log h_t=\omega+\beta\log h_{t-1}+\gamma\log RV_{t-1},\qquad \log RV_t=\xi+\varphi\log h_t+\underbrace{\tau_1 z_t+\tau_2(z_t^2-1)}_{\text{leverage}}+u_t.$$ Parameters are estimated by joint maximum likelihood of returns and realized measures (realgarch.py); the effective persistence is $\beta+\varphi\gamma$. Data: spx_rv_ret.csv (S&P 500 returns + 5-min RV, 2000–2013).

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

df = pd.read_csv("spx_rv_ret.csv", parse_dates=["date"])
r = df["ret"].values; RV = df["rv"].values * 1e4; dates = df["date"]     # returns %, RV %^2
th, logh0 = RG.mle(r, RV); p = RG.params_readable(th)                    # joint ML fit
print("Realized GARCH:  omega %.3f  beta %.3f  gamma %.3f  phi %.3f  tau1 %.3f  tau2 %.3f  sigma_u %.3f"
      % (p["omega"], p["beta"], p["gamma"], p["phi"], p["tau1"], p["tau2"], p["sigma_u"]))
print("  effective persistence (beta + phi*gamma) = %.3f" % p["persistence"])
h_rg = np.exp(RG.filter_logh(th, r, np.log(RV), logh0))                  # RealGARCH latent variance
thg, _, _ = G.garch_mle(r, student=True); r2, s0 = G.prepare(r); neg = (r < 0).astype(float)
h_g = G.garch_var(thg, r2, s0, neg, False)                              # standard GARCH-t variance
print("  corr with RV:  RealGARCH %.3f   standard GARCH-t %.3f" % (np.corrcoef(h_rg, RV)[0,1], np.corrcoef(h_g, RV)[0,1]))

fig, ax = plt.subplots(1, 2, figsize=(13, 4.6))
w = (dates >= "2007-06-01") & (dates <= "2010-06-01")
ax[0].plot(dates[w], np.sqrt(252 * RV[w]),   color="0.7", lw=.8, label="realized vol  $\\sqrt{RV}$")
ax[0].plot(dates[w], np.sqrt(252 * h_rg[w]), color="firebrick", lw=1.5, label="Realized GARCH  $\\sqrt{h}$")
ax[0].plot(dates[w], np.sqrt(252 * h_g[w]),  color="seagreen", lw=1.3, label="standard GARCH-t  $\\sqrt{h}$")
ax[0].set_ylabel("annualized vol (%)"); ax[0].legend(fontsize=8)
ax[0].set_title("Realized GARCH's variance tracks RV\n(RV drives the recursion; standard GARCH lags)")
for lab in ax[0].get_xticklabels(): lab.set_rotation(20)
z = np.linspace(-3, 3, 200); tau = p["tau1"] * z + p["tau2"] * (z ** 2 - 1)
ax[1].plot(z, tau, color="slateblue", lw=2)
ax[1].axvline(0, color="0.6", lw=.8); ax[1].axhline(0, color="0.6", lw=.8)
ax[1].fill_between(z, tau, where=(z < 0), color="firebrick", alpha=.12)
ax[1].set_xlabel("return shock  $z_t = r_t/\\sqrt{h_t}$"); ax[1].set_ylabel("leverage effect on $\\log RV_t$")
ax[1].set_title("Measurement-equation leverage $\\tau(z)$\n(a down move $z<0$ lifts realized volatility more)")
plt.tight_layout(); plt.show()
Realized GARCH:  omega 0.127  beta 0.654  gamma 0.330  phi 0.975  tau1 -0.076  tau2 0.132  sigma_u 0.524
  effective persistence (beta + phi*gamma) = 0.976
  corr with RV:  RealGARCH 0.753   standard GARCH-t 0.711
No description has been provided for this image

Reading the figure¶

  • Left — it tracks RV. Because $RV_{t-1}$ (not $r_{t-1}^2$) drives the recursion, Realized GARCH's $\sqrt{h_t}$ follows realized volatility closely and reacts fast; standard GARCH-$t$, updating from squared returns, is smoother and lags — most visibly in early 2009, where it stays elevated while realized vol (and Realized GARCH) has already come down. Realized GARCH correlates 0.75 with RV versus 0.71 for standard GARCH.
  • Right — leverage lives in the measurement equation. $\tau(z)=\tau_1 z+\tau_2(z^2-1)$ maps a return shock to contemporaneous log-RV. With $\tau_1<0$ the curve tilts so a down move ($z<0$) lifts realized volatility more than an up move of the same size — the leverage effect, recovered from the joint return-and-RV likelihood.

Results¶

  • Realized GARCH is GARCH that "sees" realized volatility. The RV loading $\gamma=0.33$ pulls the precise realized measure into the variance recursion; the measurement slope $\varphi=0.98$ says RV is nearly proportional to the latent $h$; $\tau_1<0$ carries the leverage; and the effective persistence $\beta+\varphi\gamma=0.98$ reproduces the near-integrated volatility seen throughout the arc.
  • This is the formal bridge between the GARCH/SV track and the HAR/realized track — and it sets up the forecasting tournament (next notebook): do the models that use realized measures (HAR, Realized GARCH) actually out-forecast the ones that use only returns (GARCH, SV)?

Reference¶

  • Hansen, P. R., Huang, Z. & Shek, H. H. (2012). Realized GARCH: a joint model for returns and realized measures of volatility. J. Applied Econometrics 27, 877–906.

Next: rv_forecast_horserace.ipynb — HAR vs GARCH vs SV vs Realized GARCH, forecasting RV out of sample.