diff options
author | Igor Radovanovic <74266147+IgorWounds@users.noreply.github.com> | 2024-06-27 15:09:46 +0200 |
---|---|---|
committer | Igor Radovanovic <74266147+IgorWounds@users.noreply.github.com> | 2024-06-27 15:09:46 +0200 |
commit | ff6dc848d25d86068c48fd1310ef42d601114a03 (patch) | |
tree | 6e52d80c13a64b7e1e3b3160d8aba4e1efbb03ba | |
parent | 34122c4524df379d1b17ccd9c1bbae6455e046ba (diff) |
Add chart
7 files changed, 168 insertions, 7 deletions
diff --git a/openbb_platform/extensions/derivatives/integration/test_derivatives_api.py b/openbb_platform/extensions/derivatives/integration/test_derivatives_api.py index 97e9a3551eb..37042528326 100644 --- a/openbb_platform/extensions/derivatives/integration/test_derivatives_api.py +++ b/openbb_platform/extensions/derivatives/integration/test_derivatives_api.py @@ -128,8 +128,18 @@ def test_derivatives_futures_historical(params, headers): @parametrize( "params", [ - ({"provider": "cboe", "symbol": "VX", "date": None}), - ({"provider": "yfinance", "symbol": "ES", "date": "2023-08-01"}), + ( + { + "provider": "yfinance", + "symbol": "VX", + } + ), + ( + { + "provider": "cboe", + "symbol": "VX", + } + ), ], ) @pytest.mark.integration @@ -139,7 +149,7 @@ def test_derivatives_futures_curve(params, headers): query_str = get_querystring(params, []) url = f"http://0.0.0.0:8000/api/v1/derivatives/futures/curve?{query_str}" - result = requests.get(url, headers=headers, timeout=60) + result = requests.get(url, headers=headers, timeout=10) assert isinstance(result, requests.Response) assert result.status_code == 200 diff --git a/openbb_platform/extensions/derivatives/integration/test_derivatives_python.py b/openbb_platform/extensions/derivatives/integration/test_derivatives_python.py index 4e04039bc7a..a3af4584c4b 100644 --- a/openbb_platform/extensions/derivatives/integration/test_derivatives_python.py +++ b/openbb_platform/extensions/derivatives/integration/test_derivatives_python.py @@ -115,8 +115,8 @@ def test_derivatives_futures_historical(params, obb): @parametrize( "params", [ - ({"symbol": "VX", "provider": "cboe", "date": None}), - ({"provider": "yfinance", "symbol": "ES", "date": "2023-08-01"}), + ({"provider": "yfinance", "symbol": "VX"}), + ({"provider": "cboe", "symbol": "VX"}), ], ) @pytest.mark.integration diff --git a/openbb_platform/extensions/derivatives/openbb_derivatives/derivatives_views.py b/openbb_platform/extensions/derivatives/openbb_derivatives/derivatives_views.py index c83b090e206..2965e176a75 100644 --- a/openbb_platform/extensions/derivatives/openbb_derivatives/derivatives_views.py +++ b/openbb_platform/extensions/derivatives/openbb_derivatives/derivatives_views.py @@ -2,6 +2,7 @@ from typing import Any, Dict, Tuple +from openbb_charting.charts.futures_curve import futures_curve from openbb_charting.charts.price_historical import price_historical from openbb_charting.core.openbb_figure import OpenBBFigure @@ -13,5 +14,12 @@ class DerivativesViews: def derivatives_futures_historical( # noqa: PLR0912 **kwargs, ) -> Tuple[OpenBBFigure, Dict[str, Any]]: - """Get Derivatives Price Historical Chart.""" + """Get Derivatives Futures Historical Chart.""" return price_historical(**kwargs) + + @staticmethod + def derivatives_futures_curve( # noqa: PLR0912 + **kwargs, + ) -> Tuple[OpenBBFigure, Dict[str, Any]]: + """Get Derivatives Futures Curve Chart.""" + return futures_curve(**kwargs) diff --git a/openbb_platform/obbject_extensions/charting/integration/test_charting_api.py b/openbb_platform/obbject_extensions/charting/integration/test_charting_api.py index 76bcba65d7f..7dbd1497eb1 100644 --- a/openbb_platform/obbject_extensions/charting/integration/test_charting_api.py +++ b/openbb_platform/obbject_extensions/charting/integration/test_charting_api.py @@ -791,3 +791,39 @@ def test_charting_derivatives_futures_historical(params, headers): assert chart assert not fig assert list(chart.keys()) == ["content", "format"] + + +@parametrize( + "params", + [ + ( + { + "provider": "yfinance", + "symbol": "VX", + } + ), + ( + { + "provider": "cboe", + "symbol": "VX", + } + ), + ], +) +@pytest.mark.integration +def test_charting_derivatives_futures_curve(params, headers): + """Test chart derivatives futures curve.""" + params = {p: v for p, v in params.items() if v} + body = (json.dumps({"extra_params": {"chart_params": {"title": "test chart"}}}),) + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/derivatives/futures/curve?{query_str}" + result = requests.get(url, headers=headers, timeout=10, json=body) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] diff --git a/openbb_platform/obbject_extensions/charting/integration/test_charting_python.py b/openbb_platform/obbject_extensions/charting/integration/test_charting_python.py index 34705bb149f..6b95902bf2c 100644 --- a/openbb_platform/obbject_extensions/charting/integration/test_charting_python.py +++ b/openbb_platform/obbject_extensions/charting/integration/test_charting_python.py @@ -646,3 +646,31 @@ def test_charting_derivatives_futures_historical(params, obb): assert len(result.results) > 0 assert result.chart.content assert isinstance(result.chart.fig, OpenBBFigure) + + +@parametrize( + "params", + [ + ( + { + "provider": "yfinance", + "symbol": "VX", + } + ), + ( + { + "provider": "cboe", + "symbol": "VX", + } + ), + ], +) +@pytest.mark.integration +def test_charting_derivatives_futures_curve(params, obb): + """Test chart derivatives futures curve.""" + result = obb.derivatives.futures.curve(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure) diff --git a/openbb_platform/obbject_extensions/charting/openbb_charting/charts/futures_curve.py b/openbb_platform/obbject_extensions/charting/openbb_charting/charts/futures_curve.py new file mode 100644 index 00000000000..719e805af48 --- /dev/null +++ b/openbb_platform/obbject_extensions/charting/openbb_charting/charts/futures_curve.py @@ -0,0 +1,61 @@ +"""Yield curve chart.""" + +from typing import Any, Dict, Tuple, Union + +import pandas as pd +from openbb_core.app.utils import basemodel_to_df +from plotly.graph_objs import Figure + +from openbb_charting.charts.generic_charts import line_chart +from openbb_charting.core.openbb_figure import OpenBBFigure + + +def futures_curve( + **kwargs, +) -> Tuple[Union[OpenBBFigure, Figure], Dict[str, Any]]: # noqa: PLR0912 + """Futures curve chart.""" + if "data" in kwargs and isinstance(kwargs["data"], pd.DataFrame): + data = kwargs["data"] + elif "data" in kwargs and isinstance(kwargs["data"], list): + data = basemodel_to_df(kwargs["data"], index=kwargs.get("index", "symbol")) # type: ignore + else: + data = basemodel_to_df( + kwargs["obbject_item"], index=kwargs.get("index", "symbol") # type: ignore + ) + if not isinstance(data, pd.DataFrame): + raise ValueError("Data must be a pandas DataFrame") + + # Check for required columns + required_columns = {"expiration", "price", "symbol"} + if not required_columns.issubset(data.columns): + missing = required_columns - set(data.columns) + raise ValueError(f"Missing columns in the DataFrame: {missing}") + + data["expiration"] = pd.to_datetime(data["expiration"]) + + layout_kwargs: Dict[str, Any] = kwargs.get("layout_kwargs", {}) + title = kwargs.pop("title", "Futures Curve Chart") + orientation = kwargs.pop("orientation", "v") + + ytitle = kwargs.pop("ytitle", "Price") + xtitle = kwargs.pop("xtitle", "Expiration Date") + + fig = line_chart( + data=data, + x="expiration", + y="price", + title=title, + xtitle=xtitle, + ytitle=ytitle, + orientation=orientation, + layout_kwargs=layout_kwargs, + **kwargs, + ) + + fig.update_traces( + hovertemplate="Symbol: %{text}<br>Expiration: %{x|%Y-%m-%d}<br>Price: %{y:.2f}", + text=data["symbol"], + ) + content = {"plotly_json": fig.to_json()} + + return fig, content diff --git a/openbb_platform/obbject_extensions/charting/openbb_charting/query_params.py b/openbb_platform/obbject_extensions/charting/openbb_charting/query_params.py index c9caad2ebd9..3eb92d55fbd 100644 --- a/openbb_platform/obbject_extensions/charting/openbb_charting/query_params.py +++ b/openbb_platform/obbject_extensions/charting/openbb_charting/query_params.py @@ -116,6 +116,23 @@ class EtfHoldingsChartQueryParams(ChartQueryParams): ) +class FuturesCurveChartQueryParams(ChartQueryParams): + """ETF Holdings Chart Query Params.""" + + title: Optional[str] = Field( + default=None, + description="Title of the chart.", + ) + orientation: Literal["v", "h"] = Field( + default="v", + description="Orientation of the bars.", + ) + layout_kwargs: Optional[Dict[str, Any]] = Field( + default=None, + description="Additional keyword arguments to pass to the Plotly `update_layout` method.", + ) + + class EquityPriceHistoricalChartQueryParams(ChartQueryParams): """Equity Historical Price Chart Query Params.""" @@ -396,10 +413,11 @@ class ChartParams: """Chart Query Params.""" crypto_price_historical = EquityPriceHistoricalChartQueryParams + derivatives_futures_curve = FuturesCurveChartQueryParams + derivatives_futures_historical = EquityPriceHistoricalChartQueryParams equity_price_historical = EquityPriceHistoricalChartQueryParams economy_fred_series = EconomyFredSeriesChartQueryParams equity_price_historical = EquityPriceHistoricalChartQueryParams - derivatives_futures_historical = EquityPriceHistoricalChartQueryParams equity_price_performance = EquityPricePerformanceChartQueryParams etf_historical = EtfPricePerformanceChartQueryParams etf_holdings = EtfHoldingsChartQueryParams |