summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanglewood <85772166+deeleeramone@users.noreply.github.com>2024-05-21 10:02:19 -0700
committerGitHub <noreply@github.com>2024-05-21 17:02:19 +0000
commit8baf4d74b23fdeb3e6bfcaa8d648c3a3a9deb6b6 (patch)
tree10929fda4b1cbc7978cca683977e9e59c88c8ac2
parent63b8d6070470745a2d3723707efc359d5d48c63d (diff)
[Feature] Government Yield Curves + Chart (#6417)
* stashing * ecb yield curve * field_description * federal reserve yield curve * econdb yield curve * countries literal for python 3.9 * list date * fmp yield curve * fred yield curve * integration tests * chart integration tests * static assets * black * ruff * pylint * more pylint * more pylint * now black * country not a standard param * mypy * merge branch develop * add more countries * econdb date filter * mypy * future linting * make to_chart work * plot_bgcolor should be 'rbga(255,255,255,0)' * push deprecation * push deprecation --------- Co-authored-by: Igor Radovanovic <74266147+IgorWounds@users.noreply.github.com> Co-authored-by: hjoaquim <henriquecjoaquim@gmail.com>
-rw-r--r--openbb_platform/core/openbb_core/provider/standard_models/yield_curve.py37
-rw-r--r--openbb_platform/extensions/fixedincome/integration/test_fixedincome_api.py43
-rw-r--r--openbb_platform/extensions/fixedincome/integration/test_fixedincome_python.py42
-rw-r--r--openbb_platform/extensions/fixedincome/openbb_fixedincome/government/government_router.py45
-rw-r--r--openbb_platform/obbject_extensions/charting/integration/test_charting_api.py39
-rw-r--r--openbb_platform/obbject_extensions/charting/integration/test_charting_python.py31
-rw-r--r--openbb_platform/obbject_extensions/charting/openbb_charting/__init__.py3
-rw-r--r--openbb_platform/obbject_extensions/charting/openbb_charting/charting_router.py172
-rw-r--r--openbb_platform/obbject_extensions/charting/openbb_charting/query_params.py17
-rw-r--r--openbb_platform/obbject_extensions/charting/openbb_charting/utils/helpers.py19
-rw-r--r--openbb_platform/openbb/assets/reference.json135
-rw-r--r--openbb_platform/openbb/package/fixedincome_government.py110
-rw-r--r--openbb_platform/providers/ecb/openbb_ecb/__init__.py2
-rw-r--r--openbb_platform/providers/ecb/openbb_ecb/models/yield_curve.py160
-rw-r--r--openbb_platform/providers/ecb/openbb_ecb/utils/yield_curve_series.py35
-rw-r--r--openbb_platform/providers/ecb/tests/record/http/test_ecb_fetchers/test_ecb_yield_curve_fetcher.yaml113787
-rw-r--r--openbb_platform/providers/ecb/tests/test_ecb_fetchers.py11
-rw-r--r--openbb_platform/providers/econdb/openbb_econdb/__init__.py2
-rw-r--r--openbb_platform/providers/econdb/openbb_econdb/models/yield_curve.py195
-rw-r--r--openbb_platform/providers/econdb/openbb_econdb/utils/yield_curves.py219
-rw-r--r--openbb_platform/providers/econdb/tests/record/http/test_econdb_fetchers/test_econdb_yield_curve_fetcher.yaml8692
-rw-r--r--openbb_platform/providers/econdb/tests/test_econdb_fetchers.py15
-rw-r--r--openbb_platform/providers/federal_reserve/openbb_federal_reserve/__init__.py2
-rw-r--r--openbb_platform/providers/federal_reserve/openbb_federal_reserve/models/yield_curve.py109
-rw-r--r--openbb_platform/providers/federal_reserve/tests/record/http/test_federal_reserve_fetchers/test_federal_reserve_yield_curve_fetcher.yaml71
-rw-r--r--openbb_platform/providers/federal_reserve/tests/test_federal_reserve_fetchers.py11
-rw-r--r--openbb_platform/providers/fmp/openbb_fmp/__init__.py2
-rw-r--r--openbb_platform/providers/fmp/openbb_fmp/models/yield_curve.py126
-rw-r--r--openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_yield_curve_fetcher.yaml276
-rw-r--r--openbb_platform/providers/fmp/tests/test_fmp_fetchers.py11
-rw-r--r--openbb_platform/providers/fred/openbb_fred/__init__.py8
-rw-r--r--openbb_platform/providers/fred/openbb_fred/models/yield_curve.py106
-rw-r--r--openbb_platform/providers/fred/openbb_fred/utils/fred_helpers.py49
-rw-r--r--openbb_platform/providers/fred/tests/record/http/test_fred_fetchers/test_fred_us_yield_curve_fetcher.yaml718
-rw-r--r--openbb_platform/providers/fred/tests/record/http/test_fred_fetchers/test_fred_yield_curve_fetcher.yaml13964
-rw-r--r--openbb_platform/providers/fred/tests/test_fred_fetchers.py21
36 files changed, 139102 insertions, 183 deletions
diff --git a/openbb_platform/core/openbb_core/provider/standard_models/yield_curve.py b/openbb_platform/core/openbb_core/provider/standard_models/yield_curve.py
new file mode 100644
index 00000000000..97909e40804
--- /dev/null
+++ b/openbb_platform/core/openbb_core/provider/standard_models/yield_curve.py
@@ -0,0 +1,37 @@
+"""Yield Curve Standard Model."""
+
+from datetime import date as dateType
+from typing import Optional
+
+from pydantic import Field
+
+from openbb_core.provider.abstract.data import Data
+from openbb_core.provider.abstract.query_params import QueryParams
+from openbb_core.provider.utils.descriptions import (
+ DATA_DESCRIPTIONS,
+ QUERY_DESCRIPTIONS,
+)
+
+
+class YieldCurveQueryParams(QueryParams):
+ """Yield Curve Query."""
+
+ date: Optional[str] = Field(
+ default=None,
+ description=QUERY_DESCRIPTIONS.get("date", "")
+ + " By default is the current data.",
+ )
+
+
+class YieldCurveData(Data):
+ """Yield Curve Data."""
+
+ date: Optional[dateType] = Field(
+ default=None,
+ description=DATA_DESCRIPTIONS.get("date", ""),
+ )
+ maturity: str = Field(description="Maturity length of the security.")
+ rate: float = Field(
+ description="The yield as a normalized percent (0.05 is 5%)",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
diff --git a/openbb_platform/extensions/fixedincome/integration/test_fixedincome_api.py b/openbb_platform/extensions/fixedincome/integration/test_fixedincome_api.py
index da9c88c77c4..45e7c86a685 100644
--- a/openbb_platform/extensions/fixedincome/integration/test_fixedincome_api.py
+++ b/openbb_platform/extensions/fixedincome/integration/test_fixedincome_api.py
@@ -623,3 +623,46 @@ def test_fixedincome_corporate_bond_prices(params, headers):
result = requests.get(url, headers=headers, timeout=40)
assert isinstance(result, requests.Response)
assert result.status_code == 200
+
+
+@parametrize(
+ "params",
+ [
+ ({"date": "2023-05-01,2024-05-01", "provider": "fmp"}),
+ (
+ {
+ "date": "2023-05-01",
+ "country": "united_kingdom",
+ "provider": "econdb",
+ "use_cache": True,
+ }
+ ),
+ (
+ {
+ "provider": "ecb",
+ "yield_curve_type": "par_yield",
+ "date": None,
+ "rating": "aaa",
+ "use_cache": True,
+ }
+ ),
+ (
+ {
+ "provider": "fred",
+ "yield_curve_type": "nominal",
+ "date": "2023-05-01,2024-05-01",
+ }
+ ),
+ ({"provider": "federal_reserve", "date": "2023-05-01,2024-05-01"}),
+ ],
+)
+@pytest.mark.integration
+def test_fixedincome_government_yield_curve(params, headers):
+ """Test the treasury rates endpoint."""
+ params = {p: v for p, v in params.items() if v}
+
+ query_str = get_querystring(params, [])
+ url = f"http://0.0.0.0:8000/api/v1/fixedincome/government/yield_curve?{query_str}"
+ result = requests.get(url, headers=headers, timeout=10)
+ assert isinstance(result, requests.Response)
+ assert result.status_code == 200
diff --git a/openbb_platform/extensions/fixedincome/integration/test_fixedincome_python.py b/openbb_platform/extensions/fixedincome/integration/test_fixedincome_python.py
index 57ba30d7fad..3efa8727269 100644
--- a/openbb_platform/extensions/fixedincome/integration/test_fixedincome_python.py
+++ b/openbb_platform/extensions/fixedincome/integration/test_fixedincome_python.py
@@ -578,3 +578,45 @@ def test_fixedincome_corporate_bond_prices(params, obb):
assert result
assert isinstance(result, OBBject)
assert len(result.results) > 0
+
+
+@parametrize(
+ "params",
+ [
+ ({"date": "2023-05-01,2024-05-01", "provider": "fmp"}),
+ (
+ {
+ "date": "2023-05-01",
+ "country": "united_kingdom",
+ "provider": "econdb",
+ "use_cache": True,
+ }
+ ),
+ (
+ {
+ "provider": "ecb",
+ "yield_curve_type": "par_yield",
+ "date": None,
+ "rating": "aaa",
+ "use_cache": True,
+ }
+ ),
+ (
+ {
+ "provider": "fred",
+ "yield_curve_type": "nominal",
+ "date": "2023-05-01,2024-05-01",
+ }
+ ),
+ ({"provider": "federal_reserve", "date": "2023-05-01,2024-05-01"}),
+ ],
+)
+@pytest.mark.integration
+def test_fixedincome_government_yield_curve(params, obb):
+ """Test the government yield curve endpoint."""
+ params = {p: v for p, v in params.items() if v}
+
+ result = obb.fixedincome.government.yield_curve(**params)
+ assert result
+ assert isinstance(result, OBBject)
+ assert len(result.results) > 0
diff --git a/openbb_platform/extensions/fixedincome/openbb_fixedincome/government/government_router.py b/openbb_platform/extensions/fixedincome/openbb_fixedincome/government/government_router.py
index 7d7a325eb7a..641afb26577 100644
--- a/openbb_platform/extensions/fixedincome/openbb_fixedincome/government/government_router.py
+++ b/openbb_platform/extensions/fixedincome/openbb_fixedincome/government/government_router.py
@@ -1,5 +1,6 @@
"""Fixed Income Government Router."""
+from openbb_core.app.deprecation import OpenBBDeprecationWarning
from openbb_core.app.model.command_context import CommandContext
from openbb_core.app.model.example import APIEx
from openbb_core.app.model.obbject import OBBject
@@ -17,7 +18,45 @@ router = Router(prefix="/government")
@router.command(
+ model="YieldCurve",
+ examples=[
+ APIEx(parameters={"provider": "federal_reserve"}),
+ APIEx(parameters={"date": "2023-05-01,2024-05-01", "provider": "fmp"}),
+ APIEx(
+ parameters={
+ "date": "2023-05-01",
+ "country": "united_kingdom",
+ "provider": "econdb",
+ }
+ ),
+ APIEx(parameters={"provider": "ecb", "yield_curve_type": "par_yield"}),
+ APIEx(
+ parameters={
+ "provider": "fred",
+ "yield_curve_type": "real",
+ "date": "2023-05-01,2024-05-01",
+ }
+ ),
+ ],
+)
+async def yield_curve(
+ cc: CommandContext,
+ provider_choices: ProviderChoices,
+ standard_params: StandardParams,
+ extra_params: ExtraParams,
+) -> OBBject: # type: ignore
+ """Get yield curve data by country and date."""
+ return await OBBject.from_query(Query(**locals()))
+
+
+@router.command(
model="USYieldCurve",
+ deprecated=True,
+ deprecation=OpenBBDeprecationWarning(
+ message="This endpoint will be removed in a future version. Use, `/fixedincome/government/yield_curve`, instead.",
+ since=(4, 2),
+ expected_removal=(4, 4),
+ ),
examples=[
APIEx(parameters={"provider": "fred"}),
APIEx(parameters={"inflation_adjusted": True, "provider": "fred"}),
@@ -35,6 +74,12 @@ async def us_yield_curve(
@router.command(
model="EUYieldCurve",
+ deprecated=True,
+ deprecation=OpenBBDeprecationWarning(
+ message="This endpoint will be removed in a future version. Use, `/fixedincome/government/yield_curve`, instead.",
+ since=(4, 2),
+ expected_removal=(4, 4),
+ ),
examples=[
APIEx(parameters={"provider": "ecb"}),
APIEx(parameters={"yield_curve_type": "spot_rate", "provider": "ecb"}),
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 5066d5a40b7..fc9f2b0b646 100644
--- a/openbb_platform/obbject_extensions/charting/integration/test_charting_api.py
+++ b/openbb_platform/obbject_extensions/charting/integration/test_charting_api.py
@@ -719,3 +719,42 @@ def test_charting_etf_holdings(params, headers):
assert chart
assert not fig
assert list(chart.keys()) == ["content", "format"]
+
+
+@parametrize(
+ "params",
+ [
+ (
+ {
+ "provider": "econdb",
+ "country": "united_kingdom",
+ "date": None,
+ "chart": True,
+ }
+ ),
+ (
+ {
+ "provider": "fred",
+ "date": "2023-05-10,2024-05-10",
+ "chart": True,
+ }
+ ),
+ ],
+)
+@pytest.mark.integration
+def test_charting_fixedincome_government_yield_curve(params, headers):
+ """Test chart fixedincome government yield 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/fixedincome/government/yield_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 f8bc9275e59..b07b5792de8 100644
--- a/openbb_platform/obbject_extensions/charting/integration/test_charting_python.py
+++ b/openbb_platform/obbject_extensions/charting/integration/test_charting_python.py
@@ -590,3 +590,34 @@ def test_charting_etf_holdings(params, obb):
assert len(result.results) > 0
assert result.chart.content
assert isinstance(result.chart.fig, OpenBBFigure)
+
+
+@parametrize(
+ "params",
+ [
+ (
+ {
+ "provider": "econdb",
+ "country": "united_kingdom",
+ "date": None,
+ "chart": True,
+ }
+ ),
+ (
+ {
+ "provider": "fred",
+ "date": "2023-05-10,2024-05-10",
+ "chart": True,
+ }
+ ),
+ ],
+)
+@pytest.mark.integration
+def test_charting_fixedincome_government_yield_curve(params, obb):
+ """Test chart fixedincome government yield curve."""
+ result = obb.fixedincome.government.yield_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/__init__.py b/openbb_platform/obbject_extensions/charting/openbb_charting/__init__.py
index 913849cd41e..b2e5efcfd4a 100644
--- a/openbb_platform/obbject_extensions/charting/openbb_charting/__init__.py
+++ b/openbb_platform/obbject_extensions/charting/openbb_charting/__init__.py
@@ -459,6 +459,9 @@ class Charting:
)
kwargs["provider"] = self._obbject.provider # pylint: disable=protected-access
kwargs["extra"] = self._obbject.extra # pylint: disable=protected-access
+ kwargs["extra_params"] = kwargs["extra"]["metadata"].arguments.get(
+ "extra_params"
+ )
if "kwargs" in kwargs:
_kwargs = kwargs.pop("kwargs")
kwargs.update(_kwargs.get("chart_params", {}))
diff --git a/openbb_platform/obbject_extensions/charting/openbb_charting/charting_router.py b/openbb_platform/obbject_extensions/charting/openbb_charting/charting_router.py
index 43e534ce2f9..94dcb63ca45 100644
--- a/openbb_platform/obbject_extensions/charting/openbb_charting/charting_router.py
+++ b/openbb_platform/obbject_extensions/charting/openbb_charting/charting_router.py
@@ -8,6 +8,7 @@ from warnings import warn
import pandas as pd
from openbb_core.app.model.charts.chart import ChartFormat
from openbb_core.app.utils import basemodel_to_df
+from openbb_core.provider.abstract.data import Data
from plotly.graph_objs import Figure
from openbb_charting.core.chart_style import ChartStyle
@@ -19,6 +20,7 @@ from openbb_charting.utils import relative_rotation
from openbb_charting.utils.generic_charts import bar_chart
from openbb_charting.utils.helpers import (
calculate_returns,
+ duration_sorter,
heikin_ashi,
should_share_axis,
z_score_standardization,
@@ -403,7 +405,7 @@ def equity_price_historical( # noqa: PLR0912
name=data[col].name,
mode="lines",
hovertemplate=hovertemplate,
- line=dict(width=1, color=LARGE_CYCLER[i % len(LARGE_CYCLER)]),
+ line=dict(width=2, color=LARGE_CYCLER[i % len(LARGE_CYCLER)]),
yaxis=yaxis,
)
@@ -1106,7 +1108,7 @@ def economy_fred_series( # noqa: PLR0912
name=df_ta[col].name,
mode="lines",
hovertemplate=f"{df_ta[col].name}: %{{y}}<extra></extra>",
- line=dict(width=1, color=LARGE_CYCLER[i % len(LARGE_CYCLER)]),
+ line=dict(width=2, color=LARGE_CYCLER[i % len(LARGE_CYCLER)]),
yaxis="y1" if kwargs.get("same_axis") is True else yaxes,
)
@@ -1239,7 +1241,7 @@ def technical_relative_rotation(
ratios_df, momentum_df, benchmark_symbol, study, date # type: ignore
)
- figure = OpenBBFigure(fig)
+ figure = OpenBBFigure(fig) # pylint: disable=E0606
font_color = "black" if ChartStyle().plt_style == "light" else "white"
figure.update_layout(
paper_bgcolor="rgba(0,0,0,0)",
@@ -1278,3 +1280,167 @@ def technical_relative_rotation(
content = figure.to_plotly_json()
return figure, content
+
+
+def fixedincome_government_yield_curve( # noqa: PLR0912
+ **kwargs,
+) -> Tuple[OpenBBFigure, Dict[str, Any]]:
+ """Government Yield Curve Chart."""
+ data = kwargs.get("data", None)
+ df: pd.DataFrame = pd.DataFrame()
+ if data:
+ if isinstance(data, pd.DataFrame) and not data.empty: # noqa: SIM108
+ df = data
+ elif isinstance(data, (list, Data)):
+ df = basemodel_to_df(data, index=None) # type: ignore
+ else:
+ pass
+ else:
+ df = pd.DataFrame([d.model_dump() for d in kwargs["obbject_item"]]) # type: ignore
+
+ if df.empty:
+ raise ValueError("Error: No data to plot.")
+
+ if "maturity" not in df.columns:
+ raise ValueError("Error: Maturity column not found in the data.")
+
+ if "rate" not in df.columns:
+ raise ValueError("Error: Rate column not found in the data.")
+
+ if "date" not in df.columns:
+ raise ValueError("Error: Date column not found in the data.")
+
+ provider = kwargs.get("provider")
+ df["date"] = df["date"].astype(str)
+ maturities = duration_sorter(df["maturity"].unique().tolist())
+
+ # Use the supplied colors, if any.
+ colors = kwargs.get("colors", [])
+ if not colors:
+ colors = LARGE_CYCLER
+ color_count = 0
+
+ figure = OpenBBFigure().create_subplots(shared_xaxes=True)
+ figure.update_layout(ChartStyle().plotly_template.get("layout", {}))
+
+ def create_fig(figure, df, dates, color_count, country: Optional[str] = None):
+ """Create a scatter for each date in the data."""
+ for date in dates:
+ color = colors[color_count % len(colors)]
+ plot_df = df[df["date"] == date].copy()
+ plot_df["rate"] = plot_df["rate"].apply(lambda x: x * 100)
+ plot_df = (
+ plot_df.drop(columns=["date"])
+ .set_index("maturity")
+ .filter(items=maturities, axis=0)
+ .reset_index()
+ .rename(columns={"maturity": "Maturity", "rate": "Yield"})
+ )
+ plot_df["Maturity"] = [
+ (
+ d.split("_")[1] + " " + d.split("_")[0].title()
+ if d != "long_term"
+