daily update
This commit is contained in:
595
to_explore/pyquantnews/23_ConditionalValueAtRisk.ipynb
Normal file
595
to_explore/pyquantnews/23_ConditionalValueAtRisk.ipynb
Normal file
@ -0,0 +1,595 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "431b9977",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "937cf4f7",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"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."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5b1162c9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import pandas as pd\n",
|
||||
"import yfinance as yf"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b3d76629",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import matplotlib.pyplot as plt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b8b5d355",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Define a list of stock tickers representing the portfolio components"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9fd6d834",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"oex = ['MMM','T','ABBV','ABT','ACN','ALL','GOOGL','GOOG','MO','AMZN','AXP','AIG','AMGN','AAPL','BAC',\n",
|
||||
" 'BRK-B','BIIB','BLK','BA','BMY','CVS','COF','CAT','CVX','CSCO','C','KO','CL','CMCSA',\n",
|
||||
" 'COP','DHR','DUK','DD','EMC','EMR','EXC','XOM','META','FDX','F','GD','GE','GM','GILD',\n",
|
||||
" 'GS','HAL','HD','HON','INTC','IBM','JPM','JNJ','KMI','LLY','LMT','LOW','MA','MCD','MDT','MRK',\n",
|
||||
" 'MET','MSFT','MS','NKE','NEE','OXY','ORCL','PYPL','PEP','PFE','PM','PG','QCOM',\n",
|
||||
" 'SLB','SPG','SO','SBUX','TGT','TXN','BK','USB','UNP','UPS','UNH','VZ','V','WMT',\n",
|
||||
" 'WBA','DIS','WFC']"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2e00c960",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Count the number of stocks in the portfolio"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c5583926",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"num_stocks = len(oex)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "37a412ad",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Download historical stock data for the defined period"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c794c59a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"data = yf.download(oex, start='2014-01-01', end='2016-04-04')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "13db52ed",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Calculate daily returns and de-mean the returns by subtracting the mean"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c61098bd",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"returns = data['Adj Close'].pct_change()\n",
|
||||
"returns = returns - returns.mean(skipna=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ec932e56",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Plot the de-meaned returns for visualization"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f2d5ad90",
|
||||
"metadata": {
|
||||
"lines_to_next_cell": 1
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"returns.plot(legend=None)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "38d7b1de",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Define a function to scale weights so their absolute values sum to one"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "31ffb424",
|
||||
"metadata": {
|
||||
"lines_to_next_cell": 1
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def scale(x):\n",
|
||||
" return x / np.sum(np.abs(x))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "87766d95",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Generate random weights for the portfolio and scale them"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0884a511",
|
||||
"metadata": {
|
||||
"lines_to_next_cell": 1
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"weights = scale(np.random.random(num_stocks))\n",
|
||||
"plt.bar(np.arange(num_stocks), weights)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1f97cb07",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Define a function to calculate Value at Risk (VaR)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5bccf1c9",
|
||||
"metadata": {
|
||||
"lines_to_next_cell": 1
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def value_at_risk(value_invested, returns, weights, alpha=0.95, lookback_days=500):\n",
|
||||
" \"\"\"Calculates Value at Risk (VaR) for a portfolio\n",
|
||||
" \n",
|
||||
" Parameters\n",
|
||||
" ----------\n",
|
||||
" value_invested : float\n",
|
||||
" Total value of the portfolio\n",
|
||||
" returns : pd.DataFrame\n",
|
||||
" Historical returns of the portfolio components\n",
|
||||
" weights : np.ndarray\n",
|
||||
" Weights of each asset in the portfolio\n",
|
||||
" alpha : float, optional\n",
|
||||
" Confidence level for VaR, by default 0.95\n",
|
||||
" lookback_days : int, optional\n",
|
||||
" Number of days to look back for historical data, by default 500\n",
|
||||
" \n",
|
||||
" Returns\n",
|
||||
" -------\n",
|
||||
" float\n",
|
||||
" The Value at Risk (VaR) at the specified confidence level\n",
|
||||
" \"\"\"\n",
|
||||
" \n",
|
||||
" # Fill missing values in returns with zero and calculate portfolio returns\n",
|
||||
"\n",
|
||||
" returns = returns.fillna(0.0)\n",
|
||||
" portfolio_returns = returns.iloc[-lookback_days:].dot(weights)\n",
|
||||
"\n",
|
||||
" # Calculate the VaR as the percentile of portfolio returns\n",
|
||||
"\n",
|
||||
" return np.percentile(portfolio_returns, 100 * (1 - alpha)) * value_invested"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "700ce7bd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Define the total value invested in the portfolio"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b087d682",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"value_invested = 1000000"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "926f99ac",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Calculate Value at Risk (VaR) using the defined function"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b0d5a7f9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"value_at_risk(value_invested, returns, weights, alpha=0.95, lookback_days=520)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c6bc2883",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Define parameters for lookback days and confidence level"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5e9379f3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"lookback_days = 500\n",
|
||||
"alpha = 0.95"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "260bc52d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Calculate portfolio returns using historical data and weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2396b2f1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"portfolio_returns = returns.fillna(0.0).iloc[-lookback_days:].dot(weights)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "79001b24",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Calculate VaR and express it as a return rather than absolute loss"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "64973e13",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"portfolio_VaR = value_at_risk(value_invested, returns, weights, alpha=0.95)\n",
|
||||
"portfolio_VaR_return = portfolio_VaR / value_invested"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "43704fbe",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Plot histogram of portfolio returns and mark the VaR on the plot"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bd62e764",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"plt.hist(portfolio_returns, bins=30)\n",
|
||||
"plt.axvline(portfolio_VaR_return, color='red', linestyle='solid')\n",
|
||||
"plt.legend(['VaR', 'Returns'])\n",
|
||||
"plt.title('Historical VaR')\n",
|
||||
"plt.xlabel('Return')\n",
|
||||
"plt.ylabel('Observation Frequency')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "376798ce",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Define the number of iterations for VaR calculation and initialize an array"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c6eecfc0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"N = 1000\n",
|
||||
"VaRs = np.zeros((N, 1))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9d5cb851",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Iterate to calculate VaR over different lookback windows"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "58bf2dfe",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"for i in range(N):\n",
|
||||
" VaRs[i] = value_at_risk(value_invested, returns, weights, lookback_days=i + 1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "aadb983c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Plot the VaR values over different lookback windows"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "58715c8f",
|
||||
"metadata": {
|
||||
"lines_to_next_cell": 1
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"plt.plot(VaRs)\n",
|
||||
"plt.xlabel('Lookback Window')\n",
|
||||
"plt.ylabel('VaR')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9d78afc3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Define a function to calculate Conditional Value at Risk (CVaR)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c9debae5",
|
||||
"metadata": {
|
||||
"lines_to_next_cell": 1
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def cvar(value_invested, returns, weights, alpha=0.95, lookback_days=500):\n",
|
||||
" \"\"\"Calculates Conditional Value at Risk (CVaR) for a portfolio\n",
|
||||
" \n",
|
||||
" Parameters\n",
|
||||
" ----------\n",
|
||||
" value_invested : float\n",
|
||||
" Total value of the portfolio\n",
|
||||
" returns : pd.DataFrame\n",
|
||||
" Historical returns of the portfolio components\n",
|
||||
" weights : np.ndarray\n",
|
||||
" Weights of each asset in the portfolio\n",
|
||||
" alpha : float, optional\n",
|
||||
" Confidence level for CVaR, by default 0.95\n",
|
||||
" lookback_days : int, optional\n",
|
||||
" Number of days to look back for historical data, by default 500\n",
|
||||
" \n",
|
||||
" Returns\n",
|
||||
" -------\n",
|
||||
" float\n",
|
||||
" The Conditional Value at Risk (CVaR) at the specified confidence level\n",
|
||||
" \"\"\"\n",
|
||||
" \n",
|
||||
" # Calculate VaR and portfolio returns for the specified lookback period\n",
|
||||
"\n",
|
||||
" var = value_at_risk(value_invested, returns, weights, alpha, lookback_days=lookback_days)\n",
|
||||
" \n",
|
||||
" returns = returns.fillna(0.0)\n",
|
||||
" portfolio_returns = returns.iloc[-lookback_days:].dot(weights)\n",
|
||||
" var_pct_loss = var / value_invested\n",
|
||||
" \n",
|
||||
" # Calculate the mean of returns below the VaR threshold\n",
|
||||
"\n",
|
||||
" return np.nanmean(portfolio_returns[portfolio_returns < var_pct_loss]) * value_invested"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3362b55d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Calculate CVaR using the defined function"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f8273f2f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cvar(value_invested, returns, weights, lookback_days=500)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "64439069",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Calculate VaR again for consistency"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ff33b141",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"value_at_risk(value_invested, returns, weights, lookback_days=500)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "db4a0e67",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Calculate portfolio returns using historical data and weights"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2dc1b37c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"lookback_days = 500"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a2a13483",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"portfolio_returns = returns.fillna(0.0).iloc[-lookback_days:].dot(weights)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0ac89dd2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Calculate VaR and CVaR and express them as returns"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "36b35c9e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"portfolio_VaR = value_at_risk(value_invested, returns, weights)\n",
|
||||
"portfolio_VaR_return = portfolio_VaR / value_invested"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8efa2126",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"portfolio_CVaR = cvar(value_invested, returns, weights)\n",
|
||||
"portfolio_CVaR_return = portfolio_CVaR / value_invested"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "40bead66",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Plot histogram of portfolio returns, marking VaR and CVaR on the plot"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b4bc480d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"plt.hist(portfolio_returns[portfolio_returns > portfolio_VaR_return], bins=20)\n",
|
||||
"plt.hist(portfolio_returns[portfolio_returns < portfolio_VaR_return], bins=10)\n",
|
||||
"plt.axvline(portfolio_VaR_return, color='red', linestyle='solid')\n",
|
||||
"plt.axvline(portfolio_CVaR_return, color='red', linestyle='dashed')\n",
|
||||
"plt.legend(['VaR', 'CVaR', 'Returns', 'Returns < VaR'])\n",
|
||||
"plt.title('Historical VaR and CVaR')\n",
|
||||
"plt.xlabel('Return')\n",
|
||||
"plt.ylabel('Observation Frequency')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4b6c6fbc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<a href=\"https://pyquantnews.com/\">PyQuant News</a> 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 <a href=\"https://gettingstartedwithpythonforquantfinance.com/\">get started with Python for quant finance</a>. For educational purposes. Not investment advise. Use at your own risk."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"jupytext": {
|
||||
"cell_metadata_filter": "-all",
|
||||
"main_language": "python",
|
||||
"notebook_metadata_filter": "-all"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user