When Does Precision Pay? Asymmetric Loss and the Economic Value of Machine-Learning Volatility Forecasts
Description
Replication package for When Does Complexity Pay? — a multi-asset volatility-forecasting pipeline covering S&P 500, Bitcoin, and clean-energy/carbon ETFs, with KRBN, SPYX, and PBW as robustness assets. main.py is the entry point, with four subcommands: screen (liquidity and proxy-validity screening, run first), run (main results), robust (rolling-window grid), and selftest (offline check on synthetic data). config.py holds all configuration — assets, transaction costs, window lengths, paths — and is the only file that should need editing. src/ contains the eight computation modules: data cleaning and the Garman–Klass proxy, market-efficiency diagnostics, the seven forecasting models (GARCH, EGARCH, GJR, HAR-RV, XGBoost, LSTM, Hybrid), statistical evaluation (DM, GW, MCS, and three VaR backtests), economic-value calculations, mechanism decomposition, and the table and figure writers. data/ holds raw yfinance dumps and cleaned series for six tickers. output.zip contains the produced results: forecast caches, 25 tables in CSV and LaTeX, six figures in PNG and PDF, and full run logs. requirements.txt lists the eleven dependencies.
Files
Steps to reproduce
Steps to reproduce Install dependencies into a clean Python environment: pip install -r requirements.txt. The heaviest requirements are tensorflow>=2.15, xgboost>=2.0, and arch>=6.2. Unzip output.zip in the project root so that output/ sits alongside main.py. This restores the forecast caches in output/cache/, which lets tables and figures regenerate in seconds instead of hours. To reproduce from scratch instead, skip this step or pass --force later to ignore the caches. Run the screening step first: python main.py screen. It reports, per ticker, the first valid date, median daily dollar volume, and two diagnostics for whether the range-based Garman–Klass proxy is usable. If Liquid reads NO for a ticker, that ticker must be dropped rather than patched. Output goes to output/tables/table0_screening.csv. Reproduce the main results: python main.py run. This covers the three core assets (SPX, BTC, ICLN) and writes every table and figure used in the main text. Add --all to include the robustness assets KRBN, SPYX, and PBW. Reproduce the window-sensitivity results: python main.py robust. This sweeps the rolling window over N = 500, 1000, and 1500, and is the slowest step. Verify the outputs. Tables land in output/tables/ as paired .csv and .tex files, figures in output/figures/ as 300 dpi PNG and PDF, and a full console transcript of each run in output/logs/. Nothing is ever written outside data/ and output/. Useful flags: --refresh re-downloads the raw data, --force ignores the forecast cache, --assets SPX,BTC restricts the run to a subset, --window 1500 overrides the rolling window, and --boot 2000 sets the number of Model Confidence Set replications. Runtime and determinism: a full cold run takes roughly 2 to 5 hours, dominated by refitting three GARCH variants every five steps across about 3,000 test days per asset. All random seeds are fixed at 42, so the XGBoost and bootstrap results are exactly reproducible; LSTM and Hybrid figures may differ in the last decimal places across TensorFlow versions or GPU/CPU backends, which is expected. For an offline sanity check that needs no network access and finishes in minutes, run python main.py selftest — but note it writes synthetic results into output/, so use a scratch copy of the folder.
Institutions
- Monash UniversityVictoria, Melbourne