Monte Carlo Portfolio Risk Engine cover

Monte Carlo Portfolio Risk Engine

A Python-based risk simulation framework for a three-asset portfolio. It quantifies tail risk across market regimes using VaR, Expected Shortfall, and scenario analysis, built from scratch on historical data with a full parameter estimation pipeline.

Project type: Quantitative Risk Assets: S&P 500 · Gold · VIX Simulations: 10,000 Horizon: 252 days Methods: VaR · ES · Scenario Analysis Tools: Python · NumPy · pandas

Key Takeaways

What the model does

  • Runs 10,000 correlated return paths for a 60/25/15 portfolio of S&P 500, Gold, and VIX over a one-year horizon.
  • Computes VaR and Expected Shortfall at 95% and 99% confidence, then stress-tests those figures across three distinct market regimes.
  • Includes a full parameter estimation script that reads the historical dataset and calibrates all inputs from scratch.

Main finding

  • Under base conditions, VaR 95% is only −4.1%. In the stress scenario it reaches −68.9%, a 17× deterioration driven purely by regime change.
  • The average loss in the worst 5% of base-case simulations is nearly six times the VaR 95% threshold, revealing a tail structure that summary statistics miss entirely.
  • VIX is the dominant driver of both the portfolio's extreme upside and its fat-tailed downside.

Disclaimer: this is an educational project and does not constitute investment advice.

Overview: Why This Portfolio, Why This Model

Most discussions of portfolio risk stop at annualized volatility. It is a useful number, but it tells you nothing about the shape of the distribution: whether tail losses are symmetric or skewed, moderate or catastrophic, and how much the picture changes when market conditions shift. This project was built to answer exactly those questions.

The portfolio chosen for the analysis, 60% S&P 500, 25% Gold and 15% VIX, is deliberately unconventional. Including VIX as a direct portfolio component creates a risk profile that is genuinely difficult to read from static statistics. VIX is mean-reverting, highly non-normal, and dominated by spike behavior during crises. A Monte Carlo simulation run across multiple regimes is one of the few tools that makes this kind of distribution visible in a meaningful way.

The model is built end to end in Python. It starts from raw historical price data, runs a parameter estimation step to calibrate all inputs, and generates 10,000 correlated return paths using a multivariate normal distribution. Both central tendency and tail risk metrics are then derived from the resulting distribution. Scenario analysis tests whether the conclusions hold when market conditions change. As the results show, they do not hold at all.

Part 1: Data and Inputs

The simulation is calibrated on daily historical price data covering January 2015 through late 2024, approximately 2,140 trading days in total. Returns are computed as simple daily percentage changes. Mean returns and the full covariance matrix are estimated from this sample using estimate_params.py, which reads the Excel dataset and exports all parameters to CSV for verification before the simulation runs.

Estimated Daily Parameters

AssetDaily Mean ReturnDaily VolatilityRole in PortfolioWeight
S&P 5000.14%~4.4%Core equity exposure60%
Gold0.15%~4.7%Defensive layer25%
VIX2.25%~25.5%Volatility overlay / tail hedge15%

The 2.25% daily mean for VIX is a statistical artifact of large historical spikes, not a genuine return expectation. See Part 4 for a full discussion.

Correlation Structure

The covariance matrix is the most consequential input. It governs how asset returns move together and ultimately shapes the tail risk profile more than any individual asset's mean return. Two figures stand out.

PairCorrelationImplication
S&P 500 / Gold+0.39 Moderate positive. Gold provides less diversification than most investors assume. The defensive benefit exists, but it is partial.
S&P 500 / VIX−0.54 Strong inverse. VIX reliably gains when equities fall, which is the structural hedge the allocation is built around.
Gold / VIX+0.002 Essentially uncorrelated. The two defensive assets provide independent risk contributions within the portfolio.

All correlations estimated from the full 2015–2024 sample. Daily figures.

The +0.39 correlation between S&P 500 and Gold is worth pausing on. Many investors treat Gold as a near-zero or negative correlation asset relative to equities. Over this sample period, that assumption does not hold. The relationship is meaningfully positive, which reduces the diversification benefit from the Gold allocation compared to what a naive assumption would suggest. The VIX correlation behaves exactly as expected: strongly negative and consistent throughout.

Part 2: Methodology

2.1 Multivariate Normal Simulation

The simulation draws 10,000 joint return scenarios from a multivariate normal distribution parameterized by the estimated mean vector and covariance matrix. For each scenario, 252 daily return vectors are generated, one per trading day, preserving the full correlation structure at every step. Portfolio daily returns are the weighted sum of asset returns, and portfolio value paths are built by compounding from a normalized starting value of 1.0.

V_t = V_0 × ∏(1 + r_p,t)   for t = 1 … 252
r_p,t = w_SP500 × r_SP500,t + w_Gold × r_Gold,t + w_VIX × r_VIX,t
[r_SP500,t, r_Gold,t, r_VIX,t] ~ N(μ, Σ)

The final portfolio value at day 252 is recorded for each of the 10,000 paths, producing the distribution from which all risk metrics are derived. Using 10,000 paths ensures that even the 1st-percentile estimates are based on 100 data points, making VaR 99% numerically stable. This is a meaningful improvement over the 100-path Excel prototype built earlier in the project, where a single outlier path could move the VaR 99% figure by several percentage points.

2.2 Scenario Construction

Three scenarios are tested by modifying the simulation inputs. Rather than imposing arbitrary price shocks, the approach models changes to the statistical properties of returns directly, which is more consistent with how risk regimes actually shift in financial markets.

ScenarioCovariance scalingMean return adjustmentImplied volatility change
Base1.0× (unchanged)NoneBaseline
High Volatility1.5×None+22% (= √1.5)
Stress2.0×−0.2 pp/day+41% (= √2)

Scaling the covariance matrix by k increases variances by k, so volatilities increase by √k. A 1.5× covariance scale means roughly +22% volatility, not +50%.

The mean return adjustment in the stress scenario (−0.2 pp/day) is aggressive by design. Over 252 trading days it represents roughly −40 percentage points of annualized expected return, consistent with a prolonged deterioration in fundamentals rather than a short-term shock. Combined with doubled covariances, this is what produces the near-total drawdown scenarios visible at the left tail of the stress distribution.

2.3 Risk Metrics

Two families of tail risk metrics are computed at both 95% and 99% confidence levels.

Value at Risk (VaR) is the percentile threshold of the final return distribution. VaR 95% is the 5th percentile, the level below which only 5% of simulated outcomes fall. It answers one question: what is the minimum loss in the worst 5% of scenarios? It says nothing about how bad things get once you are inside that tail.

Expected Shortfall (ES), also called Conditional VaR, is the average return across all simulations that fall below the VaR threshold. Given that you are in the worst 5% of scenarios, ES tells you how bad it is on average. It is the more conservative and more informative measure for portfolios with fat-tailed distributions. A large gap between VaR and ES is itself a risk signal: the tail is not just long, it is heavy.

Part 3: Results

3.1 Full Results Table

MetricBaseHigh VolatilityStress
Mean Final Return+217.4%+217.9%+93.0%
Median Final Return+164.9%+141.8%+33.0%
Std of Final Return213.1%271.7%203.8%
Min Final Return−76.8%−84.8%−94.8%
Max Final Return+2,716.6%+4,510.6%+2,808.2%
VaR 95%−4.1%−29.4%−68.9%
VaR 99%−35.8%−54.5%−82.3%
ES 95%−23.9%−45.0%−77.1%
ES 99%−47.7%−63.3%−86.5%

All figures represent final portfolio returns after 252 trading days. Stress scenario values highlighted in red.

3.2 Base Scenario

The base scenario produces a mean final return of +217.4% and a median of +164.9% over the year. The gap between these two figures is the first diagnostic signal: the distribution is right-skewed, with a small number of extreme upside paths pulling the mean well above the central outcome. The standard deviation of 213.1% reflects an exceptionally wide distribution. It does not look like a bell curve, even though the simulation draws from a normal at the daily level. A year of compounding transforms daily normality into annual non-normality.

Annualized portfolio volatility implied by the simulation is approximately 60.8%, well above the 12–20% range typical of diversified equity portfolios. The driver is VIX. With a daily standard deviation of roughly 25.5%, it dominates the portfolio's variance even at a 15% weight because its volatility is nearly six times that of the equity component.

The base case VaR 95% of −4.1% sounds reassuring: 95% of simulations end without losing more than 4.1% over the year. The ES 95% of −23.9% immediately qualifies that reading. Once you are in the worst 5% of outcomes, the average loss is nearly 24%. The average tail loss is nearly six times the entry point of the tail. That gap is the clearest sign of a fat-tailed distribution, and it is a direct consequence of holding VIX.

3.3 High Volatility and Stress Scenarios

The high-volatility scenario makes the regime-dependence of VaR impossible to ignore. Scaling covariances by 1.5× without touching expected returns pushes VaR 95% from −4.1% to −29.4%, more than seven times larger. ES 95% moves from −23.9% to −45.0%. The base-case risk figure offers almost no useful guidance once market volatility rises. This is the core limitation of VaR as a risk measure: it is calibrated to a specific regime and breaks down the moment that regime changes.

The stress scenario compounds the problem further. Adding a daily return penalty of −0.2 pp on top of doubled covariances pushes VaR 95% to −68.9% and ES 95% to −77.1%. The worst simulated outcome across 10,000 paths is −94.8%, near-total capital loss. Mean final return falls to +93% and the median collapses to +33%. Even the central outcome becomes modest and uncertain. The maximum of +2,808% confirms the distribution remains right-skewed; the issue is that the entire left tail has shifted dramatically to the downside.

The progression from base to stress illustrates the core principle this model was built to demonstrate. VaR is not a fixed number. It is a function of the market environment. A portfolio that looks reasonably hedged under normal conditions can carry extreme tail exposure once volatility rises, especially when it holds assets whose own volatility is regime-dependent.

Part 4: The Role of VIX

VIX is the unconventional element of this model and deserves its own discussion. It is not a conventional asset. You cannot buy it directly, its returns are mean-reverting, it exhibits strong jump behavior, and its historical mean return of +2.25% per day is a statistical artifact of large crisis spikes rather than a genuine drift. Knowing why it is included and what it actually contributes is essential to reading the results correctly.

The structural role of VIX in the portfolio is that of a convex hedge. It spikes sharply when equity markets fall, providing positive returns precisely when the 60% equity allocation is losing value. The −0.54 correlation with S&P 500 captures this relationship. In calm markets, VIX mean-reverts downward and acts as a drag on returns. In a crisis, it can more than offset equity losses. That asymmetric payoff structure is what makes the allocation defensible from a tail risk management perspective.

The practical limitation is significant. Modeling VIX returns with a multivariate normal distribution understates how extreme real-world spikes can be. During March 2020, VIX moved from roughly 15 to 85 in a matter of weeks, a move of more than 20 historical standard deviations. A normal simulation simply cannot generate that. The model produces plausible tail scenarios under ordinary stress, but will underestimate the severity of genuine market dislocations, which is exactly when the VIX allocation is most active. A Student-t copula or a regime-switching model for VIX would be the most impactful methodological extension of this framework.

Despite this limitation, the model correctly captures the structural effect. VIX is the primary source of both the portfolio's extreme upside scenarios (max final return of +2,716% in the base case) and its heavy-tailed downside distribution. The combination of a high observed mean and high variance produces the right-skewed, fat-tailed return distribution that appears consistently across all three scenarios.

Part 5: Project Files

The project is structured as a pipeline: parameter estimation feeds the simulation scripts, and unit tests verify the core risk functions independently of the simulation results. All scripts run from the same directory as the dataset.

FileDescription
estimate_params.py Reads financial_data_merged.xlsx and estimates mean returns, volatilities, and the full covariance matrix from the historical data. Exports all parameters to CSV. Run this first to verify inputs before executing the simulation scripts.
portfolio_monte_carlo_simulation.py Core simulation: generates 10,000 correlated return paths, builds portfolio value paths via compound growth, and computes VaR and ES at 95% and 99% confidence. Outputs a formatted summary table.
portfolio_scenarios_simulation.py Extends the simulation across Base, High Volatility, and Stress regimes. Runs all three scenarios sequentially and generates two comparison charts: distribution of final returns and risk metrics by scenario.
test_metrics.py Unit tests for the VaR and ES functions. Verifies that VaR 99% ≤ VaR 95%, ES ≤ VaR at both confidence levels, and that base-case VaR is negative. No test framework required; run directly with Python.
financial_data_merged.xlsx Historical daily prices for S&P 500, Gold, and VIX from January 2015 through late 2024. Includes pre-computed returns, summary statistics, and the Excel-based prototype (100 paths) built as an exploratory tool before the Python model was developed.

Recommended execution order: estimate_params.pyportfolio_monte_carlo_simulation.pyportfolio_scenarios_simulation.py. Unit tests can be run at any point independently.

Part 6: Limitations and Extensions

Three assumptions in the current model are meaningful simplifications of real market dynamics. They do not undermine the model's core purpose, but they are worth understanding clearly before extending the framework.

Distributional assumption

The multivariate normal assumption is a poor fit for VIX, which exhibits jump behavior and strong non-normality. A Student-t distribution or a copula-based approach would capture tail dependence more accurately and is the single most impactful methodological extension available.

Static covariance matrix

The covariance matrix is estimated from the full sample and held constant. In practice, volatility and correlation are time-varying, compressing in bull markets and spiking in crises. A DCC-GARCH framework would produce more realistic stress scenarios.

Fixed weights, no rebalancing

Weights are held at 60/25/15 throughout with no rebalancing and no transaction costs. The model is a buy-and-hold benchmark. Adding threshold-based rebalancing rules would be a straightforward and meaningful extension.

These are real constraints, but they do not undermine what the model is designed to show. The simulation makes visible how correlation structure shapes diversification, how tail metrics differ from central tendency measures, and how dramatically risk estimates change across volatility regimes. The specific numbers matter less than the structural relationships they reveal.

Read Also