[Feature] Add Intrinio ETF Info/Search (#6198)

* add intrinio etf info

* black

* should have been "x-unit_measurement"

* field order thing

* another field order

* review things
This commit is contained in:
Danglewood
2024-03-13 10:06:11 -07:00
committed by GitHub
parent a7a7c647b0
commit d984637844
10 changed files with 1928 additions and 22 deletions

View File

@@ -32,6 +32,13 @@ def headers():
"use_cache": False,
}
),
(
{
"query": "vanguard",
"provider": "intrinio",
"exchange": "arcx",
}
),
],
)
@pytest.mark.integration
@@ -235,6 +242,7 @@ def test_etf_historical(params, headers):
({"symbol": "IOO", "provider": "fmp"}),
({"symbol": "XIU", "provider": "tmx", "use_cache": False}),
({"symbol": "QQQ", "provider": "yfinance"}),
({"symbol": "IOO,QQQ", "provider": "intrinio"}),
],
)
@pytest.mark.integration

View File

@@ -31,6 +31,13 @@ def obb(pytestconfig): # pylint: disable=inconsistent-return-statements
"use_cache": False,
}
),
(
{
"query": "vanguard",
"provider": "intrinio",
"exchange": "arcx",
}
),
],
)
@pytest.mark.integration
@@ -230,6 +237,7 @@ def test_etf_historical(params, obb):
({"symbol": "IOO", "provider": "fmp"}),
({"symbol": "XIU", "provider": "tmx", "use_cache": False}),
({"symbol": "QQQ", "provider": "yfinance"}),
({"symbol": "IOO,QQQ", "provider": "intrinio"}),
],
)
@pytest.mark.integration

View File

@@ -778,11 +778,11 @@ class ROUTER_etf(Container):
symbol: Annotated[
Union[str, List[str]],
OpenBBCustomParameter(
description="Symbol to get data for. (ETF) Multiple items allowed for provider(s): fmp, yfinance."
description="Symbol to get data for. (ETF) Multiple items allowed for provider(s): fmp, intrinio, yfinance."
),
],
provider: Annotated[
Optional[Literal["fmp", "yfinance"]],
Optional[Literal["fmp", "intrinio", "yfinance"]],
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."
),
@@ -794,8 +794,8 @@ class ROUTER_etf(Container):
Parameters
----------
symbol : Union[str, List[str]]
Symbol to get data for. (ETF) Multiple items allowed for provider(s): fmp, yfinance.
provider : Optional[Literal['fmp', 'yfinance']]
Symbol to get data for. (ETF) Multiple items allowed for provider(s): fmp, intrinio, yfinance.
provider : Optional[Literal['fmp', 'intrinio', 'yfinance']]
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.
@@ -805,7 +805,7 @@ class ROUTER_etf(Container):
OBBject
results : List[EtfInfo]
Serializable results.
provider : Optional[Literal['fmp', 'yfinance']]
provider : Optional[Literal['fmp', 'intrinio', 'yfinance']]
Provider name.
warnings : Optional[List[Warning_]]
List of warnings.
@@ -825,15 +825,19 @@ class ROUTER_etf(Container):
inception_date : Optional[str]
Inception date of the ETF.
issuer : Optional[str]
Company of the ETF. (provider: fmp)
Company of the ETF. (provider: fmp);
Issuer of the ETF. (provider: intrinio)
cusip : Optional[str]
CUSIP of the ETF. (provider: fmp)
isin : Optional[str]
ISIN of the ETF. (provider: fmp)
ISIN of the ETF. (provider: fmp);
International Securities Identification Number (ISIN). (provider: intrinio)
domicile : Optional[str]
Domicile of the ETF. (provider: fmp)
Domicile of the ETF. (provider: fmp);
2 letter ISO country code for the country where the ETP is domiciled. (provider: intrinio)
asset_class : Optional[str]
Asset class of the ETF. (provider: fmp)
Asset class of the ETF. (provider: fmp);
Captures the underlying nature of the securities in the Exchanged Traded Product (ETP). (provider: intrinio)
aum : Optional[float]
Assets under management. (provider: fmp)
nav : Optional[float]
@@ -848,14 +852,232 @@ class ROUTER_etf(Container):
Average daily trading volume. (provider: fmp)
website : Optional[str]
Website of the issuer. (provider: fmp)
fund_listing_date : Optional[date]
The date on which the Exchange Traded Product (ETP) or share class of the ETP is listed on a specific exchange. (provider: intrinio)
data_change_date : Optional[date]
The last date on which there was a change in a classifications data field for this ETF. (provider: intrinio)
etn_maturity_date : Optional[date]
If the product is an ETN, this field identifies the maturity date for the ETN. (provider: intrinio)
is_listed : Optional[bool]
If true, the ETF is still listed on an exchange. (provider: intrinio)
close_date : Optional[date]
The date on which the ETF was de-listed if it is no longer listed. (provider: intrinio)
exchange : Optional[str]
The exchange Market Identifier Code (MIC). (provider: intrinio);
The exchange the fund is listed on. (provider: yfinance)
ric : Optional[str]
Reuters Instrument Code (RIC). (provider: intrinio)
sedol : Optional[str]
Stock Exchange Daily Official List (SEDOL). (provider: intrinio)
figi_symbol : Optional[str]
Financial Instrument Global Identifier (FIGI) symbol. (provider: intrinio)
share_class_figi : Optional[str]
Financial Instrument Global Identifier (FIGI). (provider: intrinio)
firstbridge_id : Optional[str]
The FirstBridge unique identifier for the Exchange Traded Fund (ETF). (provider: intrinio)
firstbridge_parent_id : Optional[str]
The FirstBridge unique identifier for the parent Exchange Traded Fund (ETF), if applicable. (provider: intrinio)
intrinio_id : Optional[str]
Intrinio unique identifier for the security. (provider: intrinio)
intraday_nav_symbol : Optional[str]
Intraday Net Asset Value (NAV) symbol. (provider: intrinio)
primary_symbol : Optional[str]
The primary ticker field is used for Exchange Traded Products (ETPs) that have multiple listings and share classes. If an ETP has multiple listings or share classes, the same primary ticker is assigned to all the listings and share classes. (provider: intrinio)
etp_structure_type : Optional[str]
Classifies Exchange Traded Products (ETPs) into very broad categories based on its legal structure. (provider: intrinio)
legal_structure : Optional[str]
Legal structure of the fund. (provider: intrinio)
etn_issuing_bank : Optional[str]
If the product is an Exchange Traded Note (ETN), this field identifies the issuing bank. (provider: intrinio)
fund_family : Optional[str]
This field identifies the fund family to which the ETF belongs, as categorized by the ETF Sponsor. (provider: intrinio);
The fund family. (provider: yfinance)
investment_style : Optional[str]
Investment style of the ETF. (provider: intrinio)
derivatives_based : Optional[str]
This field is populated if the ETF holds either listed or over-the-counter derivatives in its portfolio. (provider: intrinio)
other_asset_types : Optional[str]
If 'asset_class' field is classified as 'Other Asset Types' this field captures the specific category of the underlying assets. (provider: intrinio)
single_category_designation : Optional[str]
This categorization is created for those users who want every ETF to be 'forced' into a single bucket, so that the assets for all categories will always sum to the total market. (provider: intrinio)
beta_type : Optional[str]
This field identifies whether an ETF provides 'Traditional' beta exposure or 'Smart' beta exposure. ETFs that are active (i.e. non-indexed), leveraged / inverse or have a proprietary quant model (i.e. that don't provide indexed exposure to a targeted factor) are classified separately. (provider: intrinio)
beta_details : Optional[str]
This field provides further detail within the traditional and smart beta categories. (provider: intrinio)
market_cap_range : Optional[str]
Equity ETFs are classified as falling into categories based on the description of their investment strategy in the prospectus. Examples ('Mega Cap', 'Large Cap', 'Mid Cap', etc.) (provider: intrinio)
market_cap_weighting_type : Optional[str]
For ETFs that take the value 'Market Cap Weighted' in the 'index_weighting_scheme' field, this field provides detail on the market cap weighting type. (provider: intrinio)
index_weighting_scheme : Optional[str]
For ETFs that track an underlying index, this field provides detail on the index weighting type. (provider: intrinio)
index_linked : Optional[str]
This field identifies whether an ETF is index linked or active. (provider: intrinio)
index_name : Optional[str]
This field identifies the name of the underlying index tracked by the ETF, if applicable. (provider: intrinio)
index_symbol : Optional[str]
This field identifies the OpenFIGI ticker for the Index underlying the ETF. (provider: intrinio)
parent_index : Optional[str]
This field identifies the name of the parent index, which represents the broader universe from which the index underlying the ETF is created, if applicable. (provider: intrinio)
index_family : Optional[str]
This field identifies the index family to which the index underlying the ETF belongs. The index family is represented as categorized by the index provider. (provider: intrinio)
broader_index_family : Optional[str]
This field identifies the broader index family to which the index underlying the ETF belongs. The broader index family is represented as categorized by the index provider. (provider: intrinio)
index_provider : Optional[str]
This field identifies the Index provider for the index underlying the ETF, if applicable. (provider: intrinio)
index_provider_code : Optional[str]
This field provides the First Bridge code for each Index provider, corresponding to the index underlying the ETF if applicable. (provider: intrinio)
replication_structure : Optional[str]
The replication structure of the Exchange Traded Product (ETP). (provider: intrinio)
growth_value_tilt : Optional[str]
Classifies equity ETFs as either 'Growth' or Value' based on the stated style tilt in the ETF prospectus. Equity ETFs that do not have a stated style tilt are classified as 'Core / Blend'. (provider: intrinio)
growth_type : Optional[str]
For ETFs that are classified as 'Growth' in 'growth_value_tilt', this field further identifies those where the stocks in the ETF are both selected and weighted based on their growth (style factor) scores. (provider: intrinio)
value_type : Optional[str]
For ETFs that are classified as 'Value' in 'growth_value_tilt', this field further identifies those where the stocks in the ETF are both selected and weighted based on their value (style factor) scores. (provider: intrinio)
sector : Optional[str]
For equity ETFs that aim to provide targeted exposure to a sector or industry, this field identifies the Sector that it provides the exposure to. (provider: intrinio)
industry : Optional[str]
For equity ETFs that aim to provide targeted exposure to an industry, this field identifies the Industry that it provides the exposure to. (provider: intrinio)
industry_group : Optional[str]
For equity ETFs that aim to provide targeted exposure to a sub-industry, this field identifies the sub-Industry that it provides the exposure to. (provider: intrinio)
cross_sector_theme : Optional[str]
For equity ETFs that aim to provide targeted exposure to a specific investment theme that cuts across GICS sectors, this field identifies the specific cross-sector theme. Examples ('Agri-business', 'Natural Resources', 'Green Investing', etc.) (provider: intrinio)
natural_resources_type : Optional[str]
For ETFs that are classified as 'Natural Resources' in the 'cross_sector_theme' field, this field provides further detail on the type of Natural Resources exposure. (provider: intrinio)
us_or_excludes_us : Optional[str]
Takes the value of 'Domestic' for US exposure, 'International' for non-US exposure and 'Global' for exposure that includes all regions including the US. (provider: intrinio)
developed_emerging : Optional[str]
This field identifies the stage of development of the markets that the ETF provides exposure to. (provider: intrinio)
specialized_region : Optional[str]
This field is populated if the ETF provides targeted exposure to a specific type of geography-based grouping that does not fall into a specific country or continent grouping. Examples ('BRIC', 'Chindia', etc.) (provider: intrinio)
continent : Optional[str]
This field is populated if the ETF provides targeted exposure to a specific continent or country within that Continent. (provider: intrinio)
latin_america_sub_group : Optional[str]
For ETFs that are classified as 'Latin America' in the 'continent' field, this field provides further detail on the type of regional exposure. (provider: intrinio)
europe_sub_group : Optional[str]
For ETFs that are classified as 'Europe' in the 'continent' field, this field provides further detail on the type of regional exposure. (provider: intrinio)
asia_sub_group : Optional[str]
For ETFs that are classified as 'Asia' in the 'continent' field, this field provides further detail on the type of regional exposure. (provider: intrinio)
specific_country : Optional[str]
This field is populated if the ETF provides targeted exposure to a specific country. (provider: intrinio)
china_listing_location : Optional[str]
For ETFs that are classified as 'China' in the 'country' field, this field provides further detail on the type of exposure in the underlying securities. (provider: intrinio)
us_state : Optional[str]
Takes the value of a US state if the ETF provides targeted exposure to the municipal bonds or equities of companies. (provider: intrinio)
real_estate : Optional[str]
For ETFs that provide targeted real estate exposure, this field is populated if the ETF provides targeted exposure to a specific segment of the real estate market. (provider: intrinio)
fundamental_weighting_type : Optional[str]
For ETFs that take the value 'Fundamental Weighted' in the 'index_weighting_scheme' field, this field provides detail on the fundamental weighting methodology. (provider: intrinio)
dividend_weighting_type : Optional[str]
For ETFs that take the value 'Dividend Weighted' in the 'index_weighting_scheme' field, this field provides detail on the dividend weighting methodology. (provider: intrinio)
bond_type : Optional[str]
For ETFs where 'asset_class_type' is 'Bonds', this field provides detail on the type of bonds held in the ETF. (provider: intrinio)
government_bond_types : Optional[str]
For bond ETFs that take the value 'Treasury & Government' in 'bond_type', this field provides detail on the exposure. (provider: intrinio)
municipal_bond_region : Optional[str]
For bond ETFs that take the value 'Municipal' in 'bond_type', this field provides additional detail on the geographic exposure. (provider: intrinio)
municipal_vrdo : Optional[bool]
For bond ETFs that take the value 'Municipal' in 'bond_type', this field identifies those ETFs that specifically provide exposure to Variable Rate Demand Obligations. (provider: intrinio)
mortgage_bond_types : Optional[str]
For bond ETFs that take the value 'Mortgage' in 'bond_type', this field provides additional detail on the type of underlying securities. (provider: intrinio)
bond_tax_status : Optional[str]
For all US bond ETFs, this field provides additional detail on the tax treatment of the underlying securities. (provider: intrinio)
credit_quality : Optional[str]
For all bond ETFs, this field helps to identify if the ETF provides targeted exposure to securities of a specific credit quality range. (provider: intrinio)
average_maturity : Optional[str]
For all bond ETFs, this field helps to identify if the ETF provides targeted exposure to securities of a specific maturity range. (provider: intrinio)
specific_maturity_year : Optional[int]
For all bond ETFs that take the value 'Specific Maturity Year' in the 'average_maturity' field, this field specifies the calendar year. (provider: intrinio)
commodity_types : Optional[str]
For ETFs where 'asset_class_type' is 'Commodities', this field provides detail on the type of commodities held in the ETF. (provider: intrinio)
energy_type : Optional[str]
For ETFs where 'commodity_type' is 'Energy', this field provides detail on the type of energy exposure provided by the ETF. (provider: intrinio)
agricultural_type : Optional[str]
For ETFs where 'commodity_type' is 'Agricultural', this field provides detail on the type of agricultural exposure provided by the ETF. (provider: intrinio)
metal_type : Optional[str]
For ETFs where 'commodity_type' is 'Gold & Metals', this field provides detail on the type of exposure provided by the ETF. (provider: intrinio)
inverse_leveraged : Optional[str]
This field is populated if the ETF provides inverse or leveraged exposure. (provider: intrinio)
target_date_multi_asset_type : Optional[str]
For ETFs where 'asset_class_type' is 'Target Date / MultiAsset', this field provides detail on the type of commodities held in the ETF. (provider: intrinio)
currency_pair : Optional[str]
This field is populated if the ETF's strategy involves providing exposure to the movements of a currency or involves hedging currency exposure. (provider: intrinio)
social_environmental_type : Optional[str]
This field is populated if the ETF's strategy involves providing exposure to a specific social or environmental theme. (provider: intrinio)
clean_energy_type : Optional[str]
This field is populated if the ETF has a value of 'Clean Energy' in the 'social_environmental_type' field. (provider: intrinio)
dividend_type : Optional[str]
This field is populated if the ETF has an intended investment objective of holding dividend-oriented stocks as stated in the prospectus. (provider: intrinio)
regular_dividend_payor_type : Optional[str]
This field is populated if the ETF has a value of'Dividend - Regular Payors' in the 'dividend_type' field. (provider: intrinio)
excludes_financials : Optional[bool]
For equity ETFs, identifies those ETFs where the underlying fund holdings will not hold financials stocks, based on the funds intended objective. (provider: intrinio)
excludes_technology : Optional[bool]
For equity ETFs, identifies those ETFs where the underlying fund holdings will not hold technology stocks, based on the funds intended objective. (provider: intrinio)
holds_only_nyse_stocks : Optional[bool]
If true, the ETF is an equity ETF and holds only stocks listed on NYSE. (provider: intrinio)
holds_only_nasdaq_stocks : Optional[bool]
If true, the ETF is an equity ETF and holds only stocks listed on Nasdaq. (provider: intrinio)
holds_mlp : Optional[bool]
If true, the ETF's investment objective explicitly specifies that it holds MLPs as an intended part of its investment strategy. (provider: intrinio)
holds_preferred_stock : Optional[bool]
If true, the ETF's investment objective explicitly specifies that it holds preferred stock as an intended part of its investment strategy. (provider: intrinio)
holds_closed_end_funds : Optional[bool]
If true, the ETF's investment objective explicitly specifies that it holds closed end funds as an intended part of its investment strategy. (provider: intrinio)
holds_adr : Optional[bool]
If true, he ETF's investment objective explicitly specifies that it holds American Depositary Receipts (ADRs) as an intended part of its investment strategy. (provider: intrinio)
laddered : Optional[bool]
For bond ETFs, this field identifies those ETFs that specifically hold bonds in a laddered structure, where the bonds are scheduled to mature in an annual, sequential structure. (provider: intrinio)
zero_coupon : Optional[bool]
For bond ETFs, this field identifies those ETFs that specifically hold zero coupon Treasury Bills. (provider: intrinio)
floating_rate : Optional[bool]
For bond ETFs, this field identifies those ETFs that specifically hold floating rate bonds. (provider: intrinio)
build_america_bonds : Optional[bool]
For municipal bond ETFs, this field identifies those ETFs that specifically hold Build America Bonds. (provider: intrinio)
dynamic_futures_roll : Optional[bool]
If the product holds futures contracts, this field identifies those products where the roll strategy is dynamic (rather than entirely rules based), so as to minimize roll costs. (provider: intrinio)
currency_hedged : Optional[bool]
This field is populated if the ETF's strategy involves hedging currency exposure. (provider: intrinio)
includes_short_exposure : Optional[bool]
This field is populated if the ETF has short exposure in any of its holdings e.g. in a long/short or inverse ETF. (provider: intrinio)
ucits : Optional[bool]
If true, the Exchange Traded Product (ETP) is Undertakings for the Collective Investment in Transferable Securities (UCITS) compliant (provider: intrinio)
quant_strategies_type : Optional[str]
This field is populated if the ETF has either an index-linked or active strategy that is based on a proprietary quantitative strategy. (provider: intrinio)
other_quant_models : Optional[str]
For ETFs where 'quant_strategies_type' is 'Other Quant Model', this field provides the name of the specific proprietary quant model used as the underlying strategy for the ETF. (provider: intrinio)
hedge_fund_type : Optional[str]
For ETFs where 'other_asset_types' is 'Hedge Fund Replication', this field provides detail on the type of hedge fund replication strategy. (provider: intrinio)
livestock : Optional[str]
For ETFs where 'commodity_type' is 'Livestock', this field provides detail on the type of livestock exposure provided by the ETF. (provider: intrinio)
registered_countries : Optional[str]
The list of countries where the ETF is legally registered for sale. This may differ from where the ETF is domiciled or traded, particularly in Europe. (provider: intrinio)
issuer_country : Optional[str]
2 letter ISO country code for the country where the issuer is located. (provider: intrinio)
listing_country : Optional[str]
2 letter ISO country code for the country of the primary listing. (provider: intrinio)
listing_region : Optional[str]
Geographic region in the country of the primary listing falls. (provider: intrinio)
bond_currency_denomination : Optional[str]
For all bond ETFs, this field provides additional detail on the currency denomination of the underlying securities. (provider: intrinio)
base_currency : Optional[str]
Base currency in which NAV is reported. (provider: intrinio)
listing_currency : Optional[str]
Listing currency of the Exchange Traded Product (ETP) in which it is traded. Reported using the 3-digit ISO currency code. (provider: intrinio)
income_category : Optional[str]
Identifies if an Exchange Traded Fund (ETF) falls into a category that is specifically designed to provide a high yield or income (provider: intrinio)
number_of_holdings : Optional[int]
The number of holdings in the ETF. (provider: intrinio)
month_end_assets : Optional[float]
Net assets in millions of dollars as of the most recent month end. (provider: intrinio)
net_expense_ratio : Optional[float]
Gross expense net of Fee Waivers, as a percentage of net assets as published by the ETF issuer. (provider: intrinio)
etf_portfolio_turnover : Optional[float]
The percentage of positions turned over in the last 12 months. (provider: intrinio)
fund_type : Optional[str]
The legal type of fund. (provider: yfinance)
fund_family : Optional[str]
The fund family. (provider: yfinance)
category : Optional[str]
The fund category. (provider: yfinance)
exchange : Optional[str]
The exchange the fund is listed on. (provider: yfinance)
exchange_timezone : Optional[str]
The timezone of the exchange. (provider: yfinance)
currency : Optional[str]
@@ -926,14 +1148,18 @@ class ROUTER_etf(Container):
"provider": self._get_provider(
provider,
"/etf/info",
("fmp", "yfinance"),
("fmp", "intrinio", "yfinance"),
)
},
standard_params={
"symbol": symbol,
},
extra_params=kwargs,
extra_info={"symbol": {"multiple_items_allowed": ["fmp", "yfinance"]}},
extra_info={
"symbol": {
"multiple_items_allowed": ["fmp", "intrinio", "yfinance"]
}
},
)
)
@@ -1046,7 +1272,7 @@ class ROUTER_etf(Container):
Optional[str], OpenBBCustomParameter(description="Search query.")
] = "",
provider: Annotated[
Optional[Literal["fmp"]],
Optional[Literal["fmp", "intrinio"]],
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."
),
@@ -1062,12 +1288,13 @@ class ROUTER_etf(Container):
----------
query : Optional[str]
Search query.
provider : Optional[Literal['fmp']]
provider : Optional[Literal['fmp', 'intrinio']]
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.
exchange : Optional[Literal['AMEX', 'NYSE', 'NASDAQ', 'ETF', 'TSX', 'EURONEXT']]
The exchange code the ETF trades on. (provider: fmp)
exchange : Optional[Union[Literal['AMEX', 'NYSE', 'NASDAQ', 'ETF', 'TSX', 'EURONEXT'], Literal['xnas', 'arcx', 'bats', 'xnys', 'bvmf', 'xshg', 'xshe', 'xhkg', 'xbom', 'xnse', 'xidx', 'tase', 'xkrx', 'xkls', 'xmex', 'xses', 'roco', 'xtai', 'xbkk', 'xist']]]
The exchange code the ETF trades on. (provider: fmp);
Target a specific exchange by providing the MIC code. (provider: intrinio)
is_active : Optional[Literal[True, False]]
Whether the ETF is actively trading. (provider: fmp)
@@ -1076,7 +1303,7 @@ class ROUTER_etf(Container):
OBBject
results : List[EtfSearch]
Serializable results.
provider : Optional[Literal['fmp']]
provider : Optional[Literal['fmp', 'intrinio']]
Provider name.
warnings : Optional[List[Warning_]]
List of warnings.
@@ -1106,13 +1333,24 @@ class ROUTER_etf(Container):
volume : Optional[float]
The current trading volume of the ETF. (provider: fmp)
exchange : Optional[str]
The exchange code the ETF trades on. (provider: fmp)
The exchange code the ETF trades on. (provider: fmp);
The exchange MIC code. (provider: intrinio)
exchange_name : Optional[str]
The full name of the exchange the ETF trades on. (provider: fmp)
country : Optional[str]
The country the ETF is registered in. (provider: fmp)
actively_trading : Optional[Literal[True, False]]
Whether the ETF is actively trading. (provider: fmp)
figi_ticker : Optional[str]
The OpenFIGI ticker. (provider: intrinio)
ric : Optional[str]
The Reuters Instrument Code. (provider: intrinio)
isin : Optional[str]
The International Securities Identification Number. (provider: intrinio)
sedol : Optional[str]
The Stock Exchange Daily Official List. (provider: intrinio)
intrinio_id : Optional[str]
The unique Intrinio ID for the security. (provider: intrinio)
Examples
--------
@@ -1130,7 +1368,7 @@ class ROUTER_etf(Container):
"provider": self._get_provider(
provider,
"/etf/search",
("fmp",),
("fmp", "intrinio"),
)
},
standard_params={

View File

@@ -11,6 +11,8 @@ 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_info import IntrinioEtfInfoFetcher
from openbb_intrinio.models.etf_search import IntrinioEtfSearchFetcher
from openbb_intrinio.models.financial_ratios import IntrinioFinancialRatiosFetcher
from openbb_intrinio.models.fred_series import IntrinioFredSeriesFetcher
from openbb_intrinio.models.historical_attributes import (
@@ -55,6 +57,8 @@ intrinio_provider = Provider(
"EquityQuote": IntrinioEquityQuoteFetcher,
"EquitySearch": IntrinioEquitySearchFetcher,
"EtfHistorical": IntrinioEquityHistoricalFetcher,
"EtfInfo": IntrinioEtfInfoFetcher,
"EtfSearch": IntrinioEtfSearchFetcher,
"FinancialRatios": IntrinioFinancialRatiosFetcher,
"FredSeries": IntrinioFredSeriesFetcher,
"HistoricalAttributes": IntrinioHistoricalAttributesFetcher,

View File

@@ -0,0 +1,655 @@
"""Intrinio ETF Info Model."""
# pylint: disable=unused-argument
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.etf_info import (
EtfInfoData,
EtfInfoQueryParams,
)
from openbb_core.provider.utils.errors import EmptyDataError
from openbb_core.provider.utils.helpers import amake_requests
from pydantic import Field
class IntrinioEtfInfoQueryParams(EtfInfoQueryParams):
"""
Intrinio ETF Info Query Params.
Source: https://docs.intrinio.com/documentation/web_api/get_etf_v2
"""
__json_schema_extra__ = {"symbol": ["multiple_items_allowed"]}
class IntrinioEtfInfoData(EtfInfoData):
"""Intrinio ETF Info Data."""
__alias_dict__ = {
"symbol": "ticker",
"exchange": "exchange_mic",
"issuer": "sponsor",
"investment_style": "type",
"industry_group": "sub_industry",
"holds_mlp": "holds_ml_ps",
"holds_adr": "holds_ad_rs",
"index_symbol": "index_ticker",
"figi_symbol": "figi_ticker",
"intrinio_id": "id",
"is_listed": "is_live_listed",
"beta_type": "smartvs_traditional_beta",
"beta_details": "smartvs_traditional_beta_level2",
"listing_country": "primary_ticker_country_code",
"listing_region": "primary_listing_region",
"primary_symbol": "primary_ticker",
"intraday_nav_symbol": "intraday_nav_ticker",
"issuer_country": "issuing_entity_country_code",
"livestock_type": "livestock",
}
fund_listing_date: Optional[dateType] = Field(
default=None,
description="The date on which the Exchange Traded Product (ETP)"
+ " or share class of the ETP is listed on a specific exchange.",
)
data_change_date: Optional[dateType] = Field(
default=None,
description="The last date on which there was a change in a classifications data field for this ETF.",
)
etn_maturity_date: Optional[dateType] = Field(
default=None,
description="If the product is an ETN, this field identifies the maturity date for the ETN.",
)
is_listed: Optional[bool] = Field(
default=None,
description="If true, the ETF is still listed on an exchange.",
)
close_date: Optional[dateType] = Field(
default=None,
description="The date on which the ETF was de-listed if it is no longer listed.",
)
exchange: Optional[str] = Field(
default=None,
description="The exchange Market Identifier Code (MIC).",
)
isin: Optional[str] = Field(
default=None,
description="International Securities Identification Number (ISIN).",
)
ric: Optional[str] = Field(
default=None,
description="Reuters Instrument Code (RIC).",
)
sedol: Optional[str] = Field(
default=None,
description="Stock Exchange Daily Official List (SEDOL).",
)
figi_symbol: Optional[str] = Field(
default=None,
description="Financial Instrument Global Identifier (FIGI) symbol.",
)
share_class_figi: Optional[str] = Field(
default=None,
description="Financial Instrument Global Identifier (FIGI).",
)
firstbridge_id: Optional[str] = Field(
default=None,
description="The FirstBridge unique identifier for the Exchange Traded Fund (ETF).",
)
firstbridge_parent_id: Optional[str] = Field(
default=None,
description="The FirstBridge unique identifier for the parent Exchange Traded Fund (ETF), if applicable.",
)
intrinio_id: Optional[str] = Field(
default=None,
description="Intrinio unique identifier for the security.",
)
intraday_nav_symbol: Optional[str] = Field(
default=None,
description="Intraday Net Asset Value (NAV) symbol.",
)
primary_symbol: Optional[str] = Field(
default=None,
description="The primary ticker field is used for Exchange Traded Products (ETPs)"
+ " that have multiple listings and share classes."
+ " If an ETP has multiple listings or share classes,"
+ " the same primary ticker is assigned to all the listings and share classes.",
)
etp_structure_type: Optional[str] = Field(
default=None,
description="Classifies Exchange Traded Products (ETPs) into very broad categories based on its legal structure.",
)
legal_structure: Optional[str] = Field(
default=None,
description="Legal structure of the fund.",
)
issuer: Optional[str] = Field(
default=None,
description="Issuer of the ETF.",
)
etn_issuing_bank: Optional[str] = Field(
default=None,
description="If the product is an Exchange Traded Note (ETN), this field identifies the issuing bank.",
)
fund_family: Optional[str] = Field(
default=None,
description="This field identifies the fund family to which the ETF belongs, as categorized by the ETF Sponsor.",
)
investment_style: Optional[str] = Field(
default=None,
description="Investment style of the ETF.",
)
derivatives_based: Optional[str] = Field(
default=None,
description="This field is populated if the ETF holds either"
+ " listed or over-the-counter derivatives in its portfolio.",
)
income_category: Optional[str] = Field(
default=None,
description="Identifies if an Exchange Traded Fund (ETF) falls into a category"
+ " that is specifically designed to provide a high yield or income",
)
asset_class: Optional[str] = Field(
default=None,
description="Captures the underlying nature of the securities in the Exchanged Traded Product (ETP).",
)
other_asset_types: Optional[str] = Field(
default=None,
description="If 'asset_class' field is classified as 'Other Asset Types'"
+ " this field captures the specific category of the underlying assets.",
)
single_category_designation: Optional[str] = Field(
default=None,
description="This categorization is created for those users who want every ETF to be 'forced'"
+ " into a single bucket, so that the assets for all categories will always sum to the total market.",
)
beta_type: Optional[str] = Field(
default=None,
description="This field identifies whether an ETF provides 'Traditional' beta exposure or 'Smart' beta exposure."
+ " ETFs that are active (i.e. non-indexed), leveraged / inverse or have a proprietary quant model"
+ " (i.e. that don't provide indexed exposure to a targeted factor) are classified separately.",
)
beta_details: Optional[str] = Field(
default=None,
description="This field provides further detail within the traditional and smart beta categories.",
)
market_cap_range: Optional[str] = Field(
default=None,
description="Equity ETFs are classified as falling into categories"
+ " based on the description of their investment strategy in the prospectus."
+ " Examples ('Mega Cap', 'Large Cap', 'Mid Cap', etc.)",
)
market_cap_weighting_type: Optional[str] = Field(
default=None,
description="For ETFs that take the value 'Market Cap Weighted' in the 'index_weighting_scheme' field,"
+ " this field provides detail on the market cap weighting type.",
)
index_weighting_scheme: Optional[str] = Field(
default=None,
description="For ETFs that track an underlying index,"
+ " this field provides detail on the index weighting type.",
)
index_linked: Optional[str] = Field(
default=None,
description="This field identifies whether an ETF is index linked or active.",
)
index_name: Optional[str] = Field(
default=None,
description="This field identifies the name of the underlying index tracked by the ETF, if applicable.",
)
index_symbol: Optional[str] = Field(
default=None,
description="This field identifies the OpenFIGI ticker for the Index underlying the ETF.",
)
parent_index: Optional[str] = Field(
default=None,
description="This field identifies the name of the parent index, which represents"
+ " the broader universe from which the index underlying the ETF is created, if applicable.",
)
index_family: Optional[str] = Field(
default=None,
description="This field identifies the index family to which the index underlying the ETF belongs."
+ " The index family is represented as categorized by the index provider.",
)
broader_index_family: Optional[str] = Field(
default=None,
description="This field identifies the broader index family to which the index underlying the ETF belongs."
+ " The broader index family is represented as categorized by the index provider.",
)
index_provider: Optional[str] = Field(
default=None,
description="This field identifies the Index provider for the index underlying the ETF, if applicable.",
)
index_provider_code: Optional[str] = Field(
default=None,
description="This field provides the First Bridge code for each Index provider,"
+ " corresponding to the index underlying the ETF if applicable.",
)
replication_structure: Optional[str] = Field(
default=None,
description="The replication structure of the Exchange Traded Product (ETP).",
)
growth_value_tilt: Optional[str] = Field(
default=None,
description="Classifies equity ETFs as either 'Growth' or Value' based on the stated style tilt"
+ " in the ETF prospectus. Equity ETFs that do not have a stated style tilt are classified as 'Core / Blend'.",
)
growth_type: Optional[str] = Field(
default=None,
description="For ETFs that are classified as 'Growth' in 'growth_value_tilt',"
+ " this field further identifies those where the stocks in the"
+ " ETF are both selected and weighted based on their growth (style factor) scores.",
)
value_type: Optional[str] = Field(
default=None,
description="For ETFs that are classified as 'Value' in 'growth_value_tilt',"
+ " this field further identifies those where the stocks in the"
+ " ETF are both selected and weighted based on their value (style factor) scores.",
)
sector: Optional[str] = Field(
default=None,
description="For equity ETFs that aim to provide targeted exposure to a sector or industry,"
+ " this field identifies the Sector that it provides the exposure to.",
)
industry: Optional[str] = Field(
default=None,
description="For equity ETFs that aim to provide targeted exposure to an industry,"
+ " this field identifies the Industry that it provides the exposure to.",
)
industry_group: Optional[str] = Field(
default=None,
description="For equity ETFs that aim to provide targeted exposure to a sub-industry,"
+ " this field identifies the sub-Industry that it provides the exposure to.",
)
cross_sector_theme: Optional[str] = Field(
default=None,
description="For equity ETFs that aim to provide targeted exposure to a specific investment theme"
+ " that cuts across GICS sectors, this field identifies the specific cross-sector theme."
+ " Examples ('Agri-business', 'Natural Resources', 'Green Investing', etc.)",
)
natural_resources_type: Optional[str] = Field(
default=None,
description="For ETFs that are classified as 'Natural Resources' in the 'cross_sector_theme' field,"
+ " this field provides further detail on the type of Natural Resources exposure.",
)
us_or_excludes_us: Optional[str] = Field(
default=None,
description="Takes the value of 'Domestic' for US exposure,"
+ " 'International' for non-US exposure and 'Global' for exposure that includes all regions including the US.",
)
developed_emerging: Optional[str] = Field(
default=None,
description="This field identifies the stage of development of the markets that the ETF provides exposure to.",
)
specialized_region: Optional[str] = Field(
default=None,
description="This field is populated if the ETF provides targeted"
+ " exposure to a specific type of geography-based grouping"
+ " that does not fall into a specific country or continent grouping."
+ " Examples ('BRIC', 'Chindia', etc.)",
)
continent: Optional[str] = Field(
default=None,
description="This field is populated if the ETF provides targeted exposure"
+ " to a specific continent or country within that Continent.",
)
latin_america_sub_group: Optional[str] = Field(
default=None,
description="For ETFs that are classified as 'Latin America' in the 'continent' field,"
+ " this field provides further detail on the type of regional exposure.",
)
europe_sub_group: Optional[str] = Field(
default=None,
description="For ETFs that are classified as 'Europe' in the 'continent' field,"
+ " this field provides further detail on the type of regional exposure.",
)
asia_sub_group: Optional[str] = Field(
default=None,
description="For ETFs that are classified as 'Asia' in the 'continent' field,"
+ " this field provides further detail on the type of regional exposure.",
)
specific_country: Optional[str] = Field(
default=None,
description="This field is populated if the ETF provides targeted exposure to a specific country.",
)
china_listing_location: Optional[str] = Field(
default=None,
description="For ETFs that are classified as 'China' in the 'country' field,"
+ " this field provides further detail on the type of exposure in the underlying securities.",
)
us_state: Optional[str] = Field(
default=None,
description="Takes the value of a US state if the ETF provides"
+ " targeted exposure to the municipal bonds or equities of companies.",
)
real_estate: Optional[str] = Field(
default=None,
description="For ETFs that provide targeted real estate exposure,"
+ " this field is populated if the ETF provides targeted"
+ " exposure to a specific segment of the real estate market.",
)
fundamental_weighting_type: Optional[str] = Field(
default=None,
description="For ETFs that take the value 'Fundamental Weighted' in the 'index_weighting_scheme' field,"
+ " this field provides detail on the fundamental weighting methodology.",
)
dividend_weighting_type: Optional[str] = Field(
default=None,
description="For ETFs that take the value 'Dividend Weighted' in the 'index_weighting_scheme' field,"
+ " this field provides detail on the dividend weighting methodology.",
)
bond_type: Optional[str] = Field(
default=None,
description="For ETFs where 'asset_class_type' is 'Bonds',"
+ " this field provides detail on the type of bonds held in the ETF.",
)
government_bond_types: Optional[str] = Field(
default=None,
description="For bond ETFs that take the value 'Treasury & Government' in 'bond_type',"
+ " this field provides detail on the exposure.",
)
municipal_bond_region: Optional[str] = Field(
default=None,
description="For bond ETFs that take the value 'Municipal' in 'bond_type',"
+ " this field provides additional detail on the geographic exposure.",
)
municipal_vrdo: Optional[bool] = Field(
default=None,
description="For bond ETFs that take the value 'Municipal' in 'bond_type',"
+ " this field identifies those ETFs that specifically provide exposure to Variable Rate Demand Obligations.",
)
mortgage_bond_types: Optional[str] = Field(
default=None,
description="For bond ETFs that take the value 'Mortgage' in 'bond_type',"
+ " this field provides additional detail on the type of underlying securities.",
)
bond_tax_status: Optional[str] = Field(
default=None,
description="For all US bond ETFs, this field provides additional"
+ " detail on the tax treatment of the underlying securities.",
)
credit_quality: Optional[str] = Field(
default=None,
description="For all bond ETFs, this field helps to identify if the ETF"
+ " provides targeted exposure to securities of a specific credit quality range.",
)
average_maturity: Optional[str] = Field(
default=None,
description="For all bond ETFs, this field helps to identify if the ETF"
+ " provides targeted exposure to securities of a specific maturity range.",
)
specific_maturity_year: Optional[int] = Field(
default=None,
description="For all bond ETFs that take the value 'Specific Maturity Year' in the 'average_maturity' field,"
+ " this field specifies the calendar year.",
)
commodity_types: Optional[str] = Field(
default=None,
description="For ETFs where 'asset_class_type' is 'Commodities',"
+ " this field provides detail on the type of commodities held in the ETF.",
)
energy_type: Optional[str] = Field(
default=None,
description="For ETFs where 'commodity_type' is 'Energy',"
+ " this field provides detail on the type of energy exposure provided by the ETF.",
)
agricultural_type: Optional[str] = Field(
default=None,
description="For ETFs where 'commodity_type' is 'Agricultural',"
+ " this field provides detail on the type of agricultural exposure provided by the ETF.",
)
livestock_type: Optional[str] = Field(
default=None,
description="For ETFs where 'commodity_type' is 'Livestock',"
+ " this field provides detail on the type of livestock exposure provided by the ETF.",
)
metal_type: Optional[str] = Field(
default=None,
description="For ETFs where 'commodity_type' is 'Gold & Metals',"
+ " this field provides detail on the type of exposure provided by the ETF.",
)
inverse_leveraged: Optional[str] = Field(
default=None,
description="This field is populated if the ETF provides inverse or leveraged exposure.",
)
target_date_multi_asset_type: Optional[str] = Field(
default=None,
description="For ETFs where 'asset_class_type' is 'Target Date / MultiAsset',"
+ " this field provides detail on the type of commodities held in the ETF.",
)
currency_pair: Optional[str] = Field(
default=None,
description="This field is populated if the ETF's strategy involves providing exposure to"
+ " the movements of a currency or involves hedging currency exposure.",
)
social_environmental_type: Optional[str] = Field(
default=None,
description="This field is populated if the ETF's strategy involves providing"
+ " exposure to a specific social or environmental theme.",
)
clean_energy_type: Optional[str] = Field(
default=None,
description="This field is populated if the ETF has a value of 'Clean Energy'"
+ " in the 'social_environmental_type' field.",
)
dividend_type: Optional[str] = Field(
default=None,
description="This field is populated if the ETF has an intended"
+ " investment objective of holding dividend-oriented stocks as stated in the prospectus.",
)
regular_dividend_payor_type: Optional[str] = Field(
default=None,
description="This field is populated if the ETF has a value of"
+ "'Dividend - Regular Payors' in the 'dividend_type' field.",
)
quant_strategies_type: Optional[str] = Field(
default=None,
description="This field is populated if the ETF has either an index-linked"
+ " or active strategy that is based on a proprietary quantitative strategy.",
)
other_quant_models: Optional[str] = Field(
default=None,
description="For ETFs where 'quant_strategies_type' is 'Other Quant Model',"
+ " this field provides the name of the specific proprietary quant model"
+ " used as the underlying strategy for the ETF.",
)
hedge_fund_type: Optional[str] = Field(
default=None,
description="For ETFs where 'other_asset_types' is 'Hedge Fund Replication',"
+ " this field provides detail on the type of hedge fund replication strategy.",
)
excludes_financials: Optional[bool] = Field(
default=None,
description="For equity ETFs, identifies those ETFs"
+ " where the underlying fund holdings will not hold financials stocks,"
+ " based on the funds intended objective.",
)
excludes_technology: Optional[bool] = Field(
default=None,
description="For equity ETFs, identifies those ETFs"
+ " where the underlying fund holdings will not hold technology stocks,"
+ " based on the funds intended objective.",
)
holds_only_nyse_stocks: Optional[bool] = Field(
default=None,
description="If true, the ETF is an equity ETF and holds only stocks listed on NYSE.",
)
holds_only_nasdaq_stocks: Optional[bool] = Field(
default=None,
description="If true, the ETF is an equity ETF and holds only stocks listed on Nasdaq.",
)
holds_mlp: Optional[bool] = Field(
default=None,
description="If true, the ETF's investment objective explicitly specifies"
+ " that it holds MLPs as an intended part of its investment strategy.",
)
holds_preferred_stock: Optional[bool] = Field(
default=None,
description="If true, the ETF's investment objective explicitly specifies"
+ " that it holds preferred stock as an intended part of its investment strategy.",
)
holds_closed_end_funds: Optional[bool] = Field(
default=None,
description="If true, the ETF's investment objective explicitly specifies"
+ " that it holds closed end funds as an intended part of its investment strategy.",
)
holds_adr: Optional[bool] = Field(
default=None,
description="If true, he ETF's investment objective explicitly specifies that it holds"
+ " American Depositary Receipts (ADRs) as an intended part of its investment strategy.",
)
laddered: Optional[bool] = Field(
default=None,
description="For bond ETFs, this field identifies those ETFs that"
+ " specifically hold bonds in a laddered structure,"
+ " where the bonds are scheduled to mature in an annual, sequential structure.",
)
zero_coupon: Optional[bool] = Field(
default=None,
description="For bond ETFs, this field identifies those ETFs that specifically hold zero coupon Treasury Bills.",
)
floating_rate: Optional[bool] = Field(
default=None,
description="For bond ETFs, this field identifies those ETFs that specifically hold floating rate bonds.",
)
build_america_bonds: Optional[bool] = Field(
default=None,
description="For municipal bond ETFs, this field identifies those"
+ " ETFs that specifically hold Build America Bonds.",
)
dynamic_futures_roll: Optional[bool] = Field(
default=None,
description="If the product holds futures contracts, this field identifies those products where the roll strategy"
+ " is dynamic (rather than entirely rules based), so as to minimize roll costs.",
)
currency_hedged: Optional[bool] = Field(
default=None,
description="This field is populated if the ETF's strategy involves hedging currency exposure.",
)
includes_short_exposure: Optional[bool] = Field(
default=None,
description="This field is populated if the ETF has short exposure"
+ " in any of its holdings e.g. in a long/short or inverse ETF.",
)
ucits: Optional[bool] = Field(
default=None,
description="If true, the Exchange Traded Product (ETP) is Undertakings for the Collective Investment"
+ " in Transferable Securities (UCITS) compliant",
)
registered_countries: Optional[str] = Field(
default=None,
description="The list of countries where the ETF is legally registered for sale."
+ " This may differ from where the ETF is domiciled or traded, particularly in Europe.",
)
issuer_country: Optional[str] = Field(
default=None,
description="2 letter ISO country code for the country where the issuer is located.",
)
domicile: Optional[str] = Field(
default=None,
description="2 letter ISO country code for the country where the ETP is domiciled.",
)
listing_country: Optional[str] = Field(
default=None,
description="2 letter ISO country code for the country of the primary listing.",
alias="listing_country_code",
)
listing_region: Optional[str] = Field(
default=None,
description="Geographic region in the country of the primary listing falls.",
)
bond_currency_denomination: Optional[str] = Field(
default=None,
description="For all bond ETFs, this field provides additional"
+ " detail on the currency denomination of the underlying securities.",
)
base_currency: Optional[str] = Field(
default=None,
description="Base currency in which NAV is reported.",
)
listing_currency: Optional[str] = Field(
default=None,
description="Listing currency of the Exchange Traded Product (ETP) in which it is traded."
+ " Reported using the 3-digit ISO currency code.",
)
number_of_holdings: Optional[int] = Field(
default=None,
description="The number of holdings in the ETF.",
)
month_end_assets: Optional[float] = Field(
default=None,
description="Net assets in millions of dollars as of the most recent month end.",
)
net_expense_ratio: Optional[float] = Field(
default=None,
description="Gross expense net of Fee Waivers, as a percentage of net assets"
+ " as published by the ETF issuer.",
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
)
etf_portfolio_turnover: Optional[float] = Field(
default=None,
description="The percentage of positions turned over in the last 12 months.",
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
)
class IntrinioEtfInfoFetcher(
Fetcher[IntrinioEtfInfoQueryParams, List[IntrinioEtfInfoData]]
):
"""Intrinio ETF Info Fetcher."""
@staticmethod
def transform_query(params: Dict[str, Any]) -> IntrinioEtfInfoQueryParams:
"""Transform query."""
return IntrinioEtfInfoQueryParams(**params)
@staticmethod
async def aextract_data(
query: IntrinioEtfInfoQueryParams,
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 ""
base_url = "https://api-v2.intrinio.com/etfs/"
symbols = query.symbol.split(",")
symbols = [
symbol + ":US" if ":" not in symbol else symbol for symbol in symbols
]
urls = [f"{base_url}{symbol}?api_key={api_key}" for symbol in symbols]
results = []
async def response_callback(response, _):
"""Response callback."""
result = await response.json()
if "error" in result:
warn(f"Symbol Error: {result['error']} for {response.url.parts[-1]}")
return
_ = result.pop("messages", None)
results.append(result)
await amake_requests(urls, response_callback, **kwargs) # type: ignore
if not results:
raise EmptyDataError("No data was returned.")
return sorted(
results,
key=(lambda item: (symbols.index(item.get("figi_ticker", len(symbols))))),
)
@staticmethod
def transform_data(
query: IntrinioEtfInfoQueryParams,
data: List[Dict],
**kwargs: Any,
) -> List[IntrinioEtfInfoData]:
"""Transform data."""
return [IntrinioEtfInfoData.model_validate(d) for d in data]

View File

@@ -0,0 +1,144 @@
"""Intrinio ETF Search Model."""
# pylint: disable=unused-argument
import re
from typing import Any, Dict, List, Optional, Union
from openbb_core.provider.abstract.fetcher import Fetcher
from openbb_core.provider.standard_models.etf_search import (
EtfSearchData,
EtfSearchQueryParams,
)
from openbb_core.provider.utils.errors import EmptyDataError
from openbb_core.provider.utils.helpers import (
ClientResponse,
ClientSession,
amake_request,
)
from openbb_intrinio.utils.references import ETF_EXCHANGES
from pandas import DataFrame
from pydantic import Field
class IntrinioEtfSearchQueryParams(EtfSearchQueryParams):
"""
Intrinio ETF Search Query Params.
Source: https://docs.intrinio.com/documentation/web_api/search_etfs_v2
"""
exchange: Union[None, ETF_EXCHANGES] = Field(
default=None,
description="Target a specific exchange by providing the MIC code.",
)
class IntrinioEtfSearchData(EtfSearchData):
"""Intrinio ETF Search Data."""
__alias_dict__ = {
"intrinio_id": "id",
"symbol": "ticker",
"exchange": "exchange_mic",
}
exchange: Optional[str] = Field(
default=None,
description="The exchange MIC code.",
)
figi_ticker: Optional[str] = Field(
None,
description="The OpenFIGI ticker.",
)
ric: Optional[str] = Field(
None,
description="The Reuters Instrument Code.",
)
isin: Optional[str] = Field(
None,
description="The International Securities Identification Number.",
)
sedol: Optional[str] = Field(
None,
description="The Stock Exchange Daily Official List.",
)
intrinio_id: Optional[str] = Field(
None,
description="The unique Intrinio ID for the security.",
)
class IntrinioEtfSearchFetcher(
Fetcher[IntrinioEtfSearchQueryParams, List[IntrinioEtfSearchData]]
):
"""Intrinio ETF Search Fetcher."""
@staticmethod
def transform_query(params: Dict[str, Any]) -> IntrinioEtfSearchQueryParams:
"""Transform query."""
return IntrinioEtfSearchQueryParams(**params)
@staticmethod
async def aextract_data(
query: IntrinioEtfSearchQueryParams,
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 ""
BASE = "https://api-v2.intrinio.com/etfs"
if query.exchange is not None:
url = f"{BASE}?exchange={query.exchange.upper()}&page_size=10000&api_key={api_key}"
elif query.query:
url = f"{BASE}/search?query={query.query}&page_size=10000&api_key={api_key}"
else:
url = f"{BASE}?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("messages"): # type: ignore
messages = results.get("messages") # type: ignore
raise RuntimeError(str(messages))
if results.get("etfs") and len(results.get("etfs")) > 0: # type: ignore
data.extend(results.get("etfs")) # 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 (
"etfs" in results
and len(results.get("etfs")) > 0 # type: ignore
):
data.extend(results.get("etfs")) # type: ignore
return data
return await amake_request(url, response_callback=response_callback, **kwargs) # type: ignore
@staticmethod
def transform_data(
query: IntrinioEtfSearchQueryParams,
data: List[Dict],
**kwargs: Any,
) -> List[IntrinioEtfSearchData]:
"""Transform data."""
if not data:
raise EmptyDataError("No data found.")
results = DataFrame(data)
if query.query:
pattern = f".*{re.escape(query.query)}.*"
results = results[
results["name"].str.contains(pattern, case=False, regex=True)
]
return [
IntrinioEtfSearchData.model_validate(d)
for d in results.to_dict(orient="records")
]

View File

@@ -40,6 +40,30 @@ VENUES = {
}
ETF_EXCHANGES = Literal[
"xnas",
"arcx",
"bats",
"xnys",
"bvmf",
"xshg",
"xshe",
"xhkg",
"xbom",
"xnse",
"xidx",
"tase",
"xkrx",
"xkls",
"xmex",
"xses",
"roco",
"xtai",
"xbkk",
"xist",
]
class IntrinioCompany(Data):
"""Intrinio Company Data."""

View File

@@ -0,0 +1,184 @@
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?api_key=MOCK_API_KEY
response:
body:
string: !!binary |
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
headers:
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 13 Mar 2024 04:45:56 GMT
Transfer-Encoding:
- chunked
Vary:
- Origin,Accept-Encoding
status:
code: 200
message: OK
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://api-v2.intrinio.com/etfs/GOVT:US?api_key=MOCK_API_KEY
response:
body:
string: !!binary |
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
9M+/AAAA//8DAKqjrJuQEgAA
headers:
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 13 Mar 2024 04:45:56 GMT
Transfer-Encoding:
- chunked
Vary:
- Origin,Accept-Encoding
status:
code: 200
message: OK
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://api-v2.intrinio.com/etfs/SPY:US?api_key=MOCK_API_KEY
response:
body:
string: !!binary |
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
headers:
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 13 Mar 2024 04:45:56 GMT
Transfer-Encoding:
- chunked
Vary:
- Origin,Accept-Encoding
status:
code: 200
message: OK
version: 1

View File

@@ -0,0 +1,621 @@
interactions:
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://api-v2.intrinio.com/etfs?api_key=MOCK_API_KEY&exchange=BATS&page_size=10000
response:
body:
string: !!binary |
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
4P/8LwAAAP//AwB/DDBENX4CAA==
headers:
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Wed, 13 Mar 2024 04:45:55 GMT
Transfer-Encoding:
- chunked
Vary:
- Origin,Accept-Encoding
status:
code: 200
message: OK
version: 1

View File

@@ -13,6 +13,8 @@ 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_info import IntrinioEtfInfoFetcher
from openbb_intrinio.models.etf_search import IntrinioEtfSearchFetcher
from openbb_intrinio.models.financial_ratios import IntrinioFinancialRatiosFetcher
from openbb_intrinio.models.fred_series import IntrinioFredSeriesFetcher
from openbb_intrinio.models.historical_attributes import (
@@ -362,3 +364,21 @@ def test_intrinio_reported_financials_fetcher(credentials=test_credentials):
fetcher = IntrinioReportedFinancialsFetcher()
result = fetcher.test(params, credentials)
assert result is None
@pytest.mark.record_http
def test_intrinio_etf_search_fetcher(credentials=test_credentials):
params = {"query": "factor", "exchange": "bats"}
fetcher = IntrinioEtfSearchFetcher()
result = fetcher.test(params, credentials)
assert result is None
@pytest.mark.record_http
def test_intrinio_etf_info_fetcher(credentials=test_credentials):
params = {"symbol": "DJIA,SPY,GOVT"}
fetcher = IntrinioEtfInfoFetcher()
result = fetcher.test(params, credentials)
assert result is None