From 7a545ec889fbe2fd402932c3513e40a8d3765993 Mon Sep 17 00:00:00 2001 From: joshua <2541874972@qq.com> Date: Wed, 20 Nov 2024 15:47:51 +0800 Subject: [PATCH 01/11] [Feature] Add Form13f Data --- .../providers/fmp/openbb_fmp/__init__.py | 2 + .../fmp/openbb_fmp/models/form_13f.py | 109 ++++++++++++++++++ .../providers/fmp/tests/test_fmp_fetchers.py | 14 +++ 3 files changed, 125 insertions(+) create mode 100644 openbb_platform/providers/fmp/openbb_fmp/models/form_13f.py diff --git a/openbb_platform/providers/fmp/openbb_fmp/__init__.py b/openbb_platform/providers/fmp/openbb_fmp/__init__.py index 5f791bb97b06..371d153fce71 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/__init__.py +++ b/openbb_platform/providers/fmp/openbb_fmp/__init__.py @@ -39,6 +39,7 @@ from openbb_fmp.models.etf_sectors import FMPEtfSectorsFetcher from openbb_fmp.models.executive_compensation import FMPExecutiveCompensationFetcher from openbb_fmp.models.financial_ratios import FMPFinancialRatiosFetcher +from openbb_fmp.models.form_13f import FMPForm13FHRFetcher from openbb_fmp.models.forward_ebitda_estimates import FMPForwardEbitdaEstimatesFetcher from openbb_fmp.models.forward_eps_estimates import FMPForwardEpsEstimatesFetcher from openbb_fmp.models.historical_dividends import FMPHistoricalDividendsFetcher @@ -137,6 +138,7 @@ "WorldNews": FMPWorldNewsFetcher, "EtfHistorical": FMPEquityHistoricalFetcher, "YieldCurve": FMPYieldCurveFetcher, + "Form13FHR": FMPForm13FHRFetcher, }, repr_name="Financial Modeling Prep (FMP)", deprecated_credentials={"API_KEY_FINANCIALMODELINGPREP": "fmp_api_key"}, diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/form_13f.py b/openbb_platform/providers/fmp/openbb_fmp/models/form_13f.py new file mode 100644 index 000000000000..a437fb574c47 --- /dev/null +++ b/openbb_platform/providers/fmp/openbb_fmp/models/form_13f.py @@ -0,0 +1,109 @@ +"""Form 13f Model.""" + +import asyncio +from datetime import date as dateType +from typing import Any, Dict, List, Optional +from warnings import warn + +from openbb_core.provider.abstract.fetcher import Fetcher +from openbb_core.provider.standard_models.form_13FHR import ( + Form13FHRData, + Form13FHRQueryParams, +) +from openbb_core.provider.utils.errors import EmptyDataError +from openbb_core.provider.utils.helpers import amake_request +from openbb_fmp.utils.helpers import create_url +from pydantic import Field + + +class FMPForm13FHRQueryParams(Form13FHRQueryParams): + """Form 13f Query Parameters. + + Source: https://financialmodelingprep.com/api/v3/form-thirteen/0001388838?date=2021-09-30 + """ + + +class FMPForm13FHRData(Form13FHRData): + """Form13 FHR Data Model.""" + + __alias_dict__ = { + "period_ending": "date", + "issuer": "nameOfIssuer", + "principal_amount": "shares", + "asset_class": "titleOfClass", + "filling_date": "fillingDate", + "accepted_date": "acceptedDate", + "ticker_cusip": "tickercusip", + "final_link": "finalLink", + } + filling_date: dateType = Field( + default=None, description="Date when the filing was submitted to the SEC." + ) + accepted_date: dateType = Field( + default=None, description="Date when the filing was accepted by the SEC." + ) + ticker_cusip: Optional[str] = Field( + default=None, description="Ticker symbol associated with the CUSIP." + ) + link: Optional[str] = Field( + default=None, description="URL link to the SEC filing on the SEC website." + ) + final_link: Optional[str] = Field( + default=None, + description="URL link to the XML information table of the SEC filing.", + ) + + +class FMPForm13FHRFetcher( + Fetcher[ + FMPForm13FHRQueryParams, + List[FMPForm13FHRData], + ] +): + """Fetches and transforms data from the Form 13f endpoints.""" + + @staticmethod + def transform_query(params: Dict[str, Any]) -> FMPForm13FHRQueryParams: + """Transform the query params.""" + return FMPForm13FHRQueryParams(**params) + + @staticmethod + async def aextract_data( + query: FMPForm13FHRQueryParams, + credentials: Optional[Dict[str, str]] = None, + **kwargs: Any, + ) -> List[Dict]: + """Return the raw data from the House Disclosure endpoint.""" + symbols = query.symbol.split(",") + results: List[Dict] = [] + + async def get_one(symbol): + """Get data for the given symbol.""" + api_key = credentials.get("fmp_api_key") if credentials else "" + url = create_url( + 3, + f"form-thirteen/{symbol}", + api_key, + query, + exclude=["symbol", "limit"], + ) + result = await amake_request(url, **kwargs) + if not result or len(result) == 0: + warn(f"Symbol Error: No data found for symbol {symbol}") + if result: + results.extend(result) + + await asyncio.gather(*[get_one(symbol) for symbol in symbols]) + + results = [i for i in results if isinstance(i, dict)] + if not results: + raise EmptyDataError("No data returned for the given symbol.") + + return results + + @staticmethod + def transform_data( + query: FMPForm13FHRQueryParams, data: List[Dict], **kwargs: Any + ) -> List[FMPForm13FHRData]: + """Return the transformed data.""" + return [FMPForm13FHRData(**d) for d in data] diff --git a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py index 30a05855e051..aa11d0ee43d9 100644 --- a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py +++ b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py @@ -5,6 +5,7 @@ import pytest from openbb_core.app.service.user_service import UserService +from openbb_fmp.models.form_13f import FMPForm13FHRFetcher from openbb_fmp.models.analyst_estimates import FMPAnalystEstimatesFetcher from openbb_fmp.models.available_indices import FMPAvailableIndicesFetcher from openbb_fmp.models.balance_sheet import FMPBalanceSheetFetcher @@ -762,3 +763,16 @@ def test_fmp_historical_market_cap_fetcher(credentials=test_credentials): fetcher = FmpHistoricalMarketCapFetcher() result = fetcher.test(params, credentials) assert result is None + + +@pytest.mark.record_http +def test_fmp_form_13f_fetcher(credentials=test_credentials): + """Test FMP form 13f fetcher.""" + params = { + "symbol": "0001388838", + "date": date(2021, 9, 30), + "limit": 1, + } + fetcher = FMPForm13FHRFetcher() + result = fetcher.test(params, credentials) + assert result is None From 4ca868e622949d132f281b48e216b77343fa10e4 Mon Sep 17 00:00:00 2001 From: joshua <2541874972@qq.com> Date: Mon, 25 Nov 2024 15:27:31 +0800 Subject: [PATCH 02/11] [Enhancement] Standardize the endpoint form_13f from FMP --- .../equity/integration/test_equity_api.py | 8 +++ .../equity/integration/test_equity_python.py | 8 +++ .../providers/fmp/openbb_fmp/__init__.py | 2 +- .../models/{form_13f.py => form_13FHR.py} | 66 ++++++++++++++----- .../providers/fmp/tests/test_fmp_fetchers.py | 7 +- 5 files changed, 68 insertions(+), 23 deletions(-) rename openbb_platform/providers/fmp/openbb_fmp/models/{form_13f.py => form_13FHR.py} (54%) diff --git a/openbb_platform/extensions/equity/integration/test_equity_api.py b/openbb_platform/extensions/equity/integration/test_equity_api.py index 299eb328d45f..58c91d9c42c7 100644 --- a/openbb_platform/extensions/equity/integration/test_equity_api.py +++ b/openbb_platform/extensions/equity/integration/test_equity_api.py @@ -1957,6 +1957,14 @@ def test_equity_fundamental_reported_financials(params, headers): "provider": "sec", } ), + ( + { + "symbol": "NVDA", + "date": None, + "limit": 10, + "provider": "fmp", + } + ), ], ) @pytest.mark.integration diff --git a/openbb_platform/extensions/equity/integration/test_equity_python.py b/openbb_platform/extensions/equity/integration/test_equity_python.py index c47f4f919204..ce76a42ee3cd 100644 --- a/openbb_platform/extensions/equity/integration/test_equity_python.py +++ b/openbb_platform/extensions/equity/integration/test_equity_python.py @@ -1856,6 +1856,14 @@ def test_equity_fundamental_reported_financials(params, obb): "provider": "sec", } ), + ( + { + "symbol": "NVDA", + "date": None, + "limit": 10, + "provider": "fmp", + } + ), ], ) @pytest.mark.integration diff --git a/openbb_platform/providers/fmp/openbb_fmp/__init__.py b/openbb_platform/providers/fmp/openbb_fmp/__init__.py index 371d153fce71..5e9599ab8ebf 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/__init__.py +++ b/openbb_platform/providers/fmp/openbb_fmp/__init__.py @@ -39,7 +39,7 @@ from openbb_fmp.models.etf_sectors import FMPEtfSectorsFetcher from openbb_fmp.models.executive_compensation import FMPExecutiveCompensationFetcher from openbb_fmp.models.financial_ratios import FMPFinancialRatiosFetcher -from openbb_fmp.models.form_13f import FMPForm13FHRFetcher +from openbb_fmp.models.form_13FHR import FMPForm13FHRFetcher from openbb_fmp.models.forward_ebitda_estimates import FMPForwardEbitdaEstimatesFetcher from openbb_fmp.models.forward_eps_estimates import FMPForwardEpsEstimatesFetcher from openbb_fmp.models.historical_dividends import FMPHistoricalDividendsFetcher diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/form_13f.py b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py similarity index 54% rename from openbb_platform/providers/fmp/openbb_fmp/models/form_13f.py rename to openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py index a437fb574c47..c3be5c555efa 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/form_13f.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py @@ -1,18 +1,22 @@ """Form 13f Model.""" import asyncio -from datetime import date as dateType +from datetime import date as dateType, datetime from typing import Any, Dict, List, Optional from warnings import warn +import pandas as pd +import requests + from openbb_core.provider.abstract.fetcher import Fetcher from openbb_core.provider.standard_models.form_13FHR import ( Form13FHRData, Form13FHRQueryParams, ) +from openbb_core.provider.utils.descriptions import DATA_DESCRIPTIONS from openbb_core.provider.utils.errors import EmptyDataError from openbb_core.provider.utils.helpers import amake_request -from openbb_fmp.utils.helpers import create_url +from openbb_fmp.utils.helpers import create_url, response_callback from pydantic import Field @@ -33,18 +37,18 @@ class FMPForm13FHRData(Form13FHRData): "asset_class": "titleOfClass", "filling_date": "fillingDate", "accepted_date": "acceptedDate", - "ticker_cusip": "tickercusip", + "symbol": "tickercusip", "final_link": "finalLink", } - filling_date: dateType = Field( + symbol: Optional[str] = Field( + default=None, description=DATA_DESCRIPTIONS.get("symbol", "") + ) + filling_date: Optional[dateType] = Field( default=None, description="Date when the filing was submitted to the SEC." ) - accepted_date: dateType = Field( + accepted_date: Optional[dateType] = Field( default=None, description="Date when the filing was accepted by the SEC." ) - ticker_cusip: Optional[str] = Field( - default=None, description="Ticker symbol associated with the CUSIP." - ) link: Optional[str] = Field( default=None, description="URL link to the SEC filing on the SEC website." ) @@ -73,32 +77,57 @@ async def aextract_data( credentials: Optional[Dict[str, str]] = None, **kwargs: Any, ) -> List[Dict]: - """Return the raw data from the House Disclosure endpoint.""" - symbols = query.symbol.split(",") + """Return the raw data from the Form 13f endpoint.""" + """Return the raw data from the Form 13f endpoint.""" + api_key = credentials.get("fmp_api_key") if credentials else "" + symbol = query.symbol + if symbol.isnumeric(): + cik = symbol + else: + symbol_cik_json = requests.get("https://www.sec.gov/files/company_tickers.json", + headers={ + "user-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36"}).json() + df = pd.DataFrame.from_dict(symbol_cik_json, orient="index") + df.set_index("ticker", inplace=True) + cik = str(df.loc[symbol, "cik_str"]) + cik = cik.zfill(10) + date_url = create_url( + 3, + f"form-thirteen-date/{cik}", + api_key, + query, + exclude=["symbol", "limit"], + ) + dates = await amake_request(date_url, response_callback=response_callback, **kwargs) + if not dates: + raise EmptyDataError("No data returned for the given symbol.") + if not dates or len(dates) == 0: + warn(f"Symbol Error: No data found for symbol {symbol}") results: List[Dict] = [] - async def get_one(symbol): - """Get data for the given symbol.""" - api_key = credentials.get("fmp_api_key") if credentials else "" + async def get_one(date): + """Get data for the given date.""" + date = datetime.strptime(date, "%Y-%m-%d").date() + query.date = date url = create_url( 3, - f"form-thirteen/{symbol}", + f"form-thirteen/{cik}", api_key, query, exclude=["symbol", "limit"], ) - result = await amake_request(url, **kwargs) + result = await amake_request(url, response_callback=response_callback, **kwargs) if not result or len(result) == 0: warn(f"Symbol Error: No data found for symbol {symbol}") if result: results.extend(result) - await asyncio.gather(*[get_one(symbol) for symbol in symbols]) + await asyncio.gather(*[get_one(date) for date in dates]) - results = [i for i in results if isinstance(i, dict)] if not results: raise EmptyDataError("No data returned for the given symbol.") - + if query.limit: + return results[:query.limit] return results @staticmethod @@ -106,4 +135,5 @@ def transform_data( query: FMPForm13FHRQueryParams, data: List[Dict], **kwargs: Any ) -> List[FMPForm13FHRData]: """Return the transformed data.""" + [d.pop("cik", None) for d in data] return [FMPForm13FHRData(**d) for d in data] diff --git a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py index aa11d0ee43d9..fafaa510cbb2 100644 --- a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py +++ b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py @@ -5,7 +5,7 @@ import pytest from openbb_core.app.service.user_service import UserService -from openbb_fmp.models.form_13f import FMPForm13FHRFetcher +from openbb_fmp.models.form_13FHR import FMPForm13FHRFetcher from openbb_fmp.models.analyst_estimates import FMPAnalystEstimatesFetcher from openbb_fmp.models.available_indices import FMPAvailableIndicesFetcher from openbb_fmp.models.balance_sheet import FMPBalanceSheetFetcher @@ -765,12 +765,11 @@ def test_fmp_historical_market_cap_fetcher(credentials=test_credentials): assert result is None -@pytest.mark.record_http +# @pytest.mark.record_http def test_fmp_form_13f_fetcher(credentials=test_credentials): """Test FMP form 13f fetcher.""" params = { - "symbol": "0001388838", - "date": date(2021, 9, 30), + "symbol": "AAPL", "limit": 1, } fetcher = FMPForm13FHRFetcher() From 82e7c32077f9a525db2d7c883b368087d1a2e933 Mon Sep 17 00:00:00 2001 From: joshua <2541874972@qq.com> Date: Wed, 27 Nov 2024 10:18:59 +0800 Subject: [PATCH 03/11] [Feature] Use FMP endpoints for FMP data --- .../fmp/openbb_fmp/models/form_13FHR.py | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py index c3be5c555efa..7be43b9a526b 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py @@ -5,8 +5,7 @@ from typing import Any, Dict, List, Optional from warnings import warn -import pandas as pd -import requests +from pydantic import Field from openbb_core.provider.abstract.fetcher import Fetcher from openbb_core.provider.standard_models.form_13FHR import ( @@ -17,7 +16,6 @@ from openbb_core.provider.utils.errors import EmptyDataError from openbb_core.provider.utils.helpers import amake_request from openbb_fmp.utils.helpers import create_url, response_callback -from pydantic import Field class FMPForm13FHRQueryParams(Form13FHRQueryParams): @@ -84,13 +82,19 @@ async def aextract_data( if symbol.isnumeric(): cik = symbol else: - symbol_cik_json = requests.get("https://www.sec.gov/files/company_tickers.json", - headers={ - "user-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36"}).json() - df = pd.DataFrame.from_dict(symbol_cik_json, orient="index") - df.set_index("ticker", inplace=True) - cik = str(df.loc[symbol, "cik_str"]) - cik = cik.zfill(10) + query.includeCurrentQuarter = "false" + cik_url = create_url( + 4, + f"institutional-ownership/symbol-ownership", + api_key, + query, + exclude=["limit"], + ) + cik = await amake_request(cik_url, response_callback=response_callback, **kwargs) + if len(cik) == 0: + raise EmptyDataError("Can't get cik for the given symbol.") + cik = cik[0]["cik"] + del query.includeCurrentQuarter date_url = create_url( 3, f"form-thirteen-date/{cik}", @@ -135,5 +139,6 @@ def transform_data( query: FMPForm13FHRQueryParams, data: List[Dict], **kwargs: Any ) -> List[FMPForm13FHRData]: """Return the transformed data.""" - [d.pop("cik", None) for d in data] + if query.symbol.isnumeric(): + [d.pop("cik", None) for d in data] return [FMPForm13FHRData(**d) for d in data] From c40ec7e4b18e4b59d26e7bebf952a864e0800c02 Mon Sep 17 00:00:00 2001 From: joshua <2541874972@qq.com> Date: Mon, 9 Dec 2024 10:31:40 +0800 Subject: [PATCH 04/11] [Enhancement] Fix branch 13f,use FMPEquityProfileFetcher to get cik --- .../fmp/openbb_fmp/models/form_13FHR.py | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py index 7be43b9a526b..3dd1465103a2 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py @@ -5,6 +5,8 @@ from typing import Any, Dict, List, Optional from warnings import warn +from openbb_core.app.model.abstract.error import OpenBBError +from openbb_fmp.models.equity_profile import FMPEquityProfileFetcher from pydantic import Field from openbb_core.provider.abstract.fetcher import Fetcher @@ -75,26 +77,18 @@ async def aextract_data( credentials: Optional[Dict[str, str]] = None, **kwargs: Any, ) -> List[Dict]: - """Return the raw data from the Form 13f endpoint.""" """Return the raw data from the Form 13f endpoint.""" api_key = credentials.get("fmp_api_key") if credentials else "" - symbol = query.symbol - if symbol.isnumeric(): - cik = symbol + if query.symbol.isnumeric(): + cik = query.symbol else: - query.includeCurrentQuarter = "false" - cik_url = create_url( - 4, - f"institutional-ownership/symbol-ownership", - api_key, - query, - exclude=["limit"], - ) - cik = await amake_request(cik_url, response_callback=response_callback, **kwargs) - if len(cik) == 0: - raise EmptyDataError("Can't get cik for the given symbol.") - cik = cik[0]["cik"] - del query.includeCurrentQuarter + try: + profile = await FMPEquityProfileFetcher.fetch_data({"symbol": query.symbol}, {"fmp_api_key": api_key}) + cik = getattr(profile[0], "cik", "") + if not cik: + raise OpenBBError(f"Invalid symbol -> {query.symbol}") + except OpenBBError as e: + raise OpenBBError(f"Invalid symbol -> {query.symbol} -> {e}") date_url = create_url( 3, f"form-thirteen-date/{cik}", @@ -106,7 +100,7 @@ async def aextract_data( if not dates: raise EmptyDataError("No data returned for the given symbol.") if not dates or len(dates) == 0: - warn(f"Symbol Error: No data found for symbol {symbol}") + warn(f"Symbol Error: No data found for symbol {cik}") results: List[Dict] = [] async def get_one(date): From 31690672ab47acdec246f933bd91f1714a56e4b2 Mon Sep 17 00:00:00 2001 From: joshua <2541874972@qq.com> Date: Mon, 16 Dec 2024 09:10:20 +0800 Subject: [PATCH 05/11] [Enhancement] Fix branch 13f --- .../extensions/equity/integration/test_equity_api.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openbb_platform/extensions/equity/integration/test_equity_api.py b/openbb_platform/extensions/equity/integration/test_equity_api.py index 50958c31562f..662d32ebfd14 100644 --- a/openbb_platform/extensions/equity/integration/test_equity_api.py +++ b/openbb_platform/extensions/equity/integration/test_equity_api.py @@ -1986,12 +1986,12 @@ def test_equity_fundamental_reported_financials(params, headers): } ), ( - { - "symbol": "NVDA", - "date": None, - "limit": 10, - "provider": "fmp", - } + { + "symbol": "NVDA", + "date": None, + "limit": 10, + "provider": "fmp", + } ), ], ) From 3a4d20393bfac6c895c5984948059c81cdc989d2 Mon Sep 17 00:00:00 2001 From: joshua <2541874972@qq.com> Date: Mon, 16 Dec 2024 09:19:16 +0800 Subject: [PATCH 06/11] [Enhancement] Fix branch 13f --- openbb_platform/providers/fmp/tests/test_fmp_fetchers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py index 25d96d8d53ae..3883e3d50f3b 100644 --- a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py +++ b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py @@ -771,10 +771,12 @@ def test_fmp_historical_market_cap_fetcher(credentials=test_credentials): def test_fmp_form_13f_fetcher(credentials=test_credentials): """Test FMP form 13f fetcher.""" params = { - "symbol": "AAPL", + "symbol": "NVDA", "limit": 1, } fetcher = FMPForm13FHRFetcher() + result = fetcher.test(params, credentials) + assert result is None @pytest.mark.record_http From ade080d433da5845393b6f418f214f7aba01a935 Mon Sep 17 00:00:00 2001 From: joshuaBri <135589852+joshuaBri@users.noreply.github.com> Date: Tue, 17 Dec 2024 09:41:41 +0800 Subject: [PATCH 07/11] Update openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> --- openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py index 3dd1465103a2..f3878e136553 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py @@ -116,7 +116,7 @@ async def get_one(date): ) result = await amake_request(url, response_callback=response_callback, **kwargs) if not result or len(result) == 0: - warn(f"Symbol Error: No data found for symbol {symbol}") + warn(f"Symbol Error: No data found for symbol {query.symbol}") if result: results.extend(result) From bac820670bcfe6e8287a0c12aa56036d504e19a9 Mon Sep 17 00:00:00 2001 From: joshuaBri <135589852+joshuaBri@users.noreply.github.com> Date: Tue, 17 Dec 2024 09:42:05 +0800 Subject: [PATCH 08/11] Update openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> --- openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py index f3878e136553..25b9c501453e 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py @@ -134,5 +134,4 @@ def transform_data( ) -> List[FMPForm13FHRData]: """Return the transformed data.""" if query.symbol.isnumeric(): - [d.pop("cik", None) for d in data] - return [FMPForm13FHRData(**d) for d in data] + return [FMPForm13FHRData(**{k: v for k, v in d.items if k != "cik"}) for d in data] From 899777d3dae694e33c55eb47b026abf6f4cb88d8 Mon Sep 17 00:00:00 2001 From: joshua <2541874972@qq.com> Date: Tue, 17 Dec 2024 09:59:11 +0800 Subject: [PATCH 09/11] [Enhancement] Fix branch 13f --- .../providers/fmp/openbb_fmp/models/form_13FHR.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py index 25b9c501453e..8eaa2019704b 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py @@ -99,8 +99,6 @@ async def aextract_data( dates = await amake_request(date_url, response_callback=response_callback, **kwargs) if not dates: raise EmptyDataError("No data returned for the given symbol.") - if not dates or len(dates) == 0: - warn(f"Symbol Error: No data found for symbol {cik}") results: List[Dict] = [] async def get_one(date): @@ -134,4 +132,5 @@ def transform_data( ) -> List[FMPForm13FHRData]: """Return the transformed data.""" if query.symbol.isnumeric(): - return [FMPForm13FHRData(**{k: v for k, v in d.items if k != "cik"}) for d in data] + return [FMPForm13FHRData(**{k: v for k, v in d.items() if k != "cik"}) for d in data] + return [FMPForm13FHRData(**d) for d in data] From ba5c2709897b8945747489ffe7edab9eb63f2fa4 Mon Sep 17 00:00:00 2001 From: joshua <2541874972@qq.com> Date: Thu, 9 Jan 2025 11:04:11 +0800 Subject: [PATCH 10/11] [BugFix]Parameter date Functions --- .../providers/fmp/openbb_fmp/models/form_13FHR.py | 6 ++++++ .../providers/fmp/openbb_fmp/utils/parse_13f.py | 14 ++++++++++++++ .../providers/fmp/tests/test_fmp_fetchers.py | 5 +++-- 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 openbb_platform/providers/fmp/openbb_fmp/utils/parse_13f.py diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py index 8eaa2019704b..d61cfab4400d 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py +++ b/openbb_platform/providers/fmp/openbb_fmp/models/form_13FHR.py @@ -18,6 +18,7 @@ from openbb_core.provider.utils.errors import EmptyDataError from openbb_core.provider.utils.helpers import amake_request from openbb_fmp.utils.helpers import create_url, response_callback +from openbb_fmp.utils.parse_13f import date_to_quarter_end class FMPForm13FHRQueryParams(Form13FHRQueryParams): @@ -97,6 +98,11 @@ async def aextract_data( exclude=["symbol", "limit"], ) dates = await amake_request(date_url, response_callback=response_callback, **kwargs) + if query.date: + date = date_to_quarter_end(str(query.date)) + if date not in dates: + raise EmptyDataError(f"Data for Date {date} not found for cik {cik},please change the date") + dates = [date] if not dates: raise EmptyDataError("No data returned for the given symbol.") results: List[Dict] = [] diff --git a/openbb_platform/providers/fmp/openbb_fmp/utils/parse_13f.py b/openbb_platform/providers/fmp/openbb_fmp/utils/parse_13f.py new file mode 100644 index 000000000000..61ab4f38aef3 --- /dev/null +++ b/openbb_platform/providers/fmp/openbb_fmp/utils/parse_13f.py @@ -0,0 +1,14 @@ +"""Utility functions for parsing FMP Form 13F-HR.""" + + +def date_to_quarter_end(date: str) -> str: + """Convert a date to the end of the calendar quarter.""" + # pylint: disable=import-outside-toplevel + from pandas import to_datetime + from pandas.tseries.offsets import QuarterEnd + + return ( + (to_datetime(date).to_period("Q").to_timestamp("D") + QuarterEnd()) + .date() + .strftime("%Y-%m-%d") + ) diff --git a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py index 3883e3d50f3b..60c904b863f9 100644 --- a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py +++ b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py @@ -767,11 +767,12 @@ def test_fmp_historical_market_cap_fetcher(credentials=test_credentials): -@pytest.mark.record_http +# @pytest.mark.record_http def test_fmp_form_13f_fetcher(credentials=test_credentials): """Test FMP form 13f fetcher.""" params = { - "symbol": "NVDA", + "symbol": "brk-a", + "date": date(2024, 9, 30), "limit": 1, } fetcher = FMPForm13FHRFetcher() From 2b47779c9ce931c5c55319d87c1c3fb7a57e4518 Mon Sep 17 00:00:00 2001 From: joshua <2541874972@qq.com> Date: Thu, 9 Jan 2025 11:16:45 +0800 Subject: [PATCH 11/11] [BugFix] remove annotation --- openbb_platform/providers/fmp/tests/test_fmp_fetchers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py index 60c904b863f9..5f4e21599ea2 100644 --- a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py +++ b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py @@ -767,7 +767,7 @@ def test_fmp_historical_market_cap_fetcher(credentials=test_credentials): -# @pytest.mark.record_http +@pytest.mark.record_http def test_fmp_form_13f_fetcher(credentials=test_credentials): """Test FMP form 13f fetcher.""" params = {