SPB Git

Repository Public Research preview

Commit

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
9 changed files +662 −758 Browse files
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": { 2+ "CL": {
3− "n_origins": 1006, 3+ "n_origins": 1032,
4− "common_sample_n_h1": 9054, 4+ "common_sample_n_h1": 9279,
5 "status": { 5 "status": {
6 "ok": { 6 "ok": {
7− "aparch11__t__w1000_r5": 1006, 7+ "aparch11__t__w1000_r5": 1032,
8− "egarch11__t__w1000_r5": 1006, 8+ "egarch11__t__w1000_r5": 1032,
9− "garch11__normal__w1000_r5": 1006, 9+ "garch11__normal__w1000_r5": 1032,
10− "garch11__t__w1000_r5": 1006, 10+ "garch11__t__w1000_r5": 1032,
11− "gjr11__t__w1000_r5": 1006, 11+ "gjr11__t__w1000_r5": 1032,
12− "har_rv__empirical__w1000_r5": 1006, 12+ "har_rv__empirical__w1000_r5": 1032,
13− "histvar22__empirical__w1000_r5": 1006, 13+ "histvar22__empirical__w1000_r5": 1032,
14− "nagarch11__t__w1000_r5": 1006, 14+ "nagarch11__t__w1000_r5": 1032,
15− "realgarch11__normal__w1000_r5": 1006 15+ "realgarch11__normal__w1000_r5": 1032
16 } 16 }
17 }, 17 },
18 "fit_status": { 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 "ok": { 19 "ok": {
31− "aparch11__t__w1000_r5": 202, 20+ "aparch11__t__w1000_r5": 207,
32− "egarch11__t__w1000_r5": 202, 21+ "egarch11__t__w1000_r5": 207,
33− "garch11__normal__w1000_r5": 202, 22+ "garch11__normal__w1000_r5": 207,
34− "garch11__t__w1000_r5": 176, 23+ "garch11__t__w1000_r5": 207,
35− "gjr11__t__w1000_r5": 202, 24+ "gjr11__t__w1000_r5": 207,
36− "har_rv__empirical__w1000_r5": 202, 25+ "har_rv__empirical__w1000_r5": 207,
37− "histvar22__empirical__w1000_r5": 202, 26+ "histvar22__empirical__w1000_r5": 207,
38− "nagarch11__t__w1000_r5": 202, 27+ "nagarch11__t__w1000_r5": 207,
39− "realgarch11__normal__w1000_r5": 202 28+ "realgarch11__normal__w1000_r5": 207
40 } 29 }
41 }, 30 },
42 "mean_loss_common": [ 31 "mean_loss_common": [
@@ -44,169 +33,169 @@
44 "proxy": "r2", 33 "proxy": "r2",
45 "loss": "mse", 34 "loss": "mse",
46 "h": 1, 35 "h": 1,
47− "aparch11__t__w1000_r5": 1.3996, 36+ "aparch11__t__w1000_r5": 38.8482,
48− "egarch11__t__w1000_r5": 1.3836, 37+ "egarch11__t__w1000_r5": 38.7292,
49− "garch11__normal__w1000_r5": 1.4871, 38+ "garch11__normal__w1000_r5": 39.4219,
50− "garch11__t__w1000_r5": 1.4875, 39+ "garch11__t__w1000_r5": 39.4059,
51− "gjr11__t__w1000_r5": 1.4175, 40+ "gjr11__t__w1000_r5": 39.02,
52− "har_rv__empirical__w1000_r5": 1.6817, 41+ "har_rv__empirical__w1000_r5": 38.4856,
53− "histvar22__empirical__w1000_r5": 1.666, 42+ "histvar22__empirical__w1000_r5": 40.9943,
54− "nagarch11__t__w1000_r5": 1.393, 43+ "nagarch11__t__w1000_r5": 38.5934,
55− "realgarch11__normal__w1000_r5": 1.4054 44+ "realgarch11__normal__w1000_r5": 37.7234
56 }, 45 },
57 { 46 {
58 "proxy": "r2", 47 "proxy": "r2",
59 "loss": "mse", 48 "loss": "mse",
60 "h": 5, 49 "h": 5,
61− "aparch11__t__w1000_r5": 14.7187, 50+ "aparch11__t__w1000_r5": 304.1405,
62− "egarch11__t__w1000_r5": 14.5492, 51+ "egarch11__t__w1000_r5": 297.2174,
63− "garch11__normal__w1000_r5": 14.4574, 52+ "garch11__normal__w1000_r5": 356.9256,
64− "garch11__t__w1000_r5": 14.7366, 53+ "garch11__t__w1000_r5": 357.0676,
65− "gjr11__t__w1000_r5": 15.2964, 54+ "gjr11__t__w1000_r5": 311.3525,
66− "har_rv__empirical__w1000_r5": 15.2534, 55+ "har_rv__empirical__w1000_r5": 336.0283,
67− "histvar22__empirical__w1000_r5": 17.842, 56+ "histvar22__empirical__w1000_r5": 401.0389,
68− "nagarch11__t__w1000_r5": 16.0023, 57+ "nagarch11__t__w1000_r5": 298.4274,
69− "realgarch11__normal__w1000_r5": 13.4433 58+ "realgarch11__normal__w1000_r5": 322.8226
70 }, 59 },
71 { 60 {
72 "proxy": "r2", 61 "proxy": "r2",
73 "loss": "mse", 62 "loss": "mse",
74 "h": 22, 63 "h": 22,
75− "aparch11__t__w1000_r5": 221.9468, 64+ "aparch11__t__w1000_r5": 2559.3676,
76− "egarch11__t__w1000_r5": 216.7508, 65+ "egarch11__t__w1000_r5": 2357.1678,
77− "garch11__normal__w1000_r5": 171.8139, 66+ "garch11__normal__w1000_r5": 4169.6531,
78− "garch11__t__w1000_r5": 187.1507, 67+ "garch11__t__w1000_r5": 4197.1704,
79− "gjr11__t__w1000_r5": 215.6164, 68+ "gjr11__t__w1000_r5": 2807.0867,
80− "har_rv__empirical__w1000_r5": 198.7276, 69+ "har_rv__empirical__w1000_r5": 3382.7094,
81− "histvar22__empirical__w1000_r5": 212.6863, 70+ "histvar22__empirical__w1000_r5": 4987.9416,
82− "nagarch11__t__w1000_r5": 322.9919, 71+ "nagarch11__t__w1000_r5": 2423.8364,
83− "realgarch11__normal__w1000_r5": 157.673 72+ "realgarch11__normal__w1000_r5": 3417.3079
84 }, 73 },
85 { 74 {
86 "proxy": "r2", 75 "proxy": "r2",
87 "loss": "qlike", 76 "loss": "qlike",
88 "h": 1, 77 "h": 1,
89− "aparch11__t__w1000_r5": 1.4285, 78+ "aparch11__t__w1000_r5": 1.2637,
90− "egarch11__t__w1000_r5": 1.4348, 79+ "egarch11__t__w1000_r5": 1.2604,
91− "garch11__normal__w1000_r5": 1.5186, 80+ "garch11__normal__w1000_r5": 1.289,
92− "garch11__t__w1000_r5": 1.5188, 81+ "garch11__t__w1000_r5": 1.2862,
93− "gjr11__t__w1000_r5": 1.451, 82+ "gjr11__t__w1000_r5": 1.2661,
94− "har_rv__empirical__w1000_r5": 1.5021, 83+ "har_rv__empirical__w1000_r5": 1.2492,
95− "histvar22__empirical__w1000_r5": 1.6783, 84+ "histvar22__empirical__w1000_r5": 1.3069,
96− "nagarch11__t__w1000_r5": 1.422, 85+ "nagarch11__t__w1000_r5": 1.2645,
97− "realgarch11__normal__w1000_r5": 1.442 86+ "realgarch11__normal__w1000_r5": 1.2601
98 }, 87 },
99 { 88 {
100 "proxy": "r2", 89 "proxy": "r2",
101 "loss": "qlike", 90 "loss": "qlike",
102 "h": 5, 91 "h": 5,
103− "aparch11__t__w1000_r5": 0.3764, 92+ "aparch11__t__w1000_r5": 0.3128,
104− "egarch11__t__w1000_r5": 0.3866, 93+ "egarch11__t__w1000_r5": 0.3073,
105− "garch11__normal__w1000_r5": 0.4295, 94+ "garch11__normal__w1000_r5": 0.3477,
106− "garch11__t__w1000_r5": 0.4321, 95+ "garch11__t__w1000_r5": 0.3446,
107− "gjr11__t__w1000_r5": 0.3912, 96+ "gjr11__t__w1000_r5": 0.316,
108− "har_rv__empirical__w1000_r5": 0.4433, 97+ "har_rv__empirical__w1000_r5": 0.318,
109− "histvar22__empirical__w1000_r5": 0.6038, 98+ "histvar22__empirical__w1000_r5": 0.3653,
110− "nagarch11__t__w1000_r5": 0.3795, 99+ "nagarch11__t__w1000_r5": 0.3137,
111− "realgarch11__normal__w1000_r5": 0.3935 100+ "realgarch11__normal__w1000_r5": 0.3221
112 }, 101 },
113 { 102 {
114 "proxy": "r2", 103 "proxy": "r2",
115 "loss": "qlike", 104 "loss": "qlike",
116 "h": 22, 105 "h": 22,
117− "aparch11__t__w1000_r5": 0.2498, 106+ "aparch11__t__w1000_r5": 0.1604,
118− "egarch11__t__w1000_r5": 0.2602, 107+ "egarch11__t__w1000_r5": 0.1505,
119− "garch11__normal__w1000_r5": 0.2522, 108+ "garch11__normal__w1000_r5": 0.2137,
120− "garch11__t__w1000_r5": 0.2595, 109+ "garch11__t__w1000_r5": 0.2093,
121− "gjr11__t__w1000_r5": 0.2387, 110+ "gjr11__t__w1000_r5": 0.1691,
122− "har_rv__empirical__w1000_r5": 0.2843, 111+ "har_rv__empirical__w1000_r5": 0.1849,
123− "histvar22__empirical__w1000_r5": 0.4681, 112+ "histvar22__empirical__w1000_r5": 0.2493,
124− "nagarch11__t__w1000_r5": 0.27, 113+ "nagarch11__t__w1000_r5": 0.1602,
125− "realgarch11__normal__w1000_r5": 0.2328 114+ "realgarch11__normal__w1000_r5": 0.2003
126 }, 115 },
127 { 116 {
128 "proxy": "rv5ss_on", 117 "proxy": "rv5ss_on",
129 "loss": "mse", 118 "loss": "mse",
130 "h": 1, 119 "h": 1,
131− "aparch11__t__w1000_r5": 2.0112, 120+ "aparch11__t__w1000_r5": 7.4038,
132− "egarch11__t__w1000_r5": 1.9421, 121+ "egarch11__t__w1000_r5": 7.4551,
133− "garch11__normal__w1000_r5": 2.1561, 122+ "garch11__normal__w1000_r5": 8.0074,
134− "garch11__t__w1000_r5": 2.1426, 123+ "garch11__t__w1000_r5": 7.9634,
135− "gjr11__t__w1000_r5": 1.8891, 124+ "gjr11__t__w1000_r5": 7.5711,
136− "har_rv__empirical__w1000_r5": 2.185, 125+ "har_rv__empirical__w1000_r5": 6.9611,
137− "histvar22__empirical__w1000_r5": 2.4172, 126+ "histvar22__empirical__w1000_r5": 10.1669,
138− "nagarch11__t__w1000_r5": 1.9804, 127+ "nagarch11__t__w1000_r5": 7.1532,
139− "realgarch11__normal__w1000_r5": 2.1525 128+ "realgarch11__normal__w1000_r5": 6.7387
140 }, 129 },
141 { 130 {
142 "proxy": "rv5ss_on", 131 "proxy": "rv5ss_on",
143 "loss": "mse", 132 "loss": "mse",
144 "h": 5, 133 "h": 5,
145− "aparch11__t__w1000_r5": 23.9033, 134+ "aparch11__t__w1000_r5": 97.0143,
146− "egarch11__t__w1000_r5": 23.6745, 135+ "egarch11__t__w1000_r5": 94.3839,
147− "garch11__normal__w1000_r5": 23.5567, 136+ "garch11__normal__w1000_r5": 134.2716,
148− "garch11__t__w1000_r5": 23.7539, 137+ "garch11__t__w1000_r5": 133.8063,
149− "gjr11__t__w1000_r5": 23.7699, 138+ "gjr11__t__w1000_r5": 104.9043,
150− "har_rv__empirical__w1000_r5": 24.9214, 139+ "har_rv__empirical__w1000_r5": 112.4285,
151− "histvar22__empirical__w1000_r5": 26.6768, 140+ "histvar22__empirical__w1000_r5": 181.9574,
152− "nagarch11__t__w1000_r5": 25.2487, 141+ "nagarch11__t__w1000_r5": 89.047,
153− "realgarch11__normal__w1000_r5": 23.388 142+ "realgarch11__normal__w1000_r5": 108.4914
154 }, 143 },
155 { 144 {
156 "proxy": "rv5ss_on", 145 "proxy": "rv5ss_on",
157 "loss": "mse", 146 "loss": "mse",
158 "h": 22, 147 "h": 22,
159− "aparch11__t__w1000_r5": 285.5918, 148+ "aparch11__t__w1000_r5": 1649.3345,
160− "egarch11__t__w1000_r5": 281.9002, 149+ "egarch11__t__w1000_r5": 1506.3924,
161− "garch11__normal__w1000_r5": 238.7663, 150+ "garch11__normal__w1000_r5": 2977.7956,
162− "garch11__t__w1000_r5": 253.0328, 151+ "garch11__t__w1000_r5": 2997.7164,
163− "gjr11__t__w1000_r5": 274.2299, 152+ "gjr11__t__w1000_r5": 1937.2537,
164− "har_rv__empirical__w1000_r5": 273.2997, 153+ "har_rv__empirical__w1000_r5": 2274.3908,
165− "histvar22__empirical__w1000_r5": 267.3486, 154+ "histvar22__empirical__w1000_r5": 3756.9648,
166− "nagarch11__t__w1000_r5": 385.4714, 155+ "nagarch11__t__w1000_r5": 1409.9449,
167− "realgarch11__normal__w1000_r5": 228.4667 156+ "realgarch11__normal__w1000_r5": 2537.4397
168 }, 157 },
169 { 158 {
170 "proxy": "rv5ss_on", 159 "proxy": "rv5ss_on",
171 "loss": "qlike", 160 "loss": "qlike",
172 "h": 1, 161 "h": 1,
173− "aparch11__t__w1000_r5": 0.276, 162+ "aparch11__t__w1000_r5": 0.1183,
174− "egarch11__t__w1000_r5": 0.2916, 163+ "egarch11__t__w1000_r5": 0.1184,
175− "garch11__normal__w1000_r5": 0.3128, 164+ "garch11__normal__w1000_r5": 0.1239,
176− "garch11__t__w1000_r5": 0.3142, 165+ "garch11__t__w1000_r5": 0.1227,
177− "gjr11__t__w1000_r5": 0.2743, 166+ "gjr11__t__w1000_r5": 0.1161,
178− "har_rv__empirical__w1000_r5": 0.3092, 167+ "har_rv__empirical__w1000_r5": 0.0902,
179− "histvar22__empirical__w1000_r5": 0.4129, 168+ "histvar22__empirical__w1000_r5": 0.1585,
180− "nagarch11__t__w1000_r5": 0.2784, 169+ "nagarch11__t__w1000_r5": 0.1205,
181− "realgarch11__normal__w1000_r5": 0.2657 170+ "realgarch11__normal__w1000_r5": 0.0937
182 }, 171 },
183 { 172 {
184 "proxy": "rv5ss_on", 173 "proxy": "rv5ss_on",
185 "loss": "qlike", 174 "loss": "qlike",
186 "h": 5, 175 "h": 5,
187− "aparch11__t__w1000_r5": 0.2339, 176+ "aparch11__t__w1000_r5": 0.0883,
188− "egarch11__t__w1000_r5": 0.246, 177+ "egarch11__t__w1000_r5": 0.0864,
189− "garch11__normal__w1000_r5": 0.2615, 178+ "garch11__normal__w1000_r5": 0.1023,
190− "garch11__t__w1000_r5": 0.2647, 179+ "garch11__t__w1000_r5": 0.1007,
191− "gjr11__t__w1000_r5": 0.2368, 180+ "gjr11__t__w1000_r5": 0.088,
192− "har_rv__empirical__w1000_r5": 0.2862, 181+ "har_rv__empirical__w1000_r5": 0.087,
193− "histvar22__empirical__w1000_r5": 0.3764, 182+ "histvar22__empirical__w1000_r5": 0.1356,
194− "nagarch11__t__w1000_r5": 0.24, 183+ "nagarch11__t__w1000_r5": 0.0896,
195− "realgarch11__normal__w1000_r5": 0.2301 184+ "realgarch11__normal__w1000_r5": 0.0823
196 }, 185 },
197 { 186 {
198 "proxy": "rv5ss_on", 187 "proxy": "rv5ss_on",
199 "loss": "qlike", 188 "loss": "qlike",
200 "h": 22, 189 "h": 22,
201− "aparch11__t__w1000_r5": 0.2557, 190+ "aparch11__t__w1000_r5": 0.1025,
202− "egarch11__t__w1000_r5": 0.2623, 191+ "egarch11__t__w1000_r5": 0.095,
203− "garch11__normal__w1000_r5": 0.2643, 192+ "garch11__normal__w1000_r5": 0.1405,
204− "garch11__t__w1000_r5": 0.2712, 193+ "garch11__t__w1000_r5": 0.1365,
205− "gjr11__t__w1000_r5": 0.2422, 194+ "gjr11__t__w1000_r5": 0.1104,
206− "har_rv__empirical__w1000_r5": 0.3086, 195+ "har_rv__empirical__w1000_r5": 0.1238,
207− "histvar22__empirical__w1000_r5": 0.3961, 196+ "histvar22__empirical__w1000_r5": 0.1673,
208− "nagarch11__t__w1000_r5": 0.2792, 197+ "nagarch11__t__w1000_r5": 0.1019,
209− "realgarch11__normal__w1000_r5": 0.24 198+ "realgarch11__normal__w1000_r5": 0.1425
210 } 199 }
211 ], 200 ],
212 "ratio_to_garch11_normal": [ 201 "ratio_to_garch11_normal": [
@@ -214,727 +203,263 @@
214 "proxy": "r2", 203 "proxy": "r2",
215 "loss": "mse", 204 "loss": "mse",
216 "h": 1, 205 "h": 1,
217− "aparch11__t__w1000_r5": 0.9411, 206+ "aparch11__t__w1000_r5": 0.9854,
218− "egarch11__t__w1000_r5": 0.9304, 207+ "egarch11__t__w1000_r5": 0.9824,
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,
303 "garch11__normal__w1000_r5": 1.0, 208 "garch11__normal__w1000_r5": 1.0,
304− "garch11__t__w1000_r5": 0.9937, 209+ "garch11__t__w1000_r5": 0.9996,
305− "gjr11__t__w1000_r5": 0.8762, 210+ "gjr11__t__w1000_r5": 0.9898,
306− "har_rv__empirical__w1000_r5": 1.0134, 211+ "har_rv__empirical__w1000_r5": 0.9762,
307− "histvar22__empirical__w1000_r5": 1.1211, 212+ "histvar22__empirical__w1000_r5": 1.0399,
308− "nagarch11__t__w1000_r5": 0.9185, 213+ "nagarch11__t__w1000_r5": 0.979,
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,
337 "realgarch11__normal__w1000_r5": 0.9569 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 "proxy": "r2", 217 "proxy": "r2",
693 "loss": "mse", 218 "loss": "mse",
694 "h": 5, 219 "h": 5,
695− "aparch11__t__w1000_r5": 0.8951, 220+ "aparch11__t__w1000_r5": 0.8521,
696− "egarch11__t__w1000_r5": 0.9575, 221+ "egarch11__t__w1000_r5": 0.8327,
697 "garch11__normal__w1000_r5": 1.0, 222 "garch11__normal__w1000_r5": 1.0,
698− "garch11__t__w1000_r5": 0.9817, 223+ "garch11__t__w1000_r5": 1.0004,
699− "gjr11__t__w1000_r5": 1.1569, 224+ "gjr11__t__w1000_r5": 0.8723,
700− "har_rv__empirical__w1000_r5": 1.0379, 225+ "har_rv__empirical__w1000_r5": 0.9415,
701− "histvar22__empirical__w1000_r5": 1.0965, 226+ "histvar22__empirical__w1000_r5": 1.1236,
702− "nagarch11__t__w1000_r5": 0.9964, 227+ "nagarch11__t__w1000_r5": 0.8361,
703− "realgarch11__normal__w1000_r5": 0.9353 228+ "realgarch11__normal__w1000_r5": 0.9045
704 }, 229 },
705 { 230 {
706 "proxy": "r2", 231 "proxy": "r2",
707 "loss": "mse", 232 "loss": "mse",
708 "h": 22, 233 "h": 22,
709− "aparch11__t__w1000_r5": 0.7471, 234+ "aparch11__t__w1000_r5": 0.6138,
710− "egarch11__t__w1000_r5": 0.7964, 235+ "egarch11__t__w1000_r5": 0.5653,
711 "garch11__normal__w1000_r5": 1.0, 236 "garch11__normal__w1000_r5": 1.0,
712− "garch11__t__w1000_r5": 0.9667, 237+ "garch11__t__w1000_r5": 1.0066,
713− "gjr11__t__w1000_r5": 1.0803, 238+ "gjr11__t__w1000_r5": 0.6732,
714− "har_rv__empirical__w1000_r5": 1.0397, 239+ "har_rv__empirical__w1000_r5": 0.8113,
715− "histvar22__empirical__w1000_r5": 1.4306, 240+ "histvar22__empirical__w1000_r5": 1.1962,
716− "nagarch11__t__w1000_r5": 0.8822, 241+ "nagarch11__t__w1000_r5": 0.5813,
717− "realgarch11__normal__w1000_r5": 0.8609 242+ "realgarch11__normal__w1000_r5": 0.8196
718 }, 243 },
719 { 244 {
720 "proxy": "r2", 245 "proxy": "r2",
721 "loss": "qlike", 246 "loss": "qlike",
722 "h": 1, 247 "h": 1,
723− "aparch11__t__w1000_r5": 0.9763, 248+ "aparch11__t__w1000_r5": 0.9804,
724− "egarch11__t__w1000_r5": 0.9794, 249+ "egarch11__t__w1000_r5": 0.9778,
725 "garch11__normal__w1000_r5": 1.0, 250 "garch11__normal__w1000_r5": 1.0,
726− "garch11__t__w1000_r5": 1.0004, 251+ "garch11__t__w1000_r5": 0.9979,
727− "gjr11__t__w1000_r5": 0.9803, 252+ "gjr11__t__w1000_r5": 0.9823,
728− "har_rv__empirical__w1000_r5": 1.0114, 253+ "har_rv__empirical__w1000_r5": 0.9691,
729− "histvar22__empirical__w1000_r5": 1.0869, 254+ "histvar22__empirical__w1000_r5": 1.0139,
730− "nagarch11__t__w1000_r5": 0.9824, 255+ "nagarch11__t__w1000_r5": 0.981,
731− "realgarch11__normal__w1000_r5": 1.0119 256+ "realgarch11__normal__w1000_r5": 0.9776
732 }, 257 },
733 { 258 {
734 "proxy": "r2", 259 "proxy": "r2",
735 "loss": "qlike", 260 "loss": "qlike",
736 "h": 5, 261 "h": 5,
737− "aparch11__t__w1000_r5": 0.9414, 262+ "aparch11__t__w1000_r5": 0.8997,
738− "egarch11__t__w1000_r5": 0.9532, 263+ "egarch11__t__w1000_r5": 0.8838,
739 "garch11__normal__w1000_r5": 1.0, 264 "garch11__normal__w1000_r5": 1.0,
740− "garch11__t__w1000_r5": 0.9968, 265+ "garch11__t__w1000_r5": 0.9912,
741− "gjr11__t__w1000_r5": 0.962, 266+ "gjr11__t__w1000_r5": 0.9089,
742− "har_rv__empirical__w1000_r5": 1.0293, 267+ "har_rv__empirical__w1000_r5": 0.9147,
743− "histvar22__empirical__w1000_r5": 1.2737, 268+ "histvar22__empirical__w1000_r5": 1.0507,
744− "nagarch11__t__w1000_r5": 0.9583, 269+ "nagarch11__t__w1000_r5": 0.9022,
745− "realgarch11__normal__w1000_r5": 1.0412 270+ "realgarch11__normal__w1000_r5": 0.9265
746 }, 271 },
747 { 272 {
748 "proxy": "r2", 273 "proxy": "r2",
749 "loss": "qlike", 274 "loss": "qlike",
750 "h": 22, 275 "h": 22,
751− "aparch11__t__w1000_r5": 0.855, 276+ "aparch11__t__w1000_r5": 0.7507,
752− "egarch11__t__w1000_r5": 0.8838, 277+ "egarch11__t__w1000_r5": 0.7042,
753 "garch11__normal__w1000_r5": 1.0, 278 "garch11__normal__w1000_r5": 1.0,
754− "garch11__t__w1000_r5": 0.9979, 279+ "garch11__t__w1000_r5": 0.9795,
755− "gjr11__t__w1000_r5": 0.9394, 280+ "gjr11__t__w1000_r5": 0.7913,
756− "har_rv__empirical__w1000_r5": 1.0289, 281+ "har_rv__empirical__w1000_r5": 0.8653,
757− "histvar22__empirical__w1000_r5": 1.9325, 282+ "histvar22__empirical__w1000_r5": 1.1667,
758− "nagarch11__t__w1000_r5": 0.8973, 283+ "nagarch11__t__w1000_r5": 0.7496,
759− "realgarch11__normal__w1000_r5": 0.9807 284+ "realgarch11__normal__w1000_r5": 0.9371
760 }, 285 },
761 { 286 {
762 "proxy": "rv5ss_on", 287 "proxy": "rv5ss_on",
763 "loss": "mse", 288 "loss": "mse",
764 "h": 1, 289 "h": 1,
765− "aparch11__t__w1000_r5": 0.9782, 290+ "aparch11__t__w1000_r5": 0.9246,
766− "egarch11__t__w1000_r5": 0.9953, 291+ "egarch11__t__w1000_r5": 0.931,
767 "garch11__normal__w1000_r5": 1.0, 292 "garch11__normal__w1000_r5": 1.0,
768− "garch11__t__w1000_r5": 1.0062, 293+ "garch11__t__w1000_r5": 0.9945,
769− "gjr11__t__w1000_r5": 1.0196, 294+ "gjr11__t__w1000_r5": 0.9455,
770− "har_rv__empirical__w1000_r5": 1.0162, 295+ "har_rv__empirical__w1000_r5": 0.8693,
771− "histvar22__empirical__w1000_r5": 1.0279, 296+ "histvar22__empirical__w1000_r5": 1.2697,
772− "nagarch11__t__w1000_r5": 0.9974, 297+ "nagarch11__t__w1000_r5": 0.8933,
773− "realgarch11__normal__w1000_r5": 0.982 298+ "realgarch11__normal__w1000_r5": 0.8416
774 }, 299 },
775 { 300 {
776 "proxy": "rv5ss_on", 301 "proxy": "rv5ss_on",
777 "loss": "mse", 302 "loss": "mse",
778 "h": 5, 303 "h": 5,
779− "aparch11__t__w1000_r5": 0.9421, 304+ "aparch11__t__w1000_r5": 0.7225,
780− "egarch11__t__w1000_r5": 0.9747, 305+ "egarch11__t__w1000_r5": 0.7029,
781 "garch11__normal__w1000_r5": 1.0, 306 "garch11__normal__w1000_r5": 1.0,
782− "garch11__t__w1000_r5": 1.0028, 307+ "garch11__t__w1000_r5": 0.9965,
783− "gjr11__t__w1000_r5": 1.0826, 308+ "gjr11__t__w1000_r5": 0.7813,
784− "har_rv__empirical__w1000_r5": 1.0561, 309+ "har_rv__empirical__w1000_r5": 0.8373,
785− "histvar22__empirical__w1000_r5": 1.0788, 310+ "histvar22__empirical__w1000_r5": 1.3551,
786− "nagarch11__t__w1000_r5": 1.0043, 311+ "nagarch11__t__w1000_r5": 0.6632,
787− "realgarch11__normal__w1000_r5": 0.9787 312+ "realgarch11__normal__w1000_r5": 0.808
788 }, 313 },
789 { 314 {
790 "proxy": "rv5ss_on", 315 "proxy": "rv5ss_on",
791 "loss": "mse", 316 "loss": "mse",
792 "h": 22, 317 "h": 22,
793− "aparch11__t__w1000_r5": 0.8396, 318+ "aparch11__t__w1000_r5": 0.5539,
794− "egarch11__t__w1000_r5": 0.873, 319+ "egarch11__t__w1000_r5": 0.5059,
795 "garch11__normal__w1000_r5": 1.0, 320 "garch11__normal__w1000_r5": 1.0,
796− "garch11__t__w1000_r5": 1.0054, 321+ "garch11__t__w1000_r5": 1.0067,
797− "gjr11__t__w1000_r5": 1.0634, 322+ "gjr11__t__w1000_r5": 0.6506,
798− "har_rv__empirical__w1000_r5": 1.0465, 323+ "har_rv__empirical__w1000_r5": 0.7638,
799− "histvar22__empirical__w1000_r5": 1.3197, 324+ "histvar22__empirical__w1000_r5": 1.2617,
800− "nagarch11__t__w1000_r5": 0.9425, 325+ "nagarch11__t__w1000_r5": 0.4735,
801− "realgarch11__normal__w1000_r5": 0.9159 326+ "realgarch11__normal__w1000_r5": 0.8521
802 }, 327 },
803 { 328 {
804 "proxy": "rv5ss_on", 329 "proxy": "rv5ss_on",
805 "loss": "qlike", 330 "loss": "qlike",
806 "h": 1, 331 "h": 1,
807− "aparch11__t__w1000_r5": 0.9365, 332+ "aparch11__t__w1000_r5": 0.9549,
808− "egarch11__t__w1000_r5": 0.9393, 333+ "egarch11__t__w1000_r5": 0.9557,
809 "garch11__normal__w1000_r5": 1.0, 334 "garch11__normal__w1000_r5": 1.0,
810− "garch11__t__w1000_r5": 1.0391, 335+ "garch11__t__w1000_r5": 0.9907,
811− "gjr11__t__w1000_r5": 0.9215, 336+ "gjr11__t__w1000_r5": 0.9375,
812− "har_rv__empirical__w1000_r5": 1.1031, 337+ "har_rv__empirical__w1000_r5": 0.728,
813− "histvar22__empirical__w1000_r5": 1.2862, 338+ "histvar22__empirical__w1000_r5": 1.2798,
814− "nagarch11__t__w1000_r5": 0.9689, 339+ "nagarch11__t__w1000_r5": 0.9728,
815− "realgarch11__normal__w1000_r5": 0.9994 340+ "realgarch11__normal__w1000_r5": 0.7564
816 }, 341 },
817 { 342 {
818 "proxy": "rv5ss_on", 343 "proxy": "rv5ss_on",
819 "loss": "qlike", 344 "loss": "qlike",
820 "h": 5, 345 "h": 5,
821− "aparch11__t__w1000_r5": 0.9695, 346+ "aparch11__t__w1000_r5": 0.8635,
822− "egarch11__t__w1000_r5": 0.9735, 347+ "egarch11__t__w1000_r5": 0.8445,
823 "garch11__normal__w1000_r5": 1.0, 348 "garch11__normal__w1000_r5": 1.0,
824− "garch11__t__w1000_r5": 1.0296, 349+ "garch11__t__w1000_r5": 0.9851,
825− "gjr11__t__w1000_r5": 0.951, 350+ "gjr11__t__w1000_r5": 0.861,
826− "har_rv__empirical__w1000_r5": 1.1082, 351+ "har_rv__empirical__w1000_r5": 0.8506,
827− "histvar22__empirical__w1000_r5": 1.3756, 352+ "histvar22__empirical__w1000_r5": 1.3261,
828− "nagarch11__t__w1000_r5": 0.9962, 353+ "nagarch11__t__w1000_r5": 0.8762,
829− "realgarch11__normal__w1000_r5": 1.077 354+ "realgarch11__normal__w1000_r5": 0.8048
830 }, 355 },
831 { 356 {
832 "proxy": "rv5ss_on", 357 "proxy": "rv5ss_on",
833 "loss": "qlike", 358 "loss": "qlike",
834 "h": 22, 359 "h": 22,
835− "aparch11__t__w1000_r5": 0.9009, 360+ "aparch11__t__w1000_r5": 0.7296,
836− "egarch11__t__w1000_r5": 0.9248, 361+ "egarch11__t__w1000_r5": 0.676,
837 "garch11__normal__w1000_r5": 1.0, 362 "garch11__normal__w1000_r5": 1.0,
838− "garch11__t__w1000_r5": 1.048, 363+ "garch11__t__w1000_r5": 0.9712,
839− "gjr11__t__w1000_r5": 0.9483, 364+ "gjr11__t__w1000_r5": 0.7854,
840− "har_rv__empirical__w1000_r5": 1.0482, 365+ "har_rv__empirical__w1000_r5": 0.8813,
841− "histvar22__empirical__w1000_r5": 1.9505, 366+ "histvar22__empirical__w1000_r5": 1.1903,
842− "nagarch11__t__w1000_r5": 0.9338, 367+ "nagarch11__t__w1000_r5": 0.7253,
843− "realgarch11__normal__w1000_r5": 1.0166 368+ "realgarch11__normal__w1000_r5": 1.0137
844 } 369 }
845 ], 370 ],
846 "dm_vs_garch11_normal_h1_qlike": { 371 "dm_vs_garch11_normal_h1_qlike": {
847 "aparch11__t__w1000_r5": { 372 "aparch11__t__w1000_r5": {
848− "stat": -1.9963, 373+ "stat": -0.8398,
849− "p": 0.0462, 374+ "p": 0.4012,
850− "mean_diff": -0.0353, 375+ "mean_diff": -0.0056,
851− "n": 1005, 376+ "n": 1031,
852 "bandwidth": 6 377 "bandwidth": 6
853 }, 378 },
854 "egarch11__t__w1000_r5": { 379 "egarch11__t__w1000_r5": {
855− "stat": -2.0076, 380+ "stat": -0.7801,
856− "p": 0.045, 381+ "p": 0.4355,
857− "mean_diff": -0.0338, 382+ "mean_diff": -0.0055,
858− "n": 1005, 383+ "n": 1031,
859 "bandwidth": 6 384 "bandwidth": 6
860 }, 385 },
861 "garch11__t__w1000_r5": { 386 "garch11__t__w1000_r5": {
862− "stat": 1.5272, 387+ "stat": -1.1594,
863− "p": 0.127, 388+ "p": 0.2466,
864− "mean_diff": 0.0217, 389+ "mean_diff": -0.0012,
865− "n": 1005, 390+ "n": 1031,
866 "bandwidth": 6 391 "bandwidth": 6
867 }, 392 },
868 "gjr11__t__w1000_r5": { 393 "gjr11__t__w1000_r5": {
869− "stat": -2.2136, 394+ "stat": -1.4247,
870− "p": 0.0271, 395+ "p": 0.1545,
871− "mean_diff": -0.0437, 396+ "mean_diff": -0.0077,
872− "n": 1005, 397+ "n": 1031,
873 "bandwidth": 6 398 "bandwidth": 6
874 }, 399 },
875 "har_rv__empirical__w1000_r5": { 400 "har_rv__empirical__w1000_r5": {
876− "stat": 1.8475, 401+ "stat": -6.3176,
877− "p": 0.065, 402+ "p": 0.0,
878− "mean_diff": 0.0573, 403+ "mean_diff": -0.0337,
879− "n": 1005, 404+ "n": 1031,
880 "bandwidth": 6 405 "bandwidth": 6
881 }, 406 },
882 "histvar22__empirical__w1000_r5": { 407 "histvar22__empirical__w1000_r5": {
883− "stat": 2.5917, 408+ "stat": 2.8833,
884− "p": 0.0097, 409+ "p": 0.004,
885− "mean_diff": 0.1592, 410+ "mean_diff": 0.0347,
886− "n": 1005, 411+ "n": 1031,
887 "bandwidth": 6 412 "bandwidth": 6
888 }, 413 },
889 "nagarch11__t__w1000_r5": { 414 "nagarch11__t__w1000_r5": {
890− "stat": -0.8589, 415+ "stat": -0.525,
891− "p": 0.3906, 416+ "p": 0.5997,
892− "mean_diff": -0.0173, 417+ "mean_diff": -0.0034,
893− "n": 1005, 418+ "n": 1031,
894 "bandwidth": 6 419 "bandwidth": 6
895 }, 420 },
896 "realgarch11__normal__w1000_r5": { 421 "realgarch11__normal__w1000_r5": {
897− "stat": -0.0117, 422+ "stat": -5.6857,
898− "p": 0.9907, 423+ "p": 0.0,
899− "mean_diff": -0.0003, 424+ "mean_diff": -0.0302,
900− "n": 1005, 425+ "n": 1031,
901 "bandwidth": 6 426 "bandwidth": 6
902 } 427 }
903 }, 428 },
904 "leakage_check_passed": true, 429 "leakage_check_passed": true,
905 "timing": { 430 "timing": {
906 "mean": { 431 "mean": {
907− "aparch11__t__w1000_r5": 0.0353, 432+ "aparch11__t__w1000_r5": 0.0326,
908− "egarch11__t__w1000_r5": 0.0065, 433+ "egarch11__t__w1000_r5": 0.0088,
909− "garch11__normal__w1000_r5": 0.0042, 434+ "garch11__normal__w1000_r5": 0.0044,
910− "garch11__t__w1000_r5": 0.0073, 435+ "garch11__t__w1000_r5": 0.0066,
911− "gjr11__t__w1000_r5": 0.0065, 436+ "gjr11__t__w1000_r5": 0.0082,
912 "har_rv__empirical__w1000_r5": 0.0008, 437 "har_rv__empirical__w1000_r5": 0.0008,
913 "histvar22__empirical__w1000_r5": 0.0, 438 "histvar22__empirical__w1000_r5": 0.0,
914− "nagarch11__t__w1000_r5": 0.0081, 439+ "nagarch11__t__w1000_r5": 0.0096,
915− "realgarch11__normal__w1000_r5": 0.0233 440+ "realgarch11__normal__w1000_r5": 0.0276
916 }, 441 },
917 "median": { 442 "median": {
918− "aparch11__t__w1000_r5": 0.0313, 443+ "aparch11__t__w1000_r5": 0.0324,
919− "egarch11__t__w1000_r5": 0.0065, 444+ "egarch11__t__w1000_r5": 0.0089,
920− "garch11__normal__w1000_r5": 0.0042, 445+ "garch11__normal__w1000_r5": 0.0043,
921− "garch11__t__w1000_r5": 0.0068, 446+ "garch11__t__w1000_r5": 0.0064,
922− "gjr11__t__w1000_r5": 0.0063, 447+ "gjr11__t__w1000_r5": 0.0082,
923 "har_rv__empirical__w1000_r5": 0.0008, 448 "har_rv__empirical__w1000_r5": 0.0008,
924 "histvar22__empirical__w1000_r5": 0.0, 449 "histvar22__empirical__w1000_r5": 0.0,
925− "nagarch11__t__w1000_r5": 0.008, 450+ "nagarch11__t__w1000_r5": 0.0091,
926− "realgarch11__normal__w1000_r5": 0.0233 451+ "realgarch11__normal__w1000_r5": 0.0267
927 }, 452 },
928 "max": { 453 "max": {
929− "aparch11__t__w1000_r5": 0.105, 454+ "aparch11__t__w1000_r5": 0.0465,
930− "egarch11__t__w1000_r5": 0.0094, 455+ "egarch11__t__w1000_r5": 0.0173,
931− "garch11__normal__w1000_r5": 0.0053, 456+ "garch11__normal__w1000_r5": 0.0063,
932− "garch11__t__w1000_r5": 0.0123, 457+ "garch11__t__w1000_r5": 0.0095,
933− "gjr11__t__w1000_r5": 0.0093, 458+ "gjr11__t__w1000_r5": 0.0127,
934 "har_rv__empirical__w1000_r5": 0.0011, 459 "har_rv__empirical__w1000_r5": 0.0011,
935 "histvar22__empirical__w1000_r5": 0.0, 460 "histvar22__empirical__w1000_r5": 0.0,
936− "nagarch11__t__w1000_r5": 0.0104, 461+ "nagarch11__t__w1000_r5": 0.1042,
937− "realgarch11__normal__w1000_r5": 0.0296 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 tab = Lc.groupby(["proxy", "loss", "h", "spec_id"])["value"].mean().unstack("spec_id") 50 tab = Lc.groupby(["proxy", "loss", "h", "spec_id"])["value"].mean().unstack("spec_id")
51 bench = [s for s in specs if s.startswith("garch11__normal")][0] 51 bench = [s for s in specs if s.startswith("garch11__normal")][0]
52 ratio = tab.div(tab[bench], axis=0) 52 ratio = tab.div(tab[bench], axis=0)
53− # leakage check: perturb returns after the last origin -> forecasts at the last origin unchanged 53+ # leakage check: perturb returns AND realized measures after the last origin -> every forecast of the whole
54− p2 = panel.copy(); last = F["origin"].max(); m = p2["session"] > last; p2.loc[m, "r"] *= 3.0 54+ # job (same refit schedule) is unchanged
55− F2, _ = run_job(p2, JobSpec(sym, "gjr11", "t", "A", oos_start=str(last.date()), oos_end=str(last.date()))) 55+ p2 = panel.copy(); last = F["origin"].max(); m = p2["session"] > last
56− f1 = F[(F.spec_id.str.startswith("gjr11__t")) & (F.origin == last)]["h1"].values 56+ p2.loc[m, "r"] *= 3.0; p2.loc[m, "rv_5m_ss"] *= 9.0
57− leak_ok = bool(np.allclose(f1, F2["h1"].values)) 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 dm = {s: dm_test(Lc[(Lc.spec_id == s) & (Lc.h == 1) & (Lc.proxy == "rv5ss_on") & (Lc.loss == "qlike")].sort_values("origin")["value"].values, 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 Lc[(Lc.spec_id == bench) & (Lc.h == 1) & (Lc.proxy == "rv5ss_on") & (Lc.loss == "qlike")].sort_values("origin")["value"].values, 1) 63 Lc[(Lc.spec_id == bench) & (Lc.h == 1) & (Lc.proxy == "rv5ss_on") & (Lc.loss == "qlike")].sort_values("origin")["value"].values, 1)
60 for s in specs if s != bench} 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 raise KeyError(model_id) 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 def run_job(panel: pd.DataFrame, job: JobSpec, progress: bool = False) -> tuple[pd.DataFrame, pd.DataFrame]: 88 def run_job(panel: pd.DataFrame, job: JobSpec, progress: bool = False) -> tuple[pd.DataFrame, pd.DataFrame]:
70 model = make_model(job.model_id) 89 model = make_model(job.model_id)
71 needs_rm = bool(getattr(model, "needs_rm", False)) 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 except Exception as e: # noqa: BLE001 123 except Exception as e: # noqa: BLE001
105 new_fit, err = None, f"{type(e).__name__}: {str(e)[:120]}" 124 new_fit, err = None, f"{type(e).__name__}: {str(e)[:120]}"
106 dt = time.perf_counter() - t0 125 dt = time.perf_counter() - t0
126+ emp = {}
107 if new_fit is not None and new_fit.converged: 127 if new_fit is not None and new_fit.converged:
108 fit, stale = new_fit, False 128 fit, stale = new_fit, False
109 status = "ok" if new_fit.admissible else "inadmissible" 129 status = "ok" if new_fit.admissible else "inadmissible"
130+ emp = _empirical_tail(model, new_fit, r, x)
110 else: 131 else:
111 status = "failed" 132 status = "failed"
112 stale = fit is not None 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 loglik=new_fit.loglik if new_fit else np.nan, n_iter=new_fit.n_iter if new_fit else 0, 135 loglik=new_fit.loglik if new_fit else np.nan, n_iter=new_fit.n_iter if new_fit else 0,
115 n_restarts=new_fit.n_restarts if new_fit else 0, time_s=dt, n_obs=len(r), 136 n_restarts=new_fit.n_restarts if new_fit else 0, time_s=dt, n_obs=len(r),
116 admissible=bool(new_fit.admissible) if new_fit else False, 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