{
 "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
}
