Files
OpenBB/openbb_terminal/reports/templates/portfolio.ipynb
jose-donato c5d5b511ac Adds crypto fees revenue command (#4067)
* fix: initial commit

* fix: extra stuff

* fix: lint

* fix: ruff

* fix: linting

* fix: ruff

* fix: pylint

* fix: maybe fixed tests maybe not

* fix: pr issues

* fix: tests

* fix: updated test locally

* fix: generate sdk cmds

* fix: added source

* fix: tests maybe

* fix: lint

* fix: tests

* test

* test

* test

---------

Co-authored-by: James Maslek <jmaslek11@gmail.com>
Co-authored-by: DidierRLopes <dro.lopes@campus.fct.unl.pt>
2023-06-13 13:50:17 +00:00

512 lines
14 KiB
Plaintext
Vendored

{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"id": "70ba2c8a",
"metadata": {},
"source": [
"## Notebook setup"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "driven-billion",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import io\n",
"import warnings\n",
"import datetime\n",
"import numpy as np\n",
"import base64\n",
"import pytz\n",
"import pandas as pd\n",
"\n",
"from IPython.display import HTML\n",
"\n",
"import openbb_terminal.config_terminal as cfg\n",
"from openbb_terminal.helper_classes import TerminalStyle\n",
"from openbb_terminal.core.config.paths import REPOSITORY_DIRECTORY\n",
"from openbb_terminal import OpenBBFigure, theme\n",
"\n",
"warnings.filterwarnings(\"ignore\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "49032d55",
"metadata": {},
"outputs": [],
"source": [
"# Suppressing sdk logs\n",
"from openbb_terminal.core.session.current_system import set_system_variable\n",
"\n",
"set_system_variable(\"LOGGING_SUPPRESS\", True)\n",
"\n",
"# Import the OpenBB SDK\n",
"from openbb_terminal.sdk import openbb, widgets, helper"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "62d3ea0e",
"metadata": {},
"outputs": [],
"source": [
"from openbb_terminal.core.session.current_user import get_current_user\n",
"\n",
"user = get_current_user()\n",
"\n",
"cfg.theme = TerminalStyle(\n",
" user.preferences.MPL_STYLE,\n",
" user.preferences.PMF_STYLE,\n",
" user.preferences.RICH_STYLE,\n",
")\n",
"theme.apply_style(\"light\")\n",
"\n",
"USER_PORTFOLIO_DATA_DIRECTORY = user.preferences.USER_PORTFOLIO_DATA_DIRECTORY"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4391e874",
"metadata": {},
"outputs": [],
"source": [
"stylesheet = widgets.html_report_stylesheet()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "8136bf90",
"metadata": {},
"source": [
"### Header"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c3fe7db5-ec6a-42cf-9e66-52dc1de22370",
"metadata": {},
"outputs": [],
"source": [
"stylesheet = widgets.html_report_stylesheet()\n",
"user_time_zone = pytz.timezone(helper.get_user_timezone())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "daef64ec",
"metadata": {
"tags": [
"parameters"
]
},
"outputs": [],
"source": [
"# Parameters that will be replaced when calling this notebook\n",
"# Do not leave parameters blank as notebook will not run otherwise\n",
"transactions = \"holdings_example.xlsx\"\n",
"report_name = \"Portfolio Report\""
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dd441a31",
"metadata": {},
"outputs": [],
"source": [
"file_0 = (\n",
" str(REPOSITORY_DIRECTORY)\n",
" + \"/openbb_terminal/miscellaneous/portfolio/\"\n",
" + transactions\n",
")\n",
"file_1 = str(USER_PORTFOLIO_DATA_DIRECTORY) + \"/holdings/\" + transactions\n",
"\n",
"if os.path.isfile(file_0):\n",
" transactions_path = file_0\n",
"elif os.path.isfile(file_1):\n",
" transactions_path = file_1\n",
"else:\n",
" raise FileNotFoundError(\"File not found: \" + transactions)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1be26dae-cafe-4a22-80aa-eff296fc1a9b",
"metadata": {},
"outputs": [],
"source": [
"_, transactions_file = os.path.split(transactions_path)\n",
"report_title = f\"Portfolio report for {transactions_file}\"\n",
"report_date = pd.Timestamp.now(tz=user_time_zone).strftime(\"%d %B, %Y\")\n",
"report_time = pd.Timestamp.now(tz=user_time_zone).strftime(\"%H:%M\")\n",
"report_timezone = pd.Timestamp.now(tz=user_time_zone).tzinfo\n",
"report_title, report_date, report_time, report_timezone"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "9363f19a",
"metadata": {},
"source": [
"## Data"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "eb3dbd48",
"metadata": {},
"source": [
"Loading"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b139556d",
"metadata": {},
"outputs": [],
"source": [
"try:\n",
" P = openbb.portfolio.load(transactions_path)\n",
" openbb.portfolio.show(P)\n",
"except Exception as e:\n",
" raise Exception(\"Failed to load the transactions.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "af24ed22",
"metadata": {},
"outputs": [],
"source": [
"beta_chart = openbb.portfolio.rbeta_chart(P, external_axes=True)\n",
"\n",
"if beta_chart:\n",
" beta_chart = beta_chart.to_html()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "636c743d",
"metadata": {},
"outputs": [],
"source": [
"sharpe_chart = openbb.portfolio.rsharpe_chart(P, external_axes=True)\n",
"\n",
"if sharpe_chart:\n",
" sharpe_chart = sharpe_chart.to_html()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae0d9381",
"metadata": {},
"outputs": [],
"source": [
"volatility_chart = openbb.portfolio.rvol_chart(P, external_axes=True)\n",
"\n",
"if volatility_chart:\n",
" volatility_chart = volatility_chart.to_html()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7e5e6fff",
"metadata": {},
"outputs": [],
"source": [
"sortino_chart = openbb.portfolio.rsort_chart(P, external_axes=True)\n",
"\n",
"if sortino_chart:\n",
" sortino_chart = sortino_chart.to_html()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3567b0ca",
"metadata": {},
"outputs": [],
"source": [
"maxdd_chart = openbb.portfolio.maxdd_chart(P, external_axes=True)\n",
"\n",
"if maxdd_chart:\n",
" maxdd_chart = maxdd_chart.to_html()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5dbcc1eb",
"metadata": {},
"outputs": [],
"source": [
"country_allocation = openbb.portfolio.alloc.countries(P)\n",
"\n",
"country_allocation[\"Portfolio\"] = (country_allocation[\"Portfolio\"] * 100).map(\n",
" \"{:.3}%\".format\n",
")\n",
"country_allocation[\"Benchmark\"] = (country_allocation[\"Benchmark\"] * 100).map(\n",
" \"{:.3}%\".format\n",
")\n",
"country_allocation[\"Difference\"] = (country_allocation[\"Difference\"] * 100).map(\n",
" \"{:.3}pp\".format\n",
")\n",
"\n",
"country_allocation"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8e1a67a6",
"metadata": {},
"outputs": [],
"source": [
"sector_allocation = openbb.portfolio.alloc.sectors(P)\n",
"\n",
"sector_allocation[\"Portfolio\"] = (sector_allocation[\"Portfolio\"] * 100).map(\n",
" \"{:.3}%\".format\n",
")\n",
"sector_allocation[\"Benchmark\"] = (sector_allocation[\"Benchmark\"] * 100).map(\n",
" \"{:.3}%\".format\n",
")\n",
"sector_allocation[\"Difference\"] = (sector_allocation[\"Difference\"] * 100).map(\n",
" \"{:.3}pp\".format\n",
")\n",
"\n",
"sector_allocation"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6e1260b4",
"metadata": {},
"outputs": [],
"source": [
"distr_chart = openbb.portfolio.distr_chart(P, external_axes=True)\n",
"\n",
"if distr_chart:\n",
" distr_chart = distr_chart.to_html()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a668a58b",
"metadata": {},
"outputs": [],
"source": [
"dret_chart = openbb.portfolio.dret_chart(P, external_axes=True)\n",
"\n",
"if dret_chart:\n",
" dret_chart = dret_chart.to_html()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1ea71ca6",
"metadata": {},
"outputs": [],
"source": [
"yret_chart = openbb.portfolio.yret_chart(P, external_axes=True)\n",
"\n",
"if yret_chart:\n",
" yret_chart = yret_chart.to_html()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "ac795b8e",
"metadata": {},
"source": [
"## Render the report template to a file"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ebe0799e",
"metadata": {},
"outputs": [],
"source": [
"body = \"\"\n",
"\n",
"\n",
"body += widgets.header(\n",
" \"OpenBB\",\n",
" report_date,\n",
" report_time,\n",
" report_timezone,\n",
" report_title,\n",
" plotly_js=True,\n",
")\n",
"\n",
"body += widgets.tablinks([\"SUMMARY\", \"In-Depth Analysis\", \"Statistics\"])\n",
"\n",
"# Summary\n",
"htmlcode = widgets.p(\n",
" \"The total performance of the portfolio versus the benchmark is as follows. \"\n",
" \"Please note this calculation assumes partially shares exist for the benchmark.\"\n",
")\n",
"\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Performance\") + openbb.portfolio.perf(P).to_html()]\n",
")\n",
"\n",
"htmlcode += widgets.p(\"In which the following yearly returns are achieved:\")\n",
"\n",
"htmlcode += widgets.row([widgets.h(3, \"Yearly Performance\") + yret_chart])\n",
"\n",
"htmlcode += widgets.p(\n",
" \"The portfolio and benchmark consists of the following allocations to countries and sectors.\"\n",
")\n",
"\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Country Allocation\") + country_allocation.to_html()]\n",
")\n",
"\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Sector Allocation\") + sector_allocation.to_html()]\n",
")\n",
"\n",
"htmlcode += widgets.p(\n",
" \"The portfolio consists of the following trades including returns.\"\n",
")\n",
"\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Portfolio Trades\") + P.portfolio_trades.to_html()]\n",
")\n",
"\n",
"htmlcode += widgets.p(\n",
" \"The benchmark consists of the following trades including returns.\"\n",
")\n",
"\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Benchmark Trades\") + P.benchmark_trades.to_html()]\n",
")\n",
"\n",
"body += widgets.add_tab(\"SUMMARY\", htmlcode)\n",
"\n",
"# In Depth Analysis\n",
"htmlcode = widgets.p(\n",
" \"The following metrics, Tracking Error and Information Ratio, measure whether you are \"\n",
" \"closely aligned with the benchmark. If the Tracking Error is not close to 1, a different benchmark \"\n",
" \"might be a better fit.\"\n",
")\n",
"\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Tracking Error\") + openbb.portfolio.metric.trackerr(P)[0].to_html()]\n",
")\n",
"htmlcode += widgets.row(\n",
" [\n",
" widgets.h(3, \"Information Ratio\")\n",
" + openbb.portfolio.metric.information(P).to_html()\n",
" ]\n",
")\n",
"\n",
"htmlcode += widgets.row([widgets.h(3, \"Beta Chart\") + beta_chart])\n",
"\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Sharpe Ratio\") + openbb.portfolio.metric.sharpe(P).to_html()]\n",
")\n",
"htmlcode += widgets.row([widgets.h(3, \"Sharpe Ratio Chart\") + sharpe_chart])\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Volatility\") + openbb.portfolio.metric.volatility(P).to_html()]\n",
")\n",
"htmlcode += widgets.row([widgets.h(3, \"Volatility Chart\") + volatility_chart])\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Sortino Ratio\") + openbb.portfolio.metric.sortino(P).to_html()]\n",
")\n",
"htmlcode += widgets.row([widgets.h(3, \"Sortino Chart\") + sortino_chart])\n",
"\n",
"htmlcode += widgets.row([widgets.h(3, \"Maximum Drawdown\") + maxdd_chart])\n",
"\n",
"\n",
"body += widgets.add_tab(\"In-Depth Analysis\", htmlcode)\n",
"\n",
"# Statistics\n",
"htmlcode = widgets.row([widgets.h(3, \"Distribution\") + distr_chart])\n",
"htmlcode += widgets.row([widgets.h(3, \"Daily Returns\") + dret_chart])\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Volatility\") + openbb.portfolio.metric.volatility(P).to_html()]\n",
")\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Kurtosis\") + openbb.portfolio.metric.kurtosis(P).to_html()]\n",
")\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Skew\") + openbb.portfolio.metric.skew(P).to_html()]\n",
")\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Value at Risk (VaR)\") + openbb.portfolio.var(P).to_html()]\n",
")\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Expected Shortfall (cVaR)\") + openbb.portfolio.es(P).to_html()]\n",
")\n",
"htmlcode += widgets.row(\n",
" [widgets.h(3, \"Omega Ratio\") + openbb.portfolio.om(P).to_html()]\n",
")\n",
"\n",
"body += widgets.add_tab(\"Statistics\", htmlcode)\n",
"\n",
"body += widgets.tab_clickable_and_save_evt()\n",
"\n",
"report = widgets.html_report(title=report_name, stylesheet=stylesheet, body=body)\n",
"\n",
"# to save the results\n",
"with open(report_name + \".html\", \"w\", encoding=\"utf-8\") as fh:\n",
" fh.write(report)"
]
}
],
"metadata": {
"celltoolbar": "Tags",
"kernelspec": {
"display_name": "obb",
"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.9"
},
"vscode": {
"interpreter": {
"hash": "100174a9203096c0c10fb537684ff280825ee9e252451beb8786068677204f06"
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}