Skip to content

ENH: Add the NGARCH volatility process - #966

Open
bashtage wants to merge 2 commits into
mainfrom
a91-f636-ngarch
Open

bashtage wants to merge 2 commits into
mainfrom
a91-f636-ngarch

Conversation

@bashtage

Copy link
Copy Markdown
Owner

Target 9.1: merge after v9.0.0 is tagged. Closes #636.

Adds arch.univariate.NGARCH(p=1, o=1, q=1) (o <= p): the nonlinear asymmetric GARCH of
Engle and Ng (1993), which rugarch calls NAGARCH.

sigma2_t = omega + sum_i alpha_i (e_{t-i} - theta_i sigma_{t-i})^2 + sum_j beta_j sigma2_{t-j}

Sign convention: theta > 0 is the leverage effect. It was settled from the NBER working
paper (w3681), whose estimated model reads (e - 0.2683 sqrt(h))^2, and it matches rugarch's
eta21. The class Notes explain the naming clash with Higgins and Bera (1992).

What is included:

  • A compiled ngarch_recursion with a numba/Python twin and a .pyi stub.
  • NGARCHUpdater, so ARCHInMean works with NGARCH, including pickling.
  • arch_model(vol="ngarch"). o defaults to 0 as for every vol, so o=1 gives the
    shift.
  • The analytic forecasts are exact at every horizon, f_h = omega + phi f_{h-1} with
    phi = sum alpha (1 + theta^2) + sum beta, for any standardized distribution, because
    E[(z - theta)^2] = 1 + theta^2.
  • Simulation and bootstrap forecasts, simulate, and the crash guards.
  • Constraint: the linear sum(alpha) + sum(beta) < 1 plus non-negativity, as for APARCH.
    The Notes and the docs example tell users to check the stationarity condition
    sum(alpha (1 + theta^2)) + sum(beta) < 1.

Validation: rugarch 1.5-6 on R 4.6.1, fGARCH/NAGARCH.

  • Variances to 4e-15 relative and log-likelihoods to 6e-14, for normal and Student-t,
    with matched initial values. rugarch's fGARCH filter adds an undocumented 1e-6 inside
    (z - eta)^2. That was confirmed on three parameter sets and is accounted for.
  • 10-step forecasts to 1e-6.
  • Fits on 4,000 observations: estimates within 0.008.
  • For an ARCH order of 2, rugarch's fGARCH disagrees with its own sGARCH, so p >= 2 is
    validated against an independent NumPy recursion and simulation instead.

Tests:

  • test_ngarch.py (154): the recursion against NumPy for 7 orders; Cython against numba
    against Python; theta = 0 equals GARCH; the updaters against the recursion.
  • Analytic forecasts against simulated means within 4 standard errors (normal and
    skew-t), and parameter recovery for (1,1,1), (2,1,1) and (2,2,1).
  • arch_model, fix and ARCHInMean integration.
  • NGARCH is added to the existing validation, crash-guard, updater, string-option and
    integer-input lists.
  • Each of 6 deliberately introduced bugs is caught.
  • Fast suite 27,459 passed. The tests pass in random orders, and the numba path passes on
    Python 3.10. numpydoc lint 0, and the docs build has no new warnings.

For review:

  • Should arch_model(vol="ngarch") default o to 1?
  • Use the exact nonlinear constraint only if users report persistence of 1 or more.

Thanks to @itsNH98 for the request.

🤖 Generated with Claude Code

Add NGARCH(p, o, q), the nonlinear asymmetric GARCH of Engle and Ng (1993), which
rugarch calls NAGARCH,

    sigma2[t] = omega + sum_i alpha[i] (e[t-i] - theta[i] sigma[t-i])**2
                + sum_j beta[j] sigma2[t-j]

with o <= p, as in APARCH. A positive theta is the leverage effect, the sign
convention of rugarch (Engle and Ng write +gamma sigma and expect gamma < 0).

The recursion, ngarch_recursion, and NGARCHUpdater are implemented in Cython and in
Python with numba, so that ARCHInMean works with the process. The pre-sample shock
term is alpha (1 + theta**2) times the backcast. Analytic forecasts are exact at
every horizon, since E[(z - theta)**2] = 1 + theta**2 for any standardized
distribution. Estimation uses the linear constraint sum(alpha) + sum(beta) < 1, as
APARCH does, and not the stationarity condition sum(alpha (1 + theta**2)) +
sum(beta) < 1, which is not linear. The process is available as vol="ngarch" in
arch_model.

Tests compare the recursion with an independent NumPy implementation and with the
variances, log-likelihoods and forecasts of rugarch 1.5-6, the Cython and Python
implementations with each other, the analytic forecasts with an independent forecast
recursion and with simulated paths, and the estimates with the parameters of
simulated data for normal, Student's t and skew t errors.

xref #636
Add NGARCH to the API reference, to the list of volatility processes in the
theoretical background with the reference of Engle and Ng (1993), and a section to
the volatility process page that states the model, the sign convention of theta, the
difference between the persistence and the constraint that is used in estimation, and
the exact analytic forecasts.

xref #636
self.q: int = _check_count("q", q, 0)
if self.o > self.p:
_fail(ValueError, "o", f"an integer <= p ({self.p})", _describe(o))
self._num_params = 1 + self.p + self.o + self.q
if self.o > self.p:
_fail(ValueError, "o", f"an integer <= p ({self.p})", _describe(o))
self._num_params = 1 + self.p + self.o + self.q
self._name = "NGARCH"
@codecov

codecov Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.61941% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.97%. Comparing base (d2c90b4) to head (5aa657d).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
arch/univariate/volatility.py 97.76% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #966      +/-   ##
==========================================
+ Coverage   98.95%   98.97%   +0.02%     
==========================================
  Files         136      137       +1     
  Lines       30043    31091    +1048     
  Branches     2331     2404      +73     
==========================================
+ Hits        29729    30773    +1044     
- Misses        256      258       +2     
- Partials       58       60       +2     
Flag Coverage Δ
adder 98.91% <99.42%> (+0.01%) ⬆️
subtractor 98.91% <99.42%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ENH: Add NGARCH specification to set of volatility processes

2 participants