Skip to content

Use the skew partial moment in analytic GJR forecasts - #870

Open
shaneraphel wants to merge 1 commit into
bashtage:mainfrom
shaneraphel:gjr-skew-forecast
Open

shaneraphel wants to merge 1 commit into
bashtage:mainfrom
shaneraphel:gjr-skew-forecast

Conversation

@shaneraphel

@shaneraphel shaneraphel commented Sep 27, 2026 •

Copy link
Copy Markdown

Summary

Multi-step analytic GJR forecasts filled the future asymmetric shock with sqrt(0.5 * sigma^2). That is E[z^2 1(z<0)] = 1/2, which is right for a symmetric distribution and wrong for a skewed one. SkewStudent.partial_moment(2, 0) is about 0.55 for a typical equity skew, so the persistence should be alpha + k * gamma + beta, not alpha + 0.5 * gamma + beta.

MIDASHyperbolic with asymmetry wrote the same 0.5 into future indicator rows. Simulation and bootstrap forecasts already draw the sign from the shock, and those paths are unchanged.

What changed

ARCHModel.forecast passes distribution.partial_moment(2, 0) when the volatility model is asymmetric and the method is analytic. GARCH._analytic_forecast and MIDASHyperbolic._analytic_forecast use that weight. The default stays 0.5, so a normal GJR forecast is the same recursion as before.

Verification

Parameters [mu, omega, alpha, gamma, beta, eta, lambda] = [0.05, 0.02, 0.0, 0.20, 0.88, 7.6, -0.16], skew-t, horizon 30:

comparison max abs difference
analytic vs alpha + k gamma + beta, k = 0.5526 6e-16
analytic vs the old 0.5 recursion 0.15
normal GJR vs the 0.5 recursion 1e-16

Horizon 20, 30,000 simulations: analytic 1.318, simulation 1.317, the old half-moment path 1.11.

pytest arch/tests/univariate/test_variance_forecasting.py -k "midas_analytical or midas_asym or gjr_analytic": 4 passed.

This change was written with AI assistance and checked against the partial-moment recursion and the simulation above.

@codecov

codecov Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.59%. Comparing base (cc8df46) to head (3e43243).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #870   +/-   ##
=======================================
  Coverage   99.59%   99.59%           
=======================================
  Files          79       79           
  Lines       18154    18188   +34     
  Branches     1492     1496    +4     
=======================================
+ Hits        18081    18115   +34     
  Misses         40       40           
  Partials       33       33           
Flag Coverage Δ
adder 99.56% <100.00%> (+<0.01%) ⬆️
subtractor 99.56% <100.00%> (+<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.

@bashtage
bashtage force-pushed the gjr-skew-forecast branch 2 times, most recently from 4a84f0d to 04a8f9d Compare October 7, 2026 20:40

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.

1 participant