Skip to content

ENH: Add the Andrews (1991) AR(1) plug-in bandwidth to the kernel estimators - #964

Merged
bashtage merged 9 commits into
mainfrom
a91-f887-andrews-bandwidth
Oct 29, 2026
Merged

bashtage merged 9 commits into
mainfrom
a91-f887-andrews-bandwidth

Conversation

@bashtage

@bashtage bashtage commented Oct 18, 2026 •

Copy link
Copy Markdown
Owner

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

Adds bandwidth_method="newey-west" | "andrews" to every kernel covariance estimator
(including the Andrews, Gallant, NeweyWest and ZeroLag aliases), to
PreWhitenedRecolored, which passes it to its kernel, and to the fit methods of
DynamicOLS, FullyModifiedOLS and CanonicalCointegratingReg. It also makes the
automatic estimates of every kernel the estimators of Andrews (1991) and Newey and West
(1994).

bandwidth_method:

  • It accepts the spellings that kernel names accept: case, hyphens and underscores are
    ignored, so "Newey_West" and "neweywest" are "newey-west". It is exposed as a
    read-only bandwidth_method property.
  • "newey-west" is the default.
  • "andrews" implements Andrews (1991, Section 6, eqs. 6.3-6.4).
    • An AR(1) is fitted to each column: OLS with an intercept, and sigma^2 = RSS/(T-1),
      as R's ar(method="ols") does.
    • The optimal bandwidth is c_k (alpha(q) T)^(1/(2q+1)). The kernel constants are
      Andrews' constants (Bartlett 1.1447, Parzen 2.6614, QS 1.3221, Tukey-Hanning
      1.7462), and the derivation reproduces them.
    • Weights are respected. Constant and zero-weight columns are skipped.
    • Complex data are handled as separate real and imaginary columns.
    • An explicit bandwidth overrides the method.

Kernel weights (changes results). The kernels that are 0 beyond 1 (all except QS)
weight lag h by k(h/(H+1)) for a bandwidth H, so that H is the number of lags, as in
Newey and West (1987): Bartlett(x, bandwidth=L) is the estimator with L lags, as
sandwich::NeweyWest(lag=L), Stata's newey and statsmodels. The optimal bandwidth S of
Andrews (1991) and Newey and West (1994) is that of k(h/S), and it was used as H, so
the automatic estimates used the weights of S + 1.

  • The automatic bandwidth is now H = max(S - 1, 0), whose weights are those of S. QS,
    which weights every lag by k(h/H), keeps H = S. opt_bandwidth is still S.
  • With force_int=True, H is rounded up, which is the integer part of S, the
    m = [gamma T^(1/3)] of Newey and West (1994, eq. 2-2).
  • A fractional bandwidth now uses every lag with a positive weight. The lag
    floor(H) + 1 was dropped.
  • An explicit integer bandwidth is unchanged, so the EViews-validated cointegration
    results, which pass integer bandwidths, are unchanged.
  • The docstrings described k(h/H) and now describe the weights that are used.
  • The automatic long-run covariances of the bounded kernels fall, by 0.6% to 4.9% in
    AR(1) examples.

Pilot lag. This branch includes the commit of #983 (9.0), which uses the integer
part of 4 (T/100)^r for the pilot lag of "newey-west", as Newey and West (1994),
auto_bandwidth and sandwich::bwNeweyWest do. It drops out when this branch is rebased
on main after #983 is merged.

Other changes:

  • Extreme scales. Both estimates of alpha(q) are ratios that do not depend on the
    scale of the data. The data are divided by the power of 2 nearest their largest
    absolute value first. This is exact, so results are unchanged, and data scaled by
    1e-200 to 1e200 no longer overflow or underflow. All columns share one scale, since a
    separate scale for each column would change their weights in Andrews' estimate.
  • Tukey-Parzen constant. It was 1.8576. The formula gives 1.85874, so it is now
    1.8587, and its optimal bandwidth is 0.059% larger. Every constant is now the formula
    rounded to 4 decimals.

Validation: R 4.6.1 with sandwich 3.1.3, 6 seeded datasets (univariate and
multivariate, T = 50 to 500, nonzero means, non-uniform and zero weights). The tests
store the R values as constants and use rtol 1e-10; the largest difference is 2.2e-15.

  • "andrews": opt_bandwidth equals bwAndrews(x, kernel=..., approx="AR(1)", weights=w, prewhite=FALSE), and the long-run covariance equals
    kernHAC(lm(x ~ 1), bw=bwAndrews, kernel=..., prewhite=FALSE, adjust=FALSE), for the
    Bartlett, Parzen, QS and Tukey-Hanning kernels.
  • "newey-west": opt_bandwidth equals bwNeweyWest, the long-run covariance equals
    kernHAC with that bandwidth (Bartlett, Parzen, QS), and Bartlett with
    force_int=True equals NeweyWest(lm(x ~ 1), lag=floor(bwNeweyWest)).
  • A fractional bandwidth equals NeweyWest(lag=5.4) and kernHAC(bw=6.4).
  • For every kernel, the automatic estimate equals an independent sum of k(h/S) times
    the autocovariances.
  • The kernel constants are checked against the formula by quadrature.

Tests:

  • arch/tests/covariance/test_andrews_bandwidth.py (242 tests), including the R
    comparisons above, the accepted spellings, and the scale invariance from 1e-200 to
    1e200 (exact for powers of 2, without warnings).
  • DOLS, FMOLS and CCR: the default equals "newey-west", "andrews" gives the bandwidth
    of the kernel estimator on the same residuals or scores, an explicit bandwidth
    overrides the method, and the spellings are accepted (60 tests). Validation rows for
    every estimator.
  • Fast suite 27,547 passed, and 27,601 after a rebase on main with BUG: Use the integer part for the pilot lag of the automatic bandwidth #983. flake8, ruff,
    black, isort, numpydoc lint and mypy are clean on the changed files.

For review:

  • PhillipsPerron and phillips_ouliaris could also take bandwidth_method. That belongs
    in a separate issue.

Thanks to @ZacKienzle2 for the proposal.

🤖 Generated with Claude Code

…imators

Add bandwidth_method to the kernel covariance estimators and to
PreWhitenedRecolored. The default, "newey-west", is the existing automatic
bandwidth and is unchanged. "andrews" selects the bandwidth using the AR(1)
plug-in estimate of alpha(q) in Section 6 of Andrews (1991), eqs. (6.3)-(6.4),
with the kernel constants and exponent q of each kernel. The AR(1) is fit to each
column by OLS with an intercept, as in sandwich::bwAndrews, which the tests match.

xref #887
@codecov

codecov Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.03475% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.98%. Comparing base (d2c90b4) to head (d650041).
⚠️ Report is 49 commits behind head on main.

Files with missing lines Patch % Lines
arch/tests/covariance/test_andrews_bandwidth.py 99.09% 2 Missing and 1 partial ⚠️
arch/covariance/kernel.py 97.36% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #964      +/-   ##
==========================================
+ Coverage   98.95%   98.98%   +0.02%     
==========================================
  Files         136      141       +5     
  Lines       30043    31377    +1334     
  Branches     2331     2413      +82     
==========================================
+ Hits        29729    31057    +1328     
- Misses        256      260       +4     
- Partials       58       60       +2     
Flag Coverage Δ
adder 98.92% <99.03%> (+0.02%) ⬆️
subtractor 98.92% <99.03%> (+0.02%) ⬆️

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.

bashtage and others added 5 commits October 29, 2026 14:38
Accept the spellings of bandwidth_method that kernel names accept (case,
hyphens and underscores are ignored). Divide the data by a power of 2 before
estimating alpha(q) in both bandwidth methods, which is exact and avoids
overflow and underflow for data with an extreme scale. Correct the
TukeyParzen constant to 1.8587, its value to 4 decimals.

Work in progress: the tests are not yet updated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…cales

The spellings that kernel names accept are accepted by bandwidth_method.
Every kernel constant is the formula of Andrews (1991) to 4 decimals,
including Tukey-Parzen, whose default bandwidth is now 0.06% larger. The
bandwidths of both methods do not depend on the scale of the data from
1e-200 to 1e200, without warnings, and are exactly equal for powers of 2.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The fit methods of DynamicOLS, FullyModifiedOLS and
CanonicalCointegratingReg take bandwidth_method, which is passed to the
kernel estimator of the long-run covariance. The default, "newey-west",
is unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The nonparametric bandwidth of Newey and West (1994) estimates its scale
from the autocovariances up to the integer part of 4 (T/100)^r (eq. 2-2),
which auto_bandwidth and sandwich::bwNeweyWest use. The kernel covariance
estimators rounded up, which used one more autocovariance whenever the
value is not an integer. The bandwidths now equal those of bwNeweyWest,
which a new test checks.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The kernels that are 0 beyond 1 weight lag h by k(h/(H+1)) for a bandwidth
H, the lag count of Newey and West (1987), while the optimal bandwidth S of
Andrews (1991) and Newey and West (1994) is that of k(h/S). The estimated S
was used as H, which gave the weights of S + 1. The estimated bandwidth is
now max(S - 1, 0), so that the weights are those of S, and the estimates
equal sandwich::kernHAC with bwAndrews or bwNeweyWest and, for Bartlett with
force_int, sandwich::NeweyWest. opt_bandwidth is still S, and an explicit
integer bandwidth is unchanged.

A fractional bandwidth now uses every lag with a positive weight. The lag
floor(H) + 1 was dropped. The docstrings, which described k(h/H), describe
the weights that are used.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
bashtage and others added 3 commits October 29, 2026 15:56
The bandwidth of data scaled by a power of 2 differed from that of the
original data in the last bits on macOS Intel (5e-16 relative), since the
sums can round differently even for exactly scaled inputs. The scale test
and the comparisons of separate DOLS, FMOLS and CCR fits now use rtol 1e-13
for bandwidths and 1e-12 for parameters and covariances, instead of exact
equality.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
With the new pilot lag, a weight of the quadratic-spectral kernel of the
VAR residuals is near one of its zeros, and the weights of the two
estimates differed by 4.4e-13 on Linux, which is 1.5e-7 relative to that
weight. The weights are compared with atol 1e-11 as well.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…width

# Conflicts:
#	arch/tests/covariance/test_covariance.py
@bashtage
bashtage merged commit 0db45a4 into main Oct 29, 2026
10 of 23 checks passed
jngod2011 pushed a commit to jngod2011/arch that referenced this pull request Oct 31, 2026
phillips_ouliaris estimates the bandwidth of its kernel estimator when
bandwidth is None, as DynamicOLS, FullyModifiedOLS and
CanonicalCointegratingReg do, which take bandwidth_method since bashtage#964. It now
takes bandwidth_method too, which is passed to the kernel estimator. The
default, "newey-west", is unchanged.
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.
@bashtage
bashtage deleted the a91-f887-andrews-bandwidth branch November 3, 2026 15:49
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: Andrews (1991) AR(1) plug-in bandwidth for the kernel covariance estimators

1 participant