Files
strategy-lab/to_explore/pyquantnews/78_ValueAtRiskMonteCarlo.ipynb
David Brazda e3da60c647 daily update
2024-10-21 20:57:56 +02:00

10 KiB

No description has been provided for this image

This notebook simulates portfolio returns using Monte Carlo methods to estimate Value at Risk (VaR) and Conditional Value at Risk (CVaR). It begins by importing historical price data for various sectors, calculating daily returns, and determining portfolio statistics. The notebook then simulates portfolio returns over a specified number of days and simulations, using these to calculate VaR and CVaR. Finally, it visualizes the simulated portfolio paths and highlights the calculated risk metrics. This is useful for risk management and financial forecasting.

In [ ]:
import numpy as np
import pandas as pd
from openbb import obb

Define a list of sector symbols to analyze

In [ ]:
sectors = [
    "XLE", 
    "XLF", 
    "XLU", 
    "XLI", 
    "GDX", 
    "XLK", 
    "XLV", 
    "XLY", 
    "XLP", 
    "XLB", 
    "XOP", 
    "IYR", 
    "XHB", 
    "ITB", 
    "VNQ", 
    "GDXJ", 
    "IYE", 
    "OIH", 
    "XME", 
    "XRT", 
    "SMH", 
    "IBB", 
    "KBE", 
    "KRE", 
    "XTL", 
]

Fetch historical price data for the defined sectors from 2022-01-01 using yfinance

In [ ]:
data = obb.equity.price.historical(
    sectors, 
    start_date="2022-01-01", 
    provider="yfinance"
).to_df()

Calculate daily returns for each sector

In [ ]:
data["returns"] = data.groupby("symbol").close.pct_change()

Calculate mean daily returns and equal weights for each sector

In [ ]:
portfolio_stats = data.groupby("symbol").agg(
    daily_returns=("returns", "mean"),
)
In [ ]:
portfolio_stats["weights"] = 1 / len(sectors)

Compute the covariance matrix of the sector returns

In [ ]:
covariance_matrix = (
    data
    .pivot(
        columns="symbol", 
        values="returns"
    )
    .dropna()
    .cov()
)

Set up simulation parameters including number of simulations, days, and initial capital

In [ ]:
simulations = 1000
days = len(data.index.unique())
initial_capital = 100_000

Initialize an array to store portfolio values for each simulation

In [ ]:
portfolio = np.zeros((days, simulations))

Create an array filled with historical daily returns for each sector

In [ ]:
historical_returns = np.full(
    shape=(days, len(sectors)), 
    fill_value=portfolio_stats.daily_returns
)

Perform Cholesky decomposition on the covariance matrix to generate correlated random variables

In [ ]:
L = np.linalg.cholesky(covariance_matrix)

Run simulations to generate daily returns and simulate portfolio paths

In [ ]:
for i in range(0, simulations):
    Z = np.random.normal(size=(days, len(sectors)))
    daily_returns = historical_returns + np.dot(L, Z.T).T
    portfolio[:, i] = (
        np.cumprod(np.dot(daily_returns, portfolio_stats.weights) + 1) * initial_capital
    )

Convert simulated portfolio values into a DataFrame

In [ ]:
simulated_portfolio = pd.DataFrame(portfolio)

Set alpha level for VaR and CVaR calculations

In [ ]:
alpha = 5

Define function to calculate Monte Carlo VaR

In [ ]:
def montecarlo_var(alpha):
    """Calculate Monte Carlo Value at Risk (VaR).
    
    Parameters
    ----------
    alpha : float
        The confidence level for the VaR calculation.
    
    Returns
    -------
    float
        The VaR value at the given confidence level.
    """
    
    # Calculate the percentile of the simulated portfolio values at alpha level
    sim_val = simulated_portfolio.iloc[-1, :]
    return np.percentile(sim_val, alpha)

Define function to calculate Conditional VaR

In [ ]:
def conditional_var(alpha):
    """Calculate Conditional Value at Risk (CVaR).
    
    Parameters
    ----------
    alpha : float
        The confidence level for the CVaR calculation.
    
    Returns
    -------
    float
        The CVaR value at the given confidence level.
    """
    
    # Calculate the mean of the simulated portfolio values below the VaR threshold
    sim_val = simulated_portfolio.iloc[-1, :]
    return sim_val[sim_val <= montecarlo_var(alpha)].mean()

Calculate Monte Carlo VaR and Conditional VaR

In [ ]:
mc_var = montecarlo_var(alpha)
cond_var = conditional_var(alpha)

Plot the simulated portfolio paths and highlight VaR and CVaR

In [ ]:
ax = simulated_portfolio.plot(lw=0.25, legend=False)
ax.axhline(mc_var, lw=0.5, c="r")
ax.axhline(cond_var, lw=0.5, c="g")

PyQuant News is where finance practitioners level up with Python for quant finance, algorithmic trading, and market data analysis. Looking to get started? Check out the fastest growing, top-selling course to get started with Python for quant finance. For educational purposes. Not investment advise. Use at your own risk.