Repository Public Research preview
1# Model card — `realgarch11` (Realized GARCH(1,1), log-linear, Hansen–Huang–Shek)23## 1. Identity4- **model_id:** `realgarch11` · **family:** realized (Tier B) · **tier:** B · **status:** implemented · **impl:** custom (`src/wp46/models/custom.py::RealGARCH11`)5- **Label:** Realized GARCH(1,1), log-linear · **distributions:** normal, t (for $z_t$; the measurement error $u_t$ is always Gaussian)6- **Seminal citation:** `hansen2012realized`7- **Other references:** `hansen2016exponential` (Realized EGARCH, unsupported), `hansen2014realized` (Realized Beta GARCH), `shephard2010realising` (HEAVY), `engle2002new` (GARCH-X); literature-matrix caveat #7 (the measurement equation is part of the likelihood → in-sample log-likelihoods are not comparable with GARCH).89## 2. Definition10With $x_t$ the realized measure (`rv5ss_on`, percent², observed at the **end** of day t; only $x_{t-1}$ enters $\sigma_t^2$):11$$r_t = \mu + \sigma_t z_t,\qquad \log\sigma_t^2 = \omega + \beta\,\log\sigma_{t-1}^2 + \gamma\,\log x_{t-1},$$12$$\log x_t = \xi + \varphi\,\log\sigma_t^2 + \tau_1 z_t + \tau_2\,(z_t^2 - 1) + u_t,\qquad u_t \sim \text{N}(0, \sigma_u^2) .$$13`rec_realgarch`: $\log\sigma_0^2 = \log s_0$ (backcast), $x$ floored at 1e-8 before the log; the fit fails (`FloatingPointError` → objective 1e10) if $|\log\sigma_t^2| > 50$. Joint log-likelihood $\ell = \sum_t\big[\log f_z(z_t) - \tfrac12\log\sigma_t^2\big] + \sum_t\big[-\tfrac12\log(2\pi\sigma_u^2) - u_t^2/(2\sigma_u^2)\big]$. Innovations $z_t$: normal or standardised t(ν).1415## 3. Parameter space and admissibility16- Parameters: `mu, omega, beta, gamma, xi, phi, tau1, tau2, log_sigma_u` (+ `nu`). All unconstrained in the optimizer (identity transform; $\sigma_u = e^{\texttt{log\_sigma\_u}}$).17- Admissibility flag: $|\beta + \varphi\gamma| < 1$ (stationarity of the reduced-form AR(1) for $\log\sigma_t^2$ obtained by substituting the measurement equation). No positivity constraints are needed (log specification).1819## 4. Nesting and relations20Realized GARCH reduces to a GARCH-type model when the measurement equation is dropped; in log-linear form with $\gamma = 0$ it is a log-GARCH without ARCH term. HEAVY uses $x_{t-1}$ in levels without a measurement equation; GARCH-X adds $x_{t-1}$ to a GARCH(1,1). Realized EGARCH (unsupported) generalises the leverage function and allows several measures.2122## 5. Estimation23Custom MLE (`CustomModel.fit` with `extra_loglik` adding the measurement-equation terms): L-BFGS-B on the 8 + 1 (+1) raw parameters (maxiter 3000, ftol 1e-10, gtol 1e-6) from three starts (ω, β, γ, ξ, φ, τ₁, τ₂, log σ_u) ∈ {(0.04 ℓ̄, 0.55, 0.41, −0.1, 1.0, −0.07, 0.07, log 0.4), (0.1 ℓ̄, 0.7, 0.28, 0, 0.95, −0.05, 0.05, log 0.5), (0.02 ℓ̄, 0.4, 0.55, −0.2, 1.05, −0.1, 0.1, log 0.35)} with $\bar\ell$ = mean of $\log x$, Nelder–Mead polish on failure; μ start = sample mean, ν start 6; backcast $s_0$ arch-style on the demeaned returns. Point estimates only; the reported `loglik` is the **joint** return + measurement log-likelihood.2425## 6. Forecasting26`RealGARCH11.step_forecast`: h = 1 analytic, $\log\hat\sigma^2_{t+1|t} = \omega + \beta\log\sigma_t^2 + \gamma\log x_t$. **h > 1 by simulation** (`analytic_multistep = False`): 2,000 paths; for k = 2..22 draw $z \sim f_z$ (fitted law, `distributions.rvs`) and $u \sim$ N(0, σ_u²) with `np.random.default_rng(46 + origin)` (seeded), set $\log x_{t+k-1} = \xi + \varphi\log\sigma^2_{t+k-1} + \tau_1 z + \tau_2(z^2-1) + u$, then $\log\sigma^2_{t+k} = \omega + \beta\log\sigma^2_{t+k-1} + \gamma\log x_{t+k-1}$, clipped to ±30; $\hat\sigma^2_{t+k|t}$ = path mean of $\exp(\log\sigma^2_{t+k})$. Cumulative = sum over k ≤ h. Method: `simulation`. (The class docstring mentions a VAR-type recursion; the code simulates.)2728## 7. Implementation29- `src/wp46/models/custom.py::RealGARCH11` (numba `rec_realgarch`).30- Cross-check: attempted against rugarch `realGARCH` (normal, `realizedVol = sqrt(x)`) on the shared fixture, but **rugarch did not converge** (`results/metrics/rugarch_crosscheck.json["rugarch"]["realgarch11_n"] = {"converged": false}`), so `comparison.realgarch11_n.diff = null`; ours: joint log-likelihood −4989.2126, converged. No library cross-check is therefore available.31- Tests: `tests/simulation/test_recovery.py::test_realgarch_recovery` (T = 4,000, normal, truth (0.06, 0.55, 0.40, −0.2, 1.0, −0.07, 0.07, 0.4): β, γ, φ within 0.1, σ_u within 0.05); `tests/unit/test_custom_models.py::test_realized_models_fit_on_synthetic_measure` (converged, positive finite forecasts); pilot `realgarch11__normal`: 207/207 refits `ok`, 1,032/1,032 forecasts `ok` on CL.3233## 8. Known limitations / failure modes34No parameter constraints → the optimizer can leave the stationary region (flag `admissible = False`); the simulation step compounds $\exp(\cdot)$ of Gaussian-like paths (mean of log-normal paths grows with the simulated variance, sensitive to τ₂ and σ_u); $x_{t-1}$ imputed by $r_{t-1}^2$ on invalid sessions and floored at 1e-8 (log of a tiny number); the joint likelihood is dominated by the measurement equation (not comparable with GARCH); the t option applies to $z_t$ only.3536## 9. Computational footprint37Estimation: 9–10 free parameters, one numba pass per evaluation; pilot median fit time per refit (normal) 0.0269 s (CL) / 0.0279 s (EURUSD) — the second most expensive pilot model after `aparch11`. Forecasting by simulation (21 × 2,000 draws of z and u per origin).3839## 10. Literature expectations40`hansen2012realized` report substantial likelihood and forecast gains over GARCH when a realized measure is available; `lyocsa2021stock` and `kourtis2016international` confirm the information advantage of intraday data at h = 1 that decays with the horizon. Pre-registered H3: Tier B beats Tier A at h = 1 (pooled ratio < 0.9), advantage shrinking at h = 22; the matrix lists Realized GARCH together with HEAVY and HAR as the Tier B contenders.41