An object-oriented, Walk-Forward quantitative risk engine designed to estimate 99% Value at Risk (VaR) and 97.5% Expected Shortfall (ES) for a multi-asset portfolio.
This model bypasses the flawed assumption of normal, independent asset returns by implementing an asymmetric GJR-GARCH marginal volatility model and a Student-t Copula dependence structure to accurately capture volatility clustering and extreme tail-risk dependencies (simultaneous market crashes).
The pipeline strictly isolates marginal distributions from the dependence structure according to Sklar's Theorem.
- Marginal Volatility (GJR-GARCH): Each asset's daily returns are fitted to an ARMA(1,1) - GJR-GARCH(1,1,1) model assuming skewed Student-t innovations. The GJR-GARCH model captures the asymmetric "leverage effect" in financial markets, where negative shocks spike conditional volatility faster than positive shocks.
-
Dependence Structure (Student-t Copula):
Standardized residuals are converted to uniform variables via the Empirical CDF. The dependence structure is captured using a Multivariate Student-t Copula, optimized via Maximum Likelihood Estimation (MLE) to find the optimal degrees of freedom (
$\nu$ ), properly modeling heavy-tailed joint distributions. - Liquidity Penalty: Simulated returns are penalized using a dynamic bid-ask spread heuristic that widens as simulated shocks become more extreme.
The model evaluates out-of-sample predictions over a 2,350-day rolling window using stringent Basel Committee backtesting frameworks:
- Kupiec Proportion of Failures (POF) Test: An unconditional coverage test to verify that the observed 99% VaR breaches align mathematically with the 1% expectation.
- Christoffersen Independence Test: A conditional coverage test utilizing a First-Order Markov Chain transition matrix to penalize the model for consecutive breaches (volatility clustering failures).
-
main.py- The core orchestrator containing the OOP classes:-
MarketDataFeed: Handles YFinance ingestion and rolling window slicing. -
MarginalEngine: Fits the GJR-GARCH models and extracts residuals. -
StudentTCopula/GaussianCopula: Computes Kendall's Tau and simulates$N$ -dimensional uniform realities. -
RiskSimulator: Applies Inverse PIT,$t+1$ forecasts, and liquidity penalties. -
RegulatoryTesting: Evaluates the generated Risk Ledger against Kupiec and Christoffersen constraints.
-
- Clone the repository.
- Install dependencies:
pip install -r requirements.txt - Execute the engine:
python main.py - Input your desired portfolio value and asset weights when prompted.
Below is a truncated output from a complete 2,350-day Walk-Forward backtest (2013-2026) demonstrating the regulatory metrics.
------------------------------------------------------------------
USER INPUT FOR THE PORTFOLIO DETAILS
------------------------------------------------------------------
Enter the Portfolio value : 1000000
Weight of GLD in the portfolio : 0.1
Weight of SPY in the portfolio : 0.4
Weight of TLT in the portfolio : 0.4
Weight of USO in the portfolio : 0.1
Downloading historical data from 2013-01-01 to 2026-04-30...
[*********************100%***********************] 4 of 4 completed
Data extraction complete. Commencing Walk-Forward Simulation...
Walk-Forward Validation: 100%|██████████| 2350/2350 [58:53<00:00, 1.50s/it, Current Date=2026-04-29]
------------------------------------------------------------------
DETAILED INFO. ON VaR BREACHES
------------------------------------------------------------------
Total Trading Days : 2350
Expected Breaches : 23.50
Observed Breaches : 22
------------------------------------------------------------------
KUPIEC PROPORTION OF FAILURES (POF) TEST
------------------------------------------------------------------
Kupiec Likelihood Ratio (LR) : 0.0988
P-Value : 0.7533
BASEL GREEN ZONE
------------------------------------------------------------------
CHRISTOFFERSEN INDEPENDENCE TEST
------------------------------------------------------------------
Transition Matrix (No of Transitions):
Safe -> Safe : 2305 Safe -> Breach : 22
Breach -> Safe : 22 Breach -> Breach : 0
Christoffersen LR Statistic : 0.4160
P-Value : 0.5189
BASEL GREEN ZONE