Skip to content

Commit

Permalink
[Enhancement] Add Multi-Country Support & ECB Yield Curves To `fixedi…
Browse files Browse the repository at this point in the history
…ncome.goverment.yield_curve(provider='econdb')` (#6946)

* add multi-country suppport and ECB yield curves to EconDB

* lint

* do igor's suggestion

* mypy
  • Loading branch information
deeleeramone authored Nov 21, 2024
1 parent 685eda5 commit a905799
Show file tree
Hide file tree
Showing 6 changed files with 344 additions and 188 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@
from datetime import date as dateType
from typing import Optional, Union

from pydantic import Field, field_validator

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,
)
from pydantic import Field, computed_field, field_validator


class YieldCurveQueryParams(QueryParams):
"""Yield Curve Query."""

date: Union[None, dateType, str] = Field(
date: Optional[Union[dateType, str]] = Field(
default=None,
description=QUERY_DESCRIPTIONS.get("date", "")
+ " By default is the current data.",
Expand All @@ -34,9 +33,10 @@ def _validate_date(cls, v):
if isinstance(v, dateType):
return v.strftime("%Y-%m-%d")
new_dates: list = []
dates: list = []
if isinstance(v, str):
dates = v.split(",")
if isinstance(v, list):
elif isinstance(v, list):
dates = v
for date in dates:
new_dates.append(to_datetime(date).date().strftime("%Y-%m-%d"))
Expand All @@ -52,7 +52,21 @@ class YieldCurveData(Data):
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},

@computed_field( # type: ignore
description="Maturity length, in years, as a decimal.",
return_type=Optional[float],
)
@property
def maturity_years(self) -> Optional[float]:
"""Get the maturity in years as a decimal."""
if "_" not in self.maturity: # pylint: disable=E1135
return None

parts = self.maturity.split("_") # pylint: disable=E1101
months = sum(
int(parts[i + 1]) * (12 if parts[i] == "year" else 1)
for i in range(0, len(parts), 2)
)

return months / 12
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def fixedincome_government_yield_curve( # noqa: PLR0912
from openbb_core.app.utils import basemodel_to_df
from pandas import DataFrame

data = kwargs.get("data", None)
data = kwargs.get("data")
df: DataFrame = DataFrame()
if data:
if isinstance(data, DataFrame) and not data.empty: # noqa: SIM108
Expand All @@ -55,6 +55,9 @@ def fixedincome_government_yield_curve( # noqa: PLR0912
provider = kwargs.get("provider")
df["date"] = df["date"].astype(str)
maturities = duration_sorter(df["maturity"].unique().tolist())
countries: list = (
df["country"].unique().tolist() if "country" in df.columns else []
)

# Use the supplied colors, if any.
colors = kwargs.get("colors", [])
Expand All @@ -66,11 +69,13 @@ def fixedincome_government_yield_curve( # noqa: PLR0912
figure.update_layout(ChartStyle().plotly_template.get("layout", {}))
text_color = "white" if ChartStyle().plt_style == "dark" else "black"

def create_fig(figure, df, dates, color_count, country: Optional[str] = None):
def create_fig(
figure, dataframe, 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 = dataframe[dataframe["date"] == date].copy()
plot_df["rate"] = plot_df["rate"].apply(lambda x: x * 100)
plot_df = plot_df.rename(columns={"rate": "Yield"})
plot_df = (
Expand All @@ -81,31 +86,41 @@ def create_fig(figure, df, dates, color_count, country: Optional[str] = None):
)
plot_df = plot_df.rename(columns={"index": "Maturity"})
plot_df["Maturity"] = [
(
d.split("_")[1] + " " + d.split("_")[0].title()
if d != "long_term"
else "Long Term"
)
(d.split("_")[1] + " " + d.split("_")[0].title())
for d in plot_df["Maturity"]
]
figure.add_scatter(
x=plot_df["Maturity"],
y=plot_df["Yield"],
mode="lines+markers",
name=f"{country} - {date}" if country else date,
name=(
f"{country.replace('_', ' ').title().replace('Ecb', 'ECB')} {date}"
if country
else date
),
line=dict(width=3, color=color),
marker=dict(size=10, color=color),
hovertemplate=(
"Maturity: %{x}<br>Yield: %{y}%<extra></extra>"
if len(dates) == 1
if len(dates) == 1 and not countries
else "%{fullData.name}<br>Maturity: %{x}<br>Yield: %{y}%<extra></extra>"
),
)
color_count += 1
return figure, color_count

dates = df.date.unique().tolist()
figure, color_count = create_fig(figure, df, dates, color_count)
if countries:
for _country in countries:
_df = df[df["country"] == _country]
dates = _df.date.unique().tolist()
figure, color_count = create_fig(
figure, _df, dates, color_count, _country
)

else:
dates = df.date.unique().tolist()
figure, color_count = create_fig(figure, df, dates, color_count)

extra_params = kwargs.get("extra_params", {})
extra_params = (
extra_params if isinstance(extra_params, dict) else extra_params.__dict__
Expand All @@ -130,14 +145,26 @@ def create_fig(figure, df, dates, color_count, country: Optional[str] = None):
)
country = f"United States {curve_type}"
elif provider == "econdb":
country = extra_params.get("country", "")
country = country.replace("_", " ").title() if country else "United States"
country = (
""
if countries
else (
extra_params.get("country", "")
.replace("_", " ")
.title()
.replace("Ecb", "ECB")
or "United States"
)
)

country = country + " " if country else ""
title = kwargs.get("title", "")
if not title:
title = f"{country}Yield Curve"
if len(dates) == 1:
if len(dates) == 1 and len(countries) == 1:
title = f"{country} Yield Curve - {dates[0]}"
elif countries:
title = f"Yield Curve - {', '.join(countries).replace('_', ' ').title().replace('Ecb', 'ECB')}"

# Update the layout of the figure.
figure.update_layout(
Expand All @@ -156,11 +183,7 @@ def create_fig(figure, df, dates, color_count, country: Optional[str] = None):
categoryorder="array",
categoryarray=(
[
(
d.split("_")[1] + " " + d.split("_")[0].title()
if d != "long_term"
else "Long Term"
)
(d.split("_")[1] + " " + d.split("_")[0].title())
for d in maturities
]
),
Expand All @@ -186,6 +209,7 @@ def create_fig(figure, df, dates, color_count, country: Optional[str] = None):
margin=dict(
b=25,
t=10,
l=20,
),
)

Expand Down
33 changes: 14 additions & 19 deletions openbb_platform/openbb/assets/reference.json
Original file line number Diff line number Diff line change
Expand Up @@ -3020,7 +3020,7 @@
},
{
"name": "date",
"type": "Union[Union[str, date], List[Union[str, date]]]",
"type": "Union[Union[date, str], List[Union[date, str]]]",
"description": "A specific date to get data for. Multiple items allowed for provider(s): yfinance.",
"default": null,
"optional": true,
Expand Down Expand Up @@ -4671,7 +4671,7 @@
"standard": [
{
"name": "date",
"type": "Union[Union[str, date], List[Union[str, date]]]",
"type": "Union[Union[date, str], List[Union[date, str]]]",
"description": "A specific date to get data for. Default is the latest report. Multiple items allowed for provider(s): fred.",
"default": null,
"optional": true,
Expand Down Expand Up @@ -9657,7 +9657,7 @@
"standard": [
{
"name": "date",
"type": "Union[Union[str, date], List[Union[str, date]]]",
"type": "Union[Union[date, str], List[Union[date, str]]]",
"description": "A specific date to get data for. Default is the latest report. Multiple items allowed for provider(s): fred.",
"default": null,
"optional": true,
Expand Down Expand Up @@ -33795,7 +33795,7 @@
"fmp": [
{
"name": "date",
"type": "Union[Union[str, date], str]",
"type": "Union[Union[date, str], str]",
"description": "A specific date to get data for. Entering a date will attempt to return the NPORT-P filing for the entered date. This needs to be _exactly_ the date of the filing. Use the holdings_date command/endpoint to find available filing dates for the ETF.",
"default": null,
"optional": true,
Expand Down Expand Up @@ -33823,7 +33823,7 @@
"sec": [
{
"name": "date",
"type": "Union[Union[str, date], str]",
"type": "Union[Union[date, str], str]",
"description": "A specific date to get data for. The date represents the period ending. The date entered will return the closest filing.",
"default": null,
"optional": true,
Expand Down Expand Up @@ -36674,7 +36674,7 @@
"standard": [
{
"name": "date",
"type": "Union[Union[None, date, str], List[Union[None, date, str]]]",
"type": "Union[Union[date, str], List[Union[date, str]]]",
"description": "A specific date to get data for. By default is the current data. Multiple items allowed for provider(s): econdb, federal_reserve, fmp, fred.",
"default": null,
"optional": true,
Expand All @@ -36684,14 +36684,17 @@
"econdb": [
{
"name": "country",
"type": "Literal['australia', 'canada', 'china', 'hong_kong', 'india', 'japan', 'mexico', 'new_zealand', 'russia', 'saudi_arabia', 'singapore', 'south_africa', 'south_korea', 'taiwan', 'thailand', 'united_kingdom', 'united_states']",
"description": "The country to get data. New Zealand, Mexico, Singapore, and Thailand have only monthly data. The nearest date to the requested one will be used.",
"type": "Union[str, List[str]]",
"description": "The country to get data. New Zealand, Mexico, Singapore, and Thailand have only monthly data. The nearest date to the requested one will be used. Multiple items allowed for provider(s): econdb.",
"default": "united_states",
"optional": true,
"choices": [
"australia",
"canada",
"china",
"ecb_instantaneous_forward",
"ecb_par_yield",
"ecb_spot_rate",
"hong_kong",
"india",
"japan",
Expand Down Expand Up @@ -36783,14 +36786,6 @@
"default": "",
"optional": false,
"choices": null
},
{
"name": "rate",
"type": "float",
"description": "The yield as a normalized percent (0.05 is 5%)",
"default": "",
"optional": false,
"choices": null
}
],
"econdb": [],
Expand Down Expand Up @@ -37456,7 +37451,7 @@
"standard": [
{
"name": "date",
"type": "Union[Union[str, date], List[Union[str, date]]]",
"type": "Union[Union[date, str], List[Union[date, str]]]",
"description": "A specific date to get data for. Multiple items allowed for provider(s): fred.",
"default": null,
"optional": true,
Expand Down Expand Up @@ -38767,7 +38762,7 @@
},
{
"name": "date_first_added",
"type": "Union[str, date]",
"type": "Union[date, str]",
"description": "Date the constituent company was added to the index.",
"default": null,
"optional": true,
Expand All @@ -38783,7 +38778,7 @@
},
{
"name": "founded",
"type": "Union[str, date]",
"type": "Union[date, str]",
"description": "Founding year of the constituent company in the index.",
"default": null,
"optional": true,
Expand Down
39 changes: 32 additions & 7 deletions openbb_platform/openbb/package/fixedincome_government.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ def us_yield_curve(
def yield_curve(
self,
date: Annotated[
Union[str, datetime.date, None, List[Union[str, datetime.date, None]]],
Union[datetime.date, str, None, List[Union[datetime.date, str, None]]],
OpenBBField(
description="A specific date to get data for. By default is the current data. Multiple comma separated items allowed for provider(s): econdb, federal_reserve, fmp, fred."
),
Expand All @@ -355,12 +355,12 @@ def yield_curve(
Parameters
----------
date : Union[str, date, None, List[Union[str, date, None]]]
date : Union[date, str, None, List[Union[date, str, None]]]
A specific date to get data for. By default is the current data. Multiple comma separated items allowed for provider(s): econdb, federal_reserve, fmp, fred.
provider : Optional[Literal['econdb', 'federal_reserve', 'fmp', 'fred']]
The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: econdb, federal_reserve, fmp, fred.
country : Literal['australia', 'canada', 'china', 'hong_kong', 'india', 'japan', 'mexico', 'new_zealand', 'russia', 'saudi_arabia', 'singapore', 'south_africa', 'south_korea', 'taiwan', 'thailand', 'united_kingdom', 'united_states']
The country to get data. New Zealand, Mexico, Singapore, and Thailand have only monthly data. The nearest date to the requested one will be used. (provider: econdb)
country : str
The country to get data. New Zealand, Mexico, Singapore, and Thailand have only monthly data. The nearest date to the requested one will be used. Multiple comma separated items allowed. (provider: econdb)
use_cache : bool
If true, cache the request for four hours. (provider: econdb)
yield_curve_type : Literal['nominal', 'real', 'breakeven', 'treasury_minus_fed_funds', 'corporate_spot', 'corporate_par']
Expand All @@ -386,8 +386,6 @@ def yield_curve(
The date of the data.
maturity : str
Maturity length of the security.
rate : float
The yield as a normalized percent (0.05 is 5%)
Examples
--------
Expand Down Expand Up @@ -421,7 +419,34 @@ def yield_curve(
},
"fmp": {"multiple_items_allowed": True, "choices": None},
"fred": {"multiple_items_allowed": True, "choices": None},
}
},
"country": {
"econdb": {
"multiple_items_allowed": True,
"choices": [
"australia",
"canada",
"china",
"ecb_instantaneous_forward",
"ecb_par_yield",
"ecb_spot_rate",
"hong_kong",
"india",
"japan",
"mexico",
"new_zealand",
"russia",
"saudi_arabia",
"singapore",
"south_africa",
"south_korea",
"taiwan",
"thailand",
"united_kingdom",
"united_states",
],
}
},
},
)
)
Loading

0 comments on commit a905799

Please sign in to comment.