{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "72b48e39",
   "metadata": {},
   "source": [
    "<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "82dd16a7",
   "metadata": {},
   "source": [
    "This notebook demonstrates how to construct and optimize a portfolio using historical asset returns and various risk measures. It utilizes `riskfolio` to model the portfolio and `yfinance` to fetch historical stock data. The notebook calculates expected returns and covariance matrices, integrates benchmark indices, and applies tracking error constraints. It then optimizes the portfolio to maximize risk-adjusted returns, plotting the efficient frontier and optimal asset allocations. This is practical for portfolio managers and financial analysts to enhance investment strategies."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a6872e45",
   "metadata": {},
   "outputs": [],
   "source": [
    "import riskfolio as rp\n",
    "import pandas as pd\n",
    "import yfinance as yf\n",
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "93795c66",
   "metadata": {},
   "source": [
    "Define the list of assets for portfolio construction"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6014ff8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "assets = [\n",
    "    \"JCI\",\n",
    "    \"TGT\",\n",
    "    \"CMCSA\",\n",
    "    \"CPB\",\n",
    "    \"MO\",\n",
    "    \"APA\",\n",
    "    \"MMC\",\n",
    "    \"JPM\",\n",
    "    \"ZION\",\n",
    "    \"PSA\",\n",
    "    \"BAX\",\n",
    "    \"BMY\",\n",
    "    \"LUV\",\n",
    "    \"PCAR\",\n",
    "    \"TXT\",\n",
    "    \"TMO\",\n",
    "    \"DE\",\n",
    "    \"MSFT\",\n",
    "    \"HPQ\",\n",
    "    \"SEE\",\n",
    "    \"VZ\",\n",
    "    \"CNP\",\n",
    "    \"NI\",\n",
    "    \"T\",\n",
    "    \"BA\",\n",
    "    \"^GSPC\",\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b37333e",
   "metadata": {},
   "source": [
    "Fetch historical stock data for the defined assets from Yahoo Finance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "72998b3d",
   "metadata": {},
   "outputs": [],
   "source": [
    "data = yf.download(assets, start=\"2016-01-01\", end=\"2019-12-30\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc2f3f83",
   "metadata": {},
   "source": [
    "Select adjusted close prices and rename columns to match asset tickers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0a2267eb",
   "metadata": {},
   "outputs": [],
   "source": [
    "data = data.loc[:, (\"Adj Close\", slice(None))]\n",
    "data.columns = assets"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf01924e",
   "metadata": {},
   "source": [
    "Calculate daily returns of the assets and isolate benchmark returns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "229bec20",
   "metadata": {},
   "outputs": [],
   "source": [
    "returns = data.pct_change().dropna()\n",
    "bench_returns = returns.pop(\"^GSPC\").to_frame()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15f6af5c",
   "metadata": {},
   "source": [
    "Build the portfolio object and load the calculated returns into it"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fee416cb",
   "metadata": {},
   "outputs": [],
   "source": [
    "port = rp.Portfolio(returns=returns)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d28c6840",
   "metadata": {},
   "source": [
    "Estimate expected returns and covariance matrix using historical data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7db95d05",
   "metadata": {},
   "outputs": [],
   "source": [
    "port.assets_stats(method_mu=\"hist\", method_cov=\"hist\", d=0.94)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41e65884",
   "metadata": {},
   "source": [
    "Set to False to indicate no benchmark weights, using index instead"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dae58fef",
   "metadata": {},
   "outputs": [],
   "source": [
    "port.kindbench = False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e80d124",
   "metadata": {},
   "source": [
    "Load benchmark returns into the portfolio object"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9f4a1a21",
   "metadata": {},
   "outputs": [],
   "source": [
    "port.benchindex = bench_returns"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29139cd2",
   "metadata": {},
   "source": [
    "Enable the use of tracking error constraints in the optimization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e856f599",
   "metadata": {},
   "outputs": [],
   "source": [
    "port.allowTE = True"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74cff10c",
   "metadata": {},
   "source": [
    "Define the maximum allowed tracking error relative to benchmark returns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3387d4f5",
   "metadata": {},
   "outputs": [],
   "source": [
    "port.TE = 0.008"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b40e308",
   "metadata": {},
   "source": [
    "Explain the goal of calculating optimal portfolios using different risk measures"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1aa657fe",
   "metadata": {},
   "source": [
    "Define the model type for optimization, here using historical data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "daa9ab9a",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = \"Classic\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba2c93a8",
   "metadata": {},
   "source": [
    "Specify the risk measure to use, in this case, Conditional Value at Risk (CVaR)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "007d98eb",
   "metadata": {},
   "outputs": [],
   "source": [
    "rm = \"CVaR\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e0aa6b66",
   "metadata": {},
   "source": [
    "Set the objective function to maximize Sharpe ratio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eee2108e",
   "metadata": {},
   "outputs": [],
   "source": [
    "obj = \"Sharpe\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a6c05fcb",
   "metadata": {},
   "source": [
    "Use historical scenarios for risk measures that depend on scenarios"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1b38bdef",
   "metadata": {},
   "outputs": [],
   "source": [
    "hist = True"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f8182805",
   "metadata": {},
   "source": [
    "Define the risk-free rate for portfolio optimization calculations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4fb85459",
   "metadata": {},
   "outputs": [],
   "source": [
    "rf = 0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7714deb9",
   "metadata": {},
   "source": [
    "Set the risk aversion factor, relevant only when the objective is 'Utility'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b9ad9f21",
   "metadata": {},
   "outputs": [],
   "source": [
    "l = 0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc2ea3dc",
   "metadata": {},
   "source": [
    "Perform the portfolio optimization to maximize the Sharpe ratio using CVaR"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "62686a64",
   "metadata": {},
   "outputs": [],
   "source": [
    "w = port.optimization(\n",
    "    model=model,\n",
    "    rm=rm,\n",
    "    obj=obj,\n",
    "    rf=rf,\n",
    "    l=l,\n",
    "    hist=hist\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e94c0bf1",
   "metadata": {},
   "source": [
    "Plot the optimized portfolio allocation using a pie chart"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c8ee7569",
   "metadata": {},
   "outputs": [],
   "source": [
    "ax = rp.plot_pie(\n",
    "    w=w,\n",
    "    title=\"Sharpe Mean CVaR\",\n",
    "    others=0.05,\n",
    "    nrow=25,\n",
    "    cmap=\"tab20\",\n",
    "    height=6,\n",
    "    width=10,\n",
    "    ax=None,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0184145",
   "metadata": {},
   "source": [
    "Calculate the efficient frontier for the portfolio using the defined risk measure"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "afe7ab13",
   "metadata": {},
   "outputs": [],
   "source": [
    "frontier = port.efficient_frontier(\n",
    "    model=model, \n",
    "    rm=rm, \n",
    "    points=50, \n",
    "    rf=rf, \n",
    "    hist=hist\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "52a38adc",
   "metadata": {},
   "source": [
    "Plot the efficient frontier and the position of the optimized portfolio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f34ffd29",
   "metadata": {},
   "outputs": [],
   "source": [
    "ax = rp.plot_frontier(\n",
    "    w_frontier=frontier,\n",
    "    mu=port.mu,\n",
    "    cov=port.cov,\n",
    "    returns=port.returns,\n",
    "    rm=rm,\n",
    "    rf=rf,\n",
    "    cmap=\"viridis\",\n",
    "    w=w,\n",
    "    label=\"Max Risk Adjusted Return Portfolio\",\n",
    "    marker=\"*\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a5f9663",
   "metadata": {},
   "source": [
    "Define the list of different risk measures to use for portfolio optimization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d7359bbf",
   "metadata": {},
   "outputs": [],
   "source": [
    "rms = [\n",
    "    \"MV\",\n",
    "    \"MAD\",\n",
    "    \"MSV\",\n",
    "    \"FLPM\",\n",
    "    \"SLPM\",\n",
    "    \"CVaR\",\n",
    "    \"EVaR\",\n",
    "    \"WR\",\n",
    "    \"MDD\",\n",
    "    \"ADD\",\n",
    "    \"CDaR\",\n",
    "    \"UCI\",\n",
    "    \"EDaR\",\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c20a237f",
   "metadata": {},
   "source": [
    "Initialize an empty DataFrame to store the weights of optimized portfolios"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aea2e6de",
   "metadata": {},
   "outputs": [],
   "source": [
    "w_s = pd.DataFrame([])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6206bbb",
   "metadata": {},
   "source": [
    "Loop through each risk measure, optimize the portfolio, and store the weights"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e7d9329a",
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in rms:\n",
    "    w = port.optimization(model=model, rm=i, obj=obj, rf=rf, l=l, hist=hist)\n",
    "    w_s = pd.concat([w_s, w], axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "696b88ff",
   "metadata": {},
   "source": [
    "Assign the columns of the DataFrame to the respective risk measures and format the output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bb0285f3",
   "metadata": {},
   "outputs": [],
   "source": [
    "w_s.columns = rms\n",
    "w_s.style.format(\"{:.2%}\").background_gradient(cmap=\"YlGn\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6422513e",
   "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"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
