[Feature] Add Intrinio to equity.historical_market_cap (#6932)

* add intrinio to historical market cap

* no-else-return
This commit is contained in:
Danglewood
2024-11-05 16:11:47 -08:00
committed by GitHub
parent 64e0a23582
commit e444a5d96c
9 changed files with 404 additions and 15 deletions

View File

@@ -2082,7 +2082,16 @@ def test_equity_compare_company_facts(params, headers):
"end_date": None,
"provider": "fmp",
}
)
),
(
{
"symbol": "AAPL,MSFT",
"start_date": None,
"end_date": None,
"provider": "intrinio",
"interval": "week",
}
),
],
)
@pytest.mark.integration

View File

@@ -1945,7 +1945,16 @@ def test_equity_compare_company_facts(params, obb):
"end_date": None,
"provider": "fmp",
}
)
),
(
{
"symbol": "AAPL,MSFT",
"start_date": None,
"end_date": None,
"provider": "intrinio",
"interval": "week",
}
),
],
)
@pytest.mark.integration

View File

@@ -29944,7 +29944,7 @@
{
"name": "symbol",
"type": "Union[str, List[str]]",
"description": "Symbol to get data for. Multiple items allowed for provider(s): fmp.",
"description": "Symbol to get data for. Multiple items allowed for provider(s): fmp, intrinio.",
"default": "",
"optional": false,
"choices": null
@@ -29966,7 +29966,22 @@
"choices": null
}
],
"fmp": []
"fmp": [],
"intrinio": [
{
"name": "interval",
"type": "Literal['week', 'month', 'quarter', 'year']",
"description": "None",
"default": "week",
"optional": true,
"choices": [
"week",
"month",
"quarter",
"year"
]
}
]
},
"returns": {
"OBBject": [
@@ -29977,7 +29992,7 @@
},
{
"name": "provider",
"type": "Optional[Literal['fmp']]",
"type": "Optional[Literal['fmp', 'intrinio']]",
"description": "Provider name."
},
{
@@ -30024,7 +30039,8 @@
"choices": null
}
],
"fmp": []
"fmp": [],
"intrinio": []
},
"model": "HistoricalMarketCap"
},

View File

@@ -81,7 +81,7 @@ class ROUTER_equity(Container):
symbol: Annotated[
Union[str, List[str]],
OpenBBField(
description="Symbol to get data for. Multiple comma separated items allowed for provider(s): fmp."
description="Symbol to get data for. Multiple comma separated items allowed for provider(s): fmp, intrinio."
),
],
start_date: Annotated[
@@ -93,9 +93,9 @@ class ROUTER_equity(Container):
OpenBBField(description="End date of the data, in YYYY-MM-DD format."),
] = None,
provider: Annotated[
Optional[Literal["fmp"]],
Optional[Literal["fmp", "intrinio"]],
OpenBBField(
description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: fmp."
description="The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: fmp, intrinio."
),
] = None,
**kwargs
@@ -105,20 +105,22 @@ class ROUTER_equity(Container):
Parameters
----------
symbol : Union[str, List[str]]
Symbol to get data for. Multiple comma separated items allowed for provider(s): fmp.
Symbol to get data for. Multiple comma separated items allowed for provider(s): fmp, intrinio.
start_date : Union[date, None, str]
Start date of the data, in YYYY-MM-DD format.
end_date : Union[date, None, str]
End date of the data, in YYYY-MM-DD format.
provider : Optional[Literal['fmp']]
The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: fmp.
provider : Optional[Literal['fmp', 'intrinio']]
The provider to use, by default None. If None, the priority list configured in the settings is used. Default priority: fmp, intrinio.
interval : Literal['week', 'month', 'quarter', 'year']
None
Returns
-------
OBBject
results : List[HistoricalMarketCap]
Serializable results.
provider : Optional[Literal['fmp']]
provider : Optional[Literal['fmp', 'intrinio']]
Provider name.
warnings : Optional[List[Warning_]]
List of warnings.
@@ -149,7 +151,7 @@ class ROUTER_equity(Container):
"provider": self._get_provider(
provider,
"equity.historical_market_cap",
("fmp",),
("fmp", "intrinio"),
)
},
standard_params={
@@ -159,7 +161,16 @@ class ROUTER_equity(Container):
},
extra_params=kwargs,
info={
"symbol": {"fmp": {"multiple_items_allowed": True, "choices": None}}
"symbol": {
"fmp": {"multiple_items_allowed": True, "choices": None},
"intrinio": {"multiple_items_allowed": True, "choices": None},
},
"interval": {
"intrinio": {
"multiple_items_allowed": False,
"choices": ["week", "month", "quarter", "year"],
}
},
},
)
)

View File

@@ -37,6 +37,9 @@ from openbb_intrinio.models.historical_attributes import (
from openbb_intrinio.models.historical_dividends import (
IntrinioHistoricalDividendsFetcher,
)
from openbb_intrinio.models.historical_market_cap import (
IntrinioHistoricalMarketCapFetcher,
)
from openbb_intrinio.models.income_statement import IntrinioIncomeStatementFetcher
from openbb_intrinio.models.index_historical import IntrinioIndexHistoricalFetcher
from openbb_intrinio.models.insider_trading import IntrinioInsiderTradingFetcher
@@ -90,6 +93,7 @@ historical financial market data to businesses and developers through an API."""
"FredSeries": IntrinioFredSeriesFetcher,
"HistoricalAttributes": IntrinioHistoricalAttributesFetcher,
"HistoricalDividends": IntrinioHistoricalDividendsFetcher,
"HistoricalMarketCap": IntrinioHistoricalMarketCapFetcher,
"IncomeStatement": IntrinioIncomeStatementFetcher,
"IndexHistorical": IntrinioIndexHistoricalFetcher,
"InsiderTrading": IntrinioInsiderTradingFetcher,

View File

@@ -0,0 +1,150 @@
"""Intrinio Historical Market Cap Model."""
# pylint: disable=unused-argument
from datetime import datetime
from typing import Any, Literal, Optional
from openbb_core.app.model.abstract.error import OpenBBError
from openbb_core.provider.abstract.fetcher import Fetcher
from openbb_core.provider.standard_models.historical_market_cap import (
HistoricalMarketCapData,
HistoricalMarketCapQueryParams,
)
from openbb_core.provider.utils.errors import EmptyDataError
from pydantic import Field
class IntrinioHistoricalMarketCapQueryParams(HistoricalMarketCapQueryParams):
"""Intrinio Historical MarketCap Query.
Source: https://docs.intrinio.com/documentation/web_api/get_historical_data_v2
"""
__json_schema_extra__ = {
"symbol": {"multiple_items_allowed": True},
"interval": {
"multiple_items_allowed": False,
"choices": ["week", "month", "quarter", "year"],
},
}
interval: Literal["week", "month", "quarter", "year"] = Field(
default="week",
)
class IntrinioHistoricalMarketCapData(HistoricalMarketCapData):
"""Intrinio Historical MarketCap Data."""
__alias_dict__ = {
"market_cap": "value",
}
class IntrinioHistoricalMarketCapFetcher(
Fetcher[
IntrinioHistoricalMarketCapQueryParams,
list[IntrinioHistoricalMarketCapData],
]
):
"""Transform the query, extract and transform the data from the Intrinio endpoints."""
@staticmethod
def transform_query(
params: dict[str, Any]
) -> IntrinioHistoricalMarketCapQueryParams:
"""Transform the query params."""
transformed_params = params
now = datetime.now().date()
if params.get("start_date") is None:
transformed_params["start_date"] = datetime(
2000,
1,
1,
).date()
if params.get("end_date") is None:
transformed_params["end_date"] = now
return IntrinioHistoricalMarketCapQueryParams(**transformed_params)
@staticmethod
async def aextract_data(
query: IntrinioHistoricalMarketCapQueryParams,
credentials: Optional[dict[str, str]],
**kwargs: Any,
) -> list[dict]:
"""Return the raw data from the Intrinio endpoint."""
# pylint: disable=import-outside-toplevel
import asyncio # noqa
from openbb_core.provider.utils.helpers import amake_request
from openbb_intrinio.utils.helpers import response_callback
from warnings import warn
api_key = credentials.get("intrinio_api_key") if credentials else ""
base_url = "https://api-v2.intrinio.com/historical_data/"
frequency = query.interval + "ly"
start_date = query.start_date
end_date = query.end_date
results: list = []
messages: list = []
symbols = query.symbol.split(",")
async def get_one(symbol):
"""Get data for one symbol."""
url_params = (
f"{symbol}/marketcap?frequency={frequency}&start_date={start_date}"
f"&end_date={end_date}&page_size=10000"
f"&api_key={api_key}"
)
url = f"{base_url}{url_params}"
try:
response = await amake_request(url, response_callback=response_callback)
except OpenBBError as e:
if "Cannot look up this item/identifier combination" in str(e):
msg = f"Symbol not found: {symbol}"
messages.append(msg)
return
raise e from e
if not isinstance(response, dict):
raise OpenBBError(
f"Unexpected response format, expected a dictionary, got {response.__class__.__name__}"
)
if not response:
msg = f"No data found for symbol: {symbol}"
messages.append(msg)
if response.get("historical_data"):
data = response.get("historical_data", {})
result = [
{"symbol": symbol, **item} for item in data if item.get("value")
]
results.extend(result)
return
await asyncio.gather(*[get_one(symbol) for symbol in symbols])
if messages and not results:
raise OpenBBError(messages)
if messages and results:
for message in messages:
warn(message)
if not results:
raise EmptyDataError("The response was returned empty.")
return results
@staticmethod
def transform_data(
query: IntrinioHistoricalMarketCapQueryParams, data: list[dict], **kwargs: Any
) -> list[IntrinioHistoricalMarketCapData]:
"""Return the transformed data."""
return [
IntrinioHistoricalMarketCapData.model_validate(d)
for d in sorted(data, key=lambda x: x["date"])
]

View File

@@ -0,0 +1,86 @@
interactions:
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://api-v2.intrinio.com/historical_data/AAPL/marketcap?api_key=MOCK_API_KEY&end_date=2020-12-31&frequency=weekly&page_size=10000&start_date=2020-01-01
response:
body:
string: !!binary |
H4sIAMFaKmcAA3SW22pUURBE/2Wec6TvF39FJAwaNBCiaCJCyL9bx6e9SQfyEDIrTe3q6u55uXy/
//3049f9l+vD7dfr0/Xy8dPLBb/cXT5ehIQOlkP8cnP5c314xh9FwsySs7vkA73evKG5FppTxbJK
3GimeaWJjFqrJXSkyRaaOgNiktqn2nxIrjSRm1d7GM80rTSrsTOTeo8060pbgNMqz8kTPihWWsOz
wpxj0k2HLkoYYFR3pPakmw5ZlHAnXtkVSjIpwc+upFLgeLnbSFNvDmqAlTSrmZZVCRyx5iiveEtT
b6niZlYKEWYfaoNeU8XFlSTOFlNOTprX2hRInxrqz/SeKgcv5kqWA12HbPkG6WUpVO/QW745+cw4
l84026rbg1S1pGrSXQfl6kmzqSTVmFjKQ1dPitxTA93sqXYesioBionPppoyCJpXJaFRxOLJNGTw
pNd8h3RlQruODuZBa77dIk2smmii45BYaW5DWTxz7GUc3CtNWDvpjGGYPAG95ht9T8TQTKdpAE1r
vqFZHdlK4qk7fsiqRCMIywRTPG3Nk16VKIqefX+nO37wqkQxZIqndrePNK2Tpiqu2EHnf830mirR
iqbEEsrJE9tTheFxuN3niRjpLVUYnhJtE9XJE9tTxVYaWCYQM/lte6qwHCzkvFI1vVK3S8KEweEy
OfMy04uSbtQ280yd7NbtkPB5SXAvE4+c6fWQwD4YiE0lMhoo26qCfYZr2YXuT/GWbVUBwm1N2G09
PVL2VWVUgp1C1jkNmuyrCimpDqvkMYK8ryosBlYmzI9NreQ9VJrBGHhJlymCvIdKsdTwZUNMZAoV
76HCV4JAbSpYPtJbqKRwSRwrRf+f4s83l8e7v0+3P6/f8Onj88PD6z8AAAD//wMAyLTn230JAAA=
headers:
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Tue, 05 Nov 2024 17:49:53 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/historical_data/MSFT/marketcap?api_key=MOCK_API_KEY&end_date=2020-12-31&frequency=weekly&page_size=10000&start_date=2020-01-01
response:
body:
string: !!binary |
H4sIAMFaKmcAA3SW3YpTQRCE3yXXe6T/f3wVEQm6qBBUdFeExXe3zt1M7L0JIakMdWq+rs7L5cvX
X0/ff379eL19+HR9ul7evnu54M3j5e1FSOhgOcQvD5ff19szPuRQZiNzE8o39PfhPzXXqiaKzHL1
olnNi9qDwzIsXGpUk23qTpIIZp6c8CG5qjMo1cy1ZFbTqjbCg2ox96xmXdXFSjDSmjqqKbYEtcOT
LWpS06GrE8vK0CKjtlEtuxNKx+FRr5zNmxPyUk5y6+l26KDeEsSxwS6dUyZQy6pG2l4lpjaoqXeq
HDmndasqj+qNKgtruFERHW7+VK9UWQMV5CJFw1NCfUdVSHEKbnRIkOqQjW8g5caKYHxWb3w7THSG
e8xn8+ZE1HD3CNGGm4eaNr4RSYe4a08J5qF7Js5cEkJjgnmIbQwyi3FbTdMANa9ODOcmkzCsz2ra
Z94FL+cvRjXpHVUphpmfpoHikJVvsFckZWk0OYmDV75N4KLhvWU+m1e+YQPlg1xoah+oaeVbTwAx
N8UVg9oPWZ2gIITPZpNp0k715sTQgJLwQxODfvDmBJmgphShTww6wNrO9j4vVJ1fUa9UwS6YbUdV
TU5sp0oSaKNjqXnKxHaqFC1VjsUD0mf1ShWWE3W5heg087ZTBbgNblIyJie6bxI8nWDIzHJqzVO9
OiFC24fgfJ3uUvdNgkrudCwT7Slv3TcJ13k82tBkmnnZu4oLMnixnnbxqea7vM8p66iJb9m7CnyA
FXL0yTRpsncVlChlLlWZOOG9qwSrDxV01uyUIN9RhUUMqpLwt2NUb1SJcJo0/p9Ez+r1LlEPIU2Y
ofEp+Y4q7zSuRGueVL1/uHx7/PP04cf1M7799ny7/f0HAAD//wMAPTPfo34JAAA=
headers:
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Tue, 05 Nov 2024 17:49:53 GMT
Transfer-Encoding:
- chunked
Vary:
- Origin,Accept-Encoding
status:
code: 200
message: OK
version: 1

View File

@@ -0,0 +1,86 @@
interactions:
- request:
body: null
headers:
Accept:
- application/json
Accept-Encoding:
- gzip, deflate
Connection:
- keep-alive
method: GET
uri: https://api-v2.intrinio.com/historical_data/AAPL/marketcap?api_key=MOCK_API_KEY&end_date=2020-12-31&frequency=weekly&page_size=10000&start_date=2020-01-01
response:
body:
string: !!binary |
H4sIANRaKmcAA3SW22pUURBE/2Wec6TvF39FJAwaNBCiaCJCyL9bx6e9SQfyEDIrTe3q6u55uXy/
//3049f9l+vD7dfr0/Xy8dPLBb/cXT5ehIQOlkP8cnP5c314xh9FwsySs7vkA73evKG5FppTxbJK
3GimeaWJjFqrJXSkyRaaOgNiktqn2nxIrjSRm1d7GM80rTSrsTOTeo8060pbgNMqz8kTPihWWsOz
wpxj0k2HLkoYYFR3pPakmw5ZlHAnXtkVSjIpwc+upFLgeLnbSFNvDmqAlTSrmZZVCRyx5iiveEtT
b6niZlYKEWYfaoNeU8XFlSTOFlNOTprX2hRInxrqz/SeKgcv5kqWA12HbPkG6WUpVO/QW745+cw4
l84026rbg1S1pGrSXQfl6kmzqSTVmFjKQ1dPitxTA93sqXYesioBionPppoyCJpXJaFRxOLJNGTw
pNd8h3RlQruODuZBa77dIk2smmii45BYaW5DWTxz7GUc3CtNWDvpjGGYPAG95ht9T8TQTKdpAE1r
vqFZHdlK4qk7fsiqRCMIywRTPG3Nk16VKIqefX+nO37wqkQxZIqndrePNK2Tpiqu2EHnf830mirR
iqbEEsrJE9tTheFxuN3niRjpLVUYnhJtE9XJE9tTxVYaWCYQM/lte6qwHCzkvFI1vVK3S8KEweEy
OfMy04uSbtQ280yd7NbtkPB5SXAvE4+c6fWQwD4YiE0lMhoo26qCfYZr2YXuT/GWbVUBwm1N2G09
PVL2VWVUgp1C1jkNmuyrCimpDqvkMYK8ryosBlYmzI9NreQ9VJrBGHhJlymCvIdKsdTwZUNMZAoV
76HCV4JAbSpYPtJbqKRwSRwrRf+f4s83l8e7v0+3P6/f8Onj88PD6z8AAAD//wMAyLTn230JAAA=
headers:
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Tue, 05 Nov 2024 17:50:12 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/historical_data/MSFT/marketcap?api_key=MOCK_API_KEY&end_date=2020-12-31&frequency=weekly&page_size=10000&start_date=2020-01-01
response:
body:
string: !!binary |
H4sIANlaKmcAA3SW3YpTQRCE3yXXe6T/f3wVEQm6qBBUdFeExXe3zt1M7L0JIakMdWq+rs7L5cvX
X0/ff379eL19+HR9ul7evnu54M3j5e1FSOhgOcQvD5ff19szPuRQZiNzE8o39PfhPzXXqiaKzHL1
olnNi9qDwzIsXGpUk23qTpIIZp6c8CG5qjMo1cy1ZFbTqjbCg2ox96xmXdXFSjDSmjqqKbYEtcOT
LWpS06GrE8vK0CKjtlEtuxNKx+FRr5zNmxPyUk5y6+l26KDeEsSxwS6dUyZQy6pG2l4lpjaoqXeq
HDmndasqj+qNKgtruFERHW7+VK9UWQMV5CJFw1NCfUdVSHEKbnRIkOqQjW8g5caKYHxWb3w7THSG
e8xn8+ZE1HD3CNGGm4eaNr4RSYe4a08J5qF7Js5cEkJjgnmIbQwyi3FbTdMANa9ODOcmkzCsz2ra
Z94FL+cvRjXpHVUphpmfpoHikJVvsFckZWk0OYmDV75N4KLhvWU+m1e+YQPlg1xoah+oaeVbTwAx
N8UVg9oPWZ2gIITPZpNp0k715sTQgJLwQxODfvDmBJmgphShTww6wNrO9j4vVJ1fUa9UwS6YbUdV
TU5sp0oSaKNjqXnKxHaqFC1VjsUD0mf1ShWWE3W5heg087ZTBbgNblIyJie6bxI8nWDIzHJqzVO9
OiFC24fgfJ3uUvdNgkrudCwT7Slv3TcJ13k82tBkmnnZu4oLMnixnnbxqea7vM8p66iJb9m7CnyA
FXL0yTRpsncVlChlLlWZOOG9qwSrDxV01uyUIN9RhUUMqpLwt2NUb1SJcJo0/p9Ez+r1LlEPIU2Y
ofEp+Y4q7zSuRGueVL1/uHx7/PP04cf1M7799ny7/f0HAAD//wMAPTPfo34JAAA=
headers:
Connection:
- keep-alive
Content-Encoding:
- gzip
Content-Type:
- application/json
Date:
- Tue, 05 Nov 2024 17:50:17 GMT
Transfer-Encoding:
- chunked
Vary:
- Origin,Accept-Encoding
status:
code: 200
message: OK
version: 1

View File

@@ -41,6 +41,9 @@ from openbb_intrinio.models.historical_attributes import (
from openbb_intrinio.models.historical_dividends import (
IntrinioHistoricalDividendsFetcher,
)
from openbb_intrinio.models.historical_market_cap import (
IntrinioHistoricalMarketCapFetcher,
)
from openbb_intrinio.models.income_statement import IntrinioIncomeStatementFetcher
from openbb_intrinio.models.index_historical import IntrinioIndexHistoricalFetcher
from openbb_intrinio.models.insider_trading import IntrinioInsiderTradingFetcher
@@ -543,3 +546,18 @@ def test_intrinio_options_snapshots(credentials=test_credentials):
fetcher = IntrinioOptionsSnapshotsFetcher()
result = fetcher.test(params, credentials)
assert result is None
@pytest.mark.record_http
def test_intrinio_historical_market_cap(credentials=test_credentials):
"""Test options snapshots fetcher."""
params = {
"symbol": "AAPL,MSFT",
"start_date": date(2020, 1, 1),
"end_date": date(2020, 12, 31),
"interval": "week",
}
fetcher = IntrinioHistoricalMarketCapFetcher()
result = fetcher.test(params, credentials)
assert result is None