{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e61b6551",
   "metadata": {},
   "source": [
    "<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8cebd5cb",
   "metadata": {},
   "source": [
    "This code retrieves stock prices, calculates returns, and evaluates portfolio performance against a benchmark. It fetches historical prices for specified stocks and computes their percentage changes to derive returns. The code then calculates portfolio returns based on equal weighting and compares them with a benchmark index. Finally, it computes the batting average to assess the portfolio's performance in up and down markets. This is useful for portfolio managers and financial analysts to evaluate investment strategies."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f484f7f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from openbb_terminal.sdk import openbb"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3fe4de2",
   "metadata": {},
   "source": [
    "Fetch historical prices for specified stocks using the OpenBB SDK"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e6394bcf",
   "metadata": {},
   "outputs": [],
   "source": [
    "prices = openbb.economy.index([\n",
    "    \"META\", \n",
    "    \"AAPL\", \n",
    "    \"AMZN\", \n",
    "    \"NFLX\", \n",
    "    \"GOOG\", \n",
    "    \"QQQ\"\n",
    "])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9006ddd4",
   "metadata": {},
   "source": [
    "Calculate percentage returns from the historical prices and remove any rows with NaN values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "97f84964",
   "metadata": {},
   "outputs": [],
   "source": [
    "returns = prices.pct_change().dropna()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4aa143ad",
   "metadata": {},
   "source": [
    "Extract the benchmark returns (QQQ) from the returns DataFrame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e639344f",
   "metadata": {},
   "outputs": [],
   "source": [
    "bench_returns = returns.pop(\"QQQ\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "664669a3",
   "metadata": {},
   "source": [
    "Calculate portfolio returns by equally weighting the individual stock returns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1f427ac8",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "port_returns = (returns * 0.2).sum(axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24341092",
   "metadata": {},
   "source": [
    "Define the function to calculate the batting average of portfolio returns against the benchmark"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d15cb24f",
   "metadata": {
    "lines_to_next_cell": 1
   },
   "outputs": [],
   "source": [
    "def batting_average(port_returns, bench_returns):\n",
    "    \"\"\"Calculate batting average of portfolio returns.\n",
    "    \n",
    "    This function computes the batting average of portfolio \n",
    "    returns compared to a benchmark, indicating performance \n",
    "    in up and down markets.\n",
    "    \n",
    "    Parameters\n",
    "    ----------\n",
    "    port_returns : pd.Series\n",
    "        Returns of the portfolio.\n",
    "    bench_returns : pd.Series\n",
    "        Returns of the benchmark index.\n",
    "    \n",
    "    Returns\n",
    "    -------\n",
    "    pd.Series\n",
    "        Batting average, up market, and down market metrics.\n",
    "    \"\"\"\n",
    "    \n",
    "    # Initialize a dictionary to store the results\n",
    "    results = dict(\n",
    "        {\n",
    "            \"batting average\": np.nan,\n",
    "            \"up market\": np.nan,\n",
    "            \"down market\": np.nan,\n",
    "        }\n",
    "    )\n",
    "    \n",
    "    # Calculate active returns by subtracting benchmark returns from portfolio returns\n",
    "    active_returns = port_returns - bench_returns\n",
    "\n",
    "    # Determine boolean arrays for batting average, up market, and down market conditions\n",
    "    ba = active_returns > 0\n",
    "    up = active_returns[bench_returns >= 0.0] > 0\n",
    "    down = active_returns[bench_returns < 0.0] > 0\n",
    "\n",
    "    # Compute the mean values for the batting average, up market, and down market\n",
    "    if len(ba) > 0:\n",
    "        results[\"batting average\"] = ba.mean()\n",
    "    if len(up) > 0:\n",
    "        results[\"up market\"] = up.mean()\n",
    "    if len(down) > 0:\n",
    "        results[\"down market\"] = down.mean()\n",
    "\n",
    "    # Return a Series with the computed results\n",
    "    return pd.Series(results, index=results.keys())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "046b9295",
   "metadata": {},
   "source": [
    "Calculate and display the batting average metrics for the portfolio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "82e94611",
   "metadata": {},
   "outputs": [],
   "source": [
    "batting_average(port_returns, bench_returns)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e210bcf1",
   "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
}
