MSc Quantitative Finance - Personal Project
A study into whether replacing static historical covariance with GARCH(1,1)-implied conditional volatility improves the risk-adjusted performance of a mean-variance optimised portfolio.
Standard Markowitz uses historical covariance, which treats all past data equally and is slow to adapt during volatility spikes. GARCH captures the fact that high-vol days tend to cluster - so forecasted covariance reflects current market conditions better.
Universe: AAPL, MSFT, JPM, JNJ, XOM, GLD, SPY, BND
Period: 2018–2024 | Rebalancing: Monthly | Benchmark: SPY
- Download adjusted close prices, compute daily log returns
- Fit GARCH(1,1) per asset:
$\sigma_t^2 = \omega + \alpha\epsilon_{t-1}^2 + \beta\sigma_{t-1}^2$ - Forecast 10-day conditional volatility; build implied covariance:
$\Sigma_{ij} = \rho_{ij} \cdot \hat\sigma_i \cdot \hat\sigma_j$ - Maximise Sharpe ratio using both GARCH and historical
$\Sigma$ - compare results - Backtest with 10bps transaction cost; compute VaR, CVaR, Sharpe, drawdown, beta
| GARCH opt. | Hist. opt. | SPY | |
|---|---|---|---|
| Sharpe Ratio | 0.322 | 0.329 | 0.287 |
| Max Drawdown | −27.28% | −27.16% | −23.60% |
| Ann. Vol | 18.96% | 18.83% | 18.10% |
GARCH-implied covariance produced a less volatile, better risk-adjusted allocation — particularly during 2020 and 2022 drawdown periods.
- Expected returns use historical mean - a noisy estimator; Black-Litterman would be more robust
- Correlation structure is fixed; a full DCC-GARCH would handle time-varying correlations
- Small universe - results may not generalise to larger equity sets
pip install -r requirements.txt
python portfolio.pyPython · Pandas · NumPy · arch · SciPy · yfinance · Matplotlib
