Calculating Value at Risk (VaR) to manage financial risk of a portfolio using Monte Carlo Simulations in Python
VaR in Financial and Portfolio Risk Management?
VaR is an acronym of ‘Value at Risk’, and is a tool which is used by many firms and banks to establish the level of financial risk within its firm. The VaR is calculated for an investments of a company’s investments or perhaps for checking the riks levels of a portfolio managed by the wealth management branch of a bank or a boutique firm.
The calculation may be thought of as a statistical measure in isolation. It can also be simplified to the following example statement –
VaR is the minimum loss which will be incurred at a certain level of probability (confidence interval) OR the maximum loss which will be realized at a level of probability.
The above image shows the maximum loss which can be faced by a company at a α% confidence. On a personal level VaR can help you predict or analyse the maximum losses which your portfolio is likely to face — this is something which we will analyse soon.
Monte Carlo Simulations
The Monte Carlo model was the brainchild of Stanislaw Ulam and John Neumann, who developed the model after the second world war. The model is named after a gambling city in Monaco, due to the chance and random encounters faced in gambling.
The Monte Carlo simulation is a probability model which generates random variables used in tandem with economic factors (expected return, volatility — in the case of a portfolio of funds) to predict outcomes over a large spectrum. While not the most accurate, the model is often used to calculate the risk and uncertainty.
We will now use the Monte Carlo simulation to generate a set of predicted returns for our portfolio of assets which will help us to find out the VaR of our investments.
Calculating VaR in Python
We will first set up the notebook by importing the required libraries and functions
#Importing all required libraries
#Created by Sanket Karve
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import pandas_datareader as web
from matplotlib.ticker import FuncFormatter
!pip install PyPortfolioOpt
#Installing the Portfolio Optimzation Library
from pypfopt.efficient_frontier import EfficientFrontier
from pypfopt import risk_models
from pypfopt import expected_returns
from matplotlib.ticker import FuncFormatter
For the purposes of our project, I have considered the ‘FAANG’ stocks for the last two years.
tickers = ['GOOGL','FB','AAPL','NFLX','AMZN']
thelen = len(tickers)
price_data = []
for ticker in range(thelen):
prices = web.DataReader(tickers[ticker], start='2018-06-20', end = '2020-06-20', data_source='yahoo')
price_data.append(prices[['Adj Close']])
df_stocks = pd.concat(price_data, axis=1)
df_stocks.columns=tickers
df_stocks.tail()
For the next step, we will calculated the portfolio weights of each asset. I have done this by using the asset weights calculated for achieving the maximum Sharpe Ratio. I have posted the snippets of the code for the calculation below.
#Annualized Return
mu = expected_returns.mean_historical_return(df_stocks)
#Sample Variance of Portfolio
Sigma = risk_models.sample_cov(df_stocks)
#Max Sharpe Ratio - Tangent to the EF
from pypfopt import objective_functions, base_optimizer
ef = EfficientFrontier(mu, Sigma, weight_bounds=(0,1)) #weight bounds in negative allows shorting of stocks
sharpe_pfolio=ef.max_sharpe()
#May use add objective to ensure minimum zero weighting to individual stocks
sharpe_pwt=ef.clean_weights()
print(sharpe_pwt)
The asset weights will be used to calculate the expected portfolio return.
#VaR Calculation
ticker_rx2 = []
#Convert Dictionary to list of asset weights from Max Sharpe Ratio Portfolio
sh_wt = list(sharpe_pwt.values())
sh_wt=np.array(sh_wt)
Now, we will convert the stock prices of the portfolio to a cumulative return, which may also be considered as the holding period returns (HPR)for this project.
for a in range(thelen):
ticker_rx = df_stocks[[tickers[a]]].pct_change()
ticker_rx = (ticker_rx+1).cumprod()
ticker_rx2.append(ticker_rx[[tickers[a]]])
ticker_final = pd.concat(ticker_rx2,axis=1)
ticker_final
#Plot graph of Cumulative/HPR of all stocks
for i, col in enumerate(ticker_final.columns):
ticker_final[col].plot()
plt.title('Cumulative Returns')
plt.xticks(rotation=80)
plt.legend(ticker_final.columns)
#Saving the graph into a JPG file
plt.savefig('CR.png', bbox_inches='tight')
Now, we will pick out the latest HPR of each asset and multiply the returns with the calculated asset weights using the .dot() function.
#Taking Latest Values of Return
pret = []
pre1 = []
price =[]
for x in range(thelen):
pret.append(ticker_final.iloc[[-1],[x]])
price.append((df_stocks.iloc[[-1],[x]]))
pre1 = pd.concat(pret,axis=1)
pre1 = np.array(pre1)
price = pd.concat(price,axis=1)
varsigma = pre1.std()
ex_rtn=pre1.dot(sh_wt)
print('The weighted expected portfolio return for selected time period is'+ str(ex_rtn))
#ex_rtn = (ex_rtn)**0.5-(1) #Annualizing the cumulative return (will not affect outcome)
price=price.dot(sh_wt) #Calculating weighted value
print(ex_rtn, varsigma,price)
Having calculated the expected portfolio return and the volatility (standard deviation of the expected returns), we will set up and run the Monte Carlo simulation. I have used a time of 1440 (no of minutes in a day) with 10,000 simulation runs. The time-steps may be changed per requirement. I have used a 95% confidence interval.
from scipy.stats import norm
import math
Time=1440 #No of days(steps or trading days in this case)
lt_price=[]
final_res=[]
for i in range(10000): #10000 runs of simulation
daily_return= (np.random.normal(ex_rtn/Time,varsigma/math.sqrt(Time),Time))
plt.plot(daily_returns)
plt.axhline(np.percentile(daily_returns,5), color='r', linestyle='dashed', linewidth=1)
plt.axhline(np.percentile(daily_returns,95), color='g', linestyle='dashed', linewidth=1)
plt.axhline(np.mean(daily_returns), color='b', linestyle='solid', linewidth=1)
plt.show()
Visualizing the distribution plot of the returns presents us with the following chart
plt.hist(daily_returns,bins=15)
plt.axvline(np.percentile(daily_returns,5), color='r', linestyle='dashed', linewidth=2)
plt.axvline(np.percentile(daily_returns,95), color='r', linestyle='dashed', linewidth=2)
plt.show()
Printing the exact values at both the upper limit and lower limit and assuming our portfolio value to be $1000, we will calculated an estimate of the amount of funds which should be kept to cover for our minimum losses.
print(np.percentile(daily_returns,5),np.percentile(daily_returns,95)) #VaR - Minimum loss of 5.7% at a 5% probability, also a gain can be higher than 15% with a 5 % probability
pvalue = 1000 #portfolio value
print('$Amount required to cover minimum losses for one day is ' + str(pvalue* - np.percentile(daily_returns,5)))
The resulting amount will signify the dollar amount required to cover your losses per day. The result can also be interpreted as the minimum losses that your portfolio will face with a 5% probability.
Conclusion
The method above has shown how we can calculate the Value at Risk (VaR) for our portfolio. For a refresher on calculating a portfolio for a certain amount of investment using the Modern Portfolio Thoery (MPT), will help to consolidate your understanding of portfolio analysis and optimization. Finally, the VaR, in tandem with Monte Carlo simulation model, may also be used to predict losses and gains via share prices. This can be done by multiplying the daily return values generated with the final price of the respective ticker.
All views expressed are my own. This article is not to be treated as expert investment advise.
Feel free to reach out to me on LinkedIn and drop me a message
Pingback: Automating Option Pricing Calculations | Sanket Karve