Skip to main content

Build New Toolkit Extension

Before adding a new toolkit extension and router path to the OpenBB Platform using a supplied template, it is important to understand the difference between a toolkit and a provider extension. You can find more information on this here.

How To Create A Router Extension

Let's create an extension which defines a new router entry point at the base of the obb namespace. It's going to be called, openbb-dashboards, and will serve as an empty router for various dashboard packages to populate future endpoints with.

By itself, it might not have any functions. Some other extension will name it as a dependency, using it as an entry point.

We'll use the ZIP file template as a starting point, renaming everything as the first step.

Create Folder

The folder does not have to be kept with the OpenBB code, and could be its own GitHub repo. For demonstration purposes, we'll unpack the ZIP file template with the rest of the OpenBB extensions:

~/OpenBBTerminal/openbb_platform/extensions/dashboards

Add Dependencies

This extension will be agnostic as to the type of components that might populate this space in the future - Plotly Dash, Streamlit, etc. The only addition to the dependencies will be openbb-charting. This will provide a Plotly charting library and custom backend with PyWry for window creation.

[tool.poetry]
name = "openbb-dashboards"
version = "1.0.0"
description = "Dashboards Extension for OpenBB"
authors = ["OpenBB Team <hello@openbb.co>"]
readme = "README.md"
packages = [{ include = "openbb_dashboards" }]

[tool.poetry.dependencies]
python = ">=3.8,<3.12"
openbb = "^4.1.7"
openbb-charting = "^2.0.3"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.poetry.plugins."openbb_core_extension"]
dashboards = "openbb_dashboards.dashboards_router:router"

Build and Install Package

Open a Terminal and navigate into the folder where the extension is, then enter:

poetry lock

pip install -e .

Add Router Commands

To demonstrate this extension, we'll make a simple function for creating and returning a line chart. This adds one endpoint to the new namespace, obb.dashboards.line_chart().

tip

After creating a new function, remember to rebuild the Python interface and static assets.

import openbb
openbb.build()
exit()
"""Dashboards Router."""

# pylint: disable = unused-argument

from typing import List, Optional, Union

from openbb_charting import charting_router
from openbb_charting.core.openbb_figure import OpenBBFigure
from openbb_core.app.model.charts.chart import Chart
from openbb_core.app.model.obbject import OBBject
from openbb_core.app.router import Router
from openbb_core.app.utils import basemodel_to_df, df_to_basemodel
from openbb_core.provider.abstract.data import Data

router = Router(prefix="")


@router.command(
methods=["POST"],
)
def line_chart(
data: Union[Data, List[Data]],
x: Optional[str] = None,
y: Optional[Union[str, List[str]]] = None,
layout_kwargs: Optional[dict] = None,
scatter_kwargs: Optional[dict] = None,
) -> OBBject:
"""Create a line chart."""
index = "date" if x is None else x
df = basemodel_to_df(data, index=index)

y = y.split(",") if isinstance(y, str) else y
if y is None:
y = df.columns.to_list()

if scatter_kwargs is None:
scatter_kwargs = {}

fig = OpenBBFigure(create_backend=True)
for col in y:
fig = fig.add_scatter(
x=df.index,
y=df[col],
name=col,
hovertemplate=
"<b>%{fullData.name}</b>: " +
"%{y:.2f}" +
"<extra></extra>",
hoverlabel=dict(font_size=10),
**scatter_kwargs,
)

if layout_kwargs is None:
layout_kwargs = {}

fig.update_layout(
hovermode="x unified",
**layout_kwargs,
)

results = OBBject(results=df_to_basemodel(df))

results.chart = Chart(
fig=fig,
content=fig.show(external=True).to_plotly_json(),
format=charting_router.CHART_FORMAT
)

return results

An example syntax for use is:

data = obb.equity.price.historical("AAPL", provider="yfinance")
chart = obb.dashboards.line_chart(
data.results, y=["high", "low"],
scatter_kwargs = {"showlegend": False},
layout_kwargs={"template":"plotly_white"}
)
chart.show()

This is demonstration is not meant to represent a finished product, only a path to explore while getting started. We hope you enjoy the journey and look forward to seeing what you build!