Files
strategy-lab/to_explore/pyquantnews/46_CalmarRatio.ipynb
David Brazda e3da60c647 daily update
2024-10-21 20:57:56 +02:00

294 lines
7.1 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "daa349e7",
"metadata": {},
"source": [
"<div style=\"background-color:#000;\"><img src=\"pqn.png\"></img></div>"
]
},
{
"cell_type": "markdown",
"id": "47f62676",
"metadata": {},
"source": [
"This code fetches historical futures data for specific indices, calculates their percentage changes, and creates two different portfolios. It then computes the annualized return and Calmar ratio for each portfolio. The annualized return provides a measure of the portfolio's performance over time. The Calmar ratio assesses the risk-adjusted return by comparing the annualized return to the maximum drawdown. This analysis helps in understanding and comparing the performance and risk of different investment portfolios."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4d4b6bf1",
"metadata": {},
"outputs": [],
"source": [
"from openbb_terminal.sdk import openbb"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b74585c6",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np"
]
},
{
"cell_type": "markdown",
"id": "f5bb635c",
"metadata": {},
"source": [
"Fetch historical futures data for specified indices from OpenBB"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a9449129",
"metadata": {},
"outputs": [],
"source": [
"data = openbb.futures.historical(\n",
" [\"ES\", \"YM\", \"NQ\"], \n",
" start_date=\"2020-01-01\", \n",
" end_date=\"2022-12-31\"\n",
")"
]
},
{
"cell_type": "markdown",
"id": "b15bfced",
"metadata": {},
"source": [
"Calculate percentage changes of adjusted closing prices and drop NaN values"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "388d9c35",
"metadata": {},
"outputs": [],
"source": [
"futs = data['Adj Close'].pct_change().dropna()"
]
},
{
"cell_type": "markdown",
"id": "0fb9dbb0",
"metadata": {},
"source": [
"Create first portfolio with specified weights for each index"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5e04783d",
"metadata": {},
"outputs": [],
"source": [
"port_1 = futs.ES * 0.60 + futs.YM * 0.10 + futs.NQ * 0.10"
]
},
{
"cell_type": "markdown",
"id": "edbeec72",
"metadata": {},
"source": [
"Create second portfolio with different weights for each index"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d1166c30",
"metadata": {
"lines_to_next_cell": 1
},
"outputs": [],
"source": [
"port_2 = futs.ES * 0.90 + futs.YM * 0.15 + futs.NQ * 0.15"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d94715de",
"metadata": {
"lines_to_next_cell": 1
},
"outputs": [],
"source": [
"def ann_return(returns):\n",
" \"\"\"Calculate annualized return of a portfolio\n",
" \n",
" Parameters\n",
" ----------\n",
" returns : pd.Series\n",
" Daily returns of the portfolio\n",
" \n",
" Returns\n",
" -------\n",
" ann_return : float\n",
" Annualized return of the portfolio\n",
" \n",
" Notes\n",
" -----\n",
" This method computes the annualized return \n",
" using the geometric mean of daily returns.\n",
" \"\"\"\n",
" \n",
" # Compute the ending value of the investment\n",
" ending_value = (returns + 1).prod()\n",
" \n",
" # Calculate the number of years based on daily returns\n",
" num_years = len(returns) / 252\n",
" \n",
" # Calculate annualized return\n",
" ann_return = ending_value ** (1/num_years) - 1\n",
" \n",
" return ann_return"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bfa077cb",
"metadata": {
"lines_to_next_cell": 1
},
"outputs": [],
"source": [
"def calmar_ratio(returns):\n",
" \"\"\"Calculate Calmar ratio of a portfolio\n",
" \n",
" Parameters\n",
" ----------\n",
" returns : pd.Series\n",
" Daily returns of the portfolio\n",
" \n",
" Returns\n",
" -------\n",
" calmar_ratio : float\n",
" Calmar ratio of the portfolio\n",
" \n",
" Notes\n",
" -----\n",
" This method computes the Calmar ratio by \n",
" dividing the annualized return by the \n",
" absolute value of maximum drawdown.\n",
" \"\"\"\n",
" \n",
" # Compute cumulative returns\n",
" cumulative_returns = (returns + 1).cumprod() * 100\n",
" \n",
" # Compute maximum drawdown\n",
" max_return = np.fmax.accumulate(cumulative_returns)\n",
" max_dd = ((cumulative_returns - max_return) / max_return).min()\n",
" \n",
" # Calculate annualized return\n",
" ann_ret = ann_return(returns)\n",
" \n",
" return ann_ret / abs(max_dd)"
]
},
{
"cell_type": "markdown",
"id": "be187227",
"metadata": {},
"source": [
"Calculate annualized return for the first portfolio and print it"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a34d0895",
"metadata": {},
"outputs": [],
"source": [
"ret = ann_return(port_1)\n",
"print(ret)"
]
},
{
"cell_type": "markdown",
"id": "e1cb6f61",
"metadata": {},
"source": [
"Calculate Calmar ratio for the first portfolio and print it"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5a4b583b",
"metadata": {},
"outputs": [],
"source": [
"p1 = calmar_ratio(port_1)\n",
"print(p1)"
]
},
{
"cell_type": "markdown",
"id": "07af7202",
"metadata": {},
"source": [
"Calculate annualized return for the second portfolio and print it"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dae931cc",
"metadata": {},
"outputs": [],
"source": [
"ret = ann_return(port_2)\n",
"print(ret)"
]
},
{
"cell_type": "markdown",
"id": "33e5bf30",
"metadata": {},
"source": [
"Calculate Calmar ratio for the second portfolio and print it"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21ca7fd9",
"metadata": {},
"outputs": [],
"source": [
"p2 = calmar_ratio(port_2)\n",
"print(p2)"
]
},
{
"cell_type": "markdown",
"id": "0850471f",
"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
}