diff options
author | Danglewood <85772166+deeleeramone@users.noreply.github.com> | 2024-05-14 21:18:35 -0700 |
---|---|---|
committer | Danglewood <85772166+deeleeramone@users.noreply.github.com> | 2024-05-14 21:18:35 -0700 |
commit | 887204b120949f2f7f09e8fad8f3f1ef4202af19 (patch) | |
tree | 1c7bfb1299874e356accd52e32fe8ad266a79f56 | |
parent | b711bd8eff341c26e4e88efd90ae39df7606d160 (diff) |
fmp yield curve
4 files changed, 416 insertions, 0 deletions
diff --git a/openbb_platform/providers/fmp/openbb_fmp/__init__.py b/openbb_platform/providers/fmp/openbb_fmp/__init__.py index 01f9a5019e5..d10dfdd2353 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/__init__.py +++ b/openbb_platform/providers/fmp/openbb_fmp/__init__.py @@ -63,6 +63,8 @@ from openbb_fmp.models.risk_premium import FMPRiskPremiumFetcher from openbb_fmp.models.share_statistics import FMPShareStatisticsFetcher from openbb_fmp.models.treasury_rates import FMPTreasuryRatesFetcher from openbb_fmp.models.world_news import FMPWorldNewsFetcher +from openbb_fmp.models.yield_curve import FMPYieldCurveFetcher + fmp_provider = Provider( name="fmp", @@ -134,6 +136,7 @@ stock market information (news, currencies, and stock prices).""", "TreasuryRates": FMPTreasuryRatesFetcher, "WorldNews": FMPWorldNewsFetcher, "EtfHistorical": FMPEquityHistoricalFetcher, + "YieldCurve": FMPYieldCurveFetcher, }, repr_name="Financial Modeling Prep (FMP)", v3_credentials=["API_KEY_FINANCIALMODELINGPREP"], diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/yield_curve.py b/openbb_platform/providers/fmp/openbb_fmp/models/yield_curve.py new file mode 100644 index 00000000000..8e2e3d8f245 --- /dev/null +++ b/openbb_platform/providers/fmp/openbb_fmp/models/yield_curve.py @@ -0,0 +1,126 @@ +"""FMP Yield Curve Model.""" + +# pylint: disable=unused-argument + +from datetime import datetime, timedelta +from typing import Any, Dict, List, Optional + +from openbb_core.provider.abstract.fetcher import Fetcher +from openbb_core.provider.standard_models.yield_curve import ( + YieldCurveData, + YieldCurveQueryParams, +) +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import amake_requests +from pandas import Categorical, DataFrame, DatetimeIndex + +maturity_dict = { + "month1": "month_1", + "month2": "month_2", + "month3": "month_3", + "month6": "month_6", + "year1": "year_1", + "year2": "year_2", + "year3": "year_3", + "year5": "year_5", + "year7": "year_7", + "year10": "year_10", + "year20": "year_20", + "year30": "year_30", +} + + +class FMPYieldCurveQueryParams(YieldCurveQueryParams): + """FMP Yield Curve Query. + + Source: https://site.financialmodelingprep.com/developer/docs/treasury-rates-api/ + """ + + __json_schema_extra__ = {"date": {"multiple_items_allowed": True}} + + +class FMPYieldCurveData(YieldCurveData): + """FMP Yield Curve Data.""" + + +class FMPYieldCurveFetcher( + Fetcher[ + FMPYieldCurveQueryParams, + List[FMPYieldCurveData], + ] +): + """FMP Yield Curve Fetcher.""" + + @staticmethod + def transform_query(params: Dict[str, Any]) -> FMPYieldCurveQueryParams: + """Transform the query params.""" + transformed_params = params + if not transformed_params.get("date"): + transformed_params["date"] = datetime.now().strftime("%Y-%m-%d") + return FMPYieldCurveQueryParams(**transformed_params) + + @staticmethod + async def aextract_data( + query: FMPYieldCurveQueryParams, + credentials: Optional[Dict[str, str]], + **kwargs: Any, + ) -> List[Dict]: + """Return the raw data from the FMP endpoint.""" + api_key = credentials.get("fmp_api_key") if credentials else "" + + def generate_url(date): + """Generate URL for a small window between each date.""" + date = datetime.strptime(date, "%Y-%m-%d") + from_date = (date - timedelta(days=3)).strftime("%Y-%m-%d") + to_date = (date + timedelta(days=3)).strftime("%Y-%m-%d") + url = ( + "https://financialmodelingprep.com/api/v4/treasury?" + + f"from={from_date}&to={to_date}&apikey={api_key}" + ) + return url + + dates = query.date.split(",") + urls = [generate_url(date) for date in dates] + + return await amake_requests(urls, **kwargs) + + @staticmethod + def transform_data( + query: FMPYieldCurveQueryParams, data: List[Dict], **kwargs: Any + ) -> List[FMPYieldCurveData]: + """Return the transformed data.""" + if not data: + raise EmptyDataError("The request was returned empty.") + df = DataFrame(data).set_index("date") + dates = query.date.split(",") if query.date else [df.index.max()] + df.index = DatetimeIndex(df.index) + dates_list = DatetimeIndex(dates) + df = df.rename(columns=maturity_dict) + df.columns.name = "maturity" + + # Find the nearest date in the DataFrame to each date in dates_list + nearest_dates = [df.index.asof(date) for date in dates_list] + + # Filter for only the nearest dates + df = df[df.index.isin(nearest_dates)] + + df = df.fillna("N/A").replace("N/A", None) + + # Flatten the DataFrame + flattened_data = df.reset_index().melt( + id_vars="date", var_name="maturity", value_name="rate" + ) + flattened_data = flattened_data.sort_values("date") + flattened_data["maturity"] = Categorical( + flattened_data["maturity"], + categories=list(maturity_dict.values()), + ordered=True, + ) + flattened_data["rate"] = flattened_data["rate"].astype(float) / 100 + flattened_data = flattened_data.sort_values( + by=["date", "maturity"] + ).reset_index(drop=True) + flattened_data.loc[:, "date"] = flattened_data["date"].dt.strftime("%Y-%m-%d") + records = flattened_data.to_dict(orient="records") + + return [FMPYieldCurveData.model_validate(d) for d in records] diff --git a/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_yield_curve_fetcher.yaml b/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_yield_curve_fetcher.yaml new file mode 100644 index 00000000000..9bf46d6f9f5 --- /dev/null +++ b/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_yield_curve_fetcher.yaml @@ -0,0 +1,276 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://financialmodelingprep.com/api/v4/treasury?apikey=MOCK_API_KEY&from=2020-05-11&to=2020-05-17 + response: + body: + string: !!binary | + H4sIAAAAAAAAA62UywrCMBBF9/2K0HUrmTz68FfERcGCGxWkGxH/3ZpM4IbGNoiLbk7Sm+Z0Zg6F + EM/5EaI8DdNY7kWppJK1tDV1ZeVXLrfrdKZ5Te4IkfIoYtozjazxzDJ7jMOd01pAnNYB8mHKALIO + adzVOmQxi6Rjrcb8D6P4TO2ZMTN6VSsubMKF7JcyYsYyVJ4MRCyjWcigHhDLIEBehsFdLKNBjSxD + 4pksQ6stGSZTRqow/ulCAfmuAkslqEjUhUQWVGyZ0JktkhCR2SH/ExGFr5REoj+03RKhMkXkmsA7 + 0hJxWvSp3kRCBV6SVeC/Di6wZcKsQIvBRbflgnLbI7c/fpaRGJz4IsuI4lcGZ1R3PDhdhxTHN0O6 + YwdHBgAA + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - X-Requested-With, content-type, auth-token, Authorization, stripe-signature, + APPS, publicauthkey, privateauthkey + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Access-Control-Max-Age: + - '3600' + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 15 May 2024 04:17:01 GMT + Etag: + - W/"647-LydzNMvIZhxt85QadA8Kg/rKyC0" + Server: + - nginx/1.18.0 (Ubuntu) + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + X-Frame-Options: + - SAMEORIGIN + X-Powered-By: + - Express + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://financialmodelingprep.com/api/v4/treasury?apikey=MOCK_API_KEY&from=2023-05-11&to=2023-05-17 + response: + body: + string: !!binary | + H4sIAAAAAAAAA4WUu27DMAxF93yF4Tkx9KbUXyk6BGiALm2BIktR9N9jiwx6WRHx4OXIpsjjKz0f + pulnfaZpfj1fL/PTNAcX4snlk6/zkVfePz+ub35dy0tuyEJnISCLnUWPrDCrwr4v5y8u5wKgrVpa + QgK0FYtLQ5Q7Kg0QMSIs75hlrO/6BmrPyO81v6Lf4wMZZMkYXbgyugiKiYt/KtLSRhVeddobRYVs + IiOiEYmJjHaCTF2wPrNa90wUy0RFxt03xURFRFa0nj8XFQfgak712lulMRYZjYkMpVpk4JePZNCe + jGzIKAmZyCBkIsM4Iyr9LINwgMC9YvpZhko/y0g4EctIVjIMF8YRqWnPRTBc0HBfrH/XcqHOErvw + YzBINcu94kjiAt8SF4hoROJCKQv3EIwyaPeUeENGVT9cZBiXp0LiwsjFoKKOscg4EKuIYyyicXVG + LHZXYeSC4qbi8HIDJk0/oEoGAAA= + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - X-Requested-With, content-type, auth-token, Authorization, stripe-signature, + APPS, publicauthkey, privateauthkey + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Access-Control-Max-Age: + - '3600' + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 15 May 2024 04:17:01 GMT + Etag: + - W/"64a-qQ86HxIoIDU3JJj3ypPqfnNTl40" + Server: + - nginx/1.18.0 (Ubuntu) + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + X-Frame-Options: + - SAMEORIGIN + X-Powered-By: + - Express + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://financialmodelingprep.com/api/v4/treasury?apikey=MOCK_API_KEY&from=2022-05-11&to=2022-05-17 + response: + body: + string: !!binary | + H4sIAAAAAAAAA42UzWrDMBAG73kK4XNi9GNprb5K6SHQQC9toeRSSt89tnZVvq0UO4dcJpFgJ7N6 + Phjzs3yMGV7P18vwZAZvvT/ZeHLzcORv3j8/rm9u+c6OMSHzhc0RWViYG21Algr7O/t9OX+t1/nR + IfIFpRlQKGieAEVGGRAVlB1eb9uf+ZWF0eNtgZmlBf0eN2RQR0ZyyDZkKGkigx6RQThTaEdiGRkP + rjIC3s0mMmoVEwHPiQm3ayL1TEzINkwQMjGB/websCiHTcQ2C4qAJAucnFpfNYuejE4Vec9F6LlQ + M7ILysjur8jUVmFRj6xIWwW1VfRWBI3VMHDw6sJ3wthz4R/cEFJ+QmG5syHT/y6cDl26UA2zC5xI + XKAx6UK9RtKFci3PRetiz4TrPZyqgA0TypiYUPvMJtTDxlW0JtTY96tQoqUKPFlNYD11ReIq4/By + AxjfFZ5IBgAA + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - X-Requested-With, content-type, auth-token, Authorization, stripe-signature, + APPS, publicauthkey, privateauthkey + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Access-Control-Max-Age: + - '3600' + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 15 May 2024 04:17:01 GMT + Etag: + - W/"648-twHy7YLcgra10np90L3C4D2swpw" + Server: + - nginx/1.18.0 (Ubuntu) + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + X-Frame-Options: + - SAMEORIGIN + X-Powered-By: + - Express + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://financialmodelingprep.com/api/v4/treasury?apikey=MOCK_API_KEY&from=2021-05-11&to=2021-05-17 + response: + body: + string: !!binary | + H4sIAAAAAAAAA62Uyw6CMBBF935FwxpIZ8rTXzEuSCRxoyaGjTH+u0CH5FYaHsKCzSkztKd3OB2U + erePUsGlaurgqALWTJFOIyqC0K7cHvfmSu2aRsAdiDUhM5YxsswyI+xVV0+yKANkuxEi28wkgNIe + FdgrbxHFXGJ73bMMK7ljHHOOH7DM5C36hBMm8l1N4La2mkBkTTieV4rI5kQkYxE/555w4bCtqcBC + ccGAJlKBlYOM1CMjnZNhdk2FxwTuapUJTyoI24sJx7SYKDwmyjkTvDQWzsHXjcgyGfiWyMCgiwyn + vcjAqAwykImMZM4FLXWxdET+doFXLi5GKpz7HlT4fheYMmdCDucv9UoTokQGAAA= + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - X-Requested-With, content-type, auth-token, Authorization, stripe-signature, + APPS, publicauthkey, privateauthkey + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Access-Control-Max-Age: + - '3600' + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 15 May 2024 04:17:01 GMT + Etag: + - W/"644-FBvvp3deUZ1C1r7lKBqDjdjmSI4" + Server: + - nginx/1.18.0 (Ubuntu) + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + X-Frame-Options: + - SAMEORIGIN + X-Powered-By: + - Express + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://financialmodelingprep.com/api/v4/treasury?apikey=MOCK_API_KEY&from=2024-05-11&to=2024-05-17 + response: + body: + string: !!binary | + H4sIAAAAAAAAA6XQTQrCMBCG4X1PEbJuS35mJq1XERcFC25UkG5EvLtpJsInBUFcdPNkOk3ffWPM + Iz/G2OO0zHZnbHCBOsedJ9vqyfl6WU4+n3HPSKEQJbSoRmiiFqvd5+mm27wArduoHzxQLCQBiAsR + vpiUGNe7rQU1GfEDajxmerZfWsQ/WnzM/dQCr19b4JS2wKGaAn/xnWLYpkgYtqaQuKZoDi/SxMk5 + GQIAAA== + headers: + Access-Control-Allow-Credentials: + - 'true' + Access-Control-Allow-Headers: + - X-Requested-With, content-type, auth-token, Authorization, stripe-signature, + APPS, publicauthkey, privateauthkey + Access-Control-Allow-Methods: + - GET, POST, OPTIONS + Access-Control-Allow-Origin: + - '*' + Access-Control-Max-Age: + - '3600' + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json; charset=utf-8 + Date: + - Wed, 15 May 2024 04:17:01 GMT + Etag: + - W/"219-AzGShdXa56qJWPx5KMZ5NeNIBjI" + Server: + - nginx/1.18.0 (Ubuntu) + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + X-Frame-Options: + - SAMEORIGIN + X-Powered-By: + - Express + status: + code: 200 + message: OK +version: 1 diff --git a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py index b740b6e8050..de3c82ef7c5 100644 --- a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py +++ b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py @@ -70,6 +70,7 @@ from openbb_fmp.models.risk_premium import FMPRiskPremiumFetcher from openbb_fmp.models.share_statistics import FMPShareStatisticsFetcher from openbb_fmp.models.treasury_rates import FMPTreasuryRatesFetcher from openbb_fmp.models.world_news import FMPWorldNewsFetcher +from openbb_fmp.models.yield_curve import FMPYieldCurveFetcher test_credentials = UserService().default_user_settings.credentials.model_dump( mode="json" @@ -746,3 +747,13 @@ def test_fmp_equity_forward_eps_fetcher(credentials=test_credentials): fetcher = FMPForwardEpsEstimatesFetcher() result = fetcher.test(params, credentials) assert result is None + + +@pytest.mark.record_http +def test_fmp_yield_curve_fetcher(credentials=test_credentials): + """Test FMP Yield Curve Fetcher.""" + params = {"date": "2024-05-14,2023-05-14,2022-05-14,2021-05-14,2020-05-14"} + + fetcher = FMPYieldCurveFetcher() + result = fetcher.test(params, credentials) + assert result is None |