{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "40c4b691",
   "metadata": {},
   "source": [
    "<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e8acbb3a",
   "metadata": {},
   "source": [
    "## Load stock data and calculate daily returns"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec0a3524-f34d-47c1-9d0d-4c214e667a05",
   "metadata": {},
   "source": [
    "We start by loading stock data for three companies: Apple (AAPL), Microsoft (MSFT), and Google (GOOGL). We will use the adjusted closing prices from January 1, 2020, to January 1, 2022. Then, we calculate the daily returns for these stocks."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dd38b0ce",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import yfinance as yf\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "98a88cab",
   "metadata": {},
   "outputs": [],
   "source": [
    "tickers = ['AAPL', 'MSFT', 'GOOGL']\n",
    "data = yf.download(tickers, start='2020-01-01', end='2022-01-01')['Adj Close']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "92f195d8",
   "metadata": {},
   "outputs": [],
   "source": [
    "returns = data.pct_change().dropna()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29257797",
   "metadata": {},
   "source": [
    "We use the yf.download method from the yfinance library to fetch adjusted closing prices for the specified tickers and date range. The pct_change method calculates the daily returns, which represent the percentage change in stock prices from one day to the next. The dropna method ensures that we remove any missing values from our data. This step is crucial for accurate calculations in subsequent steps."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d9ce685",
   "metadata": {},
   "source": [
    "## Calculate portfolio returns"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f4974cc-4fae-4684-ab89-5b1f170bf5e1",
   "metadata": {},
   "source": [
    "Next, we will calculate the returns of a portfolio consisting of the three stocks. We assign specific weights to each stock and compute the portfolio returns based on these weights."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "915c359b",
   "metadata": {},
   "outputs": [],
   "source": [
    "weights = np.array([0.4, 0.4, 0.2])\n",
    "portfolio_returns = returns.dot(weights)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3bec93fa",
   "metadata": {},
   "source": [
    "We create an array of weights that represent the proportion of the portfolio allocated to each stock: 40% to Apple, 40% to Microsoft, and 20% to Google. We then calculate the portfolio returns by taking the dot product of the daily returns and the weights. This gives us a time series of portfolio returns, which is the weighted sum of the individual stock returns for each day."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4901e227",
   "metadata": {},
   "source": [
    "## Calculate Sortino Ratio"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8082f1f7-97d0-413e-8b8e-80447bd43342",
   "metadata": {},
   "source": [
    "We will now calculate the Sortino Ratio for the portfolio. The Sortino Ratio measures the risk-adjusted return, focusing only on downside risk. We first determine the excess returns over a risk-free rate and then compute the downside deviation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bc4451fd",
   "metadata": {},
   "outputs": [],
   "source": [
    "risk_free_rate = 0.01\n",
    "target_return = 0\n",
    "excess_return = portfolio_returns - risk_free_rate / 252\n",
    "downside_returns = excess_return[excess_return < 0]\n",
    "downside_deviation = np.std(downside_returns)\n",
    "sortino_ratio = np.mean(excess_return) / downside_deviation"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a039805",
   "metadata": {},
   "source": [
    "We set the risk-free rate at 1% and assume a target return of 0. The excess return is calculated by subtracting the daily risk-free rate from the portfolio returns. We identify the downside returns, which are the negative excess returns, and compute the standard deviation of these downside returns to get the downside deviation. Finally, we calculate the Sortino Ratio by dividing the mean excess return by the downside deviation. This ratio helps us understand the portfolio's performance relative to the downside risk."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dffa0116",
   "metadata": {},
   "source": [
    "## Plot portfolio returns and visualize the downside risk"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45c15282-dddb-4f40-b31d-1101a2c8f643",
   "metadata": {},
   "source": [
    "Lastly, we will plot the portfolio returns and highlight the periods where the returns are below the target return. This will help us visualize the downside risk."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94f2cf01",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(12, 6))\n",
    "plt.plot(portfolio_returns.index, portfolio_returns, label='Portfolio Returns')\n",
    "downside_returns = portfolio_returns[portfolio_returns < target_return]\n",
    "plt.fill_between(downside_returns.index, downside_returns, alpha=0.5, color='red', label='Downside Returns')\n",
    "plt.title('Portfolio Returns with Downside Risk Highlighted')\n",
    "plt.xlabel('Date')\n",
    "plt.ylabel('Returns')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f318296",
   "metadata": {},
   "source": [
    "We create a plot with portfolio returns on the y-axis and dates on the x-axis. We use the plot method from matplotlib to visualize the portfolio returns. We then identify the dates where the returns are below the target return and highlight these periods using the fill_between method with a red fill color. The plot includes a title and labels for the axes, and a legend to distinguish between the portfolio returns and downside returns. This visualization helps us easily identify periods of negative performance."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32baf792",
   "metadata": {},
   "source": [
    "## Your next steps"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd15bfe8-42e1-4f91-ba77-123b3dc5211b",
   "metadata": {},
   "source": [
    "Try changing the weights assigned to the stocks and observe how the portfolio returns and the Sortino Ratio change. You can also experiment with different time periods to see how the portfolio would have performed in various market conditions. This will give you a deeper understanding of portfolio performance and risk management."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e461cd3",
   "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
}
