{ "cells": [ { "cell_type": "markdown", "id": "7b39d6ef", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "id": "09b6a2a7", "metadata": {}, "source": [ "This code fetches historical stock prices for AAPL, WMT, and SPY, calculates daily returns, and constructs a portfolio. It defines functions to compute the annual return and upside capture ratio of the portfolio compared to a benchmark. The upside capture ratio measures the portfolio's performance relative to the benchmark when the benchmark is up. This is useful in practice for portfolio performance analysis and risk management." ] }, { "cell_type": "code", "execution_count": null, "id": "7589769e", "metadata": {}, "outputs": [], "source": [ "from openbb_terminal.sdk import openbb" ] }, { "cell_type": "markdown", "id": "d7af040b", "metadata": {}, "source": [ "Fetch historical stock prices for AAPL, WMT, and SPY starting from 2020-01-01" ] }, { "cell_type": "code", "execution_count": null, "id": "01ac1e2a", "metadata": {}, "outputs": [], "source": [ "prices = openbb.economy.index(\n", " [\"AAPL\", \"WMT\", \"SPY\"], \n", " start_date=\"2020-01-01\"\n", ")" ] }, { "cell_type": "markdown", "id": "6cf5e1ea", "metadata": {}, "source": [ "Calculate daily returns by taking the percentage change and dropping any NaN values" ] }, { "cell_type": "code", "execution_count": null, "id": "fdd82c4a", "metadata": {}, "outputs": [], "source": [ "returns = prices.pct_change().dropna()" ] }, { "cell_type": "markdown", "id": "859f62ce", "metadata": {}, "source": [ "Construct a portfolio's returns by summing the returns of AAPL and WMT, and selecting SPY and portfolio columns" ] }, { "cell_type": "code", "execution_count": null, "id": "1138bf9a", "metadata": { "lines_to_next_cell": 1 }, "outputs": [], "source": [ "data = returns.assign(\n", " port=returns[[\"AAPL\", \"WMT\"]].sum(axis=1)\n", ")[[\"SPY\", \"port\"]]" ] }, { "cell_type": "markdown", "id": "a8b57c5b", "metadata": {}, "source": [ "Compute annualized return for a series of returns" ] }, { "cell_type": "code", "execution_count": null, "id": "a4341da4", "metadata": { "lines_to_next_cell": 1 }, "outputs": [], "source": [ "def annual_return(returns):\n", " \"\"\"Compute annualized return.\n", " \n", " This function calculates the annualized return of a series of returns.\n", " \n", " Parameters\n", " ----------\n", " returns : pd.Series\n", " Series of daily returns.\n", " \n", " Returns\n", " -------\n", " float\n", " Annualized return.\n", " \"\"\"\n", " \n", " # Calculate the number of years by dividing total days by 252 (trading days in a year)\n", " num_years = len(returns) / 252\n", " \n", " # Calculate the annualized return using the geometric average\n", " return (returns + 1).prod() ** (1 / num_years) - 1" ] }, { "cell_type": "markdown", "id": "567d5ef4", "metadata": {}, "source": [ "Compute upside capture ratio comparing portfolio returns to benchmark returns" ] }, { "cell_type": "code", "execution_count": null, "id": "1dea9509", "metadata": { "lines_to_next_cell": 1 }, "outputs": [], "source": [ "def upside_capture(port_returns, bench_returns):\n", " \"\"\"Compute upside capture ratio.\n", " \n", " This function calculates the upside capture ratio of portfolio returns \n", " compared to benchmark returns.\n", " \n", " Parameters\n", " ----------\n", " port_returns : pd.Series\n", " Series of portfolio returns.\n", " bench_returns : pd.Series\n", " Series of benchmark returns.\n", " \n", " Returns\n", " -------\n", " float\n", " Upside capture ratio.\n", " \"\"\"\n", " \n", " # Filter portfolio and benchmark returns where benchmark returns are positive\n", " mask = bench_returns > 0\n", " port_returns = port_returns[mask]\n", " bench_returns = bench_returns[mask]\n", " \n", " # Calculate the upside capture ratio by dividing annualized portfolio return by annualized benchmark return\n", " return (\n", " annual_return(port_returns) \n", " / annual_return(bench_returns)\n", " )" ] }, { "cell_type": "markdown", "id": "600cd3ac", "metadata": {}, "source": [ "Calculate the upside capture ratio for the constructed portfolio compared to SPY" ] }, { "cell_type": "code", "execution_count": null, "id": "47239c60", "metadata": {}, "outputs": [], "source": [ "upside_capture(data.port, data.SPY)" ] }, { "cell_type": "markdown", "id": "4d6184fc", "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 }