15 KiB
This code calculates Value at Risk (VaR) and Conditional Value at Risk (CVaR) for a portfolio of stocks. It uses historical stock data to compute returns, then scales these returns to simulate a portfolio's performance. It defines functions to calculate VaR and CVaR, both of which are measures of potential losses in a portfolio. The code also generates visualizations of these risk metrics to aid in financial risk assessment. This is practical for portfolio management and risk analysis in finance.
import numpy as np import pandas as pd import yfinance as yf
import matplotlib.pyplot as plt
Define a list of stock tickers representing the portfolio components
oex = ['MMM','T','ABBV','ABT','ACN','ALL','GOOGL','GOOG','MO','AMZN','AXP','AIG','AMGN','AAPL','BAC', 'BRK-B','BIIB','BLK','BA','BMY','CVS','COF','CAT','CVX','CSCO','C','KO','CL','CMCSA', 'COP','DHR','DUK','DD','EMC','EMR','EXC','XOM','META','FDX','F','GD','GE','GM','GILD', 'GS','HAL','HD','HON','INTC','IBM','JPM','JNJ','KMI','LLY','LMT','LOW','MA','MCD','MDT','MRK', 'MET','MSFT','MS','NKE','NEE','OXY','ORCL','PYPL','PEP','PFE','PM','PG','QCOM', 'SLB','SPG','SO','SBUX','TGT','TXN','BK','USB','UNP','UPS','UNH','VZ','V','WMT', 'WBA','DIS','WFC']
Count the number of stocks in the portfolio
num_stocks = len(oex)
Download historical stock data for the defined period
data = yf.download(oex, start='2014-01-01', end='2016-04-04')
Calculate daily returns and de-mean the returns by subtracting the mean
returns = data['Adj Close'].pct_change() returns = returns - returns.mean(skipna=True)
Plot the de-meaned returns for visualization
returns.plot(legend=None)
Define a function to scale weights so their absolute values sum to one
def scale(x): return x / np.sum(np.abs(x))
Generate random weights for the portfolio and scale them
weights = scale(np.random.random(num_stocks)) plt.bar(np.arange(num_stocks), weights)
Define a function to calculate Value at Risk (VaR)
def value_at_risk(value_invested, returns, weights, alpha=0.95, lookback_days=500): """Calculates Value at Risk (VaR) for a portfolio Parameters ---------- value_invested : float Total value of the portfolio returns : pd.DataFrame Historical returns of the portfolio components weights : np.ndarray Weights of each asset in the portfolio alpha : float, optional Confidence level for VaR, by default 0.95 lookback_days : int, optional Number of days to look back for historical data, by default 500 Returns ------- float The Value at Risk (VaR) at the specified confidence level """ # Fill missing values in returns with zero and calculate portfolio returns returns = returns.fillna(0.0) portfolio_returns = returns.iloc[-lookback_days:].dot(weights) # Calculate the VaR as the percentile of portfolio returns return np.percentile(portfolio_returns, 100 * (1 - alpha)) * value_invested
Define the total value invested in the portfolio
value_invested = 1000000
Calculate Value at Risk (VaR) using the defined function
value_at_risk(value_invested, returns, weights, alpha=0.95, lookback_days=520)
Define parameters for lookback days and confidence level
lookback_days = 500 alpha = 0.95
Calculate portfolio returns using historical data and weights
portfolio_returns = returns.fillna(0.0).iloc[-lookback_days:].dot(weights)
Calculate VaR and express it as a return rather than absolute loss
portfolio_VaR = value_at_risk(value_invested, returns, weights, alpha=0.95) portfolio_VaR_return = portfolio_VaR / value_invested
Plot histogram of portfolio returns and mark the VaR on the plot
plt.hist(portfolio_returns, bins=30) plt.axvline(portfolio_VaR_return, color='red', linestyle='solid') plt.legend(['VaR', 'Returns']) plt.title('Historical VaR') plt.xlabel('Return') plt.ylabel('Observation Frequency')
Define the number of iterations for VaR calculation and initialize an array
N = 1000 VaRs = np.zeros((N, 1))
Iterate to calculate VaR over different lookback windows
for i in range(N): VaRs[i] = value_at_risk(value_invested, returns, weights, lookback_days=i + 1)
Plot the VaR values over different lookback windows
plt.plot(VaRs) plt.xlabel('Lookback Window') plt.ylabel('VaR')
Define a function to calculate Conditional Value at Risk (CVaR)
def cvar(value_invested, returns, weights, alpha=0.95, lookback_days=500): """Calculates Conditional Value at Risk (CVaR) for a portfolio Parameters ---------- value_invested : float Total value of the portfolio returns : pd.DataFrame Historical returns of the portfolio components weights : np.ndarray Weights of each asset in the portfolio alpha : float, optional Confidence level for CVaR, by default 0.95 lookback_days : int, optional Number of days to look back for historical data, by default 500 Returns ------- float The Conditional Value at Risk (CVaR) at the specified confidence level """ # Calculate VaR and portfolio returns for the specified lookback period var = value_at_risk(value_invested, returns, weights, alpha, lookback_days=lookback_days) returns = returns.fillna(0.0) portfolio_returns = returns.iloc[-lookback_days:].dot(weights) var_pct_loss = var / value_invested # Calculate the mean of returns below the VaR threshold return np.nanmean(portfolio_returns[portfolio_returns < var_pct_loss]) * value_invested
Calculate CVaR using the defined function
cvar(value_invested, returns, weights, lookback_days=500)
Calculate VaR again for consistency
value_at_risk(value_invested, returns, weights, lookback_days=500)
Calculate portfolio returns using historical data and weights
lookback_days = 500
portfolio_returns = returns.fillna(0.0).iloc[-lookback_days:].dot(weights)
Calculate VaR and CVaR and express them as returns
portfolio_VaR = value_at_risk(value_invested, returns, weights) portfolio_VaR_return = portfolio_VaR / value_invested
portfolio_CVaR = cvar(value_invested, returns, weights) portfolio_CVaR_return = portfolio_CVaR / value_invested
Plot histogram of portfolio returns, marking VaR and CVaR on the plot
plt.hist(portfolio_returns[portfolio_returns > portfolio_VaR_return], bins=20) plt.hist(portfolio_returns[portfolio_returns < portfolio_VaR_return], bins=10) plt.axvline(portfolio_VaR_return, color='red', linestyle='solid') plt.axvline(portfolio_CVaR_return, color='red', linestyle='dashed') plt.legend(['VaR', 'CVaR', 'Returns', 'Returns < VaR']) plt.title('Historical VaR and CVaR') plt.xlabel('Return') plt.ylabel('Observation Frequency')
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.
