daily update
This commit is contained in:
214
to_explore/pyquantnews/56_UpsideCapture.ipynb
Normal file
214
to_explore/pyquantnews/56_UpsideCapture.ipynb
Normal file
@ -0,0 +1,214 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7b39d6ef",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": [
|
||||
"<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
|
||||
}
|
||||
Reference in New Issue
Block a user