WP46: registry/protocol configs, tests, runners, panel validity rules D-05/D-06
23 changed files +4,518 −2
added
configs/forecast_protocol.yaml
+31 −0
@@ -0,0 +1,31 @@ | |||||
| 1 | +# Pre-registered forecasting protocol (frozen with docs/preregistered_protocol.md; git tag prereg-frozen). | ||||
| 2 | +units: {returns: "percent log return", variance: "percent^2"} | ||||
| 3 | +horizons: [1, 5, 22] # trading days; target = variance of the h-day cumulative return | ||||
| 4 | +estimation: | ||||
| 5 | + scheme: rolling # primary; 'expanding' and window 2000 are robustness variants | ||||
| 6 | + window: 1000 | ||||
| 7 | + refit_every: 5 # trading days; daily filtering with fixed parameters in between | ||||
| 8 | + max_restarts: 3 | ||||
| 9 | + seed: 46 | ||||
| 10 | + simulation_paths: 2000 # multi-step forecasts for models without an analytic recursion | ||||
| 11 | +periods: | ||||
| 12 | + validation: {start: "2012-01-03", end: "2015-12-31"} # used for design checks and failure accounting only | ||||
| 13 | + test: {start: "2016-01-04", end: "2026-10-30"} # untouched until the protocol is frozen | ||||
| 14 | +primary_loss: qlike | ||||
| 15 | +primary_proxy: rv5ss_on | ||||
| 16 | +secondary_losses: [mse, mae, mse_sd] | ||||
| 17 | +secondary_proxies: [rv5_on, rv1_on, bv5_on, medrv_on, r2, rv5ss_scaled] | ||||
| 18 | +tier_b_input: rv5ss_on | ||||
| 19 | +inference: | ||||
| 20 | + dm: {hac: "Newey-West Bartlett", bandwidth: "h - 1 + floor(4 (n/100)^(2/9))"} | ||||
| 21 | + mcs: {alpha: 0.10, bootstrap: stationary, block_length: 22, reps: 2000, statistic: "Tmax"} | ||||
| 22 | + spa: {reps: 2000, block_length: 22} | ||||
| 23 | + cross_asset: "block bootstrap over time with assets kept together (dependence across assets preserved)" | ||||
| 24 | +tail_risk: {levels: [0.01, 0.05], tests: [kupiec_uc, christoffersen_cc, engle_manganelli_dq, fz0_loss]} | ||||
| 25 | +regimes: | ||||
| 26 | + trailing_vol_terciles: "terciles of the 22-day trailing realized variance of the instrument, computed at the origin (no look-ahead), thresholds from the validation period" | ||||
| 27 | + calendar_episodes: | ||||
| 28 | + covid: {start: "2020-02-20", end: "2020-06-30"} | ||||
| 29 | + rate_shock_2022: {start: "2022-01-03", end: "2022-12-30"} | ||||
| 30 | + tariff_shock_2025: {start: "2025-04-02", end: "2025-05-30"} | ||||
| 31 | + return_sign: "sign of the previous day's return at the origin" | ||||
added
configs/model_registry.yaml
+55 −0
@@ -0,0 +1,55 @@ | |||||
| 1 | +# WP46 model registry — the BINDING list of architectures and specifications (C1). One entry per architecture; | ||||
| 2 | +# specifications = architecture x innovation distribution x order (orders other than (1,1) only where listed). | ||||
| 3 | +# status: implemented | unsupported (no vetted implementation in the version-locked libraries; not scored) | extension. | ||||
| 4 | +# impl: arch (Sheppard, arch 8.0.0) | custom (src/wp46/models/custom.py, validated vs arch/rugarch) | ols | none. | ||||
| 5 | +# dists: innovation laws that are formally valid for the architecture AND available in the implementation. | ||||
| 6 | +# tier: A = daily returns only; B = daily returns + lagged realized measure; C = multivariate (configs/study.yaml). | ||||
| 7 | +version: 1 | ||||
| 8 | +frozen_with_protocol: true | ||||
| 9 | +families: | ||||
| 10 | + baseline: {label: "Baselines", color_key: 0} | ||||
| 11 | + classical: {label: "Classical ARCH/GARCH", color_key: 1} | ||||
| 12 | + asymmetric: {label: "Asymmetric", color_key: 2} | ||||
| 13 | + power: {label: "Power / absolute", color_key: 3} | ||||
| 14 | + fractional: {label: "Fractional persistence", color_key: 4} | ||||
| 15 | + component: {label: "Component", color_key: 5} | ||||
| 16 | + regime-switching: {label: "Regime switching", color_key: 6} | ||||
| 17 | + score-driven: {label: "Score-driven (non-GARCH)", color_key: 7} | ||||
| 18 | + realized: {label: "Realized-measure models (Tier B)", color_key: 8} | ||||
| 19 | +models: | ||||
| 20 | + constvar: {family: baseline, tier: A, impl: arch, status: implemented, dists: [normal], label: "Constant variance (window mean)", ref: null, nested_in: garch11} | ||||
| 21 | + histvar22: {family: baseline, tier: A, impl: ols, status: implemented, dists: [empirical], label: "Historical variance, 22 days", ref: null} | ||||
| 22 | + histvar66: {family: baseline, tier: A, impl: ols, status: implemented, dists: [empirical], label: "Historical variance, 66 days", ref: null} | ||||
| 23 | + histvar252: {family: baseline, tier: A, impl: ols, status: implemented, dists: [empirical], label: "Historical variance, 252 days", ref: null} | ||||
| 24 | + ewma094: {family: baseline, tier: A, impl: arch, status: implemented, dists: [normal], label: "EWMA (RiskMetrics 1994, lambda = 0.94)", ref: jpmorgan1996riskmetrics, nested_in: igarch11} | ||||
| 25 | + rm2006: {family: baseline, tier: A, impl: arch, status: implemented, dists: [normal], label: "RiskMetrics 2006", ref: zumbach2007riskmetrics} | ||||
| 26 | + arch5: {family: classical, tier: A, impl: arch, status: implemented, dists: [normal, t, ged, skewt], label: "ARCH(5)", ref: engle1982autoregressive} | ||||
| 27 | + garch11: {family: classical, tier: A, impl: arch, status: implemented, dists: [normal, t, ged, skewt], label: "GARCH(1,1)", ref: bollerslev1986generalized, benchmark: true} | ||||
| 28 | + garch21: {family: classical, tier: A, impl: arch, status: implemented, dists: [normal, t, ged, skewt], label: "GARCH(2,1)", ref: bollerslev1986generalized} | ||||
| 29 | + garch12: {family: classical, tier: A, impl: arch, status: implemented, dists: [normal, t, ged, skewt], label: "GARCH(1,2)", ref: bollerslev1986generalized} | ||||
| 30 | + igarch11: {family: classical, tier: A, impl: custom, status: implemented, dists: [normal, t, ged, skewt], label: "IGARCH(1,1)", ref: engle1986modelling} | ||||
| 31 | + garchm11: {family: classical, tier: A, impl: custom, status: implemented, dists: [normal, t, ged, skewt], label: "GARCH-M(1,1)", ref: engle1987estimating} | ||||
| 32 | + gjr11: {family: asymmetric, tier: A, impl: arch, status: implemented, dists: [normal, t, ged, skewt], label: "GJR-GARCH(1,1)", ref: glosten1993relation} | ||||
| 33 | + tarch11: {family: asymmetric, tier: A, impl: arch, status: implemented, dists: [normal, t, ged, skewt], label: "TGARCH(1,1) (Zakoian, threshold on sigma)", ref: zakoian1994threshold} | ||||
| 34 | + egarch11: {family: asymmetric, tier: A, impl: arch, status: implemented, dists: [normal, t, ged, skewt], label: "EGARCH(1,1)", ref: nelson1991conditional} | ||||
| 35 | + nagarch11: {family: asymmetric, tier: A, impl: custom, status: implemented, dists: [normal, t, ged, skewt], label: "NAGARCH(1,1) (Engle-Ng)", ref: engle1993measuring} | ||||
| 36 | + qgarch11: {family: asymmetric, tier: A, impl: custom, status: implemented, dists: [normal, t, ged, skewt], label: "QGARCH(1,1) (Sentana)", ref: sentana1995quadratic} | ||||
| 37 | + avgarch11: {family: power, tier: A, impl: arch, status: implemented, dists: [normal, t, ged, skewt], label: "AVGARCH(1,1) (Taylor-Schwert)", ref: taylor2008modelling} | ||||
| 38 | + aparch11: {family: power, tier: A, impl: arch, status: implemented, dists: [normal, t, ged, skewt], label: "APARCH(1,1)", ref: ding1993long} | ||||
| 39 | + figarch11: {family: fractional, tier: A, impl: arch, status: implemented, dists: [normal, t, ged, skewt], label: "FIGARCH(1,d,1)", ref: baillie1996fractionally, note: "arch truncates the ARCH(inf) representation at 1000 lags"} | ||||
| 40 | + fiegarch11: {family: fractional, tier: A, impl: none, status: unsupported, dists: [], label: "FIEGARCH", ref: bollerslev1996modeling, note: "no vetted implementation in arch 8.0.0 / rugarch 1.5-6; not scored"} | ||||
| 41 | + fiaparch11: {family: fractional, tier: A, impl: none, status: unsupported, dists: [], label: "FIAPARCH", ref: tse1998conditional, note: "no vetted implementation; not scored"} | ||||
| 42 | + hygarch11: {family: fractional, tier: A, impl: none, status: unsupported, dists: [], label: "HYGARCH", ref: davidson2004moment, note: "no vetted implementation; not scored"} | ||||
| 43 | + cgarch11: {family: component, tier: A, impl: custom, status: implemented, dists: [normal, t, ged, skewt], label: "Component GARCH (Engle-Lee)", ref: engle1999long} | ||||
| 44 | + msgarch2: {family: regime-switching, tier: A, impl: custom, status: implemented, dists: [normal, t], label: "MS-GARCH(2) (Haas-Mittnik-Paolella)", ref: haas2004new, note: "common nu across regimes; regimes ordered by unconditional variance"} | ||||
| 45 | + stgarch: {family: regime-switching, tier: A, impl: none, status: unsupported, dists: [], label: "Smooth-transition GARCH", ref: gonzalez1998smooth, note: "not implemented (no vetted library; deferred)"} | ||||
| 46 | + garch_midas: {family: component, tier: A, impl: none, status: unsupported, dists: [], label: "GARCH-MIDAS", ref: engle2013stock, note: "requires a low-frequency explanatory series outside the pre-registered information set; not scored"} | ||||
| 47 | + gas_t11: {family: score-driven, tier: A, impl: custom, status: implemented, dists: [t], label: "GAS-t(1,1) / Beta-t-GARCH (non-GARCH comparator)", ref: creal2013generalized} | ||||
| 48 | + sv: {family: score-driven, tier: A, impl: none, status: unsupported, dists: [], label: "Stochastic volatility", ref: kim1998stochastic, note: "simulation-based estimation not feasible at the rolling re-estimation cadence of this benchmark; not scored"} | ||||
| 49 | + rm_rw: {family: realized, tier: B, impl: ols, status: implemented, dists: [empirical], label: "Realized-measure random walk", ref: null} | ||||
| 50 | + har_rv: {family: realized, tier: B, impl: ols, status: implemented, dists: [empirical], label: "HAR-RV (direct, levels)", ref: corsi2009simple} | ||||
| 51 | + loghar_rv: {family: realized, tier: B, impl: ols, status: implemented, dists: [empirical], label: "log-HAR-RV (direct, smearing)", ref: corsi2009simple} | ||||
| 52 | + realgarch11: {family: realized, tier: B, impl: custom, status: implemented, dists: [normal, t], label: "Realized GARCH(1,1), log-linear", ref: hansen2012realized} | ||||
| 53 | + heavy11: {family: realized, tier: B, impl: custom, status: implemented, dists: [normal, t], label: "HEAVY(1,1)", ref: shephard2010realising} | ||||
| 54 | + garchx_rv11: {family: realized, tier: B, impl: custom, status: implemented, dists: [normal, t], label: "GARCH-X(1,1) with lagged realized measure", ref: engle2002new} | ||||
| 55 | + realegarch11: {family: realized, tier: B, impl: none, status: unsupported, dists: [], label: "Realized EGARCH", ref: hansen2016realized, note: "not implemented in this version (deferred)"} | ||||
added
configs/study.yaml
+11 −0
@@ -0,0 +1,11 @@ | |||||
| 1 | +# Study-level settings (frozen with the protocol). | ||||
| 2 | +title: "Four Decades of Conditional Volatility Modeling: A Comprehensive Empirical Benchmark Across Assets, Frequencies, and Market Regimes" | ||||
| 3 | +wp_number: 46 | ||||
| 4 | +data_source: {name: "FinData OS (FirstRate Data)", base_url: "https://findata.spboucher.ai/api/v1", license: "frd-private"} | ||||
| 5 | +sample: {start: "2000-01-03", end: "2026-10-30"} | ||||
| 6 | +universe_file: configs/instruments.yaml | ||||
| 7 | +tier_c_baskets: | ||||
| 8 | + equity_etf: [SPY, QQQ, IWM, DIA] | ||||
| 9 | + cross_asset_etf: [SPY, TLT, GLD, USO, EEM] | ||||
| 10 | +tier_c_models: [rolling_cov252, ewma_cov094, ccc_garch11, dcc11, adcc11, scalar_bekk11] | ||||
| 11 | +tier_c_horizons: [1] | ||||
added
results/metrics/rugarch_crosscheck.json
+769 −0
@@ -0,0 +1,769 @@ | |||||
| 1 | +{ | ||||
| 2 | + "rugarch": { | ||||
| 3 | + "rugarch_version": "1.5.6", | ||||
| 4 | + "garch11_t": { | ||||
| 5 | + "converged": true, | ||||
| 6 | + "loglik": -3379.50279602402, | ||||
| 7 | + "coef": { | ||||
| 8 | + "mu": 0.0272520855544271, | ||||
| 9 | + "omega": 0.0174152246241149, | ||||
| 10 | + "alpha1": 0.0766441622812045, | ||||
| 11 | + "beta1": 0.897925769946588, | ||||
| 12 | + "shape": 6.92334228660823 | ||||
| 13 | + }, | ||||
| 14 | + "sigma2_last5": [ | ||||
| 15 | + 0.331218279727791, | ||||
| 16 | + 0.332580388365619, | ||||
| 17 | + 0.386557106650745, | ||||
| 18 | + 0.41489230427875, | ||||
| 19 | + 0.395462742973217 | ||||
| 20 | + ], | ||||
| 21 | + "fc": [ | ||||
| 22 | + 0.373396880254564, | ||||
| 23 | + 0.381316596907874, | ||||
| 24 | + 0.389034914629954, | ||||
| 25 | + 0.396556955009274, | ||||
| 26 | + 0.403887709391963, | ||||
| 27 | + 0.411032042193878, | ||||
| 28 | + 0.417994694128454, | ||||
| 29 | + 0.424780285352459, | ||||
| 30 | + 0.431393318531763, | ||||
| 31 | + 0.437838181829138, | ||||
| 32 | + 0.444119151816078, | ||||
| 33 | + 0.450240396310574, | ||||
| 34 | + 0.456205977142725, | ||||
| 35 | + 0.462019852850014, | ||||
| 36 | + 0.467685881304048, | ||||
| 37 | + 0.473207822270496, | ||||
| 38 | + 0.478589339903933, | ||||
| 39 | + 0.483834005179235, | ||||
| 40 | + 0.488945298261143, | ||||
| 41 | + 0.493926610813575, | ||||
| 42 | + 0.498781248250204, | ||||
| 43 | + 0.503512431927809 | ||||
| 44 | + ] | ||||
| 45 | + }, | ||||
| 46 | + "gjr11_t": { | ||||
| 47 | + "converged": true, | ||||
| 48 | + "loglik": -3372.99049098085, | ||||
| 49 | + "coef": { | ||||
| 50 | + "mu": 0.0223490291478538, | ||||
| 51 | + "omega": 0.0174956405075909, | ||||
| 52 | + "alpha1": 0.0426372227127993, | ||||
| 53 | + "beta1": 0.900398468982572, | ||||
| 54 | + "gamma1": 0.0620237392157647, | ||||
| 55 | + "shape": 7.00993566707479 | ||||
| 56 | + }, | ||||
| 57 | + "sigma2_last5": [ | ||||
| 58 | + 0.332335215434199, | ||||
| 59 | + 0.340484527422025, | ||||
| 60 | + 0.419369166473932, | ||||
| 61 | + 0.463058113854574, | ||||
| 62 | + 0.441677271920104 | ||||
| 63 | + ], | ||||
| 64 | + "fc": [ | ||||
| 65 | + 0.416282527426611, | ||||
| 66 | + 0.422974621160647, | ||||
| 67 | + 0.429493038742298, | ||||
| 68 | + 0.435842287491262, | ||||
| 69 | + 0.442026757751298, | ||||
| 70 | + 0.448050725926038, | ||||
| 71 | + 0.453918357436013, | ||||
| 72 | + 0.45963370959893, | ||||
| 73 | + 0.465200734435209, | ||||
| 74 | + 0.470623281400702, | ||||
| 75 | + 0.475905100048492, | ||||
| 76 | + 0.481049842621618, | ||||
| 77 | + 0.486061066578505, | ||||
| 78 | + 0.490942237052855, | ||||
| 79 | + 0.495696729249701, | ||||
| 80 | + 0.500327830779275, | ||||
| 81 | + 0.504838743930304, | ||||
| 82 | + 0.509232587884315, | ||||
| 83 | + 0.513512400872467, | ||||
| 84 | + 0.51768114227641, | ||||
| 85 | + 0.521741694674624, | ||||
| 86 | + 0.525696865835649 | ||||
| 87 | + ] | ||||
| 88 | + }, | ||||
| 89 | + "egarch11_t": { | ||||
| 90 | + "converged": true, | ||||
| 91 | + "loglik": -3376.68334976327, | ||||
| 92 | + "coef": { | ||||
| 93 | + "mu": 0.0188171893640434, | ||||
| 94 | + "omega": -0.0170849884697369, | ||||
| 95 | + "alpha1": -0.0444147835573704, | ||||
| 96 | + "beta1": 0.968708686881274, | ||||
| 97 | + "gamma1": 0.156456196163122, | ||||
| 98 | + "shape": 6.99039734118426 | ||||
| 99 | + }, | ||||
| 100 | + "sigma2_last5": [ | ||||
| 101 | + 0.328885250801329, | ||||
| 102 | + 0.350822965161747, | ||||
| 103 | + 0.436863315480211, | ||||
| 104 | + 0.499447742972208, | ||||
| 105 | + 0.479693397387017 | ||||
| 106 | + ], | ||||
| 107 | + "fc": [ | ||||
| 108 | + 0.440981758288812, | ||||
| 109 | + 0.444761569483677, | ||||
| 110 | + 0.448453995963031, | ||||
| 111 | + 0.452060109871317, | ||||
| 112 | + 0.455581032094569, | ||||
| 113 | + 0.45901792729419, | ||||
| 114 | + 0.462371999182192, | ||||
| 115 | + 0.4656444860341, | ||||
| 116 | + 0.468836656435033, | ||||
| 117 | + 0.471949805253863, | ||||
| 118 | + 0.474985249839914, | ||||
| 119 | + 0.477944326436176, | ||||
| 120 | + 0.480828386802756, | ||||
| 121 | + 0.483638795043929, | ||||
| 122 | + 0.486376924632017, | ||||
| 123 | + 0.489044155621135, | ||||
| 124 | + 0.491641872043739, | ||||
| 125 | + 0.494171459482879, | ||||
| 126 | + 0.49663430281301, | ||||
| 127 | + 0.499031784102273, | ||||
| 128 | + 0.501365280669172, | ||||
| 129 | + 0.503636163286671 | ||||
| 130 | + ] | ||||
| 131 | + }, | ||||
| 132 | + "aparch11_t": { | ||||
| 133 | + "converged": true, | ||||
| 134 | + "loglik": -3372.84892807275, | ||||
| 135 | + "coef": { | ||||
| 136 | + "mu": 0.0219498032140538, | ||||
| 137 | + "omega": 0.0182869465555667, | ||||
| 138 | + "alpha1": 0.0734928958434684, | ||||
| 139 | + "beta1": 0.901720469927853, | ||||
| 140 | + "gamma1": 0.230203192227028, | ||||
| 141 | + "delta": 1.84060080476714, | ||||
| 142 | + "shape": 7.0279389234871 | ||||
| 143 | + }, | ||||
| 144 | + "sigma2_last5": [ | ||||
| 145 | + 0.332682598703389, | ||||
| 146 | + 0.342687583247142, | ||||
| 147 | + 0.423457812590537, | ||||
| 148 | + 0.47031035284744, | ||||
| 149 | + 0.448241954551476 | ||||
| 150 | + ], | ||||
| 151 | + "fc": [ | ||||
| 152 | + 0.420729778911146, | ||||
| 153 | + 0.426946162214478, | ||||
| 154 | + 0.433001778704925, | ||||
| 155 | + 0.438900519070086, | ||||
| 156 | + 0.444646200595584, | ||||
| 157 | + 0.450242566618973, | ||||
| 158 | + 0.455693286232804, | ||||
| 159 | + 0.461001954204718, | ||||
| 160 | + 0.46617209108646, | ||||
| 161 | + 0.471207143487254, | ||||
| 162 | + 0.476110484489945, | ||||
| 163 | + 0.48088541419098, | ||||
| 164 | + 0.485535160347515, | ||||
| 165 | + 0.490062879116947, | ||||
| 166 | + 0.494471655875874, | ||||
| 167 | + 0.498764506106986, | ||||
| 168 | + 0.502944376343734, | ||||
| 169 | + 0.507014145163756, | ||||
| 170 | + 0.510976624223076, | ||||
| 171 | + 0.514834559323999, | ||||
| 172 | + 0.518590631510407, | ||||
| 173 | + 0.522247458184874 | ||||
| 174 | + ] | ||||
| 175 | + }, | ||||
| 176 | + "figarch11_t": { | ||||
| 177 | + "converged": true, | ||||
| 178 | + "loglik": -3381.97980336414, | ||||
| 179 | + "coef": { | ||||
| 180 | + "mu": 0.028208711165193, | ||||
| 181 | + "omega": 0.0134114399389171, | ||||
| 182 | + "alpha1": 0.26282947219305, | ||||
| 183 | + "beta1": 0.780139313197165, | ||||
| 184 | + "delta": 0.631140189523463, | ||||
| 185 | + "shape": 6.41803885552558 | ||||
| 186 | + }, | ||||
| 187 | + "sigma2_last5": [ | ||||
| 188 | + 0.299696988917735, | ||||
| 189 | + 0.316330648317056, | ||||
| 190 | + 0.390432077409812, | ||||
| 191 | + 0.384885199689091, | ||||
| 192 | + 0.343022844513784 | ||||
| 193 | + ], | ||||
| 194 | + "fc": [ | ||||
| 195 | + 0.339059269752477, | ||||
| 196 | + 0.367590095570308, | ||||
| 197 | + 0.368843743107776, | ||||
| 198 | + 0.370160945435298, | ||||
| 199 | + 0.373457632868578, | ||||
| 200 | + 0.377938383945126, | ||||
| 201 | + 0.382963124329593, | ||||
| 202 | + 0.388198567929454, | ||||
| 203 | + 0.393484081477849, | ||||
| 204 | + 0.398744620082659, | ||||
| 205 | + 0.403945640040183, | ||||
| 206 | + 0.409071431842686, | ||||
| 207 | + 0.414115967772256, | ||||
| 208 | + 0.419078001693844, | ||||
| 209 | + 0.423958280305449, | ||||
| 210 | + 0.42875861007803, | ||||
| 211 | + 0.433481497208184, | ||||
| 212 | + 0.438129181396169, | ||||
| 213 | + 0.442704763673238, | ||||
| 214 | + 0.447212036971553, | ||||
| 215 | + 0.451653257516078, | ||||
| 216 | + 0.456031281967143 | ||||
| 217 | + ] | ||||
| 218 | + }, | ||||
| 219 | + "igarch11_t": { | ||||
| 220 | + "converged": true, | ||||
| 221 | + "loglik": -3385.51714991758, | ||||
| 222 | + "coef": { | ||||
| 223 | + "mu": 0.0273555996213812, | ||||
| 224 | + "omega": 0.00822664842815519, | ||||
| 225 | + "alpha1": 0.0911285633973949, | ||||
| 226 | + "beta1": 0.908871436602605, | ||||
| 227 | + "shape": 5.98132454596413 | ||||
| 228 | + }, | ||||
| 229 | + "sigma2_last5": [ | ||||
| 230 | + 0.301577365761645, | ||||
| 231 | + 0.303442040727677, | ||||
| 232 | + 0.367868964109828, | ||||
| 233 | + 0.402485492370637, | ||||
| 234 | + 0.380584653228751 | ||||
| 235 | + ], | ||||
| 236 | + "fc": [ | ||||
| 237 | + 0.355184003263419, | ||||
| 238 | + 0.363410651691574, | ||||
| 239 | + 0.371637300119729, | ||||
| 240 | + 0.379863948547884, | ||||
| 241 | + 0.388090596976039, | ||||
| 242 | + 0.396317245404194, | ||||
| 243 | + 0.40454389383235, | ||||
| 244 | + 0.412770542260505, | ||||
| 245 | + 0.42099719068866, | ||||
| 246 | + 0.429223839116815, | ||||
| 247 | + 0.43745048754497, | ||||
| 248 | + 0.445677135973126, | ||||
| 249 | + 0.453903784401281, | ||||
| 250 | + 0.462130432829436, | ||||
| 251 | + 0.470357081257591, | ||||
| 252 | + 0.478583729685746, | ||||
| 253 | + 0.486810378113901, | ||||
| 254 | + 0.495037026542057, | ||||
| 255 | + 0.503263674970212, | ||||
| 256 | + 0.511490323398367, | ||||
| 257 | + 0.519716971826522, | ||||
| 258 | + 0.527943620254678 | ||||
| 259 | + ] | ||||
| 260 | + }, | ||||
| 261 | + "cgarch11_t": { | ||||
| 262 | + "converged": true, | ||||
| 263 | + "loglik": -3379.76186721388, | ||||
| 264 | + "coef": { | ||||
| 265 | + "mu": 0.0273402099302754, | ||||
| 266 | + "omega": 0.0178411646698263, | ||||
| 267 | + "alpha1": 0.0472240690102781, | ||||
| 268 | + "beta1": 0.926336229155417, | ||||
| 269 | + "eta11": 0.973560849178106, | ||||
| 270 | + "eta21": 0.0299126275164861, | ||||
| 271 | + "shape": 6.89529147023611 | ||||
| 272 | + }, | ||||
| 273 | + "sigma2_last5": [ | ||||
| 274 | + 0.331806400268661, | ||||
| 275 | + 0.333156933397685, | ||||
| 276 | + 0.387466733404178, | ||||
| 277 | + 0.415888052702624, | ||||
| 278 | + 0.3961973946619 | ||||
| 279 | + ], | ||||
| 280 | + "fc": [ | ||||
| 281 | + 0.373894792219397, | ||||
| 282 | + 0.410734909756006, | ||||
| 283 | + 0.417716681277378, | ||||
| 284 | + 0.424513858333285, | ||||
| 285 | + 0.431131321506913, | ||||
| 286 | + 0.437573822341324, | ||||
| 287 | + 0.443845986751214, | ||||
| 288 | + 0.449952318344464, | ||||
| 289 | + 0.455897201655865, | ||||
| 290 | + 0.461684905295354, | ||||
| 291 | + 0.467319585013005, | ||||
| 292 | + 0.472805286682989, | ||||
| 293 | + 0.478145949208632, | ||||
| 294 | + 0.483345407350674, | ||||
| 295 | + 0.488407394480744, | ||||
| 296 | + 0.493335545262035, | ||||
| 297 | + 0.498133398259106, | ||||
| 298 | + 0.50280439847868, | ||||
| 299 | + 0.507351899843266, | ||||
| 300 | + 0.511779167599379, | ||||
| 301 | + 0.516089380662085, | ||||
| 302 | + 0.520285633897565 | ||||
| 303 | + ] | ||||
| 304 | + }, | ||||
| 305 | + "nagarch11_t": { | ||||
| 306 | + "converged": true, | ||||
| 307 | + "loglik": -3373.35050140171, | ||||
| 308 | + "coef": { | ||||
| 309 | + "mu": 0.0213271608385587, | ||||
| 310 | + "omega": 0.0169277508131017, | ||||
| 311 | + "alpha1": 0.0706508464116506, | ||||
| 312 | + "beta1": 0.895992701235594, | ||||
| 313 | + "eta21": 0.339825862746243, | ||||
| 314 | + "shape": 7.06871565857494 | ||||
| 315 | + }, | ||||
| 316 | + "sigma2_last5": [ | ||||
| 317 | + 0.320085472046233, | ||||
| 318 | + 0.335215163198902, | ||||
| 319 | + 0.410709126156738, | ||||
| 320 | + 0.458799430333668, | ||||
| 321 | + 0.445128729120879 | ||||
| 322 | + ], | ||||
| 323 | + "fc": [ | ||||
| 324 | + 0.423373945827428, | ||||
| 325 | + 0.429633698461851, | ||||
| 326 | + 0.435735720488707, | ||||
| 327 | + 0.441683986337342, | ||||
| 328 | + 0.447482370291107, | ||||
| 329 | + 0.453134649010792, | ||||
| 330 | + 0.458644503994484, | ||||
| 331 | + 0.464015523975432, | ||||
| 332 | + 0.469251207259498, | ||||
| 333 | + 0.474354964003706, | ||||
| 334 | + 0.479330118437384, | ||||
| 335 | + 0.484179911027331, | ||||
| 336 | + 0.488907500588426, | ||||
| 337 | + 0.493515966341068, | ||||
| 338 | + 0.498008309916754, | ||||
| 339 | + 0.502387457313138, | ||||
| 340 | + 0.50665626079982, | ||||
| 341 | + 0.510817500776111, | ||||
| 342 | + 0.514873887581995, | ||||
| 343 | + 0.518828063263449, | ||||
| 344 | + 0.522682603293291, | ||||
| 345 | + 0.526440018248661 | ||||
| 346 | + ] | ||||
| 347 | + }, | ||||
| 348 | + "tgarch11_t": { | ||||
| 349 | + "converged": true, | ||||
| 350 | + "loglik": -3378.26565819207, | ||||
| 351 | + "coef": { | ||||
| 352 | + "mu": 0.0185075851662991, | ||||
| 353 | + "omega": 0.0237242658452512, | ||||
| 354 | + "alpha1": 0.0806721422971265, | ||||
| 355 | + "beta1": 0.908415590277261, | ||||
| 356 | + "eta11": 0.278262852619424, | ||||
| 357 | + "shape": 7.02369203281082 | ||||
| 358 | + }, | ||||
| 359 | + "sigma2_last5": [ | ||||
| 360 | + 0.339303507806645, | ||||
| 361 | + 0.361929596403121, | ||||
| 362 | + 0.446541788728846, | ||||
| 363 | + 0.509029924970293, | ||||
| 364 | + 0.488014547239253 | ||||
| 365 | + ], | ||||
| 366 | + "fc": [ | ||||
| 367 | + 0.446902528383541, | ||||
| 368 | + 0.451531432310373, | ||||
| 369 | + 0.456042749975163, | ||||
| 370 | + 0.460438686643197, | ||||
| 371 | + 0.464721461954639, | ||||
| 372 | + 0.468893304636195, | ||||
| 373 | + 0.472956447662954, | ||||
| 374 | + 0.476913123839437, | ||||
| 375 | + 0.480765561770887, | ||||
| 376 | + 0.484515982197637, | ||||
| 377 | + 0.488166594667179, | ||||
| 378 | + 0.49171959452015, | ||||
| 379 | + 0.495177160168002, | ||||
| 380 | + 0.498541450641537, | ||||
| 381 | + 0.501814603390865, | ||||
| 382 | + 0.504998732318567, | ||||
| 383 | + 0.508095926029051, | ||||
| 384 | + 0.511108246278208, | ||||
| 385 | + 0.514037726608485, | ||||
| 386 | + 0.516886371155493, | ||||
| 387 | + 0.519656153613176, | ||||
| 388 | + 0.522349016345428 | ||||
| 389 | + ] | ||||
| 390 | + }, | ||||
| 391 | + "realgarch11_n": { | ||||
| 392 | + "converged": false | ||||
| 393 | + }, | ||||
| 394 | + "garch11_skewt": { | ||||
| 395 | + "converged": true, | ||||
| 396 | + "loglik": -3379.31479592696, | ||||
| 397 | + "coef": { | ||||
| 398 | + "mu": 0.0247602319116539, | ||||
| 399 | + "omega": 0.017295740459104, | ||||
| 400 | + "alpha1": 0.0762213395583014, | ||||
| 401 | + "beta1": 0.89844516796877, | ||||
| 402 | + "skew": 0.984514907132941, | ||||
| 403 | + "shape": 6.94374052154004 | ||||
| 404 | + }, | ||||
| 405 | + "sigma2_last5": [ | ||||
| 406 | + 0.330905238634026, | ||||
| 407 | + 0.332071373500861, | ||||
| 408 | + 0.385400191269274, | ||||
| 409 | + 0.413348758343739, | ||||
| 410 | + 0.394040260337795 | ||||
| 411 | + ], | ||||
| 412 | + "fc": [ | ||||
| 413 | + 0.372159534757372, | ||||
| 414 | + 0.380027174443972, | ||||
| 415 | + 0.387695499339791, | ||||
| 416 | + 0.395169558784582, | ||||
| 417 | + 0.402454274200687, | ||||
| 418 | + 0.40955444233363, | ||||
| 419 | + 0.41647473841062, | ||||
| 420 | + 0.423219719219034, | ||||
| 421 | + 0.429793826106908, | ||||
| 422 | + 0.436201387907421, | ||||
| 423 | + 0.442446623789292, | ||||
| 424 | + 0.448533646034957, | ||||
| 425 | + 0.454466462748379, | ||||
| 426 | + 0.460248980494249, | ||||
| 427 | + 0.465885006870329, | ||||
| 428 | + 0.471378253014633, | ||||
| 429 | + 0.476732336049089, | ||||
| 430 | + 0.481950781461291, | ||||
| 431 | + 0.487037025425924, | ||||
| 432 | + 0.491994417067363, | ||||
| 433 | + 0.496826220664968, | ||||
| 434 | + 0.501535617802502 | ||||
| 435 | + ] | ||||
| 436 | + } | ||||
| 437 | + }, | ||||
| 438 | + "ours": { | ||||
| 439 | + "garch11_t": { | ||||
| 440 | + "loglik": -3379.461796995996, | ||||
| 441 | + "params": { | ||||
| 442 | + "mu": 0.0272552165475274, | ||||
| 443 | + "omega": 0.017418392193745573, | ||||
| 444 | + "alpha[1]": 0.0766713206199158, | ||||
| 445 | + "beta[1]": 0.8979047644168446, | ||||
| 446 | + "nu": 6.915683563286161 | ||||
| 447 | + }, | ||||
| 448 | + "converged": true | ||||
| 449 | + }, | ||||
| 450 | + "gjr11_t": { | ||||
| 451 | + "loglik": -3372.953632113916, | ||||
| 452 | + "params": { | ||||
| 453 | + "mu": 0.02234711621886731, | ||||
| 454 | + "omega": 0.017500497241068884, | ||||
| 455 | + "alpha[1]": 0.04266800772043423, | ||||
| 456 | + "gamma[1]": 0.062034959552290915, | ||||
| 457 | + "beta[1]": 0.9003610818426231, | ||||
| 458 | + "nu": 7.002485146679242 | ||||
| 459 | + }, | ||||
| 460 | + "converged": true | ||||
| 461 | + }, | ||||
| 462 | + "egarch11_t": { | ||||
| 463 | + "loglik": -3376.6704308851477, | ||||
| 464 | + "params": { | ||||
| 465 | + "mu": 0.018828915964200128, | ||||
| 466 | + "omega": -0.011034952859929866, | ||||
| 467 | + "alpha[1]": 0.15651669565747273, | ||||
| 468 | + "gamma[1]": -0.044438618764715755, | ||||
| 469 | + "beta[1]": 0.9686789065580167, | ||||
| 470 | + "nu": 6.98363424230133 | ||||
| 471 | + }, | ||||
| 472 | + "converged": true | ||||
| 473 | + }, | ||||
| 474 | + "aparch11_t": { | ||||
| 475 | + "loglik": -3372.7593223523118, | ||||
| 476 | + "params": { | ||||
| 477 | + "mu": 0.021873566385943646, | ||||
| 478 | + "omega": 0.01845096728792146, | ||||
| 479 | + "alpha[1]": 0.0741123489743683, | ||||
| 480 | + "gamma[1]": 0.23185125233775555, | ||||
| 481 | + "beta[1]": 0.9019093525442575, | ||||
| 482 | + "delta": 1.810851742298129, | ||||
| 483 | + "nu": 7.017009293700917 | ||||
| 484 | + }, | ||||
| 485 | + "converged": true | ||||
| 486 | + }, | ||||
| 487 | + "figarch11_t": { | ||||
| 488 | + "loglik": -3383.4506039107964, | ||||
| 489 | + "params": { | ||||
| 490 | + "mu": 0.027341455003779366, | ||||
| 491 | + "omega": 0.018557454873431037, | ||||
| 492 | + "phi": 0.2272419820409831, | ||||
| 493 | + "d": 0.545516035918098, | ||||
| 494 | + "beta": 0.6927227001090212, | ||||
| 495 | + "nu": 6.4546568465574365 | ||||
| 496 | + }, | ||||
| 497 | + "converged": true | ||||
| 498 | + }, | ||||
| 499 | + "garch11_skewt": { | ||||
| 500 | + "loglik": -3379.275642878361, | ||||
| 501 | + "params": { | ||||
| 502 | + "mu": 0.0247698562671931, | ||||
| 503 | + "omega": 0.017301334377567416, | ||||
| 504 | + "alpha[1]": 0.07625585117671085, | ||||
| 505 | + "beta[1]": 0.8984117763911253, | ||||
| 506 | + "eta": 6.936304710964621, | ||||
| 507 | + "lambda": -0.01552668380206145 | ||||
| 508 | + }, | ||||
| 509 | + "converged": true | ||||
| 510 | + }, | ||||
| 511 | + "igarch11_t": { | ||||
| 512 | + "loglik": -3385.466983993589, | ||||
| 513 | + "params": { | ||||
| 514 | + "mu": 0.027354323480404286, | ||||
| 515 | + "omega": 0.008236861969721824, | ||||
| 516 | + "alpha": 0.09116543468488557, | ||||
| 517 | + "nu": 5.973513461861548 | ||||
| 518 | + }, | ||||
| 519 | + "converged": true | ||||
| 520 | + }, | ||||
| 521 | + "cgarch11_t": { | ||||
| 522 | + "loglik": -3379.461678802403, | ||||
| 523 | + "params": { | ||||
| 524 | + "mu": 0.027257000911121945, | ||||
| 525 | + "omega": 0.01736733788836256, | ||||
| 526 | + "rho": 0.9746416050735823, | ||||
| 527 | + "phi": 0.03393172704779641, | ||||
| 528 | + "alpha": 0.04272735073115051, | ||||
| 529 | + "beta": 0.9317694810875947, | ||||
| 530 | + "nu": 6.9169232979627395 | ||||
| 531 | + }, | ||||
| 532 | + "converged": true | ||||
| 533 | + }, | ||||
| 534 | + "nagarch11_t": { | ||||
| 535 | + "loglik": -3373.3123413949697, | ||||
| 536 | + "params": { | ||||
| 537 | + "mu": 0.02133256452316757, | ||||
| 538 | + "omega": 0.016934592629425642, | ||||
| 539 | + "alpha": 0.07068774289404209, | ||||
| 540 | + "theta": 0.3397290537185268, | ||||
| 541 | + "beta": 0.8959513510919638, | ||||
| 542 | + "nu": 7.06163608387285 | ||||
| 543 | + }, | ||||
| 544 | + "converged": true | ||||
| 545 | + }, | ||||
| 546 | + "realgarch11_n": { | ||||
| 547 | + "loglik": -4989.212643221531, | ||||
| 548 | + "params": { | ||||
| 549 | + "mu": 0.01677936657297113, | ||||
| 550 | + "omega": -0.0310098669169496, | ||||
| 551 | + "beta": 0.7043221645737289, | ||||
| 552 | + "gamma": 0.2567538036768552, | ||||
| 553 | + "xi": 0.04191198028547544, | ||||
| 554 | + "phi": 1.0024048779109547, | ||||
| 555 | + "tau1": 0.0010267719765093414, | ||||
| 556 | + "tau2": 0.013224579404035812, | ||||
| 557 | + "log_sigma_u": -0.9137863869883917 | ||||
| 558 | + }, | ||||
| 559 | + "converged": true | ||||
| 560 | + } | ||||
| 561 | + }, | ||||
| 562 | + "comparison": { | ||||
| 563 | + "garch11_t": { | ||||
| 564 | + "rugarch_loglik": -3379.50279602402, | ||||
| 565 | + "ours_loglik": -3379.461796995996, | ||||
| 566 | + "rugarch_coef": { | ||||
| 567 | + "mu": 0.0272520855544271, | ||||
| 568 | + "omega": 0.0174152246241149, | ||||
| 569 | + "alpha1": 0.0766441622812045, | ||||
| 570 | + "beta1": 0.897925769946588, | ||||
| 571 | + "shape": 6.92334228660823 | ||||
| 572 | + }, | ||||
| 573 | + "ours_params": { | ||||
| 574 | + "mu": 0.0272552165475274, | ||||
| 575 | + "omega": 0.017418392193745573, | ||||
| 576 | + "alpha[1]": 0.0766713206199158, | ||||
| 577 | + "beta[1]": 0.8979047644168446, | ||||
| 578 | + "nu": 6.915683563286161 | ||||
| 579 | + }, | ||||
| 580 | + "diff": 0.04099902802408906 | ||||
| 581 | + }, | ||||
| 582 | + "gjr11_t": { | ||||
| 583 | + "rugarch_loglik": -3372.99049098085, | ||||
| 584 | + "ours_loglik": -3372.953632113916, | ||||
| 585 | + "rugarch_coef": { | ||||
| 586 | + "mu": 0.0223490291478538, | ||||
| 587 | + "omega": 0.0174956405075909, | ||||
| 588 | + "alpha1": 0.0426372227127993, | ||||
| 589 | + "beta1": 0.900398468982572, | ||||
| 590 | + "gamma1": 0.0620237392157647, | ||||
| 591 | + "shape": 7.00993566707479 | ||||
| 592 | + }, | ||||
| 593 | + "ours_params": { | ||||
| 594 | + "mu": 0.02234711621886731, | ||||
| 595 | + "omega": 0.017500497241068884, | ||||
| 596 | + "alpha[1]": 0.04266800772043423, | ||||
| 597 | + "gamma[1]": 0.062034959552290915, | ||||
| 598 | + "beta[1]": 0.9003610818426231, | ||||
| 599 | + "nu": 7.002485146679242 | ||||
| 600 | + }, | ||||
| 601 | + "diff": 0.036858866934380785 | ||||
| 602 | + }, | ||||
| 603 | + "egarch11_t": { | ||||
| 604 | + "rugarch_loglik": -3376.68334976327, | ||||
| 605 | + "ours_loglik": -3376.6704308851477, | ||||
| 606 | + "rugarch_coef": { | ||||
| 607 | + "mu": 0.0188171893640434, | ||||
| 608 | + "omega": -0.0170849884697369, | ||||
| 609 | + "alpha1": -0.0444147835573704, | ||||
| 610 | + "beta1": 0.968708686881274, | ||||
| 611 | + "gamma1": 0.156456196163122, | ||||
| 612 | + "shape": 6.99039734118426 | ||||
| 613 | + }, | ||||
| 614 | + "ours_params": { | ||||
| 615 | + "mu": 0.018828915964200128, | ||||
| 616 | + "omega": -0.011034952859929866, | ||||
| 617 | + "alpha[1]": 0.15651669565747273, | ||||
| 618 | + "gamma[1]": -0.044438618764715755, | ||||
| 619 | + "beta[1]": 0.9686789065580167, | ||||
| 620 | + "nu": 6.98363424230133 | ||||
| 621 | + }, | ||||
| 622 | + "diff": 0.01291887812249115 | ||||
| 623 | + }, | ||||
| 624 | + "aparch11_t": { | ||||
| 625 | + "rugarch_loglik": -3372.84892807275, | ||||
| 626 | + "ours_loglik": -3372.7593223523118, | ||||
| 627 | + "rugarch_coef": { | ||||
| 628 | + "mu": 0.0219498032140538, | ||||
| 629 | + "omega": 0.0182869465555667, | ||||
| 630 | + "alpha1": 0.0734928958434684, | ||||
| 631 | + "beta1": 0.901720469927853, | ||||
| 632 | + "gamma1": 0.230203192227028, | ||||
| 633 | + "delta": 1.84060080476714, | ||||
| 634 | + "shape": 7.0279389234871 | ||||
| 635 | + }, | ||||
| 636 | + "ours_params": { | ||||
| 637 | + "mu": 0.021873566385943646, | ||||
| 638 | + "omega": 0.01845096728792146, | ||||
| 639 | + "alpha[1]": 0.0741123489743683, | ||||
| 640 | + "gamma[1]": 0.23185125233775555, | ||||
| 641 | + "beta[1]": 0.9019093525442575, | ||||
| 642 | + "delta": 1.810851742298129, | ||||
| 643 | + "nu": 7.017009293700917 | ||||
| 644 | + }, | ||||
| 645 | + "diff": 0.08960572043815773 | ||||
| 646 | + }, | ||||
| 647 | + "figarch11_t": { | ||||
| 648 | + "rugarch_loglik": -3381.97980336414, | ||||
| 649 | + "ours_loglik": -3383.4506039107964, | ||||
| 650 | + "rugarch_coef": { | ||||
| 651 | + "mu": 0.028208711165193, | ||||
| 652 | + "omega": 0.0134114399389171, | ||||
| 653 | + "alpha1": 0.26282947219305, | ||||
| 654 | + "beta1": 0.780139313197165, | ||||
| 655 | + "delta": 0.631140189523463, | ||||
| 656 | + "shape": 6.41803885552558 | ||||
| 657 | + }, | ||||
| 658 | + "ours_params": { | ||||
| 659 | + "mu": 0.027341455003779366, | ||||
| 660 | + "omega": 0.018557454873431037, | ||||
| 661 | + "phi": 0.2272419820409831, | ||||
| 662 | + "d": 0.545516035918098, | ||||
| 663 | + "beta": 0.6927227001090212, | ||||
| 664 | + "nu": 6.4546568465574365 | ||||
| 665 | + }, | ||||
| 666 | + "diff": -1.4708005466563918 | ||||
| 667 | + }, | ||||
| 668 | + "igarch11_t": { | ||||
| 669 | + "rugarch_loglik": -3385.51714991758, | ||||
| 670 | + "ours_loglik": -3385.466983993589, | ||||
| 671 | + "rugarch_coef": { | ||||
| 672 | + "mu": 0.0273555996213812, | ||||
| 673 | + "omega": 0.00822664842815519, | ||||
| 674 | + "alpha1": 0.0911285633973949, | ||||
| 675 | + "beta1": 0.908871436602605, | ||||
| 676 | + "shape": 5.98132454596413 | ||||
| 677 | + }, | ||||
| 678 | + "ours_params": { | ||||
| 679 | + "mu": 0.027354323480404286, | ||||
| 680 | + "omega": 0.008236861969721824, | ||||
| 681 | + "alpha": 0.09116543468488557, | ||||
| 682 | + "nu": 5.973513461861548 | ||||
| 683 | + }, | ||||
| 684 | + "diff": 0.05016592399078945 | ||||
| 685 | + }, | ||||
| 686 | + "cgarch11_t": { | ||||
| 687 | + "rugarch_loglik": -3379.76186721388, | ||||
| 688 | + "ours_loglik": -3379.461678802403, | ||||
| 689 | + "rugarch_coef": { | ||||
| 690 | + "mu": 0.0273402099302754, | ||||
| 691 | + "omega": 0.0178411646698263, | ||||
| 692 | + "alpha1": 0.0472240690102781, | ||||
| 693 | + "beta1": 0.926336229155417, | ||||
| 694 | + "eta11": 0.973560849178106, | ||||
| 695 | + "eta21": 0.0299126275164861, | ||||
| 696 | + "shape": 6.89529147023611 | ||||
| 697 | + }, | ||||
| 698 | + "ours_params": { | ||||
| 699 | + "mu": 0.027257000911121945, | ||||
| 700 | + "omega": 0.01736733788836256, | ||||
| 701 | + "rho": 0.9746416050735823, | ||||
| 702 | + "phi": 0.03393172704779641, | ||||
| 703 | + "alpha": 0.04272735073115051, | ||||
| 704 | + "beta": 0.9317694810875947, | ||||
| 705 | + "nu": 6.9169232979627395 | ||||
| 706 | + }, | ||||
| 707 | + "diff": 0.3001884114769382 | ||||
| 708 | + }, | ||||
| 709 | + "nagarch11_t": { | ||||
| 710 | + "rugarch_loglik": -3373.35050140171, | ||||
| 711 | + "ours_loglik": -3373.3123413949697, | ||||
| 712 | + "rugarch_coef": { | ||||
| 713 | + "mu": 0.0213271608385587, | ||||
| 714 | + "omega": 0.0169277508131017, | ||||
| 715 | + "alpha1": 0.0706508464116506, | ||||
| 716 | + "beta1": 0.895992701235594, | ||||
| 717 | + "eta21": 0.339825862746243, | ||||
| 718 | + "shape": 7.06871565857494 | ||||
| 719 | + }, | ||||
| 720 | + "ours_params": { | ||||
| 721 | + "mu": 0.02133256452316757, | ||||
| 722 | + "omega": 0.016934592629425642, | ||||
| 723 | + "alpha": 0.07068774289404209, | ||||
| 724 | + "theta": 0.3397290537185268, | ||||
| 725 | + "beta": 0.8959513510919638, | ||||
| 726 | + "nu": 7.06163608387285 | ||||
| 727 | + }, | ||||
| 728 | + "diff": 0.038160006740326935 | ||||
| 729 | + }, | ||||
| 730 | + "garch11_skewt": { | ||||
| 731 | + "rugarch_loglik": -3379.31479592696, | ||||
| 732 | + "ours_loglik": -3379.275642878361, | ||||
| 733 | + "rugarch_coef": { | ||||
| 734 | + "mu": 0.0247602319116539, | ||||
| 735 | + "omega": 0.017295740459104, | ||||
| 736 | + "alpha1": 0.0762213395583014, | ||||
| 737 | + "beta1": 0.89844516796877, | ||||
| 738 | + "skew": 0.984514907132941, | ||||
| 739 | + "shape": 6.94374052154004 | ||||
| 740 | + }, | ||||
| 741 | + "ours_params": { | ||||
| 742 | + "mu": 0.0247698562671931, | ||||
| 743 | + "omega": 0.017301334377567416, | ||||
| 744 | + "alpha[1]": 0.07625585117671085, | ||||
| 745 | + "beta[1]": 0.8984117763911253, | ||||
| 746 | + "eta": 6.936304710964621, | ||||
| 747 | + "lambda": -0.01552668380206145 | ||||
| 748 | + }, | ||||
| 749 | + "diff": 0.0391530485990188 | ||||
| 750 | + }, | ||||
| 751 | + "realgarch11_n": { | ||||
| 752 | + "rugarch_loglik": null, | ||||
| 753 | + "ours_loglik": -4989.212643221531, | ||||
| 754 | + "rugarch_coef": null, | ||||
| 755 | + "ours_params": { | ||||
| 756 | + "mu": 0.01677936657297113, | ||||
| 757 | + "omega": -0.0310098669169496, | ||||
| 758 | + "beta": 0.7043221645737289, | ||||
| 759 | + "gamma": 0.2567538036768552, | ||||
| 760 | + "xi": 0.04191198028547544, | ||||
| 761 | + "phi": 1.0024048779109547, | ||||
| 762 | + "tau1": 0.0010267719765093414, | ||||
| 763 | + "tau2": 0.013224579404035812, | ||||
| 764 | + "log_sigma_u": -0.9137863869883917 | ||||
| 765 | + }, | ||||
| 766 | + "diff": null | ||||
| 767 | + } | ||||
| 768 | + } | ||||
| 769 | +} | ||||
| \ No newline at end of file | |||||
modified
scripts/audit_findata.py
+0 −0
modified
scripts/build_panels.py
+0 −0
modified
scripts/build_references.py
+0 −0
added
scripts/dispatch_nodes.py
+70 −0
@@ -0,0 +1,70 @@ | |||||
| 1 | +#!/usr/bin/env python3 | ||||
| 2 | +"""Dispatch a job list over the MacLustr nodes (core-proportional shards) and collect results. | ||||
| 3 | +usage: dispatch_nodes.py launch --jobs results/manifests/jobs_main.json --name main [--nodes M3U96a:26,M3U96b:26,...] | ||||
| 4 | + dispatch_nodes.py status --name main | ||||
| 5 | + dispatch_nodes.py collect --name main # rsync <node>:~/wp46-cache/forecasts_<name>/ -> results/forecasts/<name>/ | ||||
| 6 | +Panels (daily returns + realized measures) must exist on every node under ~/wp46-cache/panels (synced here).""" | ||||
| 7 | +from __future__ import annotations | ||||
| 8 | + | ||||
| 9 | +import argparse | ||||
| 10 | +import json | ||||
| 11 | +import subprocess | ||||
| 12 | +from pathlib import Path | ||||
| 13 | + | ||||
| 14 | +ROOT = Path(__file__).resolve().parents[1] | ||||
| 15 | +DEFAULT_NODES = "M3U96a:24,M3U96b:26,M2U64:22,M5M36:16,M4M64a:14,M4M64c:14" | ||||
| 16 | + | ||||
| 17 | + | ||||
| 18 | +def sh(cmd: list[str], timeout=600) -> str: | ||||
| 19 | + return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout).stdout | ||||
| 20 | + | ||||
| 21 | + | ||||
| 22 | +def main() -> None: | ||||
| 23 | + ap = argparse.ArgumentParser() | ||||
| 24 | + ap.add_argument("cmd", choices=["launch", "status", "collect", "sync-panels"]) | ||||
| 25 | + ap.add_argument("--jobs", default="") | ||||
| 26 | + ap.add_argument("--name", required=True) | ||||
| 27 | + ap.add_argument("--nodes", default=DEFAULT_NODES) | ||||
| 28 | + a = ap.parse_args() | ||||
| 29 | + nodes = [(n.split(":")[0], int(n.split(":")[1])) for n in a.nodes.split(",")] | ||||
| 30 | + if a.cmd == "sync-panels": | ||||
| 31 | + for n, _ in nodes: | ||||
| 32 | + print(n, sh(["rsync", "-aq", "--delete", str(Path.home() / "wp46-cache" / "panels") + "/", f"{n}:~/wp46-cache/panels/"])) | ||||
| 33 | + return | ||||
| 34 | + if a.cmd == "launch": | ||||
| 35 | + jobs = json.loads(Path(a.jobs).read_text()) | ||||
| 36 | + tot = sum(c for _, c in nodes) | ||||
| 37 | + # proportional contiguous shards over the (heavy-first) job order -> interleave: node k takes jobs with | ||||
| 38 | + # index % N in its share; simpler and balanced: assign job i to node by weighted round robin | ||||
| 39 | + assign = {n: [] for n, _ in nodes} | ||||
| 40 | + weights = [c / tot for _, c in nodes] | ||||
| 41 | + acc = [0.0] * len(nodes) | ||||
| 42 | + for i, j in enumerate(jobs): | ||||
| 43 | + k = max(range(len(nodes)), key=lambda q: weights[q] * (i + 1) - acc[q]) | ||||
| 44 | + acc[k] += 1 | ||||
| 45 | + assign[nodes[k][0]].append(j) | ||||
| 46 | + for n, cores in nodes: | ||||
| 47 | + jf = ROOT / "results" / "manifests" / f"jobs_{a.name}_{n}.json" | ||||
| 48 | + jf.write_text(json.dumps(assign[n])) | ||||
| 49 | + subprocess.run(["scp", "-q", str(jf), f"{n}:~/wp46_uqo/results/manifests/"], check=True) | ||||
| 50 | + print(n, cores, len(assign[n]), sh(["ssh", n, f"bash ~/wp46_uqo/scripts/node_run.sh results/manifests/jobs_{a.name}_{n}.json 0/1 {cores} {a.name}"]).strip()) | ||||
| 51 | + return | ||||
| 52 | + if a.cmd == "status": | ||||
| 53 | + for n, _ in nodes: | ||||
| 54 | + out = sh(["ssh", n, f"cd ~/wp46_uqo && (wc -l < ~/wp46-cache/forecasts_{a.name}/_runs.jsonl 2>/dev/null || echo 0); " | ||||
| 55 | + f"python3 -c \"import json;print(len(json.load(open('results/manifests/jobs_{a.name}_{n}.json'))))\" 2>/dev/null; " | ||||
| 56 | + f"grep -c error ~/wp46-cache/forecasts_{a.name}/_runs.jsonl 2>/dev/null; uptime | sed 's/.*load/load/'; " | ||||
| 57 | + f"pgrep -fc run_benchmark.py"]) | ||||
| 58 | + print(n, " | ".join(x.strip() for x in out.splitlines())) | ||||
| 59 | + return | ||||
| 60 | + if a.cmd == "collect": | ||||
| 61 | + dest = ROOT / "results" / "forecasts" / a.name | ||||
| 62 | + dest.mkdir(parents=True, exist_ok=True) | ||||
| 63 | + for n, _ in nodes: | ||||
| 64 | + print(n, sh(["rsync", "-aq", f"{n}:~/wp46-cache/forecasts_{a.name}/", str(dest) + "/"], timeout=3600)) | ||||
| 65 | + runs = [json.loads(l) for l in (dest / "_runs.jsonl").read_text().splitlines()] if (dest / "_runs.jsonl").exists() else [] | ||||
| 66 | + print("collected runs:", len(runs), "errors:", sum("error" in r for r in runs)) | ||||
| 67 | + | ||||
| 68 | + | ||||
| 69 | +if __name__ == "__main__": | ||||
| 70 | + main() | ||||
modified
scripts/ingest_bars.py
+0 −0
added
scripts/make_jobs.py
+61 −0
@@ -0,0 +1,61 @@ | |||||
| 1 | +#!/usr/bin/env python3 | ||||
| 2 | +"""Expand the frozen configs into a job list (instrument x model x distribution x estimation variant). | ||||
| 3 | +usage: make_jobs.py --name main [--tier A,B] [--symbols ...] [--oos-start 2012-01-03] [--oos-end 2026-10-30] | ||||
| 4 | + [--window 1000] [--refit 5] [--expanding] [--models m1,m2]""" | ||||
| 5 | +from __future__ import annotations | ||||
| 6 | + | ||||
| 7 | +import argparse | ||||
| 8 | +import json | ||||
| 9 | +import sys | ||||
| 10 | +from pathlib import Path | ||||
| 11 | + | ||||
| 12 | +import yaml | ||||
| 13 | + | ||||
| 14 | +ROOT = Path(__file__).resolve().parents[1] | ||||
| 15 | +sys.path.insert(0, str(ROOT / "src")) | ||||
| 16 | + | ||||
| 17 | + | ||||
| 18 | +def main() -> None: | ||||
| 19 | + ap = argparse.ArgumentParser() | ||||
| 20 | + ap.add_argument("--name", required=True) | ||||
| 21 | + ap.add_argument("--tier", default="A,B") | ||||
| 22 | + ap.add_argument("--symbols", default="") | ||||
| 23 | + ap.add_argument("--models", default="") | ||||
| 24 | + ap.add_argument("--oos-start", default=None) | ||||
| 25 | + ap.add_argument("--oos-end", default=None) | ||||
| 26 | + ap.add_argument("--window", type=int, default=None) | ||||
| 27 | + ap.add_argument("--refit", type=int, default=None) | ||||
| 28 | + ap.add_argument("--expanding", action="store_true") | ||||
| 29 | + a = ap.parse_args() | ||||
| 30 | + reg = yaml.safe_load(open(ROOT / "configs" / "model_registry.yaml"))["models"] | ||||
| 31 | + inst = yaml.safe_load(open(ROOT / "configs" / "instruments.yaml")) | ||||
| 32 | + prot = yaml.safe_load(open(ROOT / "configs" / "forecast_protocol.yaml")) | ||||
| 33 | + uni = inst.get("universe") or inst["candidates"] | ||||
| 34 | + syms = [s for cls in uni for s in uni[cls]] | ||||
| 35 | + if a.symbols: | ||||
| 36 | + syms = [s for s in a.symbols.split(",") if s] | ||||
| 37 | + tiers = a.tier.split(",") | ||||
| 38 | + oos_start = a.oos_start or prot["periods"]["validation"]["start"] | ||||
| 39 | + oos_end = a.oos_end or prot["periods"]["test"]["end"] | ||||
| 40 | + window = a.window or prot["estimation"]["window"] | ||||
| 41 | + refit = a.refit or prot["estimation"]["refit_every"] | ||||
| 42 | + want = set(a.models.split(",")) if a.models else None | ||||
| 43 | + jobs = [] | ||||
| 44 | + for s in syms: | ||||
| 45 | + for mid, m in reg.items(): | ||||
| 46 | + if m["status"] != "implemented" or m["tier"] not in tiers or (want and mid not in want): | ||||
| 47 | + continue | ||||
| 48 | + for dist in m["dists"]: | ||||
| 49 | + jobs.append(dict(symbol=s, model_id=mid, dist=dist, tier=m["tier"], window=window, refit_every=refit, | ||||
| 50 | + expanding=a.expanding, rm_proxy=prot["tier_b_input"], oos_start=oos_start, oos_end=oos_end, | ||||
| 51 | + seed=prot["estimation"]["seed"], max_restarts=prot["estimation"]["max_restarts"])) | ||||
| 52 | + # heavy jobs first (better load balance): msgarch, figarch, realgarch, aparch/egarch (simulation forecasts) | ||||
| 53 | + rank = {"msgarch2": 0, "figarch11": 1, "realgarch11": 2, "aparch11": 3, "egarch11": 4, "tarch11": 5, "avgarch11": 6} | ||||
| 54 | + jobs.sort(key=lambda j: (rank.get(j["model_id"], 9), j["symbol"])) | ||||
| 55 | + out = ROOT / "results" / "manifests" / f"jobs_{a.name}.json" | ||||
| 56 | + out.write_text(json.dumps(jobs, indent=0)) | ||||
| 57 | + print(out, len(jobs), "jobs;", len(syms), "symbols;", sorted({j['model_id'] for j in jobs})) | ||||
| 58 | + | ||||
| 59 | + | ||||
| 60 | +if __name__ == "__main__": | ||||
| 61 | + main() | ||||
added
scripts/node_run.sh
+11 −0
@@ -0,0 +1,11 @@ | |||||
| 1 | +#!/bin/bash | ||||
| 2 | +# Run one shard of a job list on a cluster node (called over ssh from scripts/dispatch_nodes.py). | ||||
| 3 | +# usage: node_run.sh <jobs_file_relative> <shard i/N> <workers> <run_name> | ||||
| 4 | +set -u | ||||
| 5 | +cd ~/wp46_uqo || exit 1 | ||||
| 6 | +git pull -q | ||||
| 7 | +mkdir -p results/logs | ||||
| 8 | +export WP46_CACHE=~/wp46-cache | ||||
| 9 | +nohup .venv/bin/python scripts/run_benchmark.py --jobs "$1" --shard "$2" --workers "$3" --out ~/wp46-cache/forecasts_"$4" \ | ||||
| 10 | + > results/logs/bench_"$4"_shard_"${2/\//_}".log 2>&1 & | ||||
| 11 | +echo "started shard $2 on $(hostname) pid $!" | ||||
added
scripts/run_benchmark.py
+96 −0
@@ -0,0 +1,96 @@ | |||||
| 1 | +#!/usr/bin/env python3 | ||||
| 2 | +"""Run rolling-origin forecasting jobs (instrument x model x distribution) and write one Parquet per job. | ||||
| 3 | + | ||||
| 4 | +usage: run_benchmark.py --jobs results/manifests/jobs_<name>.json [--shard i/N] [--workers 8] [--out results/forecasts] | ||||
| 5 | +The job list is produced by scripts/make_jobs.py from the frozen configs. Each job writes | ||||
| 6 | + <out>/<symbol>/<spec_id>.parquet (forecasts, one row per origin) | ||||
| 7 | + <out>/<symbol>/<spec_id>.fits.parquet (refit attempts) | ||||
| 8 | +and a line in <out>/_runs.jsonl (git SHA, host, package versions, wall time). Existing outputs are skipped (resumable). | ||||
| 9 | +Nothing printed contains return values.""" | ||||
| 10 | +from __future__ import annotations | ||||
| 11 | + | ||||
| 12 | +import argparse | ||||
| 13 | +import json | ||||
| 14 | +import os | ||||
| 15 | +import platform | ||||
| 16 | +import resource | ||||
| 17 | +import socket | ||||
| 18 | +import subprocess | ||||
| 19 | +import sys | ||||
| 20 | +import time | ||||
| 21 | +from concurrent.futures import ProcessPoolExecutor, as_completed | ||||
| 22 | +from pathlib import Path | ||||
| 23 | + | ||||
| 24 | +ROOT = Path(__file__).resolve().parents[1] | ||||
| 25 | +sys.path.insert(0, str(ROOT / "src")) | ||||
| 26 | + | ||||
| 27 | + | ||||
| 28 | +def git_sha() -> str: | ||||
| 29 | + try: | ||||
| 30 | + return subprocess.check_output(["git", "-C", str(ROOT), "rev-parse", "--short", "HEAD"], text=True).strip() | ||||
| 31 | + except Exception: # noqa: BLE001 | ||||
| 32 | + return "unknown" | ||||
| 33 | + | ||||
| 34 | + | ||||
| 35 | +def run_one(job: dict, out: str) -> dict: | ||||
| 36 | + import numpy as np | ||||
| 37 | + import pandas as pd | ||||
| 38 | + from wp46.estimation import JobSpec, run_job | ||||
| 39 | + from wp46.preprocessing import load_panel | ||||
| 40 | + js = JobSpec(**{k: v for k, v in job.items() if k in JobSpec.__dataclass_fields__}) | ||||
| 41 | + d = Path(out) / js.symbol | ||||
| 42 | + d.mkdir(parents=True, exist_ok=True) | ||||
| 43 | + fp = d / f"{js.spec_id}.parquet" | ||||
| 44 | + if fp.exists(): | ||||
| 45 | + return {"spec_id": js.spec_id, "symbol": js.symbol, "skipped": True} | ||||
| 46 | + t0 = time.perf_counter() | ||||
| 47 | + panel = load_panel(js.symbol) | ||||
| 48 | + F, G = run_job(panel, js) | ||||
| 49 | + F.to_parquet(fp, index=False) | ||||
| 50 | + G.to_parquet(d / f"{js.spec_id}.fits.parquet", index=False) | ||||
| 51 | + ru = resource.getrusage(resource.RUSAGE_SELF) | ||||
| 52 | + return {"spec_id": js.spec_id, "symbol": js.symbol, "n_origins": int(len(F)), "n_fits": int(len(G)), | ||||
| 53 | + "status_counts": F["status"].value_counts().to_dict() if len(F) else {}, | ||||
| 54 | + "fit_status_counts": G["status"].value_counts().to_dict() if len(G) else {}, | ||||
| 55 | + "wall_s": time.perf_counter() - t0, "cpu_s": ru.ru_utime + ru.ru_stime, "maxrss_mb": ru.ru_maxrss / (1024 ** 2 if platform.system() == "Darwin" else 1024), | ||||
| 56 | + "fit_time_total_s": float(G["time_s"].sum()) if len(G) else 0.0, "fc_time_total_s": float(F["time_fc_s"].sum()) if "time_fc_s" in F else 0.0} | ||||
| 57 | + | ||||
| 58 | + | ||||
| 59 | +def main() -> None: | ||||
| 60 | + ap = argparse.ArgumentParser() | ||||
| 61 | + ap.add_argument("--jobs", required=True) | ||||
| 62 | + ap.add_argument("--shard", default="0/1") | ||||
| 63 | + ap.add_argument("--workers", type=int, default=max(1, os.cpu_count() - 2)) | ||||
| 64 | + ap.add_argument("--out", default=str(ROOT / "results" / "forecasts")) | ||||
| 65 | + a = ap.parse_args() | ||||
| 66 | + jobs = json.loads(Path(a.jobs).read_text()) | ||||
| 67 | + i, n = map(int, a.shard.split("/")) | ||||
| 68 | + jobs = [j for k, j in enumerate(jobs) if k % n == i] | ||||
| 69 | + import arch, numpy, scipy, pandas | ||||
| 70 | + meta = {"git_sha": git_sha(), "host": socket.gethostname(), "python": platform.python_version(), "arch": arch.__version__, | ||||
| 71 | + "numpy": numpy.__version__, "scipy": scipy.__version__, "pandas": pandas.__version__, "machine": platform.machine(), | ||||
| 72 | + "cpu_count": os.cpu_count(), "shard": a.shard, "n_jobs": len(jobs), "started": time.strftime("%Y-%m-%dT%H:%M:%S%z")} | ||||
| 73 | + Path(a.out).mkdir(parents=True, exist_ok=True) | ||||
| 74 | + log = Path(a.out) / "_runs.jsonl" | ||||
| 75 | + print(json.dumps(meta), flush=True) | ||||
| 76 | + done = 0 | ||||
| 77 | + t0 = time.time() | ||||
| 78 | + with ProcessPoolExecutor(a.workers) as ex: | ||||
| 79 | + futs = {ex.submit(run_one, j, a.out): j for j in jobs} | ||||
| 80 | + for f in as_completed(futs): | ||||
| 81 | + j = futs[f] | ||||
| 82 | + try: | ||||
| 83 | + rec = f.result() | ||||
| 84 | + except Exception as e: # noqa: BLE001 | ||||
| 85 | + rec = {"spec_id": j.get("model_id"), "symbol": j.get("symbol"), "error": f"{type(e).__name__}: {str(e)[:200]}"} | ||||
| 86 | + rec.update({"git_sha": meta["git_sha"], "host": meta["host"], "ts": time.strftime("%Y-%m-%dT%H:%M:%S%z")}) | ||||
| 87 | + with open(log, "a") as fh: | ||||
| 88 | + fh.write(json.dumps(rec) + "\n") | ||||
| 89 | + done += 1 | ||||
| 90 | + if done % 10 == 0 or "error" in rec: | ||||
| 91 | + print(f"[{done}/{len(jobs)} {time.time()-t0:7.0f}s] {rec.get('symbol')} {rec.get('spec_id')} {rec.get('error','') or rec.get('wall_s','')}", flush=True) | ||||
| 92 | + print("done", done, "jobs in", round(time.time() - t0), "s") | ||||
| 93 | + | ||||
| 94 | + | ||||
| 95 | +if __name__ == "__main__": | ||||
| 96 | + main() | ||||
modified
src/wp46/preprocessing/panel.py
+12 −2
@@ -28,7 +28,9 @@ from wp46.findata_client.ingest import DAILY_FOR, DATASET_FOR, cache_root | |||||
| 28 | from wp46.realized_measures import MEASURE_COLUMNS, session_measures | 28 | from wp46.realized_measures import MEASURE_COLUMNS, session_measures | ||
| 29 | 29 | ||||
| 30 | PANEL_COLUMNS = ["session", "close", "open", "r", "r_on", "r_oc", "valid_rm", "expected_bars"] + MEASURE_COLUMNS | 30 | PANEL_COLUMNS = ["session", "close", "open", "r", "r_on", "r_oc", "valid_rm", "expected_bars"] + MEASURE_COLUMNS | ||
| 31 | −EXPECTED = {"futures": 1380, "fx": 1440, "crypto": 1440} | 31 | +EXPECTED = {"futures": 1380, "fx": 1440, "crypto": 1440} # nominal; replaced by the instrument's modal bar count (D-05) | ||
| 32 | +RM_VALID_FROM = {"crypto": "2020-01-01"} # D-06: crypto 1-minute bars before 2020 are contaminated by cross-venue bounce | ||||
| 33 | + # (audit: 1-min RV 10-100x the squared daily return in 2013-2019) -> no realized measure | ||||
| 32 | 34 | ||||
| 33 | 35 | ||||
| 34 | def _read_cache(dataset_id: str, symbol: str, cols: list[str]) -> pd.DataFrame: | 36 | def _read_cache(dataset_id: str, symbol: str, cols: list[str]) -> pd.DataFrame: | ||
@@ -100,12 +102,20 @@ def build_daily_panel(asset_class: str, symbol: str) -> pd.DataFrame: | |||||
| 100 | for c in MEASURE_COLUMNS + ["expected_bars", "valid_rm"]: | 102 | for c in MEASURE_COLUMNS + ["expected_bars", "valid_rm"]: | ||
| 101 | out[c] = ir[c] | 103 | out[c] = ir[c] | ||
| 102 | # drop stub sessions (Sunday evenings, holiday fragments): they are not trading days for the daily model | 104 | # drop stub sessions (Sunday evenings, holiday fragments): they are not trading days for the daily model | ||
| 103 | − out = out[out["n_bars"] >= 0.25 * out["expected_bars"]] | 105 | + modal = int(out["n_bars"].round(-1).mode().iloc[0]) | ||
| 106 | + out = out[out["n_bars"] >= 0.25 * modal] | ||||
| 104 | out["r"] = 100.0 * np.log(out["close"] / out["close"].shift(1)) | 107 | out["r"] = 100.0 * np.log(out["close"] / out["close"].shift(1)) | ||
| 105 | out["r_on"] = 100.0 * np.log(out["open"] / out["close"].shift(1)) | 108 | out["r_on"] = 100.0 * np.log(out["open"] / out["close"].shift(1)) | ||
| 106 | out.index.name = "session" | 109 | out.index.name = "session" | ||
| 107 | out = out.iloc[1:] # first return undefined | 110 | out = out.iloc[1:] # first return undefined | ||
| 111 | + if asset_class not in ("etf", "stock"): | ||||
| 112 | + # D-05: expected bars = modal session length of THIS instrument (grains trade ~12.5 h, metals ~22 h, FX 24 h) | ||||
| 113 | + modal = int(out["n_bars"].round(-1).mode().iloc[0]) | ||||
| 114 | + out["expected_bars"] = modal | ||||
| 115 | + out["valid_rm"] = out["n_bars"] >= MIN_FRACTION * modal | ||||
| 108 | out["valid_rm"] = out["valid_rm"] & np.isfinite(out["rv_5m_ss"]) & (out["rv_5m_ss"] > 0) | 116 | out["valid_rm"] = out["valid_rm"] & np.isfinite(out["rv_5m_ss"]) & (out["rv_5m_ss"] > 0) | ||
| 117 | + if asset_class in RM_VALID_FROM: | ||||
| 118 | + out.loc[out.index < pd.Timestamp(RM_VALID_FROM[asset_class]), "valid_rm"] = False | ||||
| 109 | return out[PANEL_COLUMNS[1:]].reset_index() | 119 | return out[PANEL_COLUMNS[1:]].reset_index() | ||
| 110 | 120 | ||||
| 111 | 121 | ||||
added
tests/__init__.py
+0 −0
added
tests/conftest.py
+4 −0
@@ -0,0 +1,4 @@ | |||||
| 1 | +import sys | ||||
| 2 | +from pathlib import Path | ||||
| 3 | + | ||||
| 4 | +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) | ||||
added
tests/integration/test_rolling_driver.py
+38 −0
@@ -0,0 +1,38 @@ | |||||
| 1 | +import numpy as np | ||||
| 2 | +import pandas as pd | ||||
| 3 | + | ||||
| 4 | +from wp46.estimation import JobSpec, run_job | ||||
| 5 | + | ||||
| 6 | + | ||||
| 7 | +def synthetic_panel(T=1400, seed=0): | ||||
| 8 | + rng = np.random.default_rng(seed) | ||||
| 9 | + s = np.empty(T); r = np.empty(T); s[0] = 1.0 | ||||
| 10 | + for t in range(T): | ||||
| 11 | + if t > 0: | ||||
| 12 | + s[t] = 0.05 + 0.08 * r[t - 1] ** 2 + 0.9 * s[t - 1] | ||||
| 13 | + r[t] = np.sqrt(s[t]) * rng.standard_normal() | ||||
| 14 | + rv = s * rng.lognormal(0, 0.3, T) | ||||
| 15 | + dates = pd.bdate_range("2010-01-04", periods=T) | ||||
| 16 | + return pd.DataFrame({"session": dates, "r": r, "r_on": np.zeros(T), "rv_5m_ss": rv, "rv_5m": rv, "rv_1m": rv, "bv_5m": rv, | ||||
| 17 | + "medrv_5m": rv, "valid_rm": True, "close": 100.0, "open": 100.0, "r_oc": r, "expected_bars": 391}) | ||||
| 18 | + | ||||
| 19 | + | ||||
| 20 | +def test_driver_refit_cadence_and_outputs(): | ||||
| 21 | + p = synthetic_panel() | ||||
| 22 | + F, G = run_job(p, JobSpec("SYN", "garch11", "normal", "A", window=1000, refit_every=5, oos_start="2013-01-01", oos_end="2016-12-31")) | ||||
| 23 | + assert (F.status == "ok").all() | ||||
| 24 | + assert len(G) == int(np.ceil(len(F) / 5)) | ||||
| 25 | + assert np.all(F.h5 > F.h1) and np.all(F.h22 > F.h5) | ||||
| 26 | + # origins strictly after the first `window` observations | ||||
| 27 | + assert F.origin.min() > p.session.iloc[999] | ||||
| 28 | + | ||||
| 29 | + | ||||
| 30 | +def test_driver_tier_b_and_failure_flags(): | ||||
| 31 | + p = synthetic_panel() | ||||
| 32 | + F, G = run_job(p, JobSpec("SYN", "har_rv", "empirical", "B", window=1000, oos_start="2013-01-01", oos_end="2014-12-31")) | ||||
| 33 | + assert (F.status == "ok").all() and np.isfinite(F.h1).all() | ||||
| 34 | + # a missing return inside the window is reported as missing_input, never silently filled | ||||
| 35 | + p2 = p.copy(); p2.loc[1100, "r"] = np.nan | ||||
| 36 | + F2, _ = run_job(p2, JobSpec("SYN", "garch11", "normal", "A", window=1000, oos_start="2013-01-01", oos_end="2014-12-31")) | ||||
| 37 | + affected = (F2.origin >= p.session.iloc[1100]) & (F2.origin <= p.session.iloc[2099]) | ||||
| 38 | + assert (F2.status == "missing_input").sum() == int(affected.sum()) and affected.sum() > 0 | ||||
added
tests/replication/fixture_returns.csv
+3001 −0
Large diff (3,001 lines) is not loaded by default to keep the page fast.Load diff
added
tests/replication/rugarch_crosscheck.R
+28 −0
Large diff (28 lines) is not loaded by default to keep the page fast.Load diff
added
tests/replication/test_rugarch.py
+69 −0
Large diff (69 lines) is not loaded by default to keep the page fast.Load diff
added
tests/simulation/test_recovery.py
+89 −0
Large diff (89 lines) is not loaded by default to keep the page fast.Load diff
added
tests/unit/test_custom_models.py
+89 −0
Large diff (89 lines) is not loaded by default to keep the page fast.Load diff
added
tests/unit/test_distributions.py
+31 −0
Large diff (31 lines) is not loaded by default to keep the page fast.Load diff
added
tests/unit/test_scoring_and_panel.py
+53 −0
Large diff (54 lines) is not loaded by default to keep the page fast.Load diff