Repository navigation
ENH: Add the NGARCH volatility process - #966
Merged
Merged
Conversation
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 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #966 +/- ##
==========================================
+ Coverage 98.95% 98.99% +0.04%
==========================================
Files 136 139 +3
Lines 30043 31317 +1274
Branches 2331 2418 +87
==========================================
+ Hits 29729 31003 +1274
Misses 256 256
Partials 58 58
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…more - arch_model(vol="ngarch") with o=0 returns a GARCH process and issues a ValueWarning, and NGARCH(o=0) issues one too, since a model without a shift is a GARCH. - ARCHModel.fit issues a ValueWarning when the volatility process reports a problem with the estimates, through the new private hook VolatilityProcess._fit_warning. NGARCH reports a persistence of 1 or more, which the linear estimation constraint does not exclude. show_warning controls the warning. - Remove the unreachable branch in NGARCH.starting_values. - Test the persistence of the starting values, horizon-1 forecasts from every origin and both warnings, and add NGARCH to the shared forecast, append and hedgehog-plot tests. Co-Authored-By: Claude Opus 5.5 <[email protected]>
| 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" |
NGARCH(2, 1, 2) is weakly identified on the S&P 500 returns with an AR or HAR mean: alpha[1] and a theta[1] of about 4.4 lie on a ridge, SLSQP stops after about 88 iterations, and a relative change of 4e-16 in the data moves the conditional volatility by 4e-4 for a log-likelihood change of 5e-6. test_alt_means compares two fits, so it failed on macOS Intel. NGARCH(1, 1, 1) converges in about 16 iterations and moves by at most 4e-7. test_fix_after_append, which does not compare two fits, keeps NGARCH(2, 1, 2). Co-Authored-By: Claude Opus 5.5 <[email protected]>
jngod2011
pushed a commit
to jngod2011/arch
that referenced
this pull request
Oct 31, 2026
- Highlights and new features: NGARCH (bashtage#966), the VaR backtests (bashtage#965), the local block bootstrap (bashtage#967) and bandwidth_method (bashtage#964, and phillips_ouliaris here). - Changes that alter results: the automatic bandwidth entry of bashtage#983 now also describes the bandwidth of the kernels with bounded support, the fractional bandwidths and the Tukey-Parzen constant of bashtage#964, its S&P 500 bandwidths are those of the bandwidth attribute (30.96 and 34.50, where it said the 31.96 and 35.50 of opt_bandwidth), and it links phillips_ouliaris in arch.unitroot.cointegration. The ADF-Z tables of bashtage#972, bashtage#973 and bashtage#980. - Backward-incompatible changes: strings in object data. - Bug fixes: bashtage#954, bashtage#970, bashtage#974, bashtage#975, bashtage#977, bashtage#978, bashtage#982, and the constant data of the Newey-West bandwidth and mackinnonp at -inf and inf. - Maintenance: the CI changes and the version file. - Contributors: galafis, jackiectl2, mkzung and wavebyrd.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 ofEngle and Ng (1993), which rugarch calls NAGARCH.
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:
ngarch_recursionwith a numba/Python twin and a.pyistub.NGARCHUpdater, soARCHInMeanworks with NGARCH, including pickling.arch_model(vol="ngarch", o=1). Without a shift the model is a GARCH, soarch_model(vol="ngarch")witho=0(the defaultoof everyvol) returns aGARCHprocess and issues a
ValueWarningthat says to usevol="garch"or seto > 0.NGARCH(o=0)issues the same kind of warning.phi = sum alpha (1 + theta^2) + sum beta, for any standardized distribution, because
E[(z - theta)^2] = 1 + theta^2.
simulate, and the crash guards.It does not imply the stationarity condition phi < 1, so
fitissues aValueWarningwhen the estimated persistence phi is 1 or more (controlled by
show_warning). Thisuses a new private hook,
VolatilityProcess._fit_warning, which returns None for theother processes.
Validation: rugarch 1.5-6 on R 4.6.1,
fGARCH/NAGARCH.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.
validated against an independent NumPy recursion and simulation instead.
Tests:
test_ngarch.py(175): the recursion against NumPy for 7 orders; Cython against numbaagainst Python; theta = 0 equals GARCH; the updaters against the recursion.
skew-t), horizon 1 from every origin, and parameter recovery for (1,1,1), (2,1,1) and
(2,2,1).
oof the
plags.a model with a shift or a stationary fit;
show_warning=Falsesilences the fit warning.arch_model,fixandARCHInMeanintegration.integer-input, forecast, append and hedgehog-plot lists.
volatility.py,recursions_python.py,mean.pyandbase.pyis covered, with no partial branches.o < pparametrizations) with no warnings; the slow univariate tests, 777, passed with no
warnings. numpydoc lint, flake8, ruff, black and isort are clean, and mypy reports no
new errors.
For review:
ValueWarningforNGARCH(o=0)can be dropped if direct use of the class shouldstay silent;
arch_modelwould still return a GARCH with a warning.Thanks to @itsNH98 for the request.
🤖 Generated with Claude Code