Calculate Value at Risk (VaR) Using the Monte Carlo Method with Python
In this blog post, we will demonstrate how to perform a Value at Risk (VaR) simulation for a portfolio of stocks using Python and the yfinance
library. We will use historical stock prices to calculate the expected return and standard deviation of the portfolio, and then run a Monte Carlo simulation to estimate the VaR.
Importing Libraries
import numpy as np
import pandas as pd
import datetime as dt
import yfinance as yf
import matplotlib.pyplot as plt
from scipy.stats import norm
We begin by importing the necessary libraries: numpy
, pandas
, datetime
, yfinance
, matplotlib
, and scipy.stats
.
Setting Time Range and Ticker List
### Set time from to a certain number of years
years = 15
endDate = dt.datetime.now()
startDate = endDate - dt.timedelta(days = 365*years)
### Create a list of tickers
tickers = ['SPY','BND','GLD','QQQ','VTI']
In this section, we set the time range for our historical data to 15 years and create a list of stock tickers for our portfolio.
Downloading Adjusted Close Prices
### Download the daily adjusted close prices for the tickers
adj_close_df = pd.DataFrame()
for ticker in tickers:
data = yf.download(ticker, start = startDate, end = endDate)
adj_close_df[ticker] = data['Adj Close']
print(adj_close_df)
Next, we download the daily adjusted close prices for each stock ticker using the yfinance
library and store the data in a DataFrame.
Calculating Daily Log Returns
### Calculate the daily log returns and drop any NAs
log_returns = np.log(adj_close_df/adj_close_df.shift(1))
log_returns = log_returns.dropna()
print(log_returns)
We calculate the daily log returns for each stock in our portfolio and drop any missing values.
Defining Functions to Calculate Portfolio Expected Return and Standard Deviation
### Create a function that will be used to calculate portfolio expected return
*We are assuming that future returns are based on past returns, which is not a reliable assumption.
def expected_return(weights, log_returns):
return np.sum(log_returns.mean()*weights)
### Create a function that will be used to calculate portfolio standard deviation
def standard_deviation (weights, cov_matrix):
variance = weights.T @ cov_matrix @ weights
return np.sqrt(variance)
We define two functions, expected_return()
and standard_deviation()
, which will be used to calculate the expected return and standard deviation of our portfolio, respectively.
Creating a Covariance Matrix
### Create a covariance matrix for all the securities
cov_matrix = log_returns.cov()
print(cov_matrix)
We create a covariance matrix for all the securities in our portfolio using the daily log returns.
Calculating Portfolio Expected Return and Standard Deviation
### Create an equally weighted portfolio and find total portfolio expected return and standard deviation
portfolio_value = 1000000
weights = np.array([1/len(tickers)]*len(tickers))
portfolio_expected_return = expected_return(weights, log_returns)
portfolio_std_dev = standard_deviation (weights, cov_matrix)
We create an equally weighted portfolio and calculate the portfolio’s expected return and standard deviation using the functions we defined earlier.
Defining Functions for Monte Carlo Simulation
def random_z_score():
return np.random.normal(0, 1)
### Create a function to calculate scenarioGainLoss
days = 20
def scenario_gain_loss(portfolio_value, portfolio_std_dev, z_score, days):
return portfolio_value * portfolio_expected_return * days + portfolio_value * portfolio_std_dev * z_score * np.sqrt(days)
We define two functions: random_z_score()
and scenario_gain_loss()
. The first function generates a random Z-score based on a normal distribution, and the second function calculates the gain or loss for a given scenario.
Running Monte Carlo Simulation
### Run 10000 simulations
simulations = 10000
scenarioReturn = []
for i in range(simulations):
z_score = random_z_score()
scenarioReturn.append(scenario_gain_loss(portfolio_value, portfolio_std_dev, z_score, days))
We run 10,000 Monte Carlo simulations, calculating the scenario gain/loss for each simulation and storing the results in a list.
Calculating Value at Risk (VaR)
### Specify a confidence interval and calculate the Value at Risk (VaR)
confidence_interval = 0.99
VaR = -np.percentile(scenarioReturn, 100 * (1 - confidence_interval))
print(VaR)
We specify a confidence interval of 99% and calculate Value at Risk (VaR) using the results of our simulations.
Plotting the Results
### Plot the results of all 10000 scenarios
plt.hist(scenarioReturn, bins=50, density=True)
plt.xlabel('Scenario Gain/Loss ($)')
plt.ylabel('Frequency')
plt.title(f'Distribution of Portfolio Gain/Loss Over {days} Days')
plt.axvline(-VaR, color='r', linestyle='dashed', linewidth=2, label=f'VaR at {confidence_interval:.0%} confidence level')
plt.legend()
plt.show()
Finally, we create a histogram to visualize the distribution of portfolio gain/loss over the specified number of days. We also add a vertical dashed line to indicate the VaR at our chosen confidence level.
Conclusion
This blog post has demonstrated how to calculate Value at Risk (VaR) for a portfolio of stocks using Python and its powerful libraries such as numpy, pandas, yfinance, matplotlib, and scipy. By running Monte Carlo simulations, we have estimated the potential loss in our portfolio over a specified number of days and at a given confidence level. This information can be invaluable for investors and portfolio managers when assessing the risk associated with their investment decisions.