From 1604c78ee54afb5c7da9566ae9ecffcc56523027 Mon Sep 17 00:00:00 2001 From: Danglewood <85772166+deeleeramone@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:40:05 -0800 Subject: [PATCH] feature/intrinio-equity-search: Adds Intrinio to `obb.equity.search()` (#5863) * intrinio equity search * integration tests * test --------- Co-authored-by: James Maslek --- .../provider/standard_models/equity_search.py | 16 ++-- .../equity/integration/test_equity_api.py | 1 + .../equity/integration/test_equity_python.py | 1 + .../intrinio/openbb_intrinio/__init__.py | 2 + .../openbb_intrinio/models/equity_search.py | 89 +++++++++++++++++++ .../test_intrinio_equity_search_fetcher.yaml | 52 +++++++++++ .../intrinio/tests/test_intrinio_fetchers.py | 10 +++ 7 files changed, 160 insertions(+), 11 deletions(-) create mode 100644 openbb_platform/providers/intrinio/openbb_intrinio/models/equity_search.py create mode 100644 openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_equity_search_fetcher.yaml diff --git a/openbb_platform/core/openbb_core/provider/standard_models/equity_search.py b/openbb_platform/core/openbb_core/provider/standard_models/equity_search.py index cd23ba2a02a..8ec02ceeb80 100644 --- a/openbb_platform/core/openbb_core/provider/standard_models/equity_search.py +++ b/openbb_platform/core/openbb_core/provider/standard_models/equity_search.py @@ -1,8 +1,8 @@ """Equity Search Standard Model.""" -from typing import List, Set, Union +from typing import Optional -from pydantic import Field, field_validator +from pydantic import Field from openbb_core.provider.abstract.data import Data from openbb_core.provider.abstract.query_params import QueryParams @@ -21,13 +21,7 @@ class EquitySearchQueryParams(QueryParams): class EquitySearchData(Data): """Equity Search Data.""" - symbol: str = Field(description=DATA_DESCRIPTIONS.get("symbol", "")) + symbol: Optional[str] = Field( + default=None, description=DATA_DESCRIPTIONS.get("symbol", "") + ) name: str = Field(description="Name of the company.") - - @field_validator("symbol", mode="before", check_fields=False) - @classmethod - def upper_symbol(cls, v: Union[str, List[str], Set[str]]): - """Convert symbol to uppercase.""" - if isinstance(v, str): - return v.upper() - return ",".join([symbol.upper() for symbol in list(v)]) diff --git a/openbb_platform/extensions/equity/integration/test_equity_api.py b/openbb_platform/extensions/equity/integration/test_equity_api.py index 98df7116d07..f1a32dc4ff8 100644 --- a/openbb_platform/extensions/equity/integration/test_equity_api.py +++ b/openbb_platform/extensions/equity/integration/test_equity_api.py @@ -1017,6 +1017,7 @@ def test_equity_fundamental_latest_attributes(params, headers): [ ({"query": "AAPl", "is_symbol": True, "provider": "cboe"}), ({"query": "Apple", "provider": "sec", "use_cache": False, "is_fund": False}), + ({"query": "gold", "provider": "intrinio", "active": True, "limit": 100}), ], ) @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 d2e8e842df8..a89ef5cf312 100644 --- a/openbb_platform/extensions/equity/integration/test_equity_python.py +++ b/openbb_platform/extensions/equity/integration/test_equity_python.py @@ -974,6 +974,7 @@ def test_equity_fundamental_latest_attributes(params, obb): [ ({"query": "AAPL", "is_symbol": True, "provider": "cboe"}), ({"query": "Apple", "provider": "sec", "use_cache": False, "is_fund": False}), + ({"query": "gold", "provider": "intrinio", "active": True, "limit": 100}), ], ) @pytest.mark.integration diff --git a/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py b/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py index c4e70f9eb82..ace8efafc28 100644 --- a/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py +++ b/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py @@ -10,6 +10,7 @@ from openbb_intrinio.models.currency_pairs import IntrinioCurrencyPairsFetcher from openbb_intrinio.models.equity_historical import IntrinioEquityHistoricalFetcher from openbb_intrinio.models.equity_info import IntrinioEquityInfoFetcher from openbb_intrinio.models.equity_quote import IntrinioEquityQuoteFetcher +from openbb_intrinio.models.equity_search import IntrinioEquitySearchFetcher from openbb_intrinio.models.fred_series import IntrinioFredSeriesFetcher from openbb_intrinio.models.historical_attributes import ( IntrinioHistoricalAttributesFetcher, @@ -49,6 +50,7 @@ intrinio_provider = Provider( "EquityHistorical": IntrinioEquityHistoricalFetcher, "EquityInfo": IntrinioEquityInfoFetcher, "EquityQuote": IntrinioEquityQuoteFetcher, + "EquitySearch": IntrinioEquitySearchFetcher, "FredSeries": IntrinioFredSeriesFetcher, "HistoricalAttributes": IntrinioHistoricalAttributesFetcher, "HistoricalDividends": IntrinioHistoricalDividendsFetcher, diff --git a/openbb_platform/providers/intrinio/openbb_intrinio/models/equity_search.py b/openbb_platform/providers/intrinio/openbb_intrinio/models/equity_search.py new file mode 100644 index 00000000000..a8049501036 --- /dev/null +++ b/openbb_platform/providers/intrinio/openbb_intrinio/models/equity_search.py @@ -0,0 +1,89 @@ +"""Intrinio Equity Search Model.""" + +from typing import Any, Dict, List, Optional + +from openbb_core.provider.abstract.fetcher import Fetcher +from openbb_core.provider.standard_models.equity_search import ( + EquitySearchData, + EquitySearchQueryParams, +) +from openbb_core.provider.utils.descriptions import ( + DATA_DESCRIPTIONS, + QUERY_DESCRIPTIONS, +) +from openbb_core.provider.utils.helpers import get_querystring +from openbb_intrinio.utils.helpers import get_data_one +from pydantic import Field + + +class IntrinioEquitySearchQueryParams(EquitySearchQueryParams): + """Intrinio Equity Search Query. + + Source: https://docs.intrinio.com/documentation/web_api/search_companies_v2 + """ + + __alias_dict__ = { + "limit": "page_size", + } + + active: Optional[bool] = Field( + default=True, + description="When true, return companies that are actively traded (having stock prices within the past 14 days)." + + " When false, return companies that are not actively traded or never have been traded.", + ) + limit: Optional[int] = Field( + default=10000, + description=QUERY_DESCRIPTIONS.get("limit", ""), + ) + + +class IntrinioEquitySearchData(EquitySearchData): + """Intrinio Equity Search Data.""" + + __alias_dict__ = { + "intrinio_id": "id", + "symbol": "ticker", + } + + cik: Optional[str] = Field(description=DATA_DESCRIPTIONS.get("CIK", "")) + lei: Optional[str] = Field( + description="The Legal Entity Identifier (LEI) of the company." + ) + intrinio_id: str = Field(description="The Intrinio ID of the company.") + + +class IntrinioEquitySearchFetcher( + Fetcher[ + IntrinioEquitySearchQueryParams, + List[IntrinioEquitySearchData], + ] +): + """Transform the query, extract and transform the data from the Intrinio endpoints.""" + + @staticmethod + def transform_query(params: Dict[str, Any]) -> IntrinioEquitySearchQueryParams: + """Transform the query.""" + return IntrinioEquitySearchQueryParams(**params) + + @staticmethod + def extract_data( + query: IntrinioEquitySearchQueryParams, # pylint: disable=unused-argument + credentials: Optional[Dict[str, str]], + **kwargs: Any, + ) -> List[Dict]: + """Return the raw data from the Intrinio endpoint.""" + + api_key = credentials.get("intrinio_api_key") if credentials else "" + query_str = get_querystring(query.model_dump(by_alias=True), ["is_symbol"]) + base_url = "https://api-v2.intrinio.com/companies/search?" + url = f"{base_url}{query_str}&api_key={api_key}" + data = get_data_one(url, **kwargs) + return data + + @staticmethod + def transform_data( + query: IntrinioEquitySearchQueryParams, data: Dict, **kwargs: Any + ) -> List[IntrinioEquitySearchData]: + """Transform the data to the standard format.""" + + return [IntrinioEquitySearchData.model_validate(d) for d in data["companies"]] diff --git a/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_equity_search_fetcher.yaml b/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_equity_search_fetcher.yaml new file mode 100644 index 00000000000..292cee77eb4 --- /dev/null +++ b/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_equity_search_fetcher.yaml @@ -0,0 +1,52 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, br + Connection: + - keep-alive + method: GET + uri: https://api-v2.intrinio.com/companies/search?active=True&api_key=MOCK_API_KEY&page_size=100&query=gold + response: + body: + string: !!binary | + H4sIAHb8b2UAA4yWW3PiOBCF/wrF8+yWkGxZnjdfQAFsY2wuhq2tKQMujyfEJlwSYGr++4rNZlCL + YnHewOFT6/ic7v7ZXFYvm7Qssl3z618/m8Wq+fXy1bfF+bW/yJtfmvti+Zxtxbd84Lnic5m+ZOKT + bUVR1+k3Lt82nEEUikfrrBBP0EDr20OnN08YHve5Y08MIh4ui+fLQ/Fn6JSZWvPXF+m4c3vS3pzk + 47rWOLkeV/zBUINX61XDqbabPz8PKw/rtYRuMZ2YFCvoV1tfAHQw4V7nyg4mV/I9MEUGQ4YC9rNX + dgZgLikUZO8f3G65/C2OrpkEIZ0jHjhPIXqinkmBOOxyGIUH5RkbTMENxrE1vp40jh9eACFsIJMo + 3NkPGiQytz/irqRMHz9WRme3kifT43oGlBlFUSKBR0F06xyVrBG9ZZpKyS7N3gA59i0ukePqJa1h + FEPAEYLs08LdWkCOiTV2JPakeKvFxgRpqld6Ln8HcfKTmF/RfnY87D7Y4/gemOg6NRTwibylQyhI + xOeSHvt0W6NmTWSH6Gpwtu4rsF00a8dXdFTssjporDGqxP20Cn60gdRekMiv0SvKw/Gx+RBjwoCQ + vc2RHwF2xOXOFVWndH2TzJu8MF1XBcmPxqYPm1TgWFLVgpc2BmUdVXRDw0Q199GfPYPKff4kG9Av + ymVVQxWMGFZqT7jHpsAnPaGKxO6lYgzUKJwyitTk5JrnUuBueySZ28b5o5I1bJpEsXYeDtfQJBPZ + 2ZNit09vxfivxeKp0xl5/YndZa7G4PxhhGDVkC36boAbjGweyh2r7duDa8+6Kw+59EPlIgkNCQW+ + iXkgT6C4yEvJk//TWTBuKZXnk0UJtbd494q21ulLtbs3iEbuIDHIjM+StqmbskqtliGypRpUa//A + MFoTT45tlL1ldS5ChY2Ymi7khS7cOKaxnC5evWe7/Qfc26/uRwszTKg6q8vFM1wCOtyBw7pTHcrV + 43QxDYny1S7sDUHtHz/6jG36vqvK34XfFQVjis2bSbqlILbeIJBbgleJlrB9rLhmYKq+zrM/9dtA + ccfmcwnupIttrdeJTGYoy8WZBXYFfWnJS8sF+iI6Tpwuv+8a4ffTrlh+ntUede5GAIlhoqq/iRYa + sCXvdOFJjU6RrVc7Wf6mLnoOQqSfdO3ecObYtmtgJQLYUBvFucLTEkbAHXfkCFhu97KQXTqFGA93 + NWu1CKZInbhROAQudSNpcokP/2JvLzFHIeFRFGDic6I14TAQa5S6EvvTlQnezZi7XekS47LIHwxI + U6MaUTeotauvQf3WnMviWPNR27Eer35ipSS6GuFeSG1oqJgPZPguLfe1Zq9Y0FTpczzL2qB0zwe7 + sHd4Kco66x81CSaK4PmQtxcwxmEf7DuHTfpch65jsVuqsvdDLwXKxP6gA5bistpWdeiEtZjoEn+L + n2bH/bdNmmcf//XrHwAAAP//AwB3pkhmKg4AAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Wed, 06 Dec 2023 04:45:42 GMT + Transfer-Encoding: + - chunked + Vary: + - Origin,Accept-Encoding + status: + code: 200 + message: OK +version: 1 diff --git a/openbb_platform/providers/intrinio/tests/test_intrinio_fetchers.py b/openbb_platform/providers/intrinio/tests/test_intrinio_fetchers.py index ae1c9ac5914..49e4d46aa94 100644 --- a/openbb_platform/providers/intrinio/tests/test_intrinio_fetchers.py +++ b/openbb_platform/providers/intrinio/tests/test_intrinio_fetchers.py @@ -12,6 +12,7 @@ from openbb_intrinio.models.currency_pairs import IntrinioCurrencyPairsFetcher from openbb_intrinio.models.equity_historical import IntrinioEquityHistoricalFetcher from openbb_intrinio.models.equity_info import IntrinioEquityInfoFetcher from openbb_intrinio.models.equity_quote import IntrinioEquityQuoteFetcher +from openbb_intrinio.models.equity_search import IntrinioEquitySearchFetcher from openbb_intrinio.models.fred_series import IntrinioFredSeriesFetcher from openbb_intrinio.models.historical_attributes import ( IntrinioHistoricalAttributesFetcher, @@ -305,3 +306,12 @@ def test_intrinio_share_statistics_fetcher(credentials=test_credentials): fetcher = IntrinioShareStatisticsFetcher() result = fetcher.test(params, credentials) assert result is None + + +@pytest.mark.record_http +def test_intrinio_equity_search_fetcher(credentials=test_credentials): + params = {"query": "gold", "limit": 100} + + fetcher = IntrinioEquitySearchFetcher() + result = fetcher.test(params, credentials) + assert result is None