{ "cells": [ { "cell_type": "markdown", "id": "2725ec7a", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "id": "3289d4fc", "metadata": {}, "source": [ "This notebook simulates portfolio returns using Monte Carlo methods to estimate Value at Risk (VaR) and Conditional Value at Risk (CVaR). It begins by importing historical price data for various sectors, calculating daily returns, and determining portfolio statistics. The notebook then simulates portfolio returns over a specified number of days and simulations, using these to calculate VaR and CVaR. Finally, it visualizes the simulated portfolio paths and highlights the calculated risk metrics. This is useful for risk management and financial forecasting." ] }, { "cell_type": "code", "execution_count": null, "id": "fd3b1d48", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "from openbb import obb" ] }, { "cell_type": "markdown", "id": "67699707", "metadata": {}, "source": [ "Define a list of sector symbols to analyze" ] }, { "cell_type": "code", "execution_count": null, "id": "f8215e18", "metadata": {}, "outputs": [], "source": [ "sectors = [\n", " \"XLE\", \n", " \"XLF\", \n", " \"XLU\", \n", " \"XLI\", \n", " \"GDX\", \n", " \"XLK\", \n", " \"XLV\", \n", " \"XLY\", \n", " \"XLP\", \n", " \"XLB\", \n", " \"XOP\", \n", " \"IYR\", \n", " \"XHB\", \n", " \"ITB\", \n", " \"VNQ\", \n", " \"GDXJ\", \n", " \"IYE\", \n", " \"OIH\", \n", " \"XME\", \n", " \"XRT\", \n", " \"SMH\", \n", " \"IBB\", \n", " \"KBE\", \n", " \"KRE\", \n", " \"XTL\", \n", "]" ] }, { "cell_type": "markdown", "id": "2a89086a", "metadata": {}, "source": [ "Fetch historical price data for the defined sectors from 2022-01-01 using yfinance" ] }, { "cell_type": "code", "execution_count": null, "id": "e5a20900", "metadata": {}, "outputs": [], "source": [ "data = obb.equity.price.historical(\n", " sectors, \n", " start_date=\"2022-01-01\", \n", " provider=\"yfinance\"\n", ").to_df()" ] }, { "cell_type": "markdown", "id": "d0e9d9a4", "metadata": {}, "source": [ "Calculate daily returns for each sector" ] }, { "cell_type": "code", "execution_count": null, "id": "d25ec2bb", "metadata": {}, "outputs": [], "source": [ "data[\"returns\"] = data.groupby(\"symbol\").close.pct_change()" ] }, { "cell_type": "markdown", "id": "c5c12c22", "metadata": {}, "source": [ "Calculate mean daily returns and equal weights for each sector" ] }, { "cell_type": "code", "execution_count": null, "id": "d7f49a0b", "metadata": {}, "outputs": [], "source": [ "portfolio_stats = data.groupby(\"symbol\").agg(\n", " daily_returns=(\"returns\", \"mean\"),\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "1380c16e", "metadata": {}, "outputs": [], "source": [ "portfolio_stats[\"weights\"] = 1 / len(sectors)" ] }, { "cell_type": "markdown", "id": "57a36ec7", "metadata": {}, "source": [ "Compute the covariance matrix of the sector returns" ] }, { "cell_type": "code", "execution_count": null, "id": "f4776161", "metadata": {}, "outputs": [], "source": [ "covariance_matrix = (\n", " data\n", " .pivot(\n", " columns=\"symbol\", \n", " values=\"returns\"\n", " )\n", " .dropna()\n", " .cov()\n", ")" ] }, { "cell_type": "markdown", "id": "7031e0e7", "metadata": {}, "source": [ "Set up simulation parameters including number of simulations, days, and initial capital" ] }, { "cell_type": "code", "execution_count": null, "id": "67b604e6", "metadata": {}, "outputs": [], "source": [ "simulations = 1000\n", "days = len(data.index.unique())\n", "initial_capital = 100_000" ] }, { "cell_type": "markdown", "id": "7d5622f3", "metadata": {}, "source": [ "Initialize an array to store portfolio values for each simulation" ] }, { "cell_type": "code", "execution_count": null, "id": "25958ba0", "metadata": {}, "outputs": [], "source": [ "portfolio = np.zeros((days, simulations))" ] }, { "cell_type": "markdown", "id": "e0ba9b8c", "metadata": {}, "source": [ "Create an array filled with historical daily returns for each sector" ] }, { "cell_type": "code", "execution_count": null, "id": "6f93e3f3", "metadata": {}, "outputs": [], "source": [ "historical_returns = np.full(\n", " shape=(days, len(sectors)), \n", " fill_value=portfolio_stats.daily_returns\n", ")" ] }, { "cell_type": "markdown", "id": "8c400218", "metadata": {}, "source": [ "Perform Cholesky decomposition on the covariance matrix to generate correlated random variables" ] }, { "cell_type": "code", "execution_count": null, "id": "b2bdee40", "metadata": {}, "outputs": [], "source": [ "L = np.linalg.cholesky(covariance_matrix)" ] }, { "cell_type": "markdown", "id": "6cfae2a0", "metadata": {}, "source": [ "Run simulations to generate daily returns and simulate portfolio paths" ] }, { "cell_type": "code", "execution_count": null, "id": "8da4b25d", "metadata": {}, "outputs": [], "source": [ "for i in range(0, simulations):\n", " Z = np.random.normal(size=(days, len(sectors)))\n", " daily_returns = historical_returns + np.dot(L, Z.T).T\n", " portfolio[:, i] = (\n", " np.cumprod(np.dot(daily_returns, portfolio_stats.weights) + 1) * initial_capital\n", " )" ] }, { "cell_type": "markdown", "id": "698571d9", "metadata": {}, "source": [ "Convert simulated portfolio values into a DataFrame" ] }, { "cell_type": "code", "execution_count": null, "id": "9d3035e1", "metadata": {}, "outputs": [], "source": [ "simulated_portfolio = pd.DataFrame(portfolio)" ] }, { "cell_type": "markdown", "id": "f8b0d0d6", "metadata": {}, "source": [ "Set alpha level for VaR and CVaR calculations" ] }, { "cell_type": "code", "execution_count": null, "id": "a709e383", "metadata": { "lines_to_next_cell": 1 }, "outputs": [], "source": [ "alpha = 5" ] }, { "cell_type": "markdown", "id": "bcba57a6", "metadata": {}, "source": [ "Define function to calculate Monte Carlo VaR" ] }, { "cell_type": "code", "execution_count": null, "id": "473ac39d", "metadata": { "lines_to_next_cell": 1 }, "outputs": [], "source": [ "def montecarlo_var(alpha):\n", " \"\"\"Calculate Monte Carlo Value at Risk (VaR).\n", " \n", " Parameters\n", " ----------\n", " alpha : float\n", " The confidence level for the VaR calculation.\n", " \n", " Returns\n", " -------\n", " float\n", " The VaR value at the given confidence level.\n", " \"\"\"\n", " \n", " # Calculate the percentile of the simulated portfolio values at alpha level\n", " sim_val = simulated_portfolio.iloc[-1, :]\n", " return np.percentile(sim_val, alpha)" ] }, { "cell_type": "markdown", "id": "4641a8a4", "metadata": {}, "source": [ "Define function to calculate Conditional VaR" ] }, { "cell_type": "code", "execution_count": null, "id": "c084b860", "metadata": { "lines_to_next_cell": 1 }, "outputs": [], "source": [ "def conditional_var(alpha):\n", " \"\"\"Calculate Conditional Value at Risk (CVaR).\n", " \n", " Parameters\n", " ----------\n", " alpha : float\n", " The confidence level for the CVaR calculation.\n", " \n", " Returns\n", " -------\n", " float\n", " The CVaR value at the given confidence level.\n", " \"\"\"\n", " \n", " # Calculate the mean of the simulated portfolio values below the VaR threshold\n", " sim_val = simulated_portfolio.iloc[-1, :]\n", " return sim_val[sim_val <= montecarlo_var(alpha)].mean()" ] }, { "cell_type": "markdown", "id": "84dad355", "metadata": {}, "source": [ "Calculate Monte Carlo VaR and Conditional VaR" ] }, { "cell_type": "code", "execution_count": null, "id": "967cf6ea", "metadata": {}, "outputs": [], "source": [ "mc_var = montecarlo_var(alpha)\n", "cond_var = conditional_var(alpha)" ] }, { "cell_type": "markdown", "id": "611e4416", "metadata": {}, "source": [ "Plot the simulated portfolio paths and highlight VaR and CVaR" ] }, { "cell_type": "code", "execution_count": null, "id": "a0503bb6", "metadata": {}, "outputs": [], "source": [ "ax = simulated_portfolio.plot(lw=0.25, legend=False)\n", "ax.axhline(mc_var, lw=0.5, c=\"r\")\n", "ax.axhline(cond_var, lw=0.5, c=\"g\")" ] }, { "cell_type": "markdown", "id": "f876166a", "metadata": {}, "source": [ "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." ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }