CSE 8803 IUQ, Spring 2026, Georgia Tech. Authors: Agam Saraf, Shrey Patel, Alexander Coles.
This repository implements the OUU pipeline described in
deliverables/Final_Report.pdf: a Mean-CVaR portfolio optimiser whose scenario
generator is a conditional Neural Spline Flow (NSF) trained on 10 years of
S&P 500 daily returns. The frontier model adds a 12-component PCA
projection and a rolling-correlation context channel, fixing the
calibration failure modes diagnosed in the baseline.
.
|-- src/
| |-- data_module.py # yfinance + FRED loader, train/test/COVID split
| |-- models.py # build_realnvp_flow, build_nsf_flow (conditional)
| |-- baselines.py # Gaussian + Ledoit-Wolf Mean-CVaR baseline
| `-- evaluator.py # cvar5, sharpe, VIX bins, portfolio_metrics
|-- scripts/
| |-- train_baseline_nsf.py # 1) Train + evaluate the baseline NSF
| |-- calibrate_baseline.py # 2) Realised vs predicted CVaR / vol / coverage
| |-- bootstrap_ci_baseline.py # 3) Paired-bootstrap CIs for baseline NSF
| |-- train_pca_frontier.py # 4) Train PCA + corr NSF, run all final analyses
| |-- evaluate_cv_windows.py # 5) 4-window expanding-CV stress test
| `-- make_report_figures.py # 6) Build the head-to-head figures used in the report
|-- results/
| |-- *.csv # All numeric outputs used in the report
| `-- figures/*.png # All figures rendered by the scripts
|-- deliverables/ # Final Report and Presentation PDFs
|-- checkpoints/ # Trained NSF / PCA-NSF weights and stats
|-- requirements.txt
`-- README.md
The full pipeline runs on CPU in well under an hour. With Python 3.10+:
pip install -r requirements.txt
# (1) Baseline NSF: trains, optimises Mean-CVaR portfolio, saves weights
python scripts/train_baseline_nsf.py
# (2) Per-bin reliability of CVaR, volatility and 95% PI coverage
python scripts/calibrate_baseline.py
# (3) Paired-bootstrap 95% CIs for Sharpe / CVaR (Gaussian, NSF static, NSF adaptive)
python scripts/bootstrap_ci_baseline.py
# (4) Frontier model: PCA + corr NSF, full reliability + bootstrap including PCA
python scripts/train_pca_frontier.py
# (5) Head-to-head report figures (correlation, vol ratio, coverage, CVaR)
python scripts/make_report_figures.pyStep (4) is the canonical command for the main results: it trains the frontier flow, generates regime-adaptive weights, computes per-day predictive intervals, builds the Gaussian counterfactual table, and runs the 3-model paired bootstrap. Step (5) regenerates the cross-model comparison figures used in the report from the saved CSVs.
The 4-window expanding cross-validation (used as ablation A2 in the report) is regenerated by:
python scripts/evaluate_cv_windows.pyAll scripts use seed=42 and write to results/. Existing checkpoints
under checkpoints/ are overwritten on retraining.
| Model | Sharpe (95% CI) | CVaR_5 (%) | Coverage at VIX>=30 | Crisis corr (pred / real) |
|---|---|---|---|---|
| Gaussian | 0.68 [-0.69, 2.13] | -1.67 [-2.07, -1.32] | n/a | 0.05 / 0.66 |
| NSF (baseline) | 0.95 [-0.42, 2.37] | -1.57 [-2.03, -1.22] | 20.0% | 0.05 / 0.66 |
| NSF (PCA + corr) | 0.52 [-0.88, 1.90] | -2.28 [-2.79, -1.82] | 80.0% | 0.65 / 0.66 |
Sharpe differences are not statistically significant under N=10,000 paired bootstrap (p > 0.25 in every comparison). The PCA + corr flow's gains are concentrated in calibration: the predicted-vs-realised correlation gap drops from 0.61 to 0.01 at VIX >= 30, and overall 95% predictive interval coverage rises from 80.6% to 97.6%.
See deliverables/Final_Report.pdf for the full discussion, including the
calibration-Sharpe trade-off and the Gaussian counterfactual table.
- Equity prices: 30 S&P 500 stocks, 11 GICS sectors (Appendix A of the
report). Downloaded at runtime via
yfinance.download(period="10y")(adjusted close). - VIX: CBOE VIX close, downloaded at runtime from the FRED CSV endpoint
(
VIXCLS).
The COVID-19 crash window 2020-02-15 to 2020-05-01 (52 trading days) is removed from training and held aside for the OOD backtest.
A read-only copy lives at
https://github.gatech.edu/Acoles6/market-shocks-class. The instructor
pchen402 and TA psi6 have been added as collaborators.