From d704de554ef87be6ec65ed188b4afddf2d96b29d Mon Sep 17 00:00:00 2001 From: joshuaBri <135589852+joshuaBri@users.noreply.github.com> Date: Wed, 11 Dec 2024 00:06:04 +0800 Subject: [PATCH] [Feature]try to add fmp senate trading data api (#6957) * [Feature] Add Government Trades * [BugFix] Supplement the missing files * [Enhancement] Fix branch goverment_trades * [Enhancement] Fix branch government_trades * Capture test cassettes. * [Enhancement] Fix branch government_trades * some style things and prevent page from exceeding 30 * black * linter again * else None instead of Other --------- Co-authored-by: Danglewood <85772166+deeleeramone@users.noreply.github.com> --- .../standard_models/government_trades.py | 47 ++++ .../equity/integration/test_equity_api.py | 33 +++ .../equity/integration/test_equity_python.py | 32 +++ .../ownership/ownership_router.py | 19 ++ openbb_platform/openbb/assets/reference.json | 173 +++++++++++++- openbb_platform/openbb/package/economy.py | 2 + .../openbb/package/equity_ownership.py | 113 +++++++++ .../providers/fmp/openbb_fmp/__init__.py | 2 + .../openbb_fmp/models/government_trades.py | 226 ++++++++++++++++++ ..._government_trades_fetcher_urllib3_v1.yaml | 105 ++++++++ ..._government_trades_fetcher_urllib3_v2.yaml | 105 ++++++++ .../providers/fmp/tests/test_fmp_fetchers.py | 15 ++ 12 files changed, 871 insertions(+), 1 deletion(-) create mode 100644 openbb_platform/core/openbb_core/provider/standard_models/government_trades.py create mode 100644 openbb_platform/providers/fmp/openbb_fmp/models/government_trades.py create mode 100644 openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_government_trades_fetcher_urllib3_v1.yaml create mode 100644 openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_government_trades_fetcher_urllib3_v2.yaml diff --git a/openbb_platform/core/openbb_core/provider/standard_models/government_trades.py b/openbb_platform/core/openbb_core/provider/standard_models/government_trades.py new file mode 100644 index 00000000000..e0aa2daffa7 --- /dev/null +++ b/openbb_platform/core/openbb_core/provider/standard_models/government_trades.py @@ -0,0 +1,47 @@ +"""Government Trades Standard Model.""" + +from datetime import date as dateType +from typing import Literal, Optional + +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, NonNegativeInt, field_validator + + +class GovernmentTradesQueryParams(QueryParams): + """Government Trades Query.""" + + symbol: Optional[str] = Field( + default=None, description=QUERY_DESCRIPTIONS.get("symbol", "") + ) + chamber: Literal["house", "senate", "all"] = Field( + default="all", description="Government Chamber." + ) + limit: Optional[NonNegativeInt] = Field( + default=100, description=QUERY_DESCRIPTIONS.get("limit", "") + ) + + @field_validator("symbol", mode="before", check_fields=False) + @classmethod + def to_upper(cls, v: str): + """Convert field to uppercase.""" + return v.upper() if v else None + + +class GovernmentTradesData(Data): + """Government Trades data.""" + + symbol: Optional[str] = Field( + default=None, description=DATA_DESCRIPTIONS.get("symbol", "") + ) + date: dateType = Field(description=DATA_DESCRIPTIONS.get("date", "")) + transaction_date: Optional[dateType] = Field( + default=None, description="Date of Transaction." + ) + representative: Optional[str] = Field( + default=None, description="Name of Representative." + ) diff --git a/openbb_platform/extensions/equity/integration/test_equity_api.py b/openbb_platform/extensions/equity/integration/test_equity_api.py index a675e3dbb45..ee1da7c3883 100644 --- a/openbb_platform/extensions/equity/integration/test_equity_api.py +++ b/openbb_platform/extensions/equity/integration/test_equity_api.py @@ -2156,3 +2156,36 @@ def test_equity_discovery_latest_financial_reports(params, headers): result = requests.get(url, headers=headers, timeout=10) assert isinstance(result, requests.Response) assert result.status_code == 200 + + +@parametrize( + "params", + [ + ( + { + "chamber": "all", + "symbol": "AAPL", + "provider": "fmp", + "limit": None, + } + ), + ( + { + "symbol": None, + "chamber": "all", + "limit": 300, + "provider": "fmp", + } + ), + ], +) +@pytest.mark.integration +def test_equity_ownership_government_trades(params, headers): + """Test the equity ownership government trades 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/equity/ownership/government_trades?{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/equity/integration/test_equity_python.py b/openbb_platform/extensions/equity/integration/test_equity_python.py index f8c48a33f58..4f25f68da0f 100644 --- a/openbb_platform/extensions/equity/integration/test_equity_python.py +++ b/openbb_platform/extensions/equity/integration/test_equity_python.py @@ -2017,3 +2017,35 @@ def test_equity_discovery_latest_financial_reports(params, obb): assert result assert isinstance(result, OBBject) assert len(result.results) > 0 + + +@parametrize( + "params", + [ + ( + { + "chamber": "all", + "symbol": "AAPL", + "provider": "fmp", + "limit": None, + } + ), + ( + { + "symbol": None, + "chamber": "all", + "limit": 300, + "provider": "fmp", + } + ), + ], +) +@pytest.mark.integration +def test_equity_ownership_government_trades(params, obb): + """Test the equity ownership government trades endpoint.""" + params = {p: v for p, v in params.items() if v} + + result = obb.equity.ownership.government_trades(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 diff --git a/openbb_platform/extensions/equity/openbb_equity/ownership/ownership_router.py b/openbb_platform/extensions/equity/openbb_equity/ownership/ownership_router.py index 4f118d27b63..b4dccde57b9 100644 --- a/openbb_platform/extensions/equity/openbb_equity/ownership/ownership_router.py +++ b/openbb_platform/extensions/equity/openbb_equity/ownership/ownership_router.py @@ -112,3 +112,22 @@ async def form_13f( their investment strategy from competitors and the public. """ return await OBBject.from_query(Query(**locals())) + + +@router.command( + model="GovernmentTrades", + examples=[ + APIEx(parameters={"symbol": "AAPL", "chamber": "all", "provider": "fmp"}), + APIEx(parameters={"limit": 500, "chamber": "all", "provider": "fmp"}), + ], +) +async def government_trades( + cc: CommandContext, + provider_choices: ProviderChoices, + standard_params: StandardParams, + extra_params: ExtraParams, +) -> OBBject: + """Obtain government transaction data, including data from the Senate + and the House of Representatives. + """ + return await OBBject.from_query(Query(**locals())) diff --git a/openbb_platform/openbb/assets/reference.json b/openbb_platform/openbb/assets/reference.json index 570b3c857d4..5020528634f 100644 --- a/openbb_platform/openbb/assets/reference.json +++ b/openbb_platform/openbb/assets/reference.json @@ -3,7 +3,7 @@ "info": { "title": "OpenBB Platform (Python)", "description": "Investment research for everyone, anywhere.", - "core": "1.3.6", + "core": "1.3.7", "extensions": { "openbb_core_extension": [ "commodity@1.2.6", @@ -10271,6 +10271,7 @@ "dominica", "dominican_republic", "east_germany", + "eastern_caribbean_currency_union", "ecuador", "egypt", "el_salvador", @@ -10526,6 +10527,7 @@ "dominica", "dominican_republic", "east_germany", + "eastern_caribbean_currency_union", "ecuador", "egypt", "el_salvador", @@ -28322,6 +28324,175 @@ }, "model": "Form13FHR" }, + "/equity/ownership/government_trades": { + "deprecated": { + "flag": null, + "message": null + }, + "description": "Obtain government transaction data, including data from the Senate\nand the House of Representatives.", + "examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.equity.ownership.government_trades(symbol='AAPL', chamber='all', provider='fmp')\nobb.equity.ownership.government_trades(limit=500, chamber='all', provider='fmp')\n```\n\n", + "parameters": { + "standard": [ + { + "name": "symbol", + "type": "Union[str, List[str]]", + "description": "Symbol to get data for. Multiple items allowed for provider(s): fmp.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "chamber", + "type": "Literal['house', 'senate', 'all']", + "description": "Government Chamber.", + "default": "all", + "optional": true, + "choices": null + }, + { + "name": "limit", + "type": "Annotated[int, Ge(ge=0)]", + "description": "The number of data entries to return.", + "default": 100, + "optional": true, + "choices": null + } + ], + "fmp": [] + }, + "returns": { + "OBBject": [ + { + "name": "results", + "type": "List[GovernmentTrades]", + "description": "Serializable results." + }, + { + "name": "provider", + "type": "Optional[Literal['fmp']]", + "description": "Provider name." + }, + { + "name": "warnings", + "type": "Optional[List[Warning_]]", + "description": "List of warnings." + }, + { + "name": "chart", + "type": "Optional[Chart]", + "description": "Chart object." + }, + { + "name": "extra", + "type": "Dict[str, Any]", + "description": "Extra info." + } + ] + }, + "data": { + "standard": [ + { + "name": "symbol", + "type": "str", + "description": "Symbol representing the entity requested in the data.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "date", + "type": "Union[date, str]", + "description": "The date of the data.", + "default": "", + "optional": false, + "choices": null + }, + { + "name": "transaction_date", + "type": "date", + "description": "Date of Transaction.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "representative", + "type": "str", + "description": "Name of Representative.", + "default": null, + "optional": true, + "choices": null + } + ], + "fmp": [ + { + "name": "chamber", + "type": "Literal['house', 'senate']", + "description": "Government Chamber - House or Senate.", + "default": "", + "optional": false, + "choices": null + }, + { + "name": "owner", + "type": "str", + "description": "Ownership status (e.g., Spouse, Joint).", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "asset_type", + "type": "str", + "description": "Type of asset involved in the transaction.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "asset_description", + "type": "str", + "description": "Description of the asset.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "transaction_type", + "type": "str", + "description": "Type of transaction (e.g., Sale, Purchase).", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "amount", + "type": "str", + "description": "Transaction amount range.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "comment", + "type": "str", + "description": "Additional comments on the transaction.", + "default": null, + "optional": true, + "choices": null + }, + { + "name": "url", + "type": "str", + "description": "Link to the transaction document.", + "default": null, + "optional": true, + "choices": null + } + ] + }, + "model": "GovernmentTrades" + }, "/equity/price/quote": { "deprecated": { "flag": null, diff --git a/openbb_platform/openbb/package/economy.py b/openbb_platform/openbb/package/economy.py index b5cee686c94..8f9fe52cfb5 100644 --- a/openbb_platform/openbb/package/economy.py +++ b/openbb_platform/openbb/package/economy.py @@ -1429,6 +1429,7 @@ class ROUTER_economy(Container): "dominica", "dominican_republic", "east_germany", + "eastern_caribbean_currency_union", "ecuador", "egypt", "el_salvador", @@ -1682,6 +1683,7 @@ class ROUTER_economy(Container): "dominica", "dominican_republic", "east_germany", + "eastern_caribbean_currency_union", "ecuador", "egypt", "el_salvador", diff --git a/openbb_platform/openbb/package/equity_ownership.py b/openbb_platform/openbb/package/equity_ownership.py index 55aefe73272..f70abb43b54 100644 --- a/openbb_platform/openbb/package/equity_ownership.py +++ b/openbb_platform/openbb/package/equity_ownership.py @@ -3,6 +3,7 @@ import datetime from typing import List, Literal, Optional, Union +from annotated_types import Ge from openbb_core.app.model.field import OpenBBField from openbb_core.app.model.obbject import OBBject from openbb_core.app.static.container import Container @@ -14,6 +15,7 @@ from typing_extensions import Annotated class ROUTER_equity_ownership(Container): """/equity/ownership form_13f + government_trades insider_trading institutional major_holders @@ -148,6 +150,117 @@ class ROUTER_equity_ownership(Container): ) ) + @exception_handler + @validate + def government_trades( + self, + symbol: Annotated[ + Union[str, None, List[Optional[str]]], + OpenBBField( + description="Symbol to get data for. Multiple comma separated items allowed for provider(s): fmp." + ), + ] = None, + chamber: Annotated[ + Literal["house", "senate", "all"], + OpenBBField(description="Government Chamber."), + ] = "all", + limit: Annotated[ + Optional[Annotated[int, Ge(ge=0)]], + OpenBBField(description="The number of data entries to return."), + ] = 100, + provider: Annotated[ + Optional[Literal["fmp"]], + OpenBBField( + description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: fmp." + ), + ] = None, + **kwargs + ) -> OBBject: + """Obtain government transaction data, including data from the Senate + and the House of Representatives. + + + Parameters + ---------- + symbol : Union[str, None, List[Optional[str]]] + Symbol to get data for. Multiple comma separated items allowed for provider(s): fmp. + chamber : Literal['house', 'senate', 'all'] + Government Chamber. + limit : Optional[Annotated[int, Ge(ge=0)]] + The number of data entries to return. + provider : Optional[Literal['fmp']] + The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: fmp. + + Returns + ------- + OBBject + results : List[GovernmentTrades] + Serializable results. + provider : Optional[Literal['fmp']] + Provider name. + warnings : Optional[List[Warning_]] + List of warnings. + chart : Optional[Chart] + Chart object. + extra : Dict[str, Any] + Extra info. + + GovernmentTrades + ---------------- + symbol : Optional[str] + Symbol representing the entity requested in the data. + date : date + The date of the data. + transaction_date : Optional[date] + Date of Transaction. + representative : Optional[str] + Name of Representative. + chamber : Optional[Literal['house', 'senate']] + Government Chamber - House or Senate. (provider: fmp) + owner : Optional[str] + Ownership status (e.g., Spouse, Joint). (provider: fmp) + asset_type : Optional[str] + Type of asset involved in the transaction. (provider: fmp) + asset_description : Optional[str] + Description of the asset. (provider: fmp) + transaction_type : Optional[str] + Type of transaction (e.g., Sale, Purchase). (provider: fmp) + amount : Optional[str] + Transaction amount range. (provider: fmp) + comment : Optional[str] + Additional comments on the transaction. (provider: fmp) + url : Optional[str] + Link to the transaction document. (provider: fmp) + + Examples + -------- + >>> from openbb import obb + >>> obb.equity.ownership.government_trades(symbol='AAPL', chamber='all', provider='fmp') + >>> obb.equity.ownership.government_trades(limit=500, chamber='all', provider='fmp') + """ # noqa: E501 + + return self._run( + "/equity/ownership/government_trades", + **filter_inputs( + provider_choices={ + "provider": self._get_provider( + provider, + "equity.ownership.government_trades", + ("fmp",), + ) + }, + standard_params={ + "symbol": symbol, + "chamber": chamber, + "limit": limit, + }, + extra_params=kwargs, + info={ + "symbol": {"fmp": {"multiple_items_allowed": True, "choices": None}} + }, + ) + ) + @exception_handler @validate def insider_trading( diff --git a/openbb_platform/providers/fmp/openbb_fmp/__init__.py b/openbb_platform/providers/fmp/openbb_fmp/__init__.py index 5f791bb97b0..2e758c72cc6 100644 --- a/openbb_platform/providers/fmp/openbb_fmp/__init__.py +++ b/openbb_platform/providers/fmp/openbb_fmp/__init__.py @@ -41,6 +41,7 @@ from openbb_fmp.models.executive_compensation import FMPExecutiveCompensationFet from openbb_fmp.models.financial_ratios import FMPFinancialRatiosFetcher from openbb_fmp.models.forward_ebitda_estimates import FMPForwardEbitdaEstimatesFetcher from openbb_fmp.models.forward_eps_estimates import FMPForwardEpsEstimatesFetcher +from openbb_fmp.models.government_trades import FMPGovernmentTradesFetcher from openbb_fmp.models.historical_dividends import FMPHistoricalDividendsFetcher from openbb_fmp.models.historical_employees import FMPHistoricalEmployeesFetcher from openbb_fmp.models.historical_eps import FMPHistoricalEpsFetcher @@ -137,6 +138,7 @@ stock market information (news, currencies, and stock prices).""", "WorldNews": FMPWorldNewsFetcher, "EtfHistorical": FMPEquityHistoricalFetcher, "YieldCurve": FMPYieldCurveFetcher, + "GovernmentTrades": FMPGovernmentTradesFetcher, }, repr_name="Financial Modeling Prep (FMP)", deprecated_credentials={"API_KEY_FINANCIALMODELINGPREP": "fmp_api_key"}, diff --git a/openbb_platform/providers/fmp/openbb_fmp/models/government_trades.py b/openbb_platform/providers/fmp/openbb_fmp/models/government_trades.py new file mode 100644 index 00000000000..2391d58ef16 --- /dev/null +++ b/openbb_platform/providers/fmp/openbb_fmp/models/government_trades.py @@ -0,0 +1,226 @@ +"""FMP Government Trades Model.""" + +# pylint: disable=unused-argument,too-many-locals + +from typing import Any, Literal, Optional + +from openbb_core.provider.abstract.fetcher import Fetcher +from openbb_core.provider.standard_models.government_trades import ( + GovernmentTradesData, + GovernmentTradesQueryParams, +) +from pydantic import Field, model_validator + + +class FMPGovernmentTradesQueryParams(GovernmentTradesQueryParams): + """Government Trades Query Parameters. + + Source: https://site.financialmodelingprep.com/developer/docs#senate-trading + """ + + __json_schema_extra__ = {"symbol": {"multiple_items_allowed": True}} + + +class FMPGovernmentTradesData(GovernmentTradesData): + """Government Trades Data Model.""" + + __alias_dict__ = { + "symbol": "ticker", + "transaction_date": "transactionDate", + "representative": "office", + "url": "link", + "transaction_type": "type", + } + chamber: Literal["house", "senate"] = Field( + description="Government Chamber - House or Senate." + ) + owner: Optional[str] = Field( + default=None, description="Ownership status (e.g., Spouse, Joint)." + ) + asset_type: Optional[str] = Field( + default=None, description="Type of asset involved in the transaction." + ) + asset_description: Optional[str] = Field( + default=None, description="Description of the asset." + ) + transaction_type: Optional[str] = Field( + default=None, description="Type of transaction (e.g., Sale, Purchase)." + ) + amount: Optional[str] = Field(default=None, description="Transaction amount range.") + comment: Optional[str] = Field( + default=None, description="Additional comments on the transaction." + ) + url: Optional[str] = Field( + default=None, description="Link to the transaction document." + ) + + @model_validator(mode="before") + @classmethod + def _fill_missing(cls, values): + """Fill missing information that can be identified.""" + description = values.get("assetDescription", "").lower() + if not values.get("owner"): + values["owner"] = "Self" + if (values.get("ticker") or values.get("symbol")) and not values.get( + "assetType" + ): + values["asset_type"] = "ETF" if "etf" in description else "Stock" + elif ( + not values.get("ticker") + and not values.get("symbol") + and not values.get("assetType") + ): + values["asset_type"] = ( + "Treasury" + if "treasury" in description or "bill" in description + else ( + "Bond" + if "%" in description + or "due" in description + or "pct" in description + else ( + "Fund" + if "fund" in description + else ("ETF" if "etf" in description else None) + ) + ) + ) + return values + + +class FMPGovernmentTradesFetcher( + Fetcher[ + FMPGovernmentTradesQueryParams, + list[FMPGovernmentTradesData], + ] +): + """FMP Government Trades Fetcher.""" + + @staticmethod + def transform_query(params: dict[str, Any]) -> FMPGovernmentTradesQueryParams: + """Transform the query params.""" + return FMPGovernmentTradesQueryParams(**params) + + @staticmethod + async def aextract_data( + query: FMPGovernmentTradesQueryParams, + credentials: Optional[dict[str, str]] = None, + **kwargs: Any, + ) -> list[dict]: + """Return the raw data from the Government Trades endpoint.""" + # pylint: disable=import-outside-toplevel + import asyncio # noqa + import math + from openbb_core.app.model.abstract.error import OpenBBError + 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 warnings import warn + + symbols: list = [] + + if query.symbol: + symbols = query.symbol.split(",") + + results: list[dict] = [] + chamber_url_dict = { + "house": ["senate-disclosure"], + "senate": ["senate-trading"], + "all": ["senate-disclosure", "senate-trading"], + } + api_key = credentials.get("fmp_api_key") if credentials else "" + keys_to_remove = { + "district", + "capitalGainsOver200USD", + "disclosureYear", + "firstName", + "lastName", + } + keys_to_rename = {"dateRecieved": "date", "disclosureDate": "date"} + + async def get_one(url): + """Get data for one URL.""" + result = await amake_request( + url, response_callback=response_callback, **kwargs + ) + processed_list: list = [] + + for entry in result: + new_entry = { + keys_to_rename.get(k, k): v + for k, v in entry.items() + if k not in keys_to_remove + } + new_entry["chamber"] = "senate" if "senate-trading" in url else "house" + processed_list.append(new_entry) + + if not processed_list or len(processed_list) == 0: + warn(f"No data found for {url.replace(api_key, 'API_KEY')}") + + if processed_list: + results.extend(processed_list) + + urls_list: list = [] + + try: + if symbols: + for symbol in symbols: + query.symbol = symbol + url = [ + create_url( + 4, + f"{i}", + api_key=api_key, + query=query, + exclude=["chamber", "limit"], + ) + for i in chamber_url_dict[query.chamber] + ] + urls_list.extend(url) + await asyncio.gather(*[get_one(url) for url in urls_list]) + else: + pages = math.ceil(query.limit / 100) + + if pages > 30: + warn( + f"Limit value - {query.limit} exceeds the available data for {query.chamber}," + " returning all available data." + ) + pages = 31 + for page in range(pages): + query.page = page + url = [ + create_url( + 4, + f"{i}-rss-feed", + api_key=api_key, + query=query, + exclude=["chamber", "limit"], + ) + for i in chamber_url_dict[query.chamber] + ] + urls_list.extend(url) + await asyncio.gather(*[get_one(url) for url in urls_list]) + + if not results: + raise EmptyDataError("No data returned for the given symbol.") + + return results + except OpenBBError as e: + raise e from e + + @staticmethod + def transform_data( + query: FMPGovernmentTradesQueryParams, data: list[dict], **kwargs: Any + ) -> list[FMPGovernmentTradesData]: + """Return the transformed data.""" + return sorted( + [ + FMPGovernmentTradesData( + **{k: v for k, v in d.items() if v and v != "--"} + ) + for d in data + ], + key=lambda x: x.date, + reverse=True, + )[: query.limit or len(data)] diff --git a/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_government_trades_fetcher_urllib3_v1.yaml b/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_government_trades_fetcher_urllib3_v1.yaml new file mode 100644 index 00000000000..eb8b5cb3646 --- /dev/null +++ b/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_government_trades_fetcher_urllib3_v1.yaml @@ -0,0 +1,105 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://financialmodelingprep.com/api/v4/senate-trading-rss-feed?apikey=MOCK_API_KEY&page=0 + response: + body: + string: !!binary | + H4sIAAAAAAAAA+3dW3OjOBYA4Pf5FaquqdmeqlbCzQbPm6+JO76NIc5mt/ZBgLCpxuACnIxna//7 + Cid2kjbhInDs2HrorsQGX/g4R0dCKP/+BYD/kn8AfLFsPwgHaI6//AG+qDPsmJ775dvTcw56eepu + Zod45i0DvHnWsyzbeL0b2N3Gsd0f0RazMFwEf1xeYssMMPKN2UWAXRTii6n3cPn0yOWDjR8vF6F/ + qVTECl/lJKgoNR1KGCsQGQqGVb1W0ysVSeQl8XLzDiZ5lTE2bPyAzeidBE6QIC9ATtpsEfrIDZAR + 2p7bIhu/bMRDvrb9Mo8u9tffZfH686MgwGELB4ZvL6IXiLbo49CxLQy6rvFmM221eDoaoWf82L75 + 5kHkYPC1s3Sc37c7zb2lG0ZP/sp/4zgeQPArXyE/cZstDG8+x0+bQLh5MFjNdc9Zf5C29oU89r9v + TPNJU9nVxI6VZHmD3YflEVDeTG7biZZ95P94RCv3xeKVZp98Fnvr/CK53Qm83YLKUZKqimjyChSw + bBHHmgRrUk2ECFdquixIvCxmcBSzOAo7jt89mxy8BMiu+0Ae8ECdvOIDdlagj1w0xSZo/2XMkDvF + UPORSX7vLF0TaP4yCMFmnwnybaQT1DH5IE+PhhEWuIp2AW2tE3ty/HxejJbkeKFXuePVSVHZnBUV + 7p2zYvecmIy7V+ycWG/EQWE3U3/yc0JYnwrPJwU7K3bOim0SKDlTjOw58W2SY+yZdmjjYOEsA6CS + dwnxdPV0LjTJMQtAFwpvXihDqzBCfmij+IYhPQfEtQyjZm/0Twb+oWkgu3rR+I4Tv+7eq4ngDdtx + 4qyvybfyw9UudrQD+OlZKmjEyVVUtRSo8KYMJcPEsGYhDuq6JEqWXlMEHqVA81CoZIAWt0crRy23 + CuzpLAQaNmau53hTEtzvlnZx8Ruj+ILI50jSN+0UQs12URyhOrfD2S5gtDl48xwVnyGKsi6RONX5 + igSliowIn0nSqCTrgqkb5GE+nY9P5YtNzOkdKy16LZJF1VUQ4nnw4rjKV6AnBCUdp9bst06Wc3sI + TpTz1jWx76xsdwrW7wU8C9TJK4LmEwEY4wfPWNd6TyXg7WUdtLQW4PlLQbwUOH6br/KcEeQDvOTa + V6eEttSx/0ASckzPe70T2N2C6uywdAXLBidDZFYNKCmYg6iKLGjimm5VFEWQzWrq2cFnydU0jfJ3 + b+YGngt+A88/ZT8f3snUGeqrXcfvg++MsQBj0/ND/IDyBfR7gKkjJ7t+TW1SZ4AFALVZlPYQqYux + H0S9ogVyk8qmXKA0EamNJwy0AGh9sXAoBjTL4qvXRz3mV8BvgIMwKprq30BzhuaAlC9gQt599Wan + D/McqOOrewZaALRvtDwXOeY/ovTqLw7D2G+ycrUI4jC0A3Dn+Y75aJu4JEiKemeodVMGFhhkMuQj + dteB6JIOYXFCmlgcNplgAcG66emHLHBajeQrtcwv2e/GnuvRgAxsOsj/UVIqpZG86TcYZAHIvm34 + XuBZ4QEN+2oneQ4MQ0xGvPZcvHrEjkMyaoh98i3sqFo9XH69Hg7OAjR9QhMd6JsCJ2J8utTtgrUc + GODHfK4JM53SeeMub55J+bMv33cG7L5F1BdvrA/sfC4DefuCjqmTPH+dno9J+VyKqH0pJ7S/FwTj + iKRZw1xM+vlS2T4TdeqAUpzr2VxC2xfszqXs/eDSRe25XODeF+5Po/dH2AKfy9D+3oTfDGNsgI+q + 6T2bUY59GW/HjI+spjqbweS9wW5mOxwbbNo0iCvkx7qOMOkFbCegv5hG24O3T9Jx8pyMDcRDGZs6 + lKwKgrrCY2hJvCiZlqgLvF4Op7idJ5x5BncPzXVwh4OQKF57jmm705JmIqVWxruEvTsGmBsQT6c4 + DEkpPHJQGB7Orp18j9Tp4/FybrzNfTK90DwIWnfyrxNGy3KTYzG0/bR/qZBxzR+jPETyLFvxtLPo + vhRLqWFKp0wuZqKBqzjJDjkfsT9HMTeQRruAneepPDlJUmRdFmANCRhKOhKgwldMqOtcTVAqnFVF + GboYmW4f3TadW88ky5uVa/orJ90xjpDKblfuJnl051zkYprGJLkrTDZCDuh7obe+TJqJLWkFBwq6 + qz6jyx90k4vOxfszivZMNukkz044G7PtfKNMZixRHo0cn0+u4SDjR1SsYHDle8tFZrmSA6+RvMbF + 2ejla+bqt9qw1VZvMquVGG/1lnrDzD4wV5YccSxf0kTcPSJfDYErgpcZrsygu02+Ge9s1PLFXCc6 + RiTifPvv9cX7jMVliXCd6+TZU9Giiw6OHU7pe56PQRMt7HDbjXnhe94RxG1FhSjyBi9VeBHqRpWD + kinXIJKEKhR4jq9xVVGRFKEcRC5mvcbUVUWayHfswInuwcs5rlJy/myqyVf4Tk00fdmf4qJUqw8U + co2dEZcie/gF13Rd0MUaX4FYQgaUOLMCEYcUgmQg0eSQwBtpC67xr7DeE+VkmnW41NCP7pH9OMNd + wd44OdueiuC2dvnkgrFD1imGx7G6MRItUzR1AyqGKEBJriKoVLAOqzLGnIFFTjLSr0WkO/JUK+K1 + HRv0bMdZARQtahk/CJpbM31GTAxmL7luPTfMmLlO6Q1ldOvPHXJC0LIDlxQIeUBLLGVbKUsQMMvU + wNzrXZcUpGn3djDSDOGphsjXl8aPstZ5oXBUG7fJ46jnBhnXIUmJzSjLNj0DwabnoFw5tlAJtIt5 + M2SURWNygjdDPvP50rWNdaLN2b8sMT5TpkUx0gykfXJUsG8g//0B2H0z9pNvmDs7RppRHw0HTknr + hnLbVYCFHF0STe0xxteMfP7JbiUi0vQqGWGGhJo61sOq1qNjpKhaWSQeFSFFx6PZ7qndWxVcD3ut + 7uBKBd1Bs7gmRTySD3LNMP8olFZZlXoCiKz3eCjQKiVoarejLNLkP/WViht3wYvxFuctUs3ugfSs + Ktu9ob695hXNEVm92TyDbLl3U53TFbAsqjTF7qsR9pyihYbZY9ewO5+B9iyaFIVSadcz95CDz+na + Zhbejxvm28efQz2rgYYsnCVMCyox/9KhntPsoCymFBmY9WtOGLfIYNIeQM9oYCkTaP7ql7pBLXmZ + MtaaltCTwU5gL4P0+/loWKni86zG77OofuQEhQTMLPMUWJRm8czfhLKBwc9Hmhqin6suGtuk2+Rv + 19Z7TdpwltELz5CzS/q8G9jdJj8pWmD/0jKxqEuoAmUF6VDChhzdesRDy5CqginWqlINpaC+7na+ + e+tRDfK7qEmck/poqF23x/3oyjf4Wvn9zcYb0ThMKsJdwOgDMMISCSVG+LkJGd+n5gNfBRaBn52Q + Z4SfmzCWb++ThZhhmYbgq3h8Yfjeaj8Nz/v7/bV+fno2PxvpGGKuUjM40h3kLV6GEi+JUDcNBHWs + CFgWsY4qacsXcJBPX4Ci9qr3uEVL/asQneggAc1fkv8Hnh/OQH2OfdtALmiT15iuSHfR8skB85dG + uPQx6Czd+DXP96jb7vdGTJdCd4Lc6TJKQVeOpyMH4L/g7YV6AcaY/NIOQvIWoK11PtpzMvizyzwp + PPvIRVNsghGJVMtzbA+oJFhxADTygGcH+OcYHtkLTI5DCWGbftVk11kb3bO4pXG+a6va3XDYAn/e + 1ntd7R6o/Xqv16yPQOd20CrkSBGud3fqPd2aoyfluFsSpTpu829HU9ugRd7X8RYkfqP1kXAYHCT3 + tpOHXk+eMrp0SUFpq6SWjzLtulSCYPP7eEk2dhwgEIBDeHbv6JZOPxlPytDc+PXVZhe06532IfDa + HRaMNO3jBq8ZLfuo/jYClQMF3yT5D7efvB9l8Kmj1hj0bbOJFkB6ontKrB8N2G/RLRJ8SoACRQB2 + SF/Df8h/Kbkkts6xdh8VUdQRb8pQlMUqlJBgQCTqGBqVKqpKPOJ4C5ejRpM2641xawBG1/dqt1nv + gRHpU9RbQL3OnDoL3U+yyxh9AAZJAblp/3gognvyyUnyxChY+ivy3V3zUJzq9bEm08+hKUL5iDS7 + bZZki2j2G+qh6PqNBqOjoOsOJm21OSQt4nCsAS26nqWN2/VyHKkGUBvPDeQv//k/0SwWe4i0AAA= + 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: + - Fri, 06 Dec 2024 00:39:23 GMT + Etag: + - W/"b488-L685VcG067aMlCDn+EpysmcRcnQ" + 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/record/http/test_fmp_fetchers/test_fmp_government_trades_fetcher_urllib3_v2.yaml b/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_government_trades_fetcher_urllib3_v2.yaml new file mode 100644 index 00000000000..af4c4c8a479 --- /dev/null +++ b/openbb_platform/providers/fmp/tests/record/http/test_fmp_fetchers/test_fmp_government_trades_fetcher_urllib3_v2.yaml @@ -0,0 +1,105 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://financialmodelingprep.com/api/v4/senate-trading-rss-feed?apikey=MOCK_API_KEY&page=0 + response: + body: + string: !!binary | + H4sIAAAAAAAAA+3d23OqSBoA8Pf5K7pOTZ2dqTqdcBWcN+Ml8USjI8RsdmsfGmiUCoIFmIyztf/7 + NjGaGAmNXKIRHk5VjoIXfnzN11837b9/AeC/5B8A30zL84MbNMPf/gDflCm2Ddf59mP1nI1en7qb + WgGeugsfr591TdPS3+4GdrexLech3GIaBHP/j/NzbBo+Rp4+PfOxgwJ8NnEfz1ePnD9a+Ol8Hnjn + ssiLbI0RoCzXNShgLEOkyxjWtHpdE0WBZwX+fP0OBnmVEdYt/IiN8J04hhMgy0FGWG8ReMjxkR5Y + rtMiG79uxEK2vvkyTw72nr/L/O3nR76Pgxb2dc+ahy8QbtHHgW2ZGHQdfWszdTlfHY3A1R82b75+ + ENkY/NZZ2Pbvm51m7sIJwid/ZX8wDAsg+JUVyV/Megvdnc3wahMI1w/6y5nm2s8fpK1+I4/970el + udKUdzWxbcZZXmPncXEElNfj23asZR95D09o6bxavNHsk89ibZxfJTc7ge0tUjkKQk3mDVaGHJZM + 4lgXYF2o8xBhsa5JnMBKfAJHnurIQG43Kn+6Fjl4MZBd55E84IIGecVHbC9BHzlogg3Q/kufImeC + oeohg/y/s3AMoHoLPwDrfcbIs5BGUEfkg6weDUIscBnuAtpqJ/LkeH9eDBfkeKE3bcfrScGJzPq0 + EBnmg/Ni96wYj7qX1Vmxjm7u1M6K5xbi5aSozon358SG++AtRaRz5KUhaxMQdWm46t4rFXiGRmBo + zQh3kxxl17ACC/tze+EDhbxLgCfLFXOTHDMfdCG39UIJ0oAh8gILRWcC9PCO8h42e8N/xoJfWLYd + ZX1FTmMvWO5ihzuAd8+mgkaMVEM1U4Yya0hQ0A0M6yZioKYJvGBqdZljEQWahZxIhWYgvzlce+Ry + S9+aTAOgYn3quLY7IdYfpnZRnBGIr1HL7nHhvm5TYla1HBRFqMysYLoLGG4Otp5LxafzvKQJJE41 + VhSgIEqI8BkkqgRJ4wxNJw+zdD6WyhcZp/SOlRq+FgkqZekHeOa/Oi73S9BjWuF0nGqz3zpZzs0h + OFHOW8fAnr20nAl4fi/gmqBBXhE0VwRghB9d/TnTWyWAt+cN0FJbgGXPOf6cY9hNe7XPGUE+wGtb + ++aUUBca9h5JgxzR837eCexukersMDUZSzojQWTUdCjImIGohkxo4LpmirLMSUaNenawSdrqNFnY + ILB8cOd6tvFkkWy66Xrz5GfEB201veu9CzlQu5SWuoKMhby2ZloYX5CkUN5DTpD0zGlX8rp/UUFm + gLwh/duwtW78AM0pmgHSboIxeffl1k6fxnmjjC7vK9AMoA3D1VKUNvMCbLQu4kualV+835Xr4OUT + Jl23rhNgj3wL8gSyDyd6NbipQDOAkmtjgB9RPoApcp2mOm5UgBkA1WnYR0CP2MaeH1aU5siJqzHs + BZomItXRuALNADp4wk4I6Tmke3gYwkGzEswg2Ndb4UXR+Id/wK5Hv1kVAzIhWrrn+q4ZHNJQ6cTP + pqgQ4xF/ulPHdx3wHbz8dRjHnzc/K8YMjI353D5kr7Ex7JXCjz6hKZ3fThiuRj4dsEWXDDVmlhPd + NmpssyzBWRRuRLHV9Z7rAsekXJZKbFHKmyb4jBz6I3Kt2uaMsDEVvSOjLkupryjprcJC6LuFC27w + 04GBS1J2KMr3XdnhCC/CZalJFCW8GT07spa5NMNqRcG+jML8WNkWIksdm4mCLc3oTFGwH4zOFAmd + LoTLMmpTFPR2uXh97T2qVppaTb5EXiTxEJOOweaOg1fecHuw/WQ6WZaRsI5YKGFDg4IpIqjJLIam + wPKCYfIax2r5yPKbecKJZ3D30EwDd9gPiOKVaxskd85pcJXaIu8S9u4qwL0B8WSCgwB8B0MbBcHh + 7Nrx90idPh4r7Y23vjGqFxgHQeuO/3XCaPRbHA8TcXmnsacdekkUs4VeMVlMKsoqINMEZC45TN6U + lGQmHCqMkuyQpgV7MxRxA2m4C9h5PpUnIwiypEkcrCMOQ0FDHJRZ0YCaxtQ5WWTMGkrQ26DfPhoZ + mnGW94h8NQQuCWPW+wjpbLtojdv4CfClUdvMdUik1gmPEYk9z/r7uST7wYyiAuE6V/GjJ6WB2y/c + LjHZCNmg7wbucwUnkVvcAgsp7C77Fd3+MXdhI/0hvOZhcOm5i3ni5jJnvYv4O+fLosftp3e9dAxv + adPzlYL1ruOHrMqit2ez2bhVB622cp1YLccrXaOlXFdmnxhxOdpV0baS25TTEsmNzzpnyZPKnBvI + cSd+2kZl9lWjLVx00caR5ZS+63oYNNHcCjYZ8avfy44gaqtUijyrs4LI8lDTawwUDKkOkcDVIMcy + bJ2p8bIgc/koMhHrNVJXFWkiz7Z8O1wyYs+6Ss6x2FTiJ0Oemih92Z/soqluqMzkGjkTgyJ7+AXX + NI3T+DorQiwgHQqMIULEIJkg6Yg3GMSxOm3BNfYN1keijJRmHS4l8MIlXT7PcFewN4ovwJyK4Kaj + 8MUFI0vWFMPjWN0Y8abBG5oOZZ3noCDVEJRFrMGahDGjY54RdPpYBN0xeqYMzXGM1zXQ2WzhWPrz + RJk9W9ccUyDKcFIFSgVVAuRpC/0hr5udUyAqF7fxNbayMUblPBTGZrundG8VcDXotbo3lwro3jQP + gkk+yFWFmS0m++SYYE9H3sdjhEUz9uMnDpcOMU0vRMW+ndPSPMxmVUpujzufVaVXMb5lZPeffJEj + In3eb0VIJYyKxIrwSxGm6D62bQv0LNteAhQurR49jL93JzKNZq8XP4OmbJgp0ptCVyFMkevQ7kyu + SBMkO1XOemyMKXqR4f1uTVdHsOmSK2ZezWwKyutBRZk1IqtS3cmRVsW6E4EMG9o7ZAegZfkkGdqr + qc0Rs0X5pYJTsqwlsExxyXx7uQzHmpdbGxd3zYxcJas8V82iNLHtWwufPq3n026zKVU9PYnqZ5Zi + YzCTVGQjV2ooUzUoiWcO1aAc2116SShyYkGJikJJTFMUhbLUD+J/MzFVs1uiWkIi0P0vpfk3ueli + s2pwswdnln5nAcFZqj5oEtLPG9cs4udpqwhNEKHUFDevcl8B8Vqi0l9hvFV+9NVIP2sUtADdMo2I + puWlRmyVNJ0g6nbRfs/CQxH1waqET1f9pHsaCghaSuY0svQpyQiicC/sRfjCU2Tv4r7sBna32R8X + zbF3bhqY1wQkQklGGhSwLoW3HrHQ1IUaZ/D1mlBHFN63hcAPbz2qQ3aXN5a2MRyoV+1RP5wPD35j + f9/aeC0ahZmKMAKQfICKMEdCviL86oRcRfi1CSP5ip6rUBkWb1jxfRU+8JtYtaJfnVA4PsKPlvu5 + cN2/P17s592z+7ORLiJmxLrOkI4ha7ISFFiBh5qhI6hhmcMSjzUk0pYvYCBLX4Ci/qYfuUGj/kDE + XVtR7waDFvjzttHrqvdA6Td6vWZjCDq3N63PZry7U+7TLUt4Uo67wUd1tBTS1GAf9JVmF7QbnTZo + q53P5mt34qvnpcBLEYR95KAJNsDQ9QLTtS0XKNgLF/dRyQOu5WNwQ/6YgsaMPKwjBwytOSbHAYPO + won+BYKkyvSRzV1mdXg/LL0zl8K5Qyi9x/0LcDmFZ6dberU0TasybI1A3zKaaA4EhgkbVqB6C397 + p30DL4Vfv5VukfOTAQznPqcAXF8bn9HIMV//f7QgG9s24JiV6md7du/SLaB9Up4pmtG1XzNc9E/5 + PgTigfzG8T9Od/J+KdOdMXImi7BjfGm7GrIB/gvenilnYITJf9p+QN7iEJzjmz+rC2Qaz054kF5a + 13eJapu8xmRJMh7TIwfMW+jBwssha02h2+73qqQ1zdVzE60dVWmDFnlf252Tzkq4xiMO/INEavtY + +5kyz2uINSTIS3wNCojTIeI1DHWxhmoCixjWxDlRpgnU7khRgToCl73BRaMH1EZT7TbJH81+slJP + tjtMdiE76mW6VbrLLpkpBcp0f+Yu4vGmQV/EsH+hHMoufO8KLwMeC3lwTz45SX8w8hfeknx3xzgU + p3J1rBWCr6HJQ+mINLvtVX/kl//8H76NuteFtAAA + 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: + - Fri, 06 Dec 2024 00:37:01 GMT + Etag: + - W/"b485-xkA9fqZ3cTgtbLcCqSB0Ue9nHu4" + 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 30a05855e05..958a99104d8 100644 --- a/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py +++ b/openbb_platform/providers/fmp/tests/test_fmp_fetchers.py @@ -71,6 +71,7 @@ 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 +from openbb_fmp.models.government_trades import FMPGovernmentTradesFetcher test_credentials = UserService().default_user_settings.credentials.model_dump( mode="json" @@ -762,3 +763,17 @@ 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_government_trades_fetcher(credentials=test_credentials): + """Test FMP government trades fetcher. + params limit only functions when there is no parameter symbol. + """ + params = { + "chamber": "senate", + "limit": 1, + } + fetcher = FMPGovernmentTradesFetcher() + result = fetcher.test(params, credentials) + assert result is None