diff options
author | Danglewood <85772166+deeleeramone@users.noreply.github.com> | 2024-03-15 08:05:20 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-15 15:05:20 +0000 |
commit | c55f93c86533c8a2a53aa5c24b454e63d6dc01cf (patch) | |
tree | 2dcf7d9cd55d751a52bcb1646a5579f4f61f8037 | |
parent | 0239e6edbbaed83305108d1a4fbe9c8740563a22 (diff) |
add Intrinio ETF Holdings (#6208)
8 files changed, 453 insertions, 13 deletions
diff --git a/openbb_platform/extensions/etf/integration/test_etf_api.py b/openbb_platform/extensions/etf/integration/test_etf_api.py index d0b03385a36..850998dd540 100644 --- a/openbb_platform/extensions/etf/integration/test_etf_api.py +++ b/openbb_platform/extensions/etf/integration/test_etf_api.py @@ -333,6 +333,12 @@ def test_etf_holdings_date(params, headers): "use_cache": False, } ), + ( + { + "symbol": "DJIA", + "provider": "intrinio", + } + ), ], ) @pytest.mark.integration diff --git a/openbb_platform/extensions/etf/integration/test_etf_python.py b/openbb_platform/extensions/etf/integration/test_etf_python.py index 417c4eae3a9..f3d966b831b 100644 --- a/openbb_platform/extensions/etf/integration/test_etf_python.py +++ b/openbb_platform/extensions/etf/integration/test_etf_python.py @@ -325,6 +325,12 @@ def test_etf_holdings_date(params, obb): "use_cache": False, } ), + ( + { + "symbol": "DJIA", + "provider": "intrinio", + } + ), ], ) @pytest.mark.integration diff --git a/openbb_platform/openbb/assets/reference.json b/openbb_platform/openbb/assets/reference.json index beb7f8439a4..fd9de6d9d5d 100644 --- a/openbb_platform/openbb/assets/reference.json +++ b/openbb_platform/openbb/assets/reference.json @@ -21582,7 +21582,7 @@ }, { "name": "provider", - "type": "Literal['fmp', 'sec']", + "type": "Literal['fmp', 'intrinio', 'sec']", "description": "The provider to use for the query, by default None. If None, the provider specified in defaults is selected or 'fmp' if there is no default.", "default": "fmp", "optional": true @@ -21604,6 +21604,7 @@ "optional": true } ], + "intrinio": [], "sec": [ { "name": "date", @@ -21630,7 +21631,7 @@ }, { "name": "provider", - "type": "Optional[Literal['fmp', 'sec']]", + "type": "Optional[Literal['fmp', 'intrinio', 'sec']]", "description": "Provider name." }, { @@ -21816,6 +21817,127 @@ "optional": true } ], + "intrinio": [ + { + "name": "security_type", + "type": "str", + "description": "The type of instrument for this holding. Examples(Bond='BOND', Equity='EQUI')", + "default": null, + "optional": true + }, + { + "name": "isin", + "type": "str", + "description": "The International Securities Identification Number.", + "default": null, + "optional": true + }, + { + "name": "ric", + "type": "str", + "description": "The Reuters Instrument Code.", + "default": null, + "optional": true + }, + { + "name": "sedol", + "type": "str", + "description": "The Stock Exchange Daily Official List.", + "default": null, + "optional": true + }, + { + "name": "share_class_figi", + "type": "str", + "description": "The OpenFIGI symbol for the holding.", + "default": null, + "optional": true + }, + { + "name": "country", + "type": "str", + "description": "The country or region of the holding.", + "default": null, + "optional": true + }, + { + "name": "maturity_date", + "type": "date", + "description": "The maturity date for the debt security, if available.", + "default": null, + "optional": true + }, + { + "name": "contract_expiry_date", + "type": "date", + "description": "Expiry date for the futures contract held, if available.", + "default": null, + "optional": true + }, + { + "name": "coupon", + "type": "float", + "description": "The coupon rate of the debt security, if available.", + "default": null, + "optional": true + }, + { + "name": "balance", + "type": "Union[float, int]", + "description": "The number of units of the security held, if available.", + "default": null, + "optional": true + }, + { + "name": "unit", + "type": "str", + "description": "The units of the 'balance' field.", + "default": null, + "optional": true + }, + { + "name": "units_per_share", + "type": "float", + "description": "Number of units of the security held per share outstanding of the ETF, if available.", + "default": null, + "optional": true + }, + { + "name": "face_value", + "type": "float", + "description": "The face value of the debt security, if available.", + "default": null, + "optional": true + }, + { + "name": "derivatives_value", + "type": "float", + "description": "The notional value of derivatives contracts held.", + "default": null, + "optional": true + }, + { + "name": "value", + "type": "float", + "description": "The market value of the holding, on the 'as_of' date.", + "default": null, + "optional": true + }, + { + "name": "weight", + "type": "float", + "description": "The weight of the holding, as a normalized percent.", + "default": null, + "optional": true + }, + { + "name": "updated", + "type": "date", + "description": "The 'as_of' date for the holding.", + "default": null, + "optional": true + } + ], "sec": [ { "name": "lei", diff --git a/openbb_platform/openbb/package/etf.py b/openbb_platform/openbb/package/etf.py index 74703b23143..fba9012a51e 100644 --- a/openbb_platform/openbb/package/etf.py +++ b/openbb_platform/openbb/package/etf.py @@ -371,7 +371,7 @@ class ROUTER_etf(Container): str, OpenBBCustomParameter(description="Symbol to get data for. (ETF)") ], provider: Annotated[ - Optional[Literal["fmp", "sec"]], + Optional[Literal["fmp", "intrinio", "sec"]], OpenBBCustomParameter( description="The provider to use for the query, by default None.\n If None, the provider specified in defaults is selected or 'fmp' if there is\n no default." ), @@ -384,7 +384,7 @@ class ROUTER_etf(Container): ---------- symbol : str Symbol to get data for. (ETF) - provider : Optional[Literal['fmp', 'sec']] + provider : Optional[Literal['fmp', 'intrinio', 'sec']] The provider to use for the query, by default None. If None, the provider specified in defaults is selected or 'fmp' if there is no default. @@ -401,7 +401,7 @@ class ROUTER_etf(Container): OBBject results : List[EtfHoldings] Serializable results. - provider : Optional[Literal['fmp', 'sec']] + provider : Optional[Literal['fmp', 'intrinio', 'sec']] Provider name. warnings : Optional[List[Warning_]] List of warnings. @@ -423,9 +423,10 @@ class ROUTER_etf(Container): cusip : Optional[str] The CUSIP of the holding. (provider: fmp, sec) isin : Optional[str] - The ISIN of the holding. (provider: fmp, sec) + The ISIN of the holding. (provider: fmp, intrinio, sec) balance : Optional[int] The balance of the holding, in shares or units. (provider: fmp); + The number of units of the security held, if available. (provider: intrinio); The balance of the holding. (provider: sec) units : Optional[Union[str, float]] The type of units. (provider: fmp); @@ -433,9 +434,9 @@ class ROUTER_etf(Container): currency : Optional[str] The currency of the holding. (provider: fmp, sec) value : Optional[float] - The value of the holding, in dollars. (provider: fmp, sec) + The value of the holding, in dollars. (provider: fmp, intrinio, sec) weight : Optional[float] - The weight of the holding, as a normalized percent. (provider: fmp); + The weight of the holding, as a normalized percent. (provider: fmp, intrinio); The weight of the holding in ETF in %. (provider: sec) payoff_profile : Optional[str] The payoff profile of the holding. (provider: fmp, sec) @@ -444,7 +445,7 @@ class ROUTER_etf(Container): issuer_category : Optional[str] The issuer category of the holding. (provider: fmp, sec) country : Optional[str] - The country of the holding. (provider: fmp, sec) + The country of the holding. (provider: fmp, intrinio, sec) is_restricted : Optional[str] Whether the holding is restricted. (provider: fmp, sec) fair_value_level : Optional[int] @@ -460,7 +461,30 @@ class ROUTER_etf(Container): acceptance_datetime : Optional[str] The acceptance datetime of the filing. (provider: fmp) updated : Optional[Union[date, datetime]] - The date the data was updated. (provider: fmp) + The date the data was updated. (provider: fmp); + The 'as_of' date for the holding. (provider: intrinio) + security_type : Optional[str] + The type of instrument for this holding. Examples(Bond='BOND', Equity='EQUI') (provider: intrinio) + ric : Optional[str] + The Reuters Instrument Code. (provider: intrinio) + sedol : Optional[str] + The Stock Exchange Daily Official List. (provider: intrinio) + share_class_figi : Optional[str] + The OpenFIGI symbol for the holding. (provider: intrinio) + maturity_date : Optional[date] + The maturity date for the debt security, if available. (provider: intrinio, sec) + contract_expiry_date : Optional[date] + Expiry date for the futures contract held, if available. (provider: intrinio) + coupon : Optional[float] + The coupon rate of the debt security, if available. (provider: intrinio) + unit : Optional[str] + The units of the 'balance' field. (provider: intrinio) + units_per_share : Optional[float] + Number of units of the security held per share outstanding of the ETF, if available. (provider: intrinio) + face_value : Optional[float] + The face value of the debt security, if available. (provider: intrinio) + derivatives_value : Optional[float] + The notional value of derivatives contracts held. (provider: intrinio) other_id : Optional[str] Internal identifier for the holding. (provider: sec) loan_value : Optional[float] @@ -469,8 +493,6 @@ class ROUTER_etf(Container): The issuer conditions of the holding. (provider: sec) asset_conditional : Optional[str] The asset conditions of the holding. (provider: sec) - maturity_date : Optional[date] - The maturity date of the debt security. (provider: sec) coupon_kind : Optional[str] The type of coupon for the debt security. (provider: sec) rate_type : Optional[str] @@ -591,7 +613,7 @@ class ROUTER_etf(Container): "provider": self._get_provider( provider, "/etf/holdings", - ("fmp", "sec"), + ("fmp", "intrinio", "sec"), ) }, standard_params={ diff --git a/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py b/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py index f4d001dcc1b..554cc5b8687 100644 --- a/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py +++ b/openbb_platform/providers/intrinio/openbb_intrinio/__init__.py @@ -11,6 +11,7 @@ from openbb_intrinio.models.equity_historical import IntrinioEquityHistoricalFet 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.etf_holdings import IntrinioEtfHoldingsFetcher from openbb_intrinio.models.etf_info import IntrinioEtfInfoFetcher from openbb_intrinio.models.etf_price_performance import ( IntrinioEtfPricePerformanceFetcher, @@ -60,6 +61,7 @@ intrinio_provider = Provider( "EquityQuote": IntrinioEquityQuoteFetcher, "EquitySearch": IntrinioEquitySearchFetcher, "EtfHistorical": IntrinioEquityHistoricalFetcher, + "EtfHoldings": IntrinioEtfHoldingsFetcher, "EtfInfo": IntrinioEtfInfoFetcher, "EtfPricePerformance": IntrinioEtfPricePerformanceFetcher, "EtfSearch": IntrinioEtfSearchFetcher, diff --git a/openbb_platform/providers/intrinio/openbb_intrinio/models/etf_holdings.py b/openbb_platform/providers/intrinio/openbb_intrinio/models/etf_holdings.py new file mode 100644 index 00000000000..52d546bf002 --- /dev/null +++ b/openbb_platform/providers/intrinio/openbb_intrinio/models/etf_holdings.py @@ -0,0 +1,202 @@ +"""Intrinio ETF Holdings Model.""" + +# pylint: disable=unused-argument + +from datetime import date as dateType +from typing import Any, Dict, List, Optional, Union + +from openbb_core.provider.abstract.fetcher import Fetcher +from openbb_core.provider.standard_models.etf_holdings import ( + EtfHoldingsData, + EtfHoldingsQueryParams, +) +from openbb_core.provider.utils.helpers import ( + ClientResponse, + ClientSession, + amake_request, +) +from pydantic import Field, model_validator + + +class IntrinioEtfHoldingsQueryParams(EtfHoldingsQueryParams): + """ + Intrinio ETF Holdings Query Params. + + Source: https://docs.intrinio.com/documentation/web_api/get_etf_holdings_v2 + """ + + +class IntrinioEtfHoldingsData(EtfHoldingsData): + """Intrinio ETF Holdings Data.""" + + __alias_dict__ = { + "symbol": "ticker", + "security_type": "type", + "unit": "quantity_units", + "face_value": "face", + "balance": "quantity_held", + "value": "market_value_held", + "derivatives_value": "notional_value", + "units_per_share": "quantity_per_share", + "weight": "weighting", + "updated": "as_of_date", + "country": "location", + "maturity_date": "maturity", + } + + name: Optional[str] = Field( + default=None, + description="The common name for the holding.", + ) + security_type: Optional[str] = Field( + default=None, + description="The type of instrument for this holding. Examples(Bond='BOND', Equity='EQUI')", + ) + isin: Optional[str] = Field( + default=None, + description="The International Securities Identification Number.", + ) + ric: Optional[str] = Field( + default=None, + description="The Reuters Instrument Code.", + ) + sedol: Optional[str] = Field( + default=None, + description="The Stock Exchange Daily Official List.", + ) + share_class_figi: Optional[str] = Field( + default=None, + description="The OpenFIGI symbol for the holding.", + ) + country: Optional[str] = Field( + default=None, + description="The country or region of the holding.", + ) + maturity_date: Optional[dateType] = Field( + default=None, + description="The maturity date for the debt security, if available.", + ) + contract_expiry_date: Optional[dateType] = Field( + default=None, + description="Expiry date for the futures contract held, if available.", + ) + coupon: Optional[float] = Field( + default=None, + description="The coupon rate of the debt security, if available.", + ) + balance: Optional[Union[int, float]] = Field( + default=None, + description="The number of units of the security held, if available.", + ) + unit: Optional[str] = Field( + default=None, + description="The units of the 'balance' field.", + ) + units_per_share: Optional[float] = Field( + default=None, + description="Number of units of the security held per share outstanding of the ETF, if available.", + ) + face_value: Optional[float] = Field( + default=None, + description="The face value of the debt security, if available.", + ) + derivatives_value: Optional[float] = Field( + default=None, + description="The notional value of derivatives contracts held.", + ) + value: Optional[float] = Field( + default=None, + description="The market value of the holding, on the 'as_of' date.", + ) + weight: Optional[float] = Field( + default=None, + description="The weight of the holding, as a normalized percent.", + ) + updated: Optional[dateType] = Field( + default=None, + description="The 'as_of' date for the holding.", + ) + + @model_validator(mode="before") + @classmethod + def replace_zero(cls, values): + """Check for zero values and replace with None.""" + return ( + {k: None if v == 0 else v for k, v in values.items()} + if isinstance(values, dict) + else values + ) + + +class IntrinioEtfHoldingsFetcher( + Fetcher[IntrinioEtfHoldingsQueryParams, List[IntrinioEtfHoldingsData]] +): + """Intrinio ETF Holdings Fetcher.""" + + @staticmethod + def transform_query(params: Dict[str, Any]) -> IntrinioEtfHoldingsQueryParams: + """Transform query.""" + return IntrinioEtfHoldingsQueryParams(**params) + + @staticmethod + async def aextract_data( + query: IntrinioEtfHoldingsQueryParams, + 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 "" + + symbol = query.symbol + ":US" if ":" not in query.symbol else query.symbol + + URL = f"https://api-v2.intrinio.com/etfs/{symbol}/holdings?page_size=10000&api_key={api_key}" + + data = [] + + async def response_callback(response: ClientResponse, session: ClientSession): + """Async response callback.""" + results = await response.json() + + if results.get("error"): # type: ignore + return results + + if results.get("holdings") and len(results.get("holdings")) > 0: # type: ignore + data.extend(results.get("holdings")) # type: ignore + while results.get("next_page"): # type: ignore + next_page = results["next_page"] # type: ignore + next_url = f"{URL}&next_page={next_page}" + results = await amake_request(next_url, session=session, **kwargs) + if ( + "holdings" in results + and len(results.get("holdings")) > 0 # type: ignore + ): + data.extend(results.get("holdings")) # type: ignore + return data + + return await amake_request(URL, response_callback=response_callback, **kwargs) # type: ignore + + @staticmethod + def transform_data( + query: IntrinioEtfHoldingsQueryParams, + data: List[Dict], + **kwargs: Any, + ) -> List[IntrinioEtfHoldingsData]: + """Transform data.""" + + if not data or isinstance(data, dict) and data.get("error"): + if isinstance(data, list) and data == []: + raise RuntimeError( + str( + f"No holdings were found for {query.symbol}, and the response from Intrinio was empty." + ) + ) + raise RuntimeError(str(f"{data.get('message')} {query.symbol}: {data['error']}")) # type: ignore + + results: List[IntrinioEtfHoldingsData] = [] + for d in sorted(data, key=lambda x: x["weighting"], reverse=True): + # This field is deprecated and is dupilcated in the response. + _ = d.pop("composite_figi", None) + results.append(IntrinioEtfHoldingsData.model_validate(d)) + + return results diff --git a/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_etf_holdings_fetcher.yaml b/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_etf_holdings_fetcher.yaml new file mode 100644 index 00000000000..ef8c27abd22 --- /dev/null +++ b/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_etf_holdings_fetcher.yaml @@ -0,0 +1,70 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + method: GET + uri: https://api-v2.intrinio.com/etfs/DJIA:US/holdings?api_key=MOCK_API_KEY&page_size=10000 + response: + body: + string: !!binary | + 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 + Dp6WX6//AwAA//8DAMc4QPyTNwAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Thu, 14 Mar 2024 00:48:14 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 8c0ac8340e2..a6edc047eed 100644 --- a/openbb_platform/providers/intrinio/tests/test_intrinio_fetchers.py +++ b/openbb_platform/providers/intrinio/tests/test_intrinio_fetchers.py @@ -13,6 +13,7 @@ from openbb_intrinio.models.equity_historical import IntrinioEquityHistoricalFet 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.etf_holdings import IntrinioEtfHoldingsFetcher from openbb_intrinio.models.etf_info import IntrinioEtfInfoFetcher from openbb_intrinio.models.etf_price_performance import ( IntrinioEtfPricePerformanceFetcher, @@ -388,6 +389,15 @@ def test_intrinio_etf_info_fetcher(credentials=test_credentials): @pytest.mark.record_http +def test_intrinio_etf_holdings_fetcher(credentials=test_credentials): + params = {"symbol": "DJIA"} + + fetcher = IntrinioEtfHoldingsFetcher() + result = fetcher.test(params, credentials) + assert result is None + + +@pytest.mark.record_http def test_intrinio_etf_price_performance_fetcher(credentials=test_credentials): params = {"symbol": "SPY:US"} |