mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-11-01 23:12:21 +00:00
* 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>
512 lines
14 KiB
Plaintext
Vendored
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
|
|
}
|