SPB Git

spb/wp46_uqo

Public

WP46: pilot (SPY, AAPL, CL, EURUSD) on the validation period, feasibility report, tail-risk module, multivariate models, empirical tail quantiles in fits; protocol frozen

Simon-Pierre Boucher committed (Nov 9, 2026) parent 7b39a17 Browse files

9 changed files +662 −758

added docs/feasibility_report.md +42 −0
@@ -0,0 +1,42 @@
1 +# Feasibility report and Phase 2 pilot (2026-11-09)
2 +
3 +## Data (after audit and panel construction)
4 +- 42 instruments ingested from FinData OS (1-minute bars 2000/2008/2010/2013 → 2026-10-30; 230 M bars in the node cache),
5 + daily panels built with session windows D-02, realized measures D-03, validity rules D-05/D-06.
6 +- Proxy sanity: mean(RV5ss + r_on²)/mean(r²) over valid days lies in [0.93, 1.17] for all ETFs, stocks, futures and FX
7 + (bond ETFs/ZN ≈ 1.16–1.24: the overnight share is small and intraday noise slightly inflates RV); crypto only from 2022
8 + (BTC 1.24 on valid days — still noisier, disclosed).
9 +- Validity rates: equities 0.75–1.00 (early-year thin trading in IEF, LQD, XLF, XLE, EEM, EFA), futures 0.89–1.00,
10 + FX ≈ 1.00, crypto 0.36 (BTC) / 0.48 (ETH) because of the 2022 cutoff.
11 +
12 +## Software verification
13 +- 19 unit/integration tests, 5 Monte Carlo recovery tests (GJR, NAGARCH, Realized GARCH, HEAVY, MS-GARCH) and the
14 + rugarch 1.5-6 cross-check all pass; custom GARCH(1,1) reproduces arch's recursion to 1e-9 and arch's forecasts to 1e-15;
15 + all arch/custom log-likelihoods are within 0.3 of rugarch's maximum (FIGARCH: arch 1.47 below rugarch, documented).
16 +- Leakage: a whole-job test perturbs post-origin returns and realized measures (×3 / ×9) and finds every forecast unchanged
17 + (GJR-t Tier A, HEAVY Tier B; and in the pilot GJR-t + HAR on real panels).
18 +
19 +## Pilot (validation period 2012-01-03 → 2015-12-31, window 1,000, refit 5 days; `results/metrics/pilot/`)
20 +| instrument | origins | models | failures | fit time (s, mean) | notes |
21 +|---|---|---|---|---|---|
22 +| SPY | 1,006 | 9 | 0 forecast failures; GARCH-t 26/202 inadmissible refits (α+β ≥ 1) | 0.004–0.035 | QLIKE ratio to GARCH-N at h=1: GJR-t 0.88, APARCH-t 0.88, NAGARCH-t 0.89, EGARCH-t 0.93, HAR 0.99, Realized GARCH 0.85 |
23 +| AAPL | 1,006 | 9 | 0 | 0.004–0.035 | GJR-t 0.92, EGARCH-t 0.94, APARCH-t 0.94, HAR 1.10, RealGARCH 1.00 |
24 +| CL | 1,032 | 9 | 0 | 0.004–0.033 | HAR 0.73, GJR-t 0.94, EGARCH-t 0.96; at h=22 EGARCH-t 0.68 |
25 +| EURUSD | 556 | 9 | EGARCH-t 20/556 forecast failures (simulation with inadmissible |β| ≥ 1 fits), GJR-t 23 inadmissible refits | 0.005–0.044 | HAR 0.89, GJR-t 0.92, NAGARCH-t 0.95; EGARCH-t 1.32 (failures excluded → operational penalty) |
26 +Exploratory reading only (validation period): asymmetric models and realized-measure models beat GARCH(1,1) at h = 1 on
27 +these four instruments; historical 22-day variance is 28–42 % worse; the levels-HAR direct projection is unstable for AAPL
28 +(window includes high-variance episodes → large intercept), a known weakness that log-HAR addresses.
29 +
30 +## Compute budget (measured)
31 +Per spec and instrument over 4 years: 0.5–10 s wall (MS-GARCH ≈ 0.08 s/refit, FIGARCH ≈ 0.26 s/refit, APARCH/EGARCH
32 +simulation forecasts ≈ 2–3 ms/origin). Main run (3,276 jobs, OOS 2012–2026 ≈ 3,700 origins): ≈ 25–40 CPU-hours →
33 +< 1 hour on the six nodes (116 workers). Robustness variants (expanding, window 2,000, refit 22) are affordable.
34 +
35 +## Risks and mitigations
36 +- Inadmissible/near-integrated fits for t-distributed GARCH on FX and index ETFs: kept and flagged; failure-adjusted
37 + results reported; EGARCH simulation failures counted as failures (never replaced).
38 +- Thin early-year intraday data for bond/sector ETFs: realized measures invalid on those days; common-sample analysis.
39 +- Crypto: realized-measure evaluation only 2022–2026; Tier A daily returns from 2017 (BTC) / 2020 (ETH) with r² proxy as a diagnostic only.
40 +- Vendor futures roll rule undocumented: ratio-adjusted continuous series guarantees no roll jumps in returns; RV on roll days spans two contracts (disclosed).
41 +
42 +Gate 2: **PASS**. Protocol frozen next (tag `prereg-frozen`), then the main run.
added progress.md +36 −0
@@ -0,0 +1,36 @@
1 +# WP46 progress log
2 +
3 +All times ET. "Done" means executed with the listed command and artefact; "planned" means not yet executed.
4 +
5 +## Phase 0 — Inventory and literature (done 2026-11-09)
6 +- Repository reconnaissance: `Recherche-UQO/` conventions (HARMONISATION.md), WP41 as the FinData template; folder
7 + `finance/wp46_garch_benchmark`, repo `gitsrv:srv/git/wp46_uqo.git` created 2026-11-09.
8 +- FinData audit: `.venv/bin/python scripts/audit_findata.py` → `docs/findata_audit.md`, `results/manifests/findata_audit.json`
9 + (live API, 42 candidates, 0 errors). Dedicated API key `wp46_uqo_c` (scopes read:market, query, export; two earlier keys revoked).
10 +- Literature: `scripts/build_references.py` → `paper/references.bib` (205 entries: 200 Crossref/arXiv/OpenAlex-verified + 5 manual URL),
11 + `docs/literature_matrix.md`, `results/metrics/references_verification.json` (1 unverified: Chung 1999, excluded).
12 +- Gate 0: PASS (evidence-backed instrument list; no invented endpoints).
13 +
14 +## Phase 1 — Pre-registered protocol (done 2026-11-09, freeze tag `prereg-frozen`)
15 +- `docs/preregistered_protocol.md`, `configs/{model_registry,forecast_protocol,study,instruments}.yaml`, `docs/methodology_decisions.md` (D-01…D-15).
16 +- Disclosure: SPY 2024 forecast values (no losses) were inspected during driver smoke tests before the freeze (D-15);
17 + the pilot (Phase 2) used the validation period 2012–2015 only.
18 +
19 +## Phase 2 — Trusted data and pilot (done 2026-11-09)
20 +- Ingestion on M3U96a: `scripts/ingest_bars.py --workers 3` (1-min + daily bars, 42 instruments + VIX/SPX; manifest
21 + `results/manifests/ingest_manifest.json` with dataset versions and SHA-256) — cache `M3U96a:~/wp46-cache/bars` (not in git).
22 +- Panels: `scripts/build_panels.py` (3 runs: tz fix, per-instrument session length D-05, crypto cutoff D-06) →
23 + `~/wp46-cache/panels/*.parquet` on M3U96a, laptop and the 5 other compute nodes; `results/manifests/panels_manifest.json`.
24 +- Tests: `pytest tests/unit tests/integration` (19 passed), `pytest tests/simulation -m slow` (5 passed after fixing the
25 + NAGARCH parameter index in the test), `pytest tests/replication -m r` (rugarch 1.5-6 cross-check PASS; `results/metrics/rugarch_crosscheck.json`).
26 +- Pilot: `scripts/run_pilot.py --symbols SPY,AAPL` and `--symbols CL,EURUSD` (validation period) → `results/metrics/pilot/`;
27 + leakage check passed (future returns perturbed → forecasts unchanged).
28 +- Gate 2: PASS (see `docs/feasibility_report.md`).
29 +
30 +## Phase 3–5 — Benchmark, realized/multivariate tiers, inference (in progress)
31 +- Job list: `scripts/make_jobs.py --name main` → 3,276 jobs (42 instruments × 29 implemented models × distributions), OOS 2012-01-03 → 2026-10-30.
32 +- Dispatch: `scripts/dispatch_nodes.py launch --jobs results/manifests/jobs_main.json --name main` (M3U96a/M3U96b/M2U64/M5M36/M4M64a/M4M64c).
33 +
34 +## Open issues
35 +- FIGARCH: arch and rugarch differ by 1.47 log-likelihood units on the fixture (truncation/constraints) — caveat in the model card.
36 +- Crypto realized measures unusable before 2022 (D-06): crypto Tier B / proxy-based evaluation covers 2022–2026 only.
modified results/metrics/pilot/pilot_report.json +277 −752
@@ -1,42 +1,31 @@
1 1 {
2 − "SPY": {
3 − "n_origins": 1006,
4 − "common_sample_n_h1": 9054,
2 + "CL": {
3 + "n_origins": 1032,
4 + "common_sample_n_h1": 9279,
5 5 "status": {
6 6 "ok": {
7 − "aparch11__t__w1000_r5": 1006,
8 − "egarch11__t__w1000_r5": 1006,
9 − "garch11__normal__w1000_r5": 1006,
10 − "garch11__t__w1000_r5": 1006,
11 − "gjr11__t__w1000_r5": 1006,
12 − "har_rv__empirical__w1000_r5": 1006,
13 − "histvar22__empirical__w1000_r5": 1006,
14 − "nagarch11__t__w1000_r5": 1006,
15 − "realgarch11__normal__w1000_r5": 1006
7 + "aparch11__t__w1000_r5": 1032,
8 + "egarch11__t__w1000_r5": 1032,
9 + "garch11__normal__w1000_r5": 1032,
10 + "garch11__t__w1000_r5": 1032,
11 + "gjr11__t__w1000_r5": 1032,
12 + "har_rv__empirical__w1000_r5": 1032,
13 + "histvar22__empirical__w1000_r5": 1032,
14 + "nagarch11__t__w1000_r5": 1032,
15 + "realgarch11__normal__w1000_r5": 1032
16 16 }
17 17 },
18 18 "fit_status": {
19 − "inadmissible": {
20 − "aparch11__t__w1000_r5": 0,
21 − "egarch11__t__w1000_r5": 0,
22 − "garch11__normal__w1000_r5": 0,
23 − "garch11__t__w1000_r5": 26,
24 − "gjr11__t__w1000_r5": 0,
25 − "har_rv__empirical__w1000_r5": 0,
26 − "histvar22__empirical__w1000_r5": 0,
27 − "nagarch11__t__w1000_r5": 0,
28 − "realgarch11__normal__w1000_r5": 0
29 − },
30 19 "ok": {
31 − "aparch11__t__w1000_r5": 202,
32 − "egarch11__t__w1000_r5": 202,
33 − "garch11__normal__w1000_r5": 202,
34 − "garch11__t__w1000_r5": 176,
35 − "gjr11__t__w1000_r5": 202,
36 − "har_rv__empirical__w1000_r5": 202,
37 − "histvar22__empirical__w1000_r5": 202,
38 − "nagarch11__t__w1000_r5": 202,
39 − "realgarch11__normal__w1000_r5": 202
20 + "aparch11__t__w1000_r5": 207,
21 + "egarch11__t__w1000_r5": 207,
22 + "garch11__normal__w1000_r5": 207,
23 + "garch11__t__w1000_r5": 207,
24 + "gjr11__t__w1000_r5": 207,
25 + "har_rv__empirical__w1000_r5": 207,
26 + "histvar22__empirical__w1000_r5": 207,
27 + "nagarch11__t__w1000_r5": 207,
28 + "realgarch11__normal__w1000_r5": 207
40 29 }
41 30 },
42 31 "mean_loss_common": [
@@ -44,169 +33,169 @@
44 33 "proxy": "r2",
45 34 "loss": "mse",
46 35 "h": 1,
47 − "aparch11__t__w1000_r5": 1.3996,
48 − "egarch11__t__w1000_r5": 1.3836,
49 − "garch11__normal__w1000_r5": 1.4871,
50 − "garch11__t__w1000_r5": 1.4875,
51 − "gjr11__t__w1000_r5": 1.4175,
52 − "har_rv__empirical__w1000_r5": 1.6817,
53 − "histvar22__empirical__w1000_r5": 1.666,
54 − "nagarch11__t__w1000_r5": 1.393,
55 − "realgarch11__normal__w1000_r5": 1.4054
36 + "aparch11__t__w1000_r5": 38.8482,
37 + "egarch11__t__w1000_r5": 38.7292,
38 + "garch11__normal__w1000_r5": 39.4219,
39 + "garch11__t__w1000_r5": 39.4059,
40 + "gjr11__t__w1000_r5": 39.02,
41 + "har_rv__empirical__w1000_r5": 38.4856,
42 + "histvar22__empirical__w1000_r5": 40.9943,
43 + "nagarch11__t__w1000_r5": 38.5934,
44 + "realgarch11__normal__w1000_r5": 37.7234
56 45 },
57 46 {
58 47 "proxy": "r2",
59 48 "loss": "mse",
60 49 "h": 5,
61 − "aparch11__t__w1000_r5": 14.7187,
62 − "egarch11__t__w1000_r5": 14.5492,
63 − "garch11__normal__w1000_r5": 14.4574,
64 − "garch11__t__w1000_r5": 14.7366,
65 − "gjr11__t__w1000_r5": 15.2964,
66 − "har_rv__empirical__w1000_r5": 15.2534,
67 − "histvar22__empirical__w1000_r5": 17.842,
68 − "nagarch11__t__w1000_r5": 16.0023,
69 − "realgarch11__normal__w1000_r5": 13.4433
50 + "aparch11__t__w1000_r5": 304.1405,
51 + "egarch11__t__w1000_r5": 297.2174,
52 + "garch11__normal__w1000_r5": 356.9256,
53 + "garch11__t__w1000_r5": 357.0676,
54 + "gjr11__t__w1000_r5": 311.3525,
55 + "har_rv__empirical__w1000_r5": 336.0283,
56 + "histvar22__empirical__w1000_r5": 401.0389,
57 + "nagarch11__t__w1000_r5": 298.4274,
58 + "realgarch11__normal__w1000_r5": 322.8226
70 59 },
71 60 {
72 61 "proxy": "r2",
73 62 "loss": "mse",
74 63 "h": 22,
75 − "aparch11__t__w1000_r5": 221.9468,
76 − "egarch11__t__w1000_r5": 216.7508,
77 − "garch11__normal__w1000_r5": 171.8139,
78 − "garch11__t__w1000_r5": 187.1507,
79 − "gjr11__t__w1000_r5": 215.6164,
80 − "har_rv__empirical__w1000_r5": 198.7276,
81 − "histvar22__empirical__w1000_r5": 212.6863,
82 − "nagarch11__t__w1000_r5": 322.9919,
83 − "realgarch11__normal__w1000_r5": 157.673
64 + "aparch11__t__w1000_r5": 2559.3676,
65 + "egarch11__t__w1000_r5": 2357.1678,
66 + "garch11__normal__w1000_r5": 4169.6531,
67 + "garch11__t__w1000_r5": 4197.1704,
68 + "gjr11__t__w1000_r5": 2807.0867,
69 + "har_rv__empirical__w1000_r5": 3382.7094,
70 + "histvar22__empirical__w1000_r5": 4987.9416,
71 + "nagarch11__t__w1000_r5": 2423.8364,
72 + "realgarch11__normal__w1000_r5": 3417.3079
84 73 },
85 74 {
86 75 "proxy": "r2",
87 76 "loss": "qlike",
88 77 "h": 1,
89 − "aparch11__t__w1000_r5": 1.4285,
90 − "egarch11__t__w1000_r5": 1.4348,
91 − "garch11__normal__w1000_r5": 1.5186,
92 − "garch11__t__w1000_r5": 1.5188,
93 − "gjr11__t__w1000_r5": 1.451,
94 − "har_rv__empirical__w1000_r5": 1.5021,
95 − "histvar22__empirical__w1000_r5": 1.6783,
96 − "nagarch11__t__w1000_r5": 1.422,
97 − "realgarch11__normal__w1000_r5": 1.442
78 + "aparch11__t__w1000_r5": 1.2637,
79 + "egarch11__t__w1000_r5": 1.2604,
80 + "garch11__normal__w1000_r5": 1.289,
81 + "garch11__t__w1000_r5": 1.2862,
82 + "gjr11__t__w1000_r5": 1.2661,
83 + "har_rv__empirical__w1000_r5": 1.2492,
84 + "histvar22__empirical__w1000_r5": 1.3069,
85 + "nagarch11__t__w1000_r5": 1.2645,
86 + "realgarch11__normal__w1000_r5": 1.2601
98 87 },
99 88 {
100 89 "proxy": "r2",
101 90 "loss": "qlike",
102 91 "h": 5,
103 − "aparch11__t__w1000_r5": 0.3764,
104 − "egarch11__t__w1000_r5": 0.3866,
105 − "garch11__normal__w1000_r5": 0.4295,
106 − "garch11__t__w1000_r5": 0.4321,
107 − "gjr11__t__w1000_r5": 0.3912,
108 − "har_rv__empirical__w1000_r5": 0.4433,
109 − "histvar22__empirical__w1000_r5": 0.6038,
110 − "nagarch11__t__w1000_r5": 0.3795,
111 − "realgarch11__normal__w1000_r5": 0.3935
92 + "aparch11__t__w1000_r5": 0.3128,
93 + "egarch11__t__w1000_r5": 0.3073,
94 + "garch11__normal__w1000_r5": 0.3477,
95 + "garch11__t__w1000_r5": 0.3446,
96 + "gjr11__t__w1000_r5": 0.316,
97 + "har_rv__empirical__w1000_r5": 0.318,
98 + "histvar22__empirical__w1000_r5": 0.3653,
99 + "nagarch11__t__w1000_r5": 0.3137,
100 + "realgarch11__normal__w1000_r5": 0.3221
112 101 },
113 102 {
114 103 "proxy": "r2",
115 104 "loss": "qlike",
116 105 "h": 22,
117 − "aparch11__t__w1000_r5": 0.2498,
118 − "egarch11__t__w1000_r5": 0.2602,
119 − "garch11__normal__w1000_r5": 0.2522,
120 − "garch11__t__w1000_r5": 0.2595,
121 − "gjr11__t__w1000_r5": 0.2387,
122 − "har_rv__empirical__w1000_r5": 0.2843,
123 − "histvar22__empirical__w1000_r5": 0.4681,
124 − "nagarch11__t__w1000_r5": 0.27,
125 − "realgarch11__normal__w1000_r5": 0.2328
106 + "aparch11__t__w1000_r5": 0.1604,
107 + "egarch11__t__w1000_r5": 0.1505,
108 + "garch11__normal__w1000_r5": 0.2137,
109 + "garch11__t__w1000_r5": 0.2093,
110 + "gjr11__t__w1000_r5": 0.1691,
111 + "har_rv__empirical__w1000_r5": 0.1849,
112 + "histvar22__empirical__w1000_r5": 0.2493,
113 + "nagarch11__t__w1000_r5": 0.1602,
114 + "realgarch11__normal__w1000_r5": 0.2003
126 115 },
127 116 {
128 117 "proxy": "rv5ss_on",
129 118 "loss": "mse",
130 119 "h": 1,
131 − "aparch11__t__w1000_r5": 2.0112,
132 − "egarch11__t__w1000_r5": 1.9421,
133 − "garch11__normal__w1000_r5": 2.1561,
134 − "garch11__t__w1000_r5": 2.1426,
135 − "gjr11__t__w1000_r5": 1.8891,
136 − "har_rv__empirical__w1000_r5": 2.185,
137 − "histvar22__empirical__w1000_r5": 2.4172,
138 − "nagarch11__t__w1000_r5": 1.9804,
139 − "realgarch11__normal__w1000_r5": 2.1525
120 + "aparch11__t__w1000_r5": 7.4038,
121 + "egarch11__t__w1000_r5": 7.4551,
122 + "garch11__normal__w1000_r5": 8.0074,
123 + "garch11__t__w1000_r5": 7.9634,
124 + "gjr11__t__w1000_r5": 7.5711,
125 + "har_rv__empirical__w1000_r5": 6.9611,
126 + "histvar22__empirical__w1000_r5": 10.1669,
127 + "nagarch11__t__w1000_r5": 7.1532,
128 + "realgarch11__normal__w1000_r5": 6.7387
140 129 },
141 130 {
142 131 "proxy": "rv5ss_on",
143 132 "loss": "mse",
144 133 "h": 5,
145 − "aparch11__t__w1000_r5": 23.9033,
146 − "egarch11__t__w1000_r5": 23.6745,
147 − "garch11__normal__w1000_r5": 23.5567,
148 − "garch11__t__w1000_r5": 23.7539,
149 − "gjr11__t__w1000_r5": 23.7699,
150 − "har_rv__empirical__w1000_r5": 24.9214,
151 − "histvar22__empirical__w1000_r5": 26.6768,
152 − "nagarch11__t__w1000_r5": 25.2487,
153 − "realgarch11__normal__w1000_r5": 23.388
134 + "aparch11__t__w1000_r5": 97.0143,
135 + "egarch11__t__w1000_r5": 94.3839,
136 + "garch11__normal__w1000_r5": 134.2716,
137 + "garch11__t__w1000_r5": 133.8063,
138 + "gjr11__t__w1000_r5": 104.9043,
139 + "har_rv__empirical__w1000_r5": 112.4285,
140 + "histvar22__empirical__w1000_r5": 181.9574,
141 + "nagarch11__t__w1000_r5": 89.047,
142 + "realgarch11__normal__w1000_r5": 108.4914
154 143 },
155 144 {
156 145 "proxy": "rv5ss_on",
157 146 "loss": "mse",
158 147 "h": 22,
159 − "aparch11__t__w1000_r5": 285.5918,
160 − "egarch11__t__w1000_r5": 281.9002,
161 − "garch11__normal__w1000_r5": 238.7663,
162 − "garch11__t__w1000_r5": 253.0328,
163 − "gjr11__t__w1000_r5": 274.2299,
164 − "har_rv__empirical__w1000_r5": 273.2997,
165 − "histvar22__empirical__w1000_r5": 267.3486,
166 − "nagarch11__t__w1000_r5": 385.4714,
167 − "realgarch11__normal__w1000_r5": 228.4667
148 + "aparch11__t__w1000_r5": 1649.3345,
149 + "egarch11__t__w1000_r5": 1506.3924,
150 + "garch11__normal__w1000_r5": 2977.7956,
151 + "garch11__t__w1000_r5": 2997.7164,
152 + "gjr11__t__w1000_r5": 1937.2537,
153 + "har_rv__empirical__w1000_r5": 2274.3908,
154 + "histvar22__empirical__w1000_r5": 3756.9648,
155 + "nagarch11__t__w1000_r5": 1409.9449,
156 + "realgarch11__normal__w1000_r5": 2537.4397
168 157 },
169 158 {
170 159 "proxy": "rv5ss_on",
171 160 "loss": "qlike",
172 161 "h": 1,
173 − "aparch11__t__w1000_r5": 0.276,
174 − "egarch11__t__w1000_r5": 0.2916,
175 − "garch11__normal__w1000_r5": 0.3128,
176 − "garch11__t__w1000_r5": 0.3142,
177 − "gjr11__t__w1000_r5": 0.2743,
178 − "har_rv__empirical__w1000_r5": 0.3092,
179 − "histvar22__empirical__w1000_r5": 0.4129,
180 − "nagarch11__t__w1000_r5": 0.2784,
181 − "realgarch11__normal__w1000_r5": 0.2657
162 + "aparch11__t__w1000_r5": 0.1183,
163 + "egarch11__t__w1000_r5": 0.1184,
164 + "garch11__normal__w1000_r5": 0.1239,
165 + "garch11__t__w1000_r5": 0.1227,
166 + "gjr11__t__w1000_r5": 0.1161,
167 + "har_rv__empirical__w1000_r5": 0.0902,
168 + "histvar22__empirical__w1000_r5": 0.1585,
169 + "nagarch11__t__w1000_r5": 0.1205,
170 + "realgarch11__normal__w1000_r5": 0.0937
182 171 },
183 172 {
184 173 "proxy": "rv5ss_on",
185 174 "loss": "qlike",
186 175 "h": 5,
187 − "aparch11__t__w1000_r5": 0.2339,
188 − "egarch11__t__w1000_r5": 0.246,
189 − "garch11__normal__w1000_r5": 0.2615,
190 − "garch11__t__w1000_r5": 0.2647,
191 − "gjr11__t__w1000_r5": 0.2368,
192 − "har_rv__empirical__w1000_r5": 0.2862,
193 − "histvar22__empirical__w1000_r5": 0.3764,
194 − "nagarch11__t__w1000_r5": 0.24,
195 − "realgarch11__normal__w1000_r5": 0.2301
176 + "aparch11__t__w1000_r5": 0.0883,
177 + "egarch11__t__w1000_r5": 0.0864,
178 + "garch11__normal__w1000_r5": 0.1023,
179 + "garch11__t__w1000_r5": 0.1007,
180 + "gjr11__t__w1000_r5": 0.088,
181 + "har_rv__empirical__w1000_r5": 0.087,
182 + "histvar22__empirical__w1000_r5": 0.1356,
183 + "nagarch11__t__w1000_r5": 0.0896,
184 + "realgarch11__normal__w1000_r5": 0.0823
196 185 },
197 186 {
198 187 "proxy": "rv5ss_on",
199 188 "loss": "qlike",
200 189 "h": 22,
201 − "aparch11__t__w1000_r5": 0.2557,
202 − "egarch11__t__w1000_r5": 0.2623,
203 − "garch11__normal__w1000_r5": 0.2643,
204 − "garch11__t__w1000_r5": 0.2712,
205 − "gjr11__t__w1000_r5": 0.2422,
206 − "har_rv__empirical__w1000_r5": 0.3086,
207 − "histvar22__empirical__w1000_r5": 0.3961,
208 − "nagarch11__t__w1000_r5": 0.2792,
209 − "realgarch11__normal__w1000_r5": 0.24
190 + "aparch11__t__w1000_r5": 0.1025,
191 + "egarch11__t__w1000_r5": 0.095,
192 + "garch11__normal__w1000_r5": 0.1405,
193 + "garch11__t__w1000_r5": 0.1365,
194 + "gjr11__t__w1000_r5": 0.1104,
195 + "har_rv__empirical__w1000_r5": 0.1238,
196 + "histvar22__empirical__w1000_r5": 0.1673,
197 + "nagarch11__t__w1000_r5": 0.1019,
198 + "realgarch11__normal__w1000_r5": 0.1425
210 199 }
211 200 ],
212 201 "ratio_to_garch11_normal": [
@@ -214,727 +203,263 @@
214 203 "proxy": "r2",
215 204 "loss": "mse",
216 205 "h": 1,
217 − "aparch11__t__w1000_r5": 0.9411,
218 − "egarch11__t__w1000_r5": 0.9304,
219 − "garch11__normal__w1000_r5": 1.0,
220 − "garch11__t__w1000_r5": 1.0003,
221 − "gjr11__t__w1000_r5": 0.9532,
222 − "har_rv__empirical__w1000_r5": 1.1308,
223 − "histvar22__empirical__w1000_r5": 1.1203,
224 − "nagarch11__t__w1000_r5": 0.9368,
225 − "realgarch11__normal__w1000_r5": 0.945
226 − },
227 − {
228 − "proxy": "r2",
229 − "loss": "mse",
230 − "h": 5,
231 − "aparch11__t__w1000_r5": 1.0181,
232 − "egarch11__t__w1000_r5": 1.0064,
233 − "garch11__normal__w1000_r5": 1.0,
234 − "garch11__t__w1000_r5": 1.0193,
235 − "gjr11__t__w1000_r5": 1.058,
236 − "har_rv__empirical__w1000_r5": 1.0551,
237 − "histvar22__empirical__w1000_r5": 1.2341,
238 − "nagarch11__t__w1000_r5": 1.1069,
239 − "realgarch11__normal__w1000_r5": 0.9299
240 − },
241 − {
242 − "proxy": "r2",
243 − "loss": "mse",
244 − "h": 22,
245 − "aparch11__t__w1000_r5": 1.2918,
246 − "egarch11__t__w1000_r5": 1.2615,
247 − "garch11__normal__w1000_r5": 1.0,
248 − "garch11__t__w1000_r5": 1.0893,
249 − "gjr11__t__w1000_r5": 1.2549,
250 − "har_rv__empirical__w1000_r5": 1.1566,
251 − "histvar22__empirical__w1000_r5": 1.2379,
252 − "nagarch11__t__w1000_r5": 1.8799,
253 − "realgarch11__normal__w1000_r5": 0.9177
254 − },
255 − {
256 − "proxy": "r2",
257 − "loss": "qlike",
258 − "h": 1,
259 − "aparch11__t__w1000_r5": 0.9406,
260 − "egarch11__t__w1000_r5": 0.9448,
261 − "garch11__normal__w1000_r5": 1.0,
262 − "garch11__t__w1000_r5": 1.0001,
263 − "gjr11__t__w1000_r5": 0.9555,
264 − "har_rv__empirical__w1000_r5": 0.9891,
265 − "histvar22__empirical__w1000_r5": 1.1051,
266 − "nagarch11__t__w1000_r5": 0.9364,
267 − "realgarch11__normal__w1000_r5": 0.9496
268 − },
269 − {
270 − "proxy": "r2",
271 − "loss": "qlike",
272 − "h": 5,
273 − "aparch11__t__w1000_r5": 0.8764,
274 − "egarch11__t__w1000_r5": 0.9003,
275 − "garch11__normal__w1000_r5": 1.0,
276 − "garch11__t__w1000_r5": 1.0061,
277 − "gjr11__t__w1000_r5": 0.9109,
278 − "har_rv__empirical__w1000_r5": 1.0321,
279 − "histvar22__empirical__w1000_r5": 1.4058,
280 − "nagarch11__t__w1000_r5": 0.8837,
281 − "realgarch11__normal__w1000_r5": 0.9161
282 − },
283 − {
284 − "proxy": "r2",
285 − "loss": "qlike",
286 − "h": 22,
287 − "aparch11__t__w1000_r5": 0.9906,
288 − "egarch11__t__w1000_r5": 1.0316,
289 − "garch11__normal__w1000_r5": 1.0,
290 − "garch11__t__w1000_r5": 1.0289,
291 − "gjr11__t__w1000_r5": 0.9465,
292 − "har_rv__empirical__w1000_r5": 1.1272,
293 − "histvar22__empirical__w1000_r5": 1.8562,
294 − "nagarch11__t__w1000_r5": 1.0705,
295 − "realgarch11__normal__w1000_r5": 0.9231
296 − },
297 − {
298 − "proxy": "rv5ss_on",
299 − "loss": "mse",
300 − "h": 1,
301 − "aparch11__t__w1000_r5": 0.9328,
302 − "egarch11__t__w1000_r5": 0.9007,
206 + "aparch11__t__w1000_r5": 0.9854,
207 + "egarch11__t__w1000_r5": 0.9824,
303 208 "garch11__normal__w1000_r5": 1.0,
304 − "garch11__t__w1000_r5": 0.9937,
305 − "gjr11__t__w1000_r5": 0.8762,
306 − "har_rv__empirical__w1000_r5": 1.0134,
307 − "histvar22__empirical__w1000_r5": 1.1211,
308 − "nagarch11__t__w1000_r5": 0.9185,
309 − "realgarch11__normal__w1000_r5": 0.9983
310 − },
311 − {
312 − "proxy": "rv5ss_on",
313 − "loss": "mse",
314 − "h": 5,
315 − "aparch11__t__w1000_r5": 1.0147,
316 − "egarch11__t__w1000_r5": 1.005,
317 − "garch11__normal__w1000_r5": 1.0,
318 − "garch11__t__w1000_r5": 1.0084,
319 − "gjr11__t__w1000_r5": 1.0091,
320 − "har_rv__empirical__w1000_r5": 1.0579,
321 − "histvar22__empirical__w1000_r5": 1.1324,
322 − "nagarch11__t__w1000_r5": 1.0718,
323 − "realgarch11__normal__w1000_r5": 0.9928
324 − },
325 − {
326 − "proxy": "rv5ss_on",
327 − "loss": "mse",
328 − "h": 22,
329 − "aparch11__t__w1000_r5": 1.1961,
330 − "egarch11__t__w1000_r5": 1.1807,
331 − "garch11__normal__w1000_r5": 1.0,
332 − "garch11__t__w1000_r5": 1.0598,
333 − "gjr11__t__w1000_r5": 1.1485,
334 − "har_rv__empirical__w1000_r5": 1.1446,
335 − "histvar22__empirical__w1000_r5": 1.1197,
336 − "nagarch11__t__w1000_r5": 1.6144,
209 + "garch11__t__w1000_r5": 0.9996,
210 + "gjr11__t__w1000_r5": 0.9898,
211 + "har_rv__empirical__w1000_r5": 0.9762,
212 + "histvar22__empirical__w1000_r5": 1.0399,
213 + "nagarch11__t__w1000_r5": 0.979,
337 214 "realgarch11__normal__w1000_r5": 0.9569
338 215 },
339 − {
340 − "proxy": "rv5ss_on",
341 − "loss": "qlike",
342 − "h": 1,
343 − "aparch11__t__w1000_r5": 0.8825,
344 − "egarch11__t__w1000_r5": 0.9323,
345 − "garch11__normal__w1000_r5": 1.0,
346 − "garch11__t__w1000_r5": 1.0045,
347 − "gjr11__t__w1000_r5": 0.8768,
348 − "har_rv__empirical__w1000_r5": 0.9885,
349 − "histvar22__empirical__w1000_r5": 1.3199,
350 − "nagarch11__t__w1000_r5": 0.89,
351 − "realgarch11__normal__w1000_r5": 0.8495
352 − },
353 − {
354 − "proxy": "rv5ss_on",
355 − "loss": "qlike",
356 − "h": 5,
357 − "aparch11__t__w1000_r5": 0.8944,
358 − "egarch11__t__w1000_r5": 0.9405,
359 − "garch11__normal__w1000_r5": 1.0,
360 − "garch11__t__w1000_r5": 1.0122,
361 − "gjr11__t__w1000_r5": 0.9055,
362 − "har_rv__empirical__w1000_r5": 1.0943,
363 − "histvar22__empirical__w1000_r5": 1.4392,
364 − "nagarch11__t__w1000_r5": 0.9177,
365 − "realgarch11__normal__w1000_r5": 0.88
366 − },
367 − {
368 − "proxy": "rv5ss_on",
369 − "loss": "qlike",
370 − "h": 22,
371 − "aparch11__t__w1000_r5": 0.9674,
372 − "egarch11__t__w1000_r5": 0.9924,
373 − "garch11__normal__w1000_r5": 1.0,
374 − "garch11__t__w1000_r5": 1.0259,
375 − "gjr11__t__w1000_r5": 0.9162,
376 − "har_rv__empirical__w1000_r5": 1.1674,
377 − "histvar22__empirical__w1000_r5": 1.4987,
378 − "nagarch11__t__w1000_r5": 1.0562,
379 − "realgarch11__normal__w1000_r5": 0.9078
380 − }
381 − ],
382 − "dm_vs_garch11_normal_h1_qlike": {
383 − "aparch11__t__w1000_r5": {
384 − "stat": -2.8973,
385 − "p": 0.0038,
386 − "mean_diff": -0.0368,
387 − "n": 1006,
388 − "bandwidth": 6
389 − },
390 − "egarch11__t__w1000_r5": {
391 − "stat": -1.3778,
392 − "p": 0.1686,
393 − "mean_diff": -0.0212,
394 − "n": 1006,
395 − "bandwidth": 6
396 − },
397 − "garch11__t__w1000_r5": {
398 − "stat": 0.6327,
399 − "p": 0.5271,
400 − "mean_diff": 0.0014,
401 − "n": 1006,
402 − "bandwidth": 6
403 − },
404 − "gjr11__t__w1000_r5": {
405 − "stat": -2.704,
406 − "p": 0.007,
407 − "mean_diff": -0.0385,
408 − "n": 1006,
409 − "bandwidth": 6
410 − },
411 − "har_rv__empirical__w1000_r5": {
412 − "stat": -0.1248,
413 − "p": 0.9007,
414 − "mean_diff": -0.0036,
415 − "n": 1006,
416 − "bandwidth": 6
417 − },
418 − "histvar22__empirical__w1000_r5": {
419 − "stat": 2.4896,
420 − "p": 0.013,
421 − "mean_diff": 0.1001,
422 − "n": 1006,
423 − "bandwidth": 6
424 − },
425 − "nagarch11__t__w1000_r5": {
426 − "stat": -2.3003,
427 − "p": 0.0216,
428 − "mean_diff": -0.0344,
429 − "n": 1006,
430 − "bandwidth": 6
431 − },
432 − "realgarch11__normal__w1000_r5": {
433 − "stat": -3.2275,
434 − "p": 0.0013,
435 − "mean_diff": -0.0471,
436 − "n": 1006,
437 − "bandwidth": 6
438 − }
439 − },
440 − "leakage_check_passed": true,
441 − "timing": {
442 − "mean": {
443 − "aparch11__t__w1000_r5": 0.0321,
444 − "egarch11__t__w1000_r5": 0.0089,
445 − "garch11__normal__w1000_r5": 0.0044,
446 − "garch11__t__w1000_r5": 0.008,
447 − "gjr11__t__w1000_r5": 0.0086,
448 − "har_rv__empirical__w1000_r5": 0.0009,
449 − "histvar22__empirical__w1000_r5": 0.0,
450 − "nagarch11__t__w1000_r5": 0.0133,
451 − "realgarch11__normal__w1000_r5": 0.0172
452 − },
453 − "median": {
454 − "aparch11__t__w1000_r5": 0.0307,
455 − "egarch11__t__w1000_r5": 0.0088,
456 − "garch11__normal__w1000_r5": 0.0043,
457 − "garch11__t__w1000_r5": 0.0077,
458 − "gjr11__t__w1000_r5": 0.0084,
459 − "har_rv__empirical__w1000_r5": 0.0009,
460 − "histvar22__empirical__w1000_r5": 0.0,
461 − "nagarch11__t__w1000_r5": 0.0123,
462 − "realgarch11__normal__w1000_r5": 0.017
463 − },
464 − "max": {
465 − "aparch11__t__w1000_r5": 0.0827,
466 − "egarch11__t__w1000_r5": 0.0156,
467 − "garch11__normal__w1000_r5": 0.0058,
468 − "garch11__t__w1000_r5": 0.0175,
469 − "gjr11__t__w1000_r5": 0.0115,
470 − "har_rv__empirical__w1000_r5": 0.0013,
471 − "histvar22__empirical__w1000_r5": 0.0,
472 − "nagarch11__t__w1000_r5": 0.1999,
473 − "realgarch11__normal__w1000_r5": 0.0223
474 − }
475 − }
476 − },
477 − "AAPL": {
478 − "n_origins": 1006,
479 − "common_sample_n_h1": 9045,
480 − "status": {
481 − "ok": {
482 − "aparch11__t__w1000_r5": 1006,
483 − "egarch11__t__w1000_r5": 1006,
484 − "garch11__normal__w1000_r5": 1006,
485 − "garch11__t__w1000_r5": 1006,
486 − "gjr11__t__w1000_r5": 1006,
487 − "har_rv__empirical__w1000_r5": 1006,
488 − "histvar22__empirical__w1000_r5": 1006,
489 − "nagarch11__t__w1000_r5": 1006,
490 − "realgarch11__normal__w1000_r5": 1006
491 − }
492 − },
493 − "fit_status": {
494 − "ok": {
495 − "aparch11__t__w1000_r5": 202,
496 − "egarch11__t__w1000_r5": 202,
497 − "garch11__normal__w1000_r5": 202,
498 − "garch11__t__w1000_r5": 202,
499 − "gjr11__t__w1000_r5": 202,
500 − "har_rv__empirical__w1000_r5": 202,
501 − "histvar22__empirical__w1000_r5": 202,
502 − "nagarch11__t__w1000_r5": 202,
503 − "realgarch11__normal__w1000_r5": 202
504 − }
505 − },
506 − "mean_loss_common": [
507 − {
508 − "proxy": "r2",
509 − "loss": "mse",
510 − "h": 1,
511 − "aparch11__t__w1000_r5": 63.9954,
512 − "egarch11__t__w1000_r5": 65.6312,
513 − "garch11__normal__w1000_r5": 65.5948,
514 − "garch11__t__w1000_r5": 65.3112,
515 − "gjr11__t__w1000_r5": 68.8414,
516 − "har_rv__empirical__w1000_r5": 66.6239,
517 − "histvar22__empirical__w1000_r5": 66.7977,
518 − "nagarch11__t__w1000_r5": 65.7724,
519 − "realgarch11__normal__w1000_r5": 64.3054
520 − },
521 − {
522 − "proxy": "r2",
523 − "loss": "mse",
524 − "h": 5,
525 − "aparch11__t__w1000_r5": 331.4497,
526 − "egarch11__t__w1000_r5": 354.5569,
527 − "garch11__normal__w1000_r5": 370.295,
528 − "garch11__t__w1000_r5": 363.5172,
529 − "gjr11__t__w1000_r5": 428.4128,
530 − "har_rv__empirical__w1000_r5": 384.3455,
531 − "histvar22__empirical__w1000_r5": 406.0351,
532 − "nagarch11__t__w1000_r5": 368.9609,
533 − "realgarch11__normal__w1000_r5": 346.35
534 − },
535 − {
536 − "proxy": "r2",
537 − "loss": "mse",
538 − "h": 22,
539 − "aparch11__t__w1000_r5": 1854.1747,
540 − "egarch11__t__w1000_r5": 1976.3284,
541 − "garch11__normal__w1000_r5": 2481.6871,
542 − "garch11__t__w1000_r5": 2398.9439,
543 − "gjr11__t__w1000_r5": 2680.9436,
544 − "har_rv__empirical__w1000_r5": 2580.1309,
545 − "histvar22__empirical__w1000_r5": 3550.2234,
546 − "nagarch11__t__w1000_r5": 2189.4584,
547 − "realgarch11__normal__w1000_r5": 2136.5244
548 − },
549 − {
550 − "proxy": "r2",
551 − "loss": "qlike",
552 − "h": 1,
553 − "aparch11__t__w1000_r5": 1.573,
554 − "egarch11__t__w1000_r5": 1.5781,
555 − "garch11__normal__w1000_r5": 1.6113,
556 − "garch11__t__w1000_r5": 1.6119,
557 − "gjr11__t__w1000_r5": 1.5795,
558 − "har_rv__empirical__w1000_r5": 1.6297,
559 − "histvar22__empirical__w1000_r5": 1.7514,
560 − "nagarch11__t__w1000_r5": 1.5829,
561 − "realgarch11__normal__w1000_r5": 1.6305
562 − },
563 − {
564 − "proxy": "r2",
565 − "loss": "qlike",
566 − "h": 5,
567 − "aparch11__t__w1000_r5": 0.4378,
568 − "egarch11__t__w1000_r5": 0.4434,
569 − "garch11__normal__w1000_r5": 0.4651,
570 − "garch11__t__w1000_r5": 0.4636,
571 − "gjr11__t__w1000_r5": 0.4474,
572 − "har_rv__empirical__w1000_r5": 0.4788,
573 − "histvar22__empirical__w1000_r5": 0.5924,
574 − "nagarch11__t__w1000_r5": 0.4457,
575 − "realgarch11__normal__w1000_r5": 0.4843
576 − },
577 − {
578 − "proxy": "r2",
579 − "loss": "qlike",
580 − "h": 22,
581 − "aparch11__t__w1000_r5": 0.1763,
582 − "egarch11__t__w1000_r5": 0.1822,
583 − "garch11__normal__w1000_r5": 0.2062,
584 − "garch11__t__w1000_r5": 0.2058,
585 − "gjr11__t__w1000_r5": 0.1937,
586 − "har_rv__empirical__w1000_r5": 0.2122,
587 − "histvar22__empirical__w1000_r5": 0.3985,
588 − "nagarch11__t__w1000_r5": 0.185,
589 − "realgarch11__normal__w1000_r5": 0.2022
590 − },
591 − {
592 − "proxy": "rv5ss_on",
593 − "loss": "mse",
594 − "h": 1,
595 − "aparch11__t__w1000_r5": 79.9621,
596 − "egarch11__t__w1000_r5": 81.3617,
597 − "garch11__normal__w1000_r5": 81.7481,
598 − "garch11__t__w1000_r5": 82.257,
599 − "gjr11__t__w1000_r5": 83.3473,
600 − "har_rv__empirical__w1000_r5": 83.075,
601 − "histvar22__empirical__w1000_r5": 84.0299,
602 − "nagarch11__t__w1000_r5": 81.5333,
603 − "realgarch11__normal__w1000_r5": 80.2777
604 − },
605 − {
606 − "proxy": "rv5ss_on",
607 − "loss": "mse",
608 − "h": 5,
609 − "aparch11__t__w1000_r5": 537.1384,
610 − "egarch11__t__w1000_r5": 555.7667,
611 − "garch11__normal__w1000_r5": 570.1734,
612 − "garch11__t__w1000_r5": 571.7817,
613 − "gjr11__t__w1000_r5": 617.2462,
614 − "har_rv__empirical__w1000_r5": 602.1478,
615 − "histvar22__empirical__w1000_r5": 615.0825,
616 − "nagarch11__t__w1000_r5": 572.6534,
617 − "realgarch11__normal__w1000_r5": 558.0099
618 − },
619 − {
620 − "proxy": "rv5ss_on",
621 − "loss": "mse",
622 − "h": 22,
623 − "aparch11__t__w1000_r5": 2907.5709,
624 − "egarch11__t__w1000_r5": 3023.1704,
625 − "garch11__normal__w1000_r5": 3462.8392,
626 − "garch11__t__w1000_r5": 3481.5861,
627 − "gjr11__t__w1000_r5": 3682.221,
628 − "har_rv__empirical__w1000_r5": 3624.0079,
629 − "histvar22__empirical__w1000_r5": 4570.0597,
630 − "nagarch11__t__w1000_r5": 3263.8213,
631 − "realgarch11__normal__w1000_r5": 3171.6604
632 − },
633 − {
634 − "proxy": "rv5ss_on",
635 − "loss": "qlike",
636 − "h": 1,
637 − "aparch11__t__w1000_r5": 0.5208,
638 − "egarch11__t__w1000_r5": 0.5224,
639 − "garch11__normal__w1000_r5": 0.5562,
640 − "garch11__t__w1000_r5": 0.5779,
641 − "gjr11__t__w1000_r5": 0.5125,
642 − "har_rv__empirical__w1000_r5": 0.6135,
643 − "histvar22__empirical__w1000_r5": 0.7153,
644 − "nagarch11__t__w1000_r5": 0.5389,
645 − "realgarch11__normal__w1000_r5": 0.5558
646 − },
647 − {
648 − "proxy": "rv5ss_on",
649 − "loss": "qlike",
650 − "h": 5,
651 − "aparch11__t__w1000_r5": 0.3803,
652 − "egarch11__t__w1000_r5": 0.3819,
653 − "garch11__normal__w1000_r5": 0.3923,
654 − "garch11__t__w1000_r5": 0.4039,
655 − "gjr11__t__w1000_r5": 0.3731,
656 − "har_rv__empirical__w1000_r5": 0.4347,
657 − "histvar22__empirical__w1000_r5": 0.5396,
658 − "nagarch11__t__w1000_r5": 0.3908,
659 − "realgarch11__normal__w1000_r5": 0.4225
660 − },
661 − {
662 − "proxy": "rv5ss_on",
663 − "loss": "qlike",
664 − "h": 22,
665 − "aparch11__t__w1000_r5": 0.207,
666 − "egarch11__t__w1000_r5": 0.2125,
667 − "garch11__normal__w1000_r5": 0.2298,
668 − "garch11__t__w1000_r5": 0.2408,
669 − "gjr11__t__w1000_r5": 0.2179,
670 − "har_rv__empirical__w1000_r5": 0.2408,
671 − "histvar22__empirical__w1000_r5": 0.4482,
672 − "nagarch11__t__w1000_r5": 0.2146,
673 − "realgarch11__normal__w1000_r5": 0.2336
674 − }
675 − ],
676 − "ratio_to_garch11_normal": [
677 − {
678 − "proxy": "r2",
679 − "loss": "mse",
680 − "h": 1,
681 − "aparch11__t__w1000_r5": 0.9756,
682 − "egarch11__t__w1000_r5": 1.0006,
683 − "garch11__normal__w1000_r5": 1.0,
684 − "garch11__t__w1000_r5": 0.9957,
685 − "gjr11__t__w1000_r5": 1.0495,
686 − "har_rv__empirical__w1000_r5": 1.0157,
687 − "histvar22__empirical__w1000_r5": 1.0183,
688 − "nagarch11__t__w1000_r5": 1.0027,
689 − "realgarch11__normal__w1000_r5": 0.9803
690 − },
691 216 {
692 217 "proxy": "r2",
693 218 "loss": "mse",
694 219 "h": 5,
695 − "aparch11__t__w1000_r5": 0.8951,
696 − "egarch11__t__w1000_r5": 0.9575,
220 + "aparch11__t__w1000_r5": 0.8521,
221 + "egarch11__t__w1000_r5": 0.8327,
697 222 "garch11__normal__w1000_r5": 1.0,
698 − "garch11__t__w1000_r5": 0.9817,
699 − "gjr11__t__w1000_r5": 1.1569,
700 − "har_rv__empirical__w1000_r5": 1.0379,
701 − "histvar22__empirical__w1000_r5": 1.0965,
702 − "nagarch11__t__w1000_r5": 0.9964,
703 − "realgarch11__normal__w1000_r5": 0.9353
223 + "garch11__t__w1000_r5": 1.0004,
224 + "gjr11__t__w1000_r5": 0.8723,
225 + "har_rv__empirical__w1000_r5": 0.9415,
226 + "histvar22__empirical__w1000_r5": 1.1236,
227 + "nagarch11__t__w1000_r5": 0.8361,
228 + "realgarch11__normal__w1000_r5": 0.9045
704 229 },
705 230 {
706 231 "proxy": "r2",
707 232 "loss": "mse",
708 233 "h": 22,
709 − "aparch11__t__w1000_r5": 0.7471,
710 − "egarch11__t__w1000_r5": 0.7964,
234 + "aparch11__t__w1000_r5": 0.6138,
235 + "egarch11__t__w1000_r5": 0.5653,
711 236 "garch11__normal__w1000_r5": 1.0,
712 − "garch11__t__w1000_r5": 0.9667,
713 − "gjr11__t__w1000_r5": 1.0803,
714 − "har_rv__empirical__w1000_r5": 1.0397,
715 − "histvar22__empirical__w1000_r5": 1.4306,
716 − "nagarch11__t__w1000_r5": 0.8822,
717 − "realgarch11__normal__w1000_r5": 0.8609
237 + "garch11__t__w1000_r5": 1.0066,
238 + "gjr11__t__w1000_r5": 0.6732,
239 + "har_rv__empirical__w1000_r5": 0.8113,
240 + "histvar22__empirical__w1000_r5": 1.1962,
241 + "nagarch11__t__w1000_r5": 0.5813,
242 + "realgarch11__normal__w1000_r5": 0.8196
718 243 },
719 244 {
720 245 "proxy": "r2",
721 246 "loss": "qlike",
722 247 "h": 1,
723 − "aparch11__t__w1000_r5": 0.9763,
724 − "egarch11__t__w1000_r5": 0.9794,
248 + "aparch11__t__w1000_r5": 0.9804,
249 + "egarch11__t__w1000_r5": 0.9778,
725 250 "garch11__normal__w1000_r5": 1.0,
726 − "garch11__t__w1000_r5": 1.0004,
727 − "gjr11__t__w1000_r5": 0.9803,
728 − "har_rv__empirical__w1000_r5": 1.0114,
729 − "histvar22__empirical__w1000_r5": 1.0869,
730 − "nagarch11__t__w1000_r5": 0.9824,
731 − "realgarch11__normal__w1000_r5": 1.0119
251 + "garch11__t__w1000_r5": 0.9979,
252 + "gjr11__t__w1000_r5": 0.9823,
253 + "har_rv__empirical__w1000_r5": 0.9691,
254 + "histvar22__empirical__w1000_r5": 1.0139,
255 + "nagarch11__t__w1000_r5": 0.981,
256 + "realgarch11__normal__w1000_r5": 0.9776
732 257 },
733 258 {
734 259 "proxy": "r2",
735 260 "loss": "qlike",
736 261 "h": 5,
737 − "aparch11__t__w1000_r5": 0.9414,
738 − "egarch11__t__w1000_r5": 0.9532,
262 + "aparch11__t__w1000_r5": 0.8997,
263 + "egarch11__t__w1000_r5": 0.8838,
739 264 "garch11__normal__w1000_r5": 1.0,
740 − "garch11__t__w1000_r5": 0.9968,
741 − "gjr11__t__w1000_r5": 0.962,
742 − "har_rv__empirical__w1000_r5": 1.0293,
743 − "histvar22__empirical__w1000_r5": 1.2737,
744 − "nagarch11__t__w1000_r5": 0.9583,
745 − "realgarch11__normal__w1000_r5": 1.0412
265 + "garch11__t__w1000_r5": 0.9912,
266 + "gjr11__t__w1000_r5": 0.9089,
267 + "har_rv__empirical__w1000_r5": 0.9147,
268 + "histvar22__empirical__w1000_r5": 1.0507,
269 + "nagarch11__t__w1000_r5": 0.9022,
270 + "realgarch11__normal__w1000_r5": 0.9265
746 271 },
747 272 {
748 273 "proxy": "r2",
749 274 "loss": "qlike",
750 275 "h": 22,
751 − "aparch11__t__w1000_r5": 0.855,
752 − "egarch11__t__w1000_r5": 0.8838,
276 + "aparch11__t__w1000_r5": 0.7507,
277 + "egarch11__t__w1000_r5": 0.7042,
753 278 "garch11__normal__w1000_r5": 1.0,
754 − "garch11__t__w1000_r5": 0.9979,
755 − "gjr11__t__w1000_r5": 0.9394,
756 − "har_rv__empirical__w1000_r5": 1.0289,
757 − "histvar22__empirical__w1000_r5": 1.9325,
758 − "nagarch11__t__w1000_r5": 0.8973,
759 − "realgarch11__normal__w1000_r5": 0.9807
279 + "garch11__t__w1000_r5": 0.9795,
280 + "gjr11__t__w1000_r5": 0.7913,
281 + "har_rv__empirical__w1000_r5": 0.8653,
282 + "histvar22__empirical__w1000_r5": 1.1667,
283 + "nagarch11__t__w1000_r5": 0.7496,
284 + "realgarch11__normal__w1000_r5": 0.9371
760 285 },
761 286 {
762 287 "proxy": "rv5ss_on",
763 288 "loss": "mse",
764 289 "h": 1,
765 − "aparch11__t__w1000_r5": 0.9782,
766 − "egarch11__t__w1000_r5": 0.9953,
290 + "aparch11__t__w1000_r5": 0.9246,
291 + "egarch11__t__w1000_r5": 0.931,
767 292 "garch11__normal__w1000_r5": 1.0,
768 − "garch11__t__w1000_r5": 1.0062,
769 − "gjr11__t__w1000_r5": 1.0196,
770 − "har_rv__empirical__w1000_r5": 1.0162,
771 − "histvar22__empirical__w1000_r5": 1.0279,
772 − "nagarch11__t__w1000_r5": 0.9974,
773 − "realgarch11__normal__w1000_r5": 0.982
293 + "garch11__t__w1000_r5": 0.9945,
294 + "gjr11__t__w1000_r5": 0.9455,
295 + "har_rv__empirical__w1000_r5": 0.8693,
296 + "histvar22__empirical__w1000_r5": 1.2697,
297 + "nagarch11__t__w1000_r5": 0.8933,
298 + "realgarch11__normal__w1000_r5": 0.8416
774 299 },
775 300 {
776 301 "proxy": "rv5ss_on",
777 302 "loss": "mse",
778 303 "h": 5,
779 − "aparch11__t__w1000_r5": 0.9421,
780 − "egarch11__t__w1000_r5": 0.9747,
304 + "aparch11__t__w1000_r5": 0.7225,
305 + "egarch11__t__w1000_r5": 0.7029,
781 306 "garch11__normal__w1000_r5": 1.0,
782 − "garch11__t__w1000_r5": 1.0028,
783 − "gjr11__t__w1000_r5": 1.0826,
784 − "har_rv__empirical__w1000_r5": 1.0561,
785 − "histvar22__empirical__w1000_r5": 1.0788,
786 − "nagarch11__t__w1000_r5": 1.0043,
787 − "realgarch11__normal__w1000_r5": 0.9787
307 + "garch11__t__w1000_r5": 0.9965,
308 + "gjr11__t__w1000_r5": 0.7813,
309 + "har_rv__empirical__w1000_r5": 0.8373,
310 + "histvar22__empirical__w1000_r5": 1.3551,
311 + "nagarch11__t__w1000_r5": 0.6632,
312 + "realgarch11__normal__w1000_r5": 0.808
788 313 },
789 314 {
790 315 "proxy": "rv5ss_on",
791 316 "loss": "mse",
792 317 "h": 22,
793 − "aparch11__t__w1000_r5": 0.8396,
794 − "egarch11__t__w1000_r5": 0.873,
318 + "aparch11__t__w1000_r5": 0.5539,
319 + "egarch11__t__w1000_r5": 0.5059,
795 320 "garch11__normal__w1000_r5": 1.0,
796 − "garch11__t__w1000_r5": 1.0054,
797 − "gjr11__t__w1000_r5": 1.0634,
798 − "har_rv__empirical__w1000_r5": 1.0465,
799 − "histvar22__empirical__w1000_r5": 1.3197,
800 − "nagarch11__t__w1000_r5": 0.9425,
801 − "realgarch11__normal__w1000_r5": 0.9159
321 + "garch11__t__w1000_r5": 1.0067,
322 + "gjr11__t__w1000_r5": 0.6506,
323 + "har_rv__empirical__w1000_r5": 0.7638,
324 + "histvar22__empirical__w1000_r5": 1.2617,
325 + "nagarch11__t__w1000_r5": 0.4735,
326 + "realgarch11__normal__w1000_r5": 0.8521
802 327 },
803 328 {
804 329 "proxy": "rv5ss_on",
805 330 "loss": "qlike",
806 331 "h": 1,
807 − "aparch11__t__w1000_r5": 0.9365,
808 − "egarch11__t__w1000_r5": 0.9393,
332 + "aparch11__t__w1000_r5": 0.9549,
333 + "egarch11__t__w1000_r5": 0.9557,
809 334 "garch11__normal__w1000_r5": 1.0,
810 − "garch11__t__w1000_r5": 1.0391,
811 − "gjr11__t__w1000_r5": 0.9215,
812 − "har_rv__empirical__w1000_r5": 1.1031,
813 − "histvar22__empirical__w1000_r5": 1.2862,
814 − "nagarch11__t__w1000_r5": 0.9689,
815 − "realgarch11__normal__w1000_r5": 0.9994
335 + "garch11__t__w1000_r5": 0.9907,
336 + "gjr11__t__w1000_r5": 0.9375,
337 + "har_rv__empirical__w1000_r5": 0.728,
338 + "histvar22__empirical__w1000_r5": 1.2798,
339 + "nagarch11__t__w1000_r5": 0.9728,
340 + "realgarch11__normal__w1000_r5": 0.7564
816 341 },
817 342 {
818 343 "proxy": "rv5ss_on",
819 344 "loss": "qlike",
820 345 "h": 5,
821 − "aparch11__t__w1000_r5": 0.9695,
822 − "egarch11__t__w1000_r5": 0.9735,
346 + "aparch11__t__w1000_r5": 0.8635,
347 + "egarch11__t__w1000_r5": 0.8445,
823 348 "garch11__normal__w1000_r5": 1.0,
824 − "garch11__t__w1000_r5": 1.0296,
825 − "gjr11__t__w1000_r5": 0.951,
826 − "har_rv__empirical__w1000_r5": 1.1082,
827 − "histvar22__empirical__w1000_r5": 1.3756,
828 − "nagarch11__t__w1000_r5": 0.9962,
829 − "realgarch11__normal__w1000_r5": 1.077
349 + "garch11__t__w1000_r5": 0.9851,
350 + "gjr11__t__w1000_r5": 0.861,
351 + "har_rv__empirical__w1000_r5": 0.8506,
352 + "histvar22__empirical__w1000_r5": 1.3261,
353 + "nagarch11__t__w1000_r5": 0.8762,
354 + "realgarch11__normal__w1000_r5": 0.8048
830 355 },
831 356 {
832 357 "proxy": "rv5ss_on",
833 358 "loss": "qlike",
834 359 "h": 22,
835 − "aparch11__t__w1000_r5": 0.9009,
836 − "egarch11__t__w1000_r5": 0.9248,
360 + "aparch11__t__w1000_r5": 0.7296,
361 + "egarch11__t__w1000_r5": 0.676,
837 362 "garch11__normal__w1000_r5": 1.0,
838 − "garch11__t__w1000_r5": 1.048,
839 − "gjr11__t__w1000_r5": 0.9483,
840 − "har_rv__empirical__w1000_r5": 1.0482,
841 − "histvar22__empirical__w1000_r5": 1.9505,
842 − "nagarch11__t__w1000_r5": 0.9338,
843 − "realgarch11__normal__w1000_r5": 1.0166
363 + "garch11__t__w1000_r5": 0.9712,
364 + "gjr11__t__w1000_r5": 0.7854,
365 + "har_rv__empirical__w1000_r5": 0.8813,
366 + "histvar22__empirical__w1000_r5": 1.1903,
367 + "nagarch11__t__w1000_r5": 0.7253,
368 + "realgarch11__normal__w1000_r5": 1.0137
844 369 }
845 370 ],
846 371 "dm_vs_garch11_normal_h1_qlike": {
847 372 "aparch11__t__w1000_r5": {
848 − "stat": -1.9963,
849 − "p": 0.0462,
850 − "mean_diff": -0.0353,
851 − "n": 1005,
373 + "stat": -0.8398,
374 + "p": 0.4012,
375 + "mean_diff": -0.0056,
376 + "n": 1031,
852 377 "bandwidth": 6
853 378 },
854 379 "egarch11__t__w1000_r5": {
855 − "stat": -2.0076,
856 − "p": 0.045,
857 − "mean_diff": -0.0338,
858 − "n": 1005,
380 + "stat": -0.7801,
381 + "p": 0.4355,
382 + "mean_diff": -0.0055,
383 + "n": 1031,
859 384 "bandwidth": 6
860 385 },
861 386 "garch11__t__w1000_r5": {
862 − "stat": 1.5272,
863 − "p": 0.127,
864 − "mean_diff": 0.0217,
865 − "n": 1005,
387 + "stat": -1.1594,
388 + "p": 0.2466,
389 + "mean_diff": -0.0012,
390 + "n": 1031,
866 391 "bandwidth": 6
867 392 },
868 393 "gjr11__t__w1000_r5": {
869 − "stat": -2.2136,
870 − "p": 0.0271,
871 − "mean_diff": -0.0437,
872 − "n": 1005,
394 + "stat": -1.4247,
395 + "p": 0.1545,
396 + "mean_diff": -0.0077,
397 + "n": 1031,
873 398 "bandwidth": 6
874 399 },
875 400 "har_rv__empirical__w1000_r5": {
876 − "stat": 1.8475,
877 − "p": 0.065,
878 − "mean_diff": 0.0573,
879 − "n": 1005,
401 + "stat": -6.3176,
402 + "p": 0.0,
403 + "mean_diff": -0.0337,
404 + "n": 1031,
880 405 "bandwidth": 6
881 406 },
882 407 "histvar22__empirical__w1000_r5": {
883 − "stat": 2.5917,
884 − "p": 0.0097,
885 − "mean_diff": 0.1592,
886 − "n": 1005,
408 + "stat": 2.8833,
409 + "p": 0.004,
410 + "mean_diff": 0.0347,
411 + "n": 1031,
887 412 "bandwidth": 6
888 413 },
889 414 "nagarch11__t__w1000_r5": {
890 − "stat": -0.8589,
891 − "p": 0.3906,
892 − "mean_diff": -0.0173,
893 − "n": 1005,
415 + "stat": -0.525,
416 + "p": 0.5997,
417 + "mean_diff": -0.0034,
418 + "n": 1031,
894 419 "bandwidth": 6
895 420 },
896 421 "realgarch11__normal__w1000_r5": {
897 − "stat": -0.0117,
898 − "p": 0.9907,
899 − "mean_diff": -0.0003,
900 − "n": 1005,
422 + "stat": -5.6857,
423 + "p": 0.0,
424 + "mean_diff": -0.0302,
425 + "n": 1031,
901 426 "bandwidth": 6
902 427 }
903 428 },
904 429 "leakage_check_passed": true,
905 430 "timing": {
906 431 "mean": {
907 − "aparch11__t__w1000_r5": 0.0353,
908 − "egarch11__t__w1000_r5": 0.0065,
909 − "garch11__normal__w1000_r5": 0.0042,
910 − "garch11__t__w1000_r5": 0.0073,
911 − "gjr11__t__w1000_r5": 0.0065,
432 + "aparch11__t__w1000_r5": 0.0326,
433 + "egarch11__t__w1000_r5": 0.0088,
434 + "garch11__normal__w1000_r5": 0.0044,
435 + "garch11__t__w1000_r5": 0.0066,
436 + "gjr11__t__w1000_r5": 0.0082,
912 437 "har_rv__empirical__w1000_r5": 0.0008,
913 438 "histvar22__empirical__w1000_r5": 0.0,
914 − "nagarch11__t__w1000_r5": 0.0081,
915 − "realgarch11__normal__w1000_r5": 0.0233
439 + "nagarch11__t__w1000_r5": 0.0096,
440 + "realgarch11__normal__w1000_r5": 0.0276
916 441 },
917 442 "median": {
918 − "aparch11__t__w1000_r5": 0.0313,
919 − "egarch11__t__w1000_r5": 0.0065,
920 − "garch11__normal__w1000_r5": 0.0042,
921 − "garch11__t__w1000_r5": 0.0068,
922 − "gjr11__t__w1000_r5": 0.0063,
443 + "aparch11__t__w1000_r5": 0.0324,
444 + "egarch11__t__w1000_r5": 0.0089,
445 + "garch11__normal__w1000_r5": 0.0043,
446 + "garch11__t__w1000_r5": 0.0064,
447 + "gjr11__t__w1000_r5": 0.0082,
923 448 "har_rv__empirical__w1000_r5": 0.0008,
924 449 "histvar22__empirical__w1000_r5": 0.0,
925 − "nagarch11__t__w1000_r5": 0.008,
926 − "realgarch11__normal__w1000_r5": 0.0233
450 + "nagarch11__t__w1000_r5": 0.0091,
451 + "realgarch11__normal__w1000_r5": 0.0267
927 452 },
928 453 "max": {
929 − "aparch11__t__w1000_r5": 0.105,
930 − "egarch11__t__w1000_r5": 0.0094,
931 − "garch11__normal__w1000_r5": 0.0053,
932 − "garch11__t__w1000_r5": 0.0123,
933 − "gjr11__t__w1000_r5": 0.0093,
454 + "aparch11__t__w1000_r5": 0.0465,
455 + "egarch11__t__w1000_r5": 0.0173,
456 + "garch11__normal__w1000_r5": 0.0063,
457 + "garch11__t__w1000_r5": 0.0095,
458 + "gjr11__t__w1000_r5": 0.0127,
934 459 "har_rv__empirical__w1000_r5": 0.0011,
935 460 "histvar22__empirical__w1000_r5": 0.0,
936 − "nagarch11__t__w1000_r5": 0.0104,
937 − "realgarch11__normal__w1000_r5": 0.0296
461 + "nagarch11__t__w1000_r5": 0.1042,
462 + "realgarch11__normal__w1000_r5": 0.0368
938 463 }
939 464 }
940 465 }
modified scripts/run_pilot.py +9 −5
@@ -50,11 +50,15 @@ def main() -> None:
50 50 tab = Lc.groupby(["proxy", "loss", "h", "spec_id"])["value"].mean().unstack("spec_id")
51 51 bench = [s for s in specs if s.startswith("garch11__normal")][0]
52 52 ratio = tab.div(tab[bench], axis=0)
53 − # leakage check: perturb returns after the last origin -> forecasts at the last origin unchanged
54 − p2 = panel.copy(); last = F["origin"].max(); m = p2["session"] > last; p2.loc[m, "r"] *= 3.0
55 − F2, _ = run_job(p2, JobSpec(sym, "gjr11", "t", "A", oos_start=str(last.date()), oos_end=str(last.date())))
56 − f1 = F[(F.spec_id.str.startswith("gjr11__t")) & (F.origin == last)]["h1"].values
57 − leak_ok = bool(np.allclose(f1, F2["h1"].values))
53 + # leakage check: perturb returns AND realized measures after the last origin -> every forecast of the whole
54 + # job (same refit schedule) is unchanged
55 + p2 = panel.copy(); last = F["origin"].max(); m = p2["session"] > last
56 + p2.loc[m, "r"] *= 3.0; p2.loc[m, "rv_5m_ss"] *= 9.0
57 + leak_ok = True
58 + for mid, dist, tier in [("gjr11", "t", "A"), ("har_rv", "empirical", "B")]:
59 + F1 = F[F.spec_id.str.startswith(f"{mid}__{dist}")].sort_values("origin")
60 + F2, _ = run_job(p2, JobSpec(sym, mid, dist, tier, oos_start=a.start, oos_end=a.end))
61 + leak_ok &= bool(np.allclose(F1["h1"].values, F2.sort_values("origin")["h1"].values, equal_nan=True))
58 62 dm = {s: dm_test(Lc[(Lc.spec_id == s) & (Lc.h == 1) & (Lc.proxy == "rv5ss_on") & (Lc.loss == "qlike")].sort_values("origin")["value"].values,
59 63 Lc[(Lc.spec_id == bench) & (Lc.h == 1) & (Lc.proxy == "rv5ss_on") & (Lc.loss == "qlike")].sort_values("origin")["value"].values, 1)
60 64 for s in specs if s != bench}
added src/wp46/diagnostics/__init__.py +1 −0
@@ -0,0 +1 @@
1 +from .tailrisk import var_es_forecasts, kupiec, christoffersen_cc, engle_manganelli_dq, fz0_loss, backtest_table # noqa: F401
added src/wp46/diagnostics/tailrisk.py +108 −0
@@ -0,0 +1,108 @@
1 +"""One-day-ahead VaR / ES forecasts and backtests (percent returns).
2 +
3 +VaR_p(t+1) = mu_{t+1} + sqrt(h_{t+1}) q_p ; ES_p(t+1) = mu_{t+1} + sqrt(h_{t+1}) e_p, where q_p / e_p are the p-quantile
4 +and lower-tail mean of the model's standardized innovation law (normal, t, ged, skewt via wp46.models.distributions). For
5 +distribution-free models ('empirical'), q_p and e_p are the empirical quantile / tail mean of the standardized in-window
6 +residuals z = (r - mu)/sqrt(sigma2_filtered) supplied by the caller (the driver stores them per refit as `emp_q`).
7 +Backtests: Kupiec (1995) unconditional coverage LR, Christoffersen (1998) conditional coverage LR, Engle & Manganelli
8 +(2004) dynamic quantile test with 4 lagged hits and the VaR as regressors, Fissler & Ziegel (2016) FZ0 joint loss
9 +(Patton, Ziegel & Chen 2019 parameterization): FZ0 = -1/(alpha ES) 1{r<=VaR} (VaR - r) + VaR/ES + log(-ES) - 1, valid for ES < 0."""
10 +from __future__ import annotations
11 +
12 +import numpy as np
13 +import pandas as pd
14 +from scipy import stats
15 +
16 +from wp46.models.distributions import expected_shortfall, ppf
17 +
18 +LEVELS = (0.01, 0.05)
19 +
20 +
21 +def var_es_forecasts(mu: np.ndarray, h1: np.ndarray, dist: str, dp1: np.ndarray, dp2: np.ndarray, levels=LEVELS,
22 + emp_q: dict | None = None) -> dict:
23 + """Vectorized over origins; distribution parameters may vary by origin (refits)."""
24 + out = {}
25 + s = np.sqrt(np.maximum(h1, 1e-12))
26 + for p in levels:
27 + q = np.full(len(mu), np.nan); e = np.full(len(mu), np.nan)
28 + if dist == "empirical":
29 + if emp_q is not None:
30 + q[:] = emp_q[p]["q"]; e[:] = emp_q[p]["es"]
31 + elif dist == "normal":
32 + q[:] = stats.norm.ppf(p); e[:] = -stats.norm.pdf(stats.norm.ppf(p)) / p
33 + else:
34 + params = np.column_stack([dp1, dp2]) if dist == "skewt" else dp1[:, None]
35 + uniq, inv = np.unique(np.round(params, 10), axis=0, return_inverse=True)
36 + for k, prm in enumerate(uniq):
37 + m = inv.ravel() == k
38 + q[m] = ppf(dist, p, prm)[0]
39 + e[m] = expected_shortfall(dist, p, prm)
40 + out[p] = {"var": mu + s * q, "es": mu + s * e}
41 + return out
42 +
43 +
44 +def kupiec(hits: np.ndarray, p: float) -> dict:
45 + n = len(hits); x = int(hits.sum())
46 + if n == 0:
47 + return dict(lr=np.nan, p=np.nan, n=0, x=0, rate=np.nan)
48 + pi = x / n
49 + with np.errstate(divide="ignore", invalid="ignore"):
50 + l0 = x * np.log(p) + (n - x) * np.log(1 - p)
51 + l1 = (x * np.log(pi) if x > 0 else 0.0) + ((n - x) * np.log(1 - pi) if x < n else 0.0)
52 + lr = -2 * (l0 - l1)
53 + return dict(lr=float(lr), p=float(stats.chi2.sf(lr, 1)), n=n, x=x, rate=pi)
54 +
55 +
56 +def christoffersen_cc(hits: np.ndarray, p: float) -> dict:
57 + h = hits.astype(int)
58 + if len(h) < 2:
59 + return dict(lr_ind=np.nan, p_ind=np.nan, lr_cc=np.nan, p_cc=np.nan)
60 + n00 = np.sum((h[:-1] == 0) & (h[1:] == 0)); n01 = np.sum((h[:-1] == 0) & (h[1:] == 1))
61 + n10 = np.sum((h[:-1] == 1) & (h[1:] == 0)); n11 = np.sum((h[:-1] == 1) & (h[1:] == 1))
62 + p01 = n01 / max(n00 + n01, 1); p11 = n11 / max(n10 + n11, 1); pi = (n01 + n11) / max(len(h) - 1, 1)
63 +
64 + def ll(a, b, c, d, q0, q1):
65 + with np.errstate(divide="ignore", invalid="ignore"):
66 + t = 0.0
67 + for cnt, pr in ((a, 1 - q0), (b, q0), (c, 1 - q1), (d, q1)):
68 + if cnt > 0:
69 + t += cnt * np.log(pr)
70 + return t
71 + l_ind = ll(n00, n01, n10, n11, p01, p11); l_0 = ll(n00, n01, n10, n11, pi, pi)
72 + lr_ind = -2 * (l_0 - l_ind)
73 + lr_uc = kupiec(hits, p)["lr"]
74 + lr_cc = lr_uc + lr_ind
75 + return dict(lr_ind=float(lr_ind), p_ind=float(stats.chi2.sf(lr_ind, 1)), lr_cc=float(lr_cc), p_cc=float(stats.chi2.sf(lr_cc, 2)))
76 +
77 +
78 +def engle_manganelli_dq(hits: np.ndarray, var: np.ndarray, p: float, lags: int = 4) -> dict:
79 + h = hits.astype(float) - p
80 + n = len(h)
81 + if n <= lags + 10:
82 + return dict(stat=np.nan, p=np.nan)
83 + X = np.column_stack([np.ones(n - lags)] + [h[lags - j - 1:n - j - 1] for j in range(lags)] + [var[lags:]])
84 + y = h[lags:]
85 + XtX = X.T @ X
86 + try:
87 + b = np.linalg.solve(XtX, X.T @ y)
88 + except np.linalg.LinAlgError:
89 + return dict(stat=np.nan, p=np.nan)
90 + stat = float(b @ XtX @ b / (p * (1 - p)))
91 + return dict(stat=stat, p=float(stats.chi2.sf(stat, X.shape[1])))
92 +
93 +
94 +def fz0_loss(r: np.ndarray, var: np.ndarray, es: np.ndarray, p: float) -> np.ndarray:
95 + es = np.minimum(es, -1e-8)
96 + hit = (r <= var).astype(float)
97 + return -hit * (var - r) / (p * es) + var / es + np.log(-es) - 1.0
98 +
99 +
100 +def backtest_table(r: np.ndarray, fc: dict, p: float) -> dict:
101 + var, es = fc[p]["var"], fc[p]["es"]
102 + m = np.isfinite(r) & np.isfinite(var) & np.isfinite(es)
103 + r, var, es = r[m], var[m], es[m]
104 + hits = (r <= var)
105 + k = kupiec(hits, p); c = christoffersen_cc(hits, p); d = engle_manganelli_dq(hits, var, p)
106 + fz = fz0_loss(r, var, es, p)
107 + return dict(n=int(len(r)), hit_rate=k["rate"], kupiec_p=k["p"], cc_p=c["p_cc"], dq_p=d["p"], fz0_mean=float(np.mean(fz)),
108 + es_shortfall_ratio=float(np.mean(r[hits]) / np.mean(es[hits])) if hits.sum() > 0 else np.nan)
modified src/wp46/estimation/rolling.py +22 −1
@@ -66,6 +66,25 @@ def make_model(model_id: str):
66 66 raise KeyError(model_id)
67 67
68 68
69 +def _empirical_tail(model, fit, r: np.ndarray, x) -> dict:
70 + """Empirical 1 % / 5 % quantiles and tail means of the standardized in-window residuals z = (r - mu)/sqrt(sigma2)
71 + (used for the VaR/ES of distribution-free models and as a diagnostic for parametric ones)."""
72 + try:
73 + s2 = np.asarray(model.filter(fit, r, x), float)
74 + mu = float(fit.params[0]) if len(fit.params) else float(np.mean(r))
75 + z = (np.asarray(r, float) - mu) / np.sqrt(np.maximum(s2, 1e-12))
76 + z = z[np.isfinite(z)]
77 + out = {}
78 + for p in (0.01, 0.05):
79 + q = float(np.quantile(z, p))
80 + out[f"emp_q{int(p*100):02d}"] = q
81 + out[f"emp_es{int(p*100):02d}"] = float(np.mean(z[z <= q])) if np.any(z <= q) else q
82 + out["z_kurtosis"] = float(np.mean(z ** 4) / np.mean(z ** 2) ** 2)
83 + return out
84 + except Exception: # noqa: BLE001
85 + return {}
86 +
87 +
69 88 def run_job(panel: pd.DataFrame, job: JobSpec, progress: bool = False) -> tuple[pd.DataFrame, pd.DataFrame]:
70 89 model = make_model(job.model_id)
71 90 needs_rm = bool(getattr(model, "needs_rm", False))
@@ -104,13 +123,15 @@ def run_job(panel: pd.DataFrame, job: JobSpec, progress: bool = False) -> tuple[
104 123 except Exception as e: # noqa: BLE001
105 124 new_fit, err = None, f"{type(e).__name__}: {str(e)[:120]}"
106 125 dt = time.perf_counter() - t0
126 + emp = {}
107 127 if new_fit is not None and new_fit.converged:
108 128 fit, stale = new_fit, False
109 129 status = "ok" if new_fit.admissible else "inadmissible"
130 + emp = _empirical_tail(model, new_fit, r, x)
110 131 else:
111 132 status = "failed"
112 133 stale = fit is not None
113 − fits_rows.append(dict(fit_id=fit_id, origin=dates[t], status=status, error=err or (new_fit.notes if new_fit else ""),
134 + fits_rows.append(dict(fit_id=fit_id, origin=dates[t], status=status, error=err or (new_fit.notes if new_fit else ""), **emp,
114 135 loglik=new_fit.loglik if new_fit else np.nan, n_iter=new_fit.n_iter if new_fit else 0,
115 136 n_restarts=new_fit.n_restarts if new_fit else 0, time_s=dt, n_obs=len(r),
116 137 admissible=bool(new_fit.admissible) if new_fit else False,
added src/wp46/models/multivariate.py +154 −0
@@ -0,0 +1,154 @@
1 +"""Tier C — covariance forecasts for a fixed basket of N daily return series (percent), h = 1.
2 +
3 +Models (model_id): rolling_cov252 (sample covariance of the last 252 days), ewma_cov094 (RiskMetrics, lambda 0.94),
4 +ccc_garch11 (Bollerslev 1990: univariate GARCH(1,1)-normal per asset + constant correlation of standardized residuals),
5 +dcc11 (Engle 2002, two-step QMLE: GARCH(1,1) per asset, then DCC(1,1) correlation targeting with the sample correlation
6 +of the standardized residuals; Q_t = (1-a-b) S + a z_{t-1} z_{t-1}' + b Q_{t-1}, R_t = diag(Q_t)^{-1/2} Q_t diag(Q_t)^{-1/2}),
7 +adcc11 (Cappiello, Engle & Sheppard 2006: + g n_{t-1} n_{t-1}' with n = z 1{z<0}, targeting (1-a-b) S - g N with
8 +N = E[n n']), scalar_bekk11 (Engle & Kroner 1995, scalar: H_t = C C' + a eps_{t-1} eps_{t-1}' + b H_{t-1} with covariance
9 +targeting C C' = (1-a-b) Sigma_bar, Gaussian QMLE). All one-step forecasts are symmetric positive definite by construction
10 +(checked: minimum eigenvalue > 0 is recorded). Parameters are estimated by Gaussian QMLE with scipy; standardized
11 +residuals of the first step come from wp46.models.arch_models GARCH(1,1).
12 +"""
13 +from __future__ import annotations
14 +
15 +import math
16 +import time
17 +
18 +import numpy as np
19 +from scipy import optimize
20 +
21 +from .arch_models import ArchModel
22 +
23 +
24 +def _corr_from_cov(H):
25 + d = 1.0 / np.sqrt(np.diag(H))
26 + return H * np.outer(d, d)
27 +
28 +
29 +def _univariate_garch(R: np.ndarray):
30 + """Fit GARCH(1,1)-normal to each column; return (sigma2 matrix T x N, one-step variance forecasts, fits)."""
31 + T, N = R.shape
32 + S2 = np.empty((T, N)); f1 = np.empty(N); fits = []
33 + m = ArchModel("garch11")
34 + for j in range(N):
35 + f = m.fit(R[:, j], dist="normal")
36 + S2[:, j] = m.filter(f, R[:, j])
37 + f1[j] = m.forecast(f, R[:, j], None, 1).step_var[0]
38 + fits.append(f)
39 + return S2, f1, fits
40 +
41 +
42 +def _dcc_negll(theta, Z, S, asym, Nbar):
43 + a = 1 / (1 + math.exp(-theta[0])); b = (1 - a) / (1 + math.exp(-theta[1])); g = 0.0
44 + if asym:
45 + g = (1 - a - b) / (1 + math.exp(-theta[2])) * 0.999
46 + T, N = Z.shape
47 + Q = S.copy(); ll = 0.0
48 + Qbar = (1 - a - b) * S - (g * Nbar if asym else 0.0)
49 + try:
50 + for t in range(T):
51 + if t > 0:
52 + z = Z[t - 1]
53 + Q = Qbar + a * np.outer(z, z) + b * Q
54 + if asym:
55 + n = z * (z < 0)
56 + Q = Q + g * np.outer(n, n)
57 + Rt = _corr_from_cov(Q)
58 + L = np.linalg.cholesky(Rt)
59 + w = np.linalg.solve(L, Z[t])
60 + ll += -0.5 * (2 * np.sum(np.log(np.diag(L))) + w @ w - Z[t] @ Z[t])
61 + except np.linalg.LinAlgError:
62 + return 1e10
63 + return -ll
64 +
65 +
66 +class CovModel:
67 + def __init__(self, model_id: str):
68 + self.model_id = model_id
69 +
70 + def fit_forecast(self, R: np.ndarray) -> dict:
71 + """R: T x N returns (window). Returns dict(H1 = one-step covariance forecast, params, converged, time_s, min_eig)."""
72 + t0 = time.perf_counter()
73 + T, N = R.shape
74 + Rc = R - R.mean(axis=0)
75 + mid = self.model_id
76 + params = {}; conv = True
77 + if mid == "rolling_cov252":
78 + H1 = np.cov(Rc[-252:].T, bias=True)
79 + elif mid == "ewma_cov094":
80 + lam = 0.94; H = np.cov(Rc[:50].T, bias=True)
81 + for t in range(T):
82 + H = lam * H + (1 - lam) * np.outer(Rc[t], Rc[t])
83 + H1 = H
84 + elif mid in ("ccc_garch11", "dcc11", "adcc11"):
85 + S2, f1, fits = _univariate_garch(R)
86 + Z = Rc / np.sqrt(S2)
87 + S = np.corrcoef(Z.T)
88 + D1 = np.sqrt(f1)
89 + if mid == "ccc_garch11":
90 + R1 = S
91 + else:
92 + asym = mid == "adcc11"
93 + Nn = Z * (Z < 0); Nbar = (Nn.T @ Nn) / T
94 + th0 = np.array([math.log(0.02 / 0.98), math.log(0.95 / 0.05)] + ([math.log(0.02 / 0.98)] if asym else []))
95 + res = optimize.minimize(_dcc_negll, th0, args=(Z, S, asym, Nbar), method="L-BFGS-B", options={"maxiter": 500})
96 + conv = bool(res.success) and res.fun < 1e9
97 + a = 1 / (1 + math.exp(-res.x[0])); b = (1 - a) / (1 + math.exp(-res.x[1])); g = (1 - a - b) / (1 + math.exp(-res.x[2])) * 0.999 if asym else 0.0
98 + params = {"a": a, "b": b, "g": g, "loglik": -float(res.fun)}
99 + Q = S.copy(); Qbar = (1 - a - b) * S - g * Nbar
100 + for t in range(1, T + 1):
101 + z = Z[t - 1]
102 + Q = Qbar + a * np.outer(z, z) + b * Q
103 + if asym:
104 + n = z * (z < 0); Q = Q + g * np.outer(n, n)
105 + R1 = _corr_from_cov(Q)
106 + H1 = R1 * np.outer(D1, D1)
107 + params.update({f"garch_{j}": list(map(float, f.params)) for j, f in enumerate(fits)})
108 + elif mid == "scalar_bekk11":
109 + Sig = np.cov(Rc.T, bias=True)
110 +
111 + def negll(th):
112 + a = 1 / (1 + math.exp(-th[0])); b = (1 - a) / (1 + math.exp(-th[1]))
113 + C = (1 - a - b) * Sig; H = Sig.copy(); ll = 0.0
114 + try:
115 + for t in range(T):
116 + if t > 0:
117 + H = C + a * np.outer(Rc[t - 1], Rc[t - 1]) + b * H
118 + L = np.linalg.cholesky(H); w = np.linalg.solve(L, Rc[t])
119 + ll += -0.5 * (2 * np.sum(np.log(np.diag(L))) + w @ w)
120 + except np.linalg.LinAlgError:
121 + return 1e10
122 + return -ll
123 + res = optimize.minimize(negll, np.array([math.log(0.05 / 0.95), math.log(0.9 / 0.1)]), method="L-BFGS-B", options={"maxiter": 500})
124 + conv = bool(res.success) and res.fun < 1e9
125 + a = 1 / (1 + math.exp(-res.x[0])); b = (1 - a) / (1 + math.exp(-res.x[1]))
126 + C = (1 - a - b) * Sig; H = Sig.copy()
127 + for t in range(1, T + 1):
128 + H = C + a * np.outer(Rc[t - 1], Rc[t - 1]) + b * H
129 + H1 = H; params = {"a": a, "b": b, "loglik": -float(res.fun)}
130 + else:
131 + raise KeyError(mid)
132 + H1 = 0.5 * (H1 + H1.T)
133 + return {"H1": H1, "params": params, "converged": conv, "time_s": time.perf_counter() - t0,
134 + "min_eig": float(np.linalg.eigvalsh(H1).min())}
135 +
136 +
137 +def frobenius_loss(Y: np.ndarray, H: np.ndarray) -> float:
138 + return float(np.sum((Y - H) ** 2))
139 +
140 +
141 +def mv_qlike(Y: np.ndarray, H: np.ndarray) -> float:
142 + """Multivariate QLIKE (Laurent, Rombouts & Violante 2013): log|H| + tr(H^{-1} Y) - log|Y| - N (>= 0 iff Y, H SPD)."""
143 + N = Y.shape[0]
144 + Hi = np.linalg.inv(H)
145 + sy, ldy = np.linalg.slogdet(Y); sh, ldh = np.linalg.slogdet(H)
146 + if sy <= 0 or sh <= 0:
147 + return float("nan")
148 + return float(ldh + np.trace(Hi @ Y) - ldy - N)
149 +
150 +
151 +def portfolio_variance_loss(Y: np.ndarray, H: np.ndarray, w: np.ndarray) -> float:
152 + """QLIKE of the equally weighted (or given w) portfolio variance."""
153 + y = float(w @ Y @ w); h = float(w @ H @ w)
154 + return y / h - math.log(y / h) - 1.0
modified tests/integration/test_rolling_driver.py +13 −0
Large diff (17 lines) is not loaded by default to keep the page fast.Load diff
Menu

Theme