mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 04:31:13 +00:00
[Feature] Intrinio ETF Price Performance (#6220)
* remap to etf router * add the intrinio files this time * update standard model * the rest of the changes * static files * black * pylint * test thing * black * fix test? * try another way? * ruff * maybe? * new cassette?
This commit is contained in:
@@ -6,7 +6,10 @@ from pydantic import Field, field_validator
|
||||
|
||||
from openbb_core.provider.abstract.data import Data
|
||||
from openbb_core.provider.abstract.query_params import QueryParams
|
||||
from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS
|
||||
from openbb_core.provider.utils.descriptions import (
|
||||
DATA_DESCRIPTIONS,
|
||||
QUERY_DESCRIPTIONS,
|
||||
)
|
||||
|
||||
|
||||
class RecentPerformanceQueryParams(QueryParams):
|
||||
@@ -22,23 +25,88 @@ class RecentPerformanceQueryParams(QueryParams):
|
||||
|
||||
|
||||
class RecentPerformanceData(Data):
|
||||
"""Recent Performance Data."""
|
||||
"""Recent Performance Data. All returns are normalized percents."""
|
||||
|
||||
one_day: Optional[float] = Field(description="One-day return.", default=None)
|
||||
wtd: Optional[float] = Field(description="Week to date return.", default=None)
|
||||
one_week: Optional[float] = Field(description="One-week return.", default=None)
|
||||
mtd: Optional[float] = Field(description="Month to date return.", default=None)
|
||||
one_month: Optional[float] = Field(description="One-month return.", default=None)
|
||||
qtd: Optional[float] = Field(description="Quarter to date return.", default=None)
|
||||
symbol: Optional[str] = Field(
|
||||
default=None, description=DATA_DESCRIPTIONS.get("symbol", "")
|
||||
)
|
||||
one_day: Optional[float] = Field(
|
||||
default=None,
|
||||
description="One-day return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
wtd: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Week to date return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
one_week: Optional[float] = Field(
|
||||
default=None,
|
||||
description="One-week return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
mtd: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Month to date return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
one_month: Optional[float] = Field(
|
||||
default=None,
|
||||
description="One-month return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
qtd: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Quarter to date return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
three_month: Optional[float] = Field(
|
||||
description="Three-month return.", default=None
|
||||
default=None,
|
||||
description="Three-month return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
six_month: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Six-month return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
ytd: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Year to date return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
one_year: Optional[float] = Field(
|
||||
default=None,
|
||||
description="One-year return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
two_year: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Two-year return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
three_year: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Three-year return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
four_year: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Four-year",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
five_year: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Five-year return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
ten_year: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Ten-year return.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
six_month: Optional[float] = Field(description="Six-month return.", default=None)
|
||||
ytd: Optional[float] = Field(description="Year to date return.", default=None)
|
||||
one_year: Optional[float] = Field(description="One-year return.", default=None)
|
||||
three_year: Optional[float] = Field(description="Three-year return.", default=None)
|
||||
five_year: Optional[float] = Field(description="Five-year return.", default=None)
|
||||
ten_year: Optional[float] = Field(description="Ten-year return.", default=None)
|
||||
max: Optional[float] = Field(
|
||||
description="Return from the beginning of the time series.", default=None
|
||||
default=None,
|
||||
description="Return from the beginning of the time series.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
|
||||
@@ -351,6 +351,14 @@ def test_etf_holdings(params, headers):
|
||||
[
|
||||
({"symbol": "SPY,VOO,QQQ,IWM,IWN,GOVT,JNK", "provider": "fmp"}),
|
||||
({"symbol": "SPY,VOO,QQQ,IWM,IWN,GOVT,JNK", "provider": "finviz"}),
|
||||
(
|
||||
{
|
||||
"symbol": "SPY,VOO,QQQ,IWM,IWN,GOVT,JNK",
|
||||
"return_type": "trailing",
|
||||
"adjustment": "splits_and_dividends",
|
||||
"provider": "intrinio",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
|
||||
@@ -342,6 +342,14 @@ def test_etf_holdings(params, obb):
|
||||
[
|
||||
({"symbol": "SPY,VOO,QQQ,IWM,IWN,GOVT,JNK", "provider": "fmp"}),
|
||||
({"symbol": "SPY,VOO,QQQ,IWM,IWN,GOVT,JNK", "provider": "finviz"}),
|
||||
(
|
||||
{
|
||||
"symbol": "SPY,VOO,QQQ,IWM,IWN,GOVT,JNK",
|
||||
"return_type": "trailing",
|
||||
"adjustment": "splits_and_dividends",
|
||||
"provider": "intrinio",
|
||||
}
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.integration
|
||||
|
||||
@@ -116,7 +116,7 @@ async def countries(
|
||||
|
||||
|
||||
@router.command(
|
||||
model="PricePerformance",
|
||||
model="EtfPricePerformance",
|
||||
examples=[
|
||||
APIEx(parameters={"symbol": "QQQ", "provider": "fmp"}),
|
||||
APIEx(parameters={"symbol": "SPY,QQQ,IWM,DJIA", "provider": "fmp"}),
|
||||
@@ -128,7 +128,7 @@ async def price_performance(
|
||||
standard_params: StandardParams,
|
||||
extra_params: ExtraParams,
|
||||
) -> OBBject:
|
||||
"""Price performance as a return, over different periods. This is a proxy for `equity.price.performance`."""
|
||||
"""Price performance as a return, over different periods."""
|
||||
return await OBBject.from_query(Query(**locals()))
|
||||
|
||||
|
||||
|
||||
224
openbb_platform/openbb/assets/reference.json
vendored
224
openbb_platform/openbb/assets/reference.json
vendored
@@ -17729,6 +17729,13 @@
|
||||
},
|
||||
"data": {
|
||||
"standard": [
|
||||
{
|
||||
"name": "symbol",
|
||||
"type": "str",
|
||||
"description": "Symbol representing the entity requested in the data.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "one_day",
|
||||
"type": "float",
|
||||
@@ -17799,6 +17806,13 @@
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "two_year",
|
||||
"type": "float",
|
||||
"description": "Two-year return.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "three_year",
|
||||
"type": "float",
|
||||
@@ -17806,6 +17820,13 @@
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "four_year",
|
||||
"type": "float",
|
||||
"description": "Four-year",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "five_year",
|
||||
"type": "float",
|
||||
@@ -17828,15 +17849,7 @@
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"fmp": [
|
||||
{
|
||||
"name": "symbol",
|
||||
"type": "str",
|
||||
"description": "The ticker symbol.",
|
||||
"default": "",
|
||||
"optional": false
|
||||
}
|
||||
]
|
||||
"fmp": []
|
||||
},
|
||||
"model": "PricePerformance"
|
||||
},
|
||||
@@ -21252,37 +21265,53 @@
|
||||
"flag": null,
|
||||
"message": null
|
||||
},
|
||||
"description": "Price performance as a return, over different periods. This is a proxy for `equity.price.performance`.",
|
||||
"description": "Price performance as a return, over different periods.",
|
||||
"examples": "\nExamples\n--------\n\n```python\nfrom openbb import obb\nobb.etf.price_performance(symbol='QQQ', provider='fmp')\nobb.etf.price_performance(symbol='SPY,QQQ,IWM,DJIA', provider='fmp')\n```\n\n",
|
||||
"parameters": {
|
||||
"standard": [
|
||||
{
|
||||
"name": "symbol",
|
||||
"type": "Union[str, List[str]]",
|
||||
"description": "Symbol to get data for. Multiple items allowed for provider(s): fmp.",
|
||||
"description": "Symbol to get data for. Multiple items allowed for provider(s): fmp, intrinio.",
|
||||
"default": "",
|
||||
"optional": false
|
||||
},
|
||||
{
|
||||
"name": "provider",
|
||||
"type": "Literal['fmp']",
|
||||
"type": "Literal['fmp', 'intrinio']",
|
||||
"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
|
||||
}
|
||||
],
|
||||
"fmp": []
|
||||
"fmp": [],
|
||||
"intrinio": [
|
||||
{
|
||||
"name": "return_type",
|
||||
"type": "Literal['trailing', 'calendar']",
|
||||
"description": "The type of returns to return, a trailing or calendar window.",
|
||||
"default": "trailing",
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "adjustment",
|
||||
"type": "Literal['splits_only', 'splits_and_dividends']",
|
||||
"description": "The adjustment factor, 'splits_only' will return pure price performance.",
|
||||
"default": "splits_and_dividends",
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"returns": {
|
||||
"OBBject": [
|
||||
{
|
||||
"name": "results",
|
||||
"type": "List[PricePerformance]",
|
||||
"type": "List[EtfPricePerformance]",
|
||||
"description": "Serializable results."
|
||||
},
|
||||
{
|
||||
"name": "provider",
|
||||
"type": "Optional[Literal['fmp']]",
|
||||
"type": "Optional[Literal['fmp', 'intrinio']]",
|
||||
"description": "Provider name."
|
||||
},
|
||||
{
|
||||
@@ -21304,6 +21333,13 @@
|
||||
},
|
||||
"data": {
|
||||
"standard": [
|
||||
{
|
||||
"name": "symbol",
|
||||
"type": "str",
|
||||
"description": "Symbol representing the entity requested in the data.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "one_day",
|
||||
"type": "float",
|
||||
@@ -21374,6 +21410,13 @@
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "two_year",
|
||||
"type": "float",
|
||||
"description": "Two-year return.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "three_year",
|
||||
"type": "float",
|
||||
@@ -21381,6 +21424,13 @@
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "four_year",
|
||||
"type": "float",
|
||||
"description": "Four-year",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "five_year",
|
||||
"type": "float",
|
||||
@@ -21403,17 +21453,116 @@
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"fmp": [
|
||||
"fmp": [],
|
||||
"intrinio": [
|
||||
{
|
||||
"name": "symbol",
|
||||
"type": "str",
|
||||
"description": "The ticker symbol.",
|
||||
"default": "",
|
||||
"optional": false
|
||||
"name": "max_annualized",
|
||||
"type": "float",
|
||||
"description": "Annualized rate of return from inception.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "volatility_one_year",
|
||||
"type": "float",
|
||||
"description": "Trailing one-year annualized volatility.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "volatility_three_year",
|
||||
"type": "float",
|
||||
"description": "Trailing three-year annualized volatility.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "volatility_five_year",
|
||||
"type": "float",
|
||||
"description": "Trailing five-year annualized volatility.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "volume",
|
||||
"type": "int",
|
||||
"description": "The trading volume.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "volume_avg_30",
|
||||
"type": "float",
|
||||
"description": "The one-month average daily volume.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "volume_avg_90",
|
||||
"type": "float",
|
||||
"description": "The three-month average daily volume.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "volume_avg_180",
|
||||
"type": "float",
|
||||
"description": "The six-month average daily volume.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "beta",
|
||||
"type": "float",
|
||||
"description": "Beta compared to the S&P 500.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "nav",
|
||||
"type": "float",
|
||||
"description": "Net asset value per share.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "year_high",
|
||||
"type": "float",
|
||||
"description": "The 52-week high price.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "year_low",
|
||||
"type": "float",
|
||||
"description": "The 52-week low price.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "market_cap",
|
||||
"type": "float",
|
||||
"description": "The market capitalization.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "shares_outstanding",
|
||||
"type": "int",
|
||||
"description": "The number of shares outstanding.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "updated",
|
||||
"type": "date",
|
||||
"description": "The date of the data.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"model": "PricePerformance"
|
||||
"model": "EtfPricePerformance"
|
||||
},
|
||||
"/etf/holdings": {
|
||||
"deprecated": {
|
||||
@@ -22317,6 +22466,13 @@
|
||||
},
|
||||
"data": {
|
||||
"standard": [
|
||||
{
|
||||
"name": "symbol",
|
||||
"type": "str",
|
||||
"description": "Symbol representing the entity requested in the data.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "one_day",
|
||||
"type": "float",
|
||||
@@ -22387,6 +22543,13 @@
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "two_year",
|
||||
"type": "float",
|
||||
"description": "Two-year return.",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "three_year",
|
||||
"type": "float",
|
||||
@@ -22394,6 +22557,13 @@
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "four_year",
|
||||
"type": "float",
|
||||
"description": "Four-year",
|
||||
"default": null,
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"name": "five_year",
|
||||
"type": "float",
|
||||
@@ -22416,15 +22586,7 @@
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"fmp": [
|
||||
{
|
||||
"name": "symbol",
|
||||
"type": "str",
|
||||
"description": "The ticker symbol.",
|
||||
"default": "",
|
||||
"optional": false
|
||||
}
|
||||
]
|
||||
"fmp": []
|
||||
},
|
||||
"model": "EtfHoldingsPerformance"
|
||||
},
|
||||
|
||||
@@ -716,6 +716,8 @@ class ROUTER_etf(Container):
|
||||
|
||||
EtfHoldingsPerformance
|
||||
----------------------
|
||||
symbol : Optional[str]
|
||||
Symbol representing the entity requested in the data.
|
||||
one_day : Optional[float]
|
||||
One-day return.
|
||||
wtd : Optional[float]
|
||||
@@ -736,16 +738,18 @@ class ROUTER_etf(Container):
|
||||
Year to date return.
|
||||
one_year : Optional[float]
|
||||
One-year return.
|
||||
two_year : Optional[float]
|
||||
Two-year return.
|
||||
three_year : Optional[float]
|
||||
Three-year return.
|
||||
four_year : Optional[float]
|
||||
Four-year
|
||||
five_year : Optional[float]
|
||||
Five-year return.
|
||||
ten_year : Optional[float]
|
||||
Ten-year return.
|
||||
max : Optional[float]
|
||||
Return from the beginning of the time series.
|
||||
symbol : Optional[str]
|
||||
The ticker symbol. (provider: fmp)
|
||||
|
||||
Examples
|
||||
--------
|
||||
@@ -1170,34 +1174,38 @@ class ROUTER_etf(Container):
|
||||
symbol: Annotated[
|
||||
Union[str, List[str]],
|
||||
OpenBBCustomParameter(
|
||||
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."
|
||||
),
|
||||
],
|
||||
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."
|
||||
),
|
||||
] = None,
|
||||
**kwargs
|
||||
) -> OBBject:
|
||||
"""Price performance as a return, over different periods. This is a proxy for `equity.price.performance`.
|
||||
"""Price performance as a return, over different periods.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
symbol : Union[str, List[str]]
|
||||
Symbol to get data for. Multiple items allowed for provider(s): fmp.
|
||||
provider : Optional[Literal['fmp']]
|
||||
Symbol to get data for. Multiple items allowed for provider(s): fmp, intrinio.
|
||||
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.
|
||||
return_type : Literal['trailing', 'calendar']
|
||||
The type of returns to return, a trailing or calendar window. (provider: intrinio)
|
||||
adjustment : Literal['splits_only', 'splits_and_dividends']
|
||||
The adjustment factor, 'splits_only' will return pure price performance. (provider: intrinio)
|
||||
|
||||
Returns
|
||||
-------
|
||||
OBBject
|
||||
results : List[PricePerformance]
|
||||
results : List[EtfPricePerformance]
|
||||
Serializable results.
|
||||
provider : Optional[Literal['fmp']]
|
||||
provider : Optional[Literal['fmp', 'intrinio']]
|
||||
Provider name.
|
||||
warnings : Optional[List[Warning_]]
|
||||
List of warnings.
|
||||
@@ -1206,8 +1214,10 @@ class ROUTER_etf(Container):
|
||||
extra : Dict[str, Any]
|
||||
Extra info.
|
||||
|
||||
PricePerformance
|
||||
----------------
|
||||
EtfPricePerformance
|
||||
-------------------
|
||||
symbol : Optional[str]
|
||||
Symbol representing the entity requested in the data.
|
||||
one_day : Optional[float]
|
||||
One-day return.
|
||||
wtd : Optional[float]
|
||||
@@ -1228,16 +1238,48 @@ class ROUTER_etf(Container):
|
||||
Year to date return.
|
||||
one_year : Optional[float]
|
||||
One-year return.
|
||||
two_year : Optional[float]
|
||||
Two-year return.
|
||||
three_year : Optional[float]
|
||||
Three-year return.
|
||||
four_year : Optional[float]
|
||||
Four-year
|
||||
five_year : Optional[float]
|
||||
Five-year return.
|
||||
ten_year : Optional[float]
|
||||
Ten-year return.
|
||||
max : Optional[float]
|
||||
Return from the beginning of the time series.
|
||||
symbol : Optional[str]
|
||||
The ticker symbol. (provider: fmp)
|
||||
max_annualized : Optional[float]
|
||||
Annualized rate of return from inception. (provider: intrinio)
|
||||
volatility_one_year : Optional[float]
|
||||
Trailing one-year annualized volatility. (provider: intrinio)
|
||||
volatility_three_year : Optional[float]
|
||||
Trailing three-year annualized volatility. (provider: intrinio)
|
||||
volatility_five_year : Optional[float]
|
||||
Trailing five-year annualized volatility. (provider: intrinio)
|
||||
volume : Optional[int]
|
||||
The trading volume. (provider: intrinio)
|
||||
volume_avg_30 : Optional[float]
|
||||
The one-month average daily volume. (provider: intrinio)
|
||||
volume_avg_90 : Optional[float]
|
||||
The three-month average daily volume. (provider: intrinio)
|
||||
volume_avg_180 : Optional[float]
|
||||
The six-month average daily volume. (provider: intrinio)
|
||||
beta : Optional[float]
|
||||
Beta compared to the S&P 500. (provider: intrinio)
|
||||
nav : Optional[float]
|
||||
Net asset value per share. (provider: intrinio)
|
||||
year_high : Optional[float]
|
||||
The 52-week high price. (provider: intrinio)
|
||||
year_low : Optional[float]
|
||||
The 52-week low price. (provider: intrinio)
|
||||
market_cap : Optional[float]
|
||||
The market capitalization. (provider: intrinio)
|
||||
shares_outstanding : Optional[int]
|
||||
The number of shares outstanding. (provider: intrinio)
|
||||
updated : Optional[date]
|
||||
The date of the data. (provider: intrinio)
|
||||
|
||||
Examples
|
||||
--------
|
||||
@@ -1253,14 +1295,14 @@ class ROUTER_etf(Container):
|
||||
"provider": self._get_provider(
|
||||
provider,
|
||||
"/etf/price_performance",
|
||||
("fmp",),
|
||||
("fmp", "intrinio"),
|
||||
)
|
||||
},
|
||||
standard_params={
|
||||
"symbol": symbol,
|
||||
},
|
||||
extra_params=kwargs,
|
||||
extra_info={"symbol": {"multiple_items_allowed": ["fmp"]}},
|
||||
extra_info={"symbol": {"multiple_items_allowed": ["fmp", "intrinio"]}},
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ finviz_provider = Provider(
|
||||
credentials=None,
|
||||
fetcher_dict={
|
||||
"CompareGroups": FinvizCompareGroupsFetcher,
|
||||
"EtfPricePerformance": FinvizPricePerformanceFetcher,
|
||||
"EquityInfo": FinvizEquityProfileFetcher,
|
||||
"KeyMetrics": FinvizKeyMetricsFetcher,
|
||||
"PricePerformance": FinvizPricePerformanceFetcher,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
from typing import Any, Dict, List, Optional
|
||||
from warnings import warn
|
||||
|
||||
from finvizfinance.screener import performance
|
||||
from openbb_core.provider.abstract.fetcher import Fetcher
|
||||
@@ -108,7 +109,17 @@ class FinvizPricePerformanceFetcher(
|
||||
screen_df = screen_df.fillna("N/A").replace("N/A", None) # type: ignore
|
||||
except Exception as e:
|
||||
raise e from e
|
||||
return screen_df.to_dict(orient="records")
|
||||
symbols = query.symbol.split(",")
|
||||
|
||||
# Check for missing symbols and warn of the missing symbols.
|
||||
for symbol in symbols:
|
||||
if symbol not in screen_df["Ticker"].tolist():
|
||||
warn(f"Symbol Error: {symbol} was not found.")
|
||||
|
||||
return sorted(
|
||||
screen_df.to_dict(orient="records"),
|
||||
key=(lambda item: (symbols.index(item.get("Ticker", len(symbols))))),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
|
||||
@@ -103,6 +103,7 @@ fmp_provider = Provider(
|
||||
"EtfHoldingsDate": FMPEtfHoldingsDateFetcher,
|
||||
"EtfHoldingsPerformance": FMPEtfHoldingsPerformanceFetcher,
|
||||
"EtfInfo": FMPEtfInfoFetcher,
|
||||
"EtfPricePerformance": FMPPricePerformanceFetcher,
|
||||
"EtfSearch": FMPEtfSearchFetcher,
|
||||
"EtfSectors": FMPEtfSectorsFetcher,
|
||||
"ExecutiveCompensation": FMPExecutiveCompensationFetcher,
|
||||
|
||||
@@ -12,6 +12,9 @@ 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_price_performance import (
|
||||
IntrinioEtfPricePerformanceFetcher,
|
||||
)
|
||||
from openbb_intrinio.models.etf_search import IntrinioEtfSearchFetcher
|
||||
from openbb_intrinio.models.financial_ratios import IntrinioFinancialRatiosFetcher
|
||||
from openbb_intrinio.models.fred_series import IntrinioFredSeriesFetcher
|
||||
@@ -58,6 +61,7 @@ intrinio_provider = Provider(
|
||||
"EquitySearch": IntrinioEquitySearchFetcher,
|
||||
"EtfHistorical": IntrinioEquityHistoricalFetcher,
|
||||
"EtfInfo": IntrinioEtfInfoFetcher,
|
||||
"EtfPricePerformance": IntrinioEtfPricePerformanceFetcher,
|
||||
"EtfSearch": IntrinioEtfSearchFetcher,
|
||||
"FinancialRatios": IntrinioFinancialRatiosFetcher,
|
||||
"FredSeries": IntrinioFredSeriesFetcher,
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
"""Intrinio ETF Performance Model."""
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
import asyncio
|
||||
from datetime import date as dateType
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
from warnings import warn
|
||||
|
||||
from openbb_core.provider.abstract.fetcher import Fetcher
|
||||
from openbb_core.provider.standard_models.recent_performance import (
|
||||
RecentPerformanceData,
|
||||
RecentPerformanceQueryParams,
|
||||
)
|
||||
from openbb_core.provider.utils.descriptions import DATA_DESCRIPTIONS
|
||||
from openbb_core.provider.utils.errors import EmptyDataError
|
||||
from openbb_core.provider.utils.helpers import amake_request
|
||||
from openbb_intrinio.utils.references import ETF_PERFORMANCE_MAP
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
class IntrinioEtfPricePerformanceQueryParams(RecentPerformanceQueryParams):
|
||||
"""
|
||||
Intrinio ETF Performance Query Params.
|
||||
|
||||
Source: https://docs.intrinio.com/documentation/web_api/get_etf_stats_v2
|
||||
Source: https://docs.intrinio.com/documentation/web_api/get_etf_analytics_v2
|
||||
"""
|
||||
|
||||
__json_schema_extra__ = {"symbol": ["multiple_items_allowed"]}
|
||||
|
||||
return_type: Literal["trailing", "calendar"] = Field(
|
||||
default="trailing",
|
||||
description="The type of returns to return, a trailing or calendar window.",
|
||||
)
|
||||
adjustment: Literal["splits_only", "splits_and_dividends"] = Field(
|
||||
default="splits_and_dividends",
|
||||
description="The adjustment factor, 'splits_only' will return pure price performance.",
|
||||
)
|
||||
|
||||
|
||||
class IntrinioEtfPricePerformanceData(RecentPerformanceData):
|
||||
"""Intrinio ETF Performance Data."""
|
||||
|
||||
__alias_dict__ = {
|
||||
"updated": "date",
|
||||
"year_high": "fifty_two_week_high",
|
||||
"year_low": "fifty_two_week_low",
|
||||
"volume": "volume_traded",
|
||||
"volume_avg_30": "average_daily_volume_one_month",
|
||||
"volume_avg_90": "average_daily_volume_three_month",
|
||||
"volume_avg_180": "average_daily_volume_six_month",
|
||||
}
|
||||
|
||||
max_annualized: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Annualized rate of return from inception.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
volatility_one_year: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Trailing one-year annualized volatility.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
volatility_three_year: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Trailing three-year annualized volatility.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
volatility_five_year: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Trailing five-year annualized volatility.",
|
||||
json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
|
||||
)
|
||||
volume: Optional[int] = Field(
|
||||
default=None,
|
||||
description=DATA_DESCRIPTIONS.get("volume", ""),
|
||||
)
|
||||
volume_avg_30: Optional[float] = Field(
|
||||
default=None,
|
||||
description="The one-month average daily volume.",
|
||||
)
|
||||
volume_avg_90: Optional[float] = Field(
|
||||
default=None,
|
||||
description="The three-month average daily volume.",
|
||||
)
|
||||
volume_avg_180: Optional[float] = Field(
|
||||
default=None,
|
||||
description="The six-month average daily volume.",
|
||||
)
|
||||
beta: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Beta compared to the S&P 500.",
|
||||
)
|
||||
nav: Optional[float] = Field(
|
||||
default=None,
|
||||
description="Net asset value per share.",
|
||||
)
|
||||
year_high: Optional[float] = Field(
|
||||
default=None,
|
||||
description="The 52-week high price.",
|
||||
)
|
||||
year_low: Optional[float] = Field(
|
||||
default=None,
|
||||
description="The 52-week low price.",
|
||||
)
|
||||
|
||||
market_cap: Optional[float] = Field(
|
||||
default=None,
|
||||
description="The market capitalization.",
|
||||
)
|
||||
shares_outstanding: Optional[int] = Field(
|
||||
default=None,
|
||||
description="The number of shares outstanding.",
|
||||
)
|
||||
updated: Optional[dateType] = Field(
|
||||
default=None,
|
||||
description=DATA_DESCRIPTIONS.get("date", ""),
|
||||
)
|
||||
|
||||
|
||||
class IntrinioEtfPricePerformanceFetcher(
|
||||
Fetcher[
|
||||
IntrinioEtfPricePerformanceQueryParams, List[IntrinioEtfPricePerformanceData]
|
||||
]
|
||||
):
|
||||
"""Intrinio ETF Performance Fetcher."""
|
||||
|
||||
@staticmethod
|
||||
def transform_query(
|
||||
params: Dict[str, Any]
|
||||
) -> IntrinioEtfPricePerformanceQueryParams:
|
||||
"""Transform query."""
|
||||
return IntrinioEtfPricePerformanceQueryParams(**params)
|
||||
|
||||
@staticmethod
|
||||
async def aextract_data(
|
||||
query: IntrinioEtfPricePerformanceQueryParams,
|
||||
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
|
||||
]
|
||||
|
||||
adjustment = (
|
||||
"split_only"
|
||||
if query.adjustment == "splits_and_dividends"
|
||||
else "split_and_dividend"
|
||||
)
|
||||
|
||||
return_type = "trailing" if query.return_type == "calendar" else "calendar"
|
||||
|
||||
results = []
|
||||
|
||||
async def get_one(symbol: str, **kwargs):
|
||||
"""Get data for one symbol."""
|
||||
|
||||
url = f"{base_url}{symbol}/stats?api_key={api_key}"
|
||||
result = await amake_request(url, **kwargs)
|
||||
|
||||
if "message" in result and result["message"] != []: # type: ignore
|
||||
warn(f"Symbol Error: {symbol} - {result['message']}") # type: ignore
|
||||
return
|
||||
_ = result.pop("message", None) # type: ignore
|
||||
_ = result.pop("messages", None) # type: ignore
|
||||
|
||||
data = {}
|
||||
etf = result.pop("etf", {}) # type: ignore
|
||||
data["symbol"] = etf.get("ticker")
|
||||
# These items will be kept regardless of the adjustment and return_type.
|
||||
keep = ["volatility", "month", "year_to_date"]
|
||||
for k, v in result.copy().items(): # type: ignore
|
||||
if not any(substring in k for substring in keep):
|
||||
_ = result.pop(k, None) if adjustment in k else None # type: ignore
|
||||
_ = result.pop(k, None) if return_type in k else None # type: ignore
|
||||
if k in result:
|
||||
data[ETF_PERFORMANCE_MAP.get(k, k)] = v
|
||||
# Get an additional set of data to combine with the first set.
|
||||
analytics_url = (
|
||||
f"https://api-v2.intrinio.com/etfs/{symbol}/analytics?api_key={api_key}"
|
||||
)
|
||||
if data:
|
||||
analytics = await amake_request(analytics_url, **kwargs)
|
||||
if "messages" in analytics and analytics["messages"] != []: # type: ignore
|
||||
warn(
|
||||
f"Symbol Error: {analytics['messages']}" # type: ignore
|
||||
+ f"for {etf.get('ticker')}" # type: ignore
|
||||
)
|
||||
return
|
||||
# Remove the duplicate data from the analytics response.
|
||||
_ = analytics.pop("messages", None) # type: ignore
|
||||
_ = analytics.pop("etf", None) # type: ignore
|
||||
_ = analytics.pop("date", None) # type: ignore
|
||||
|
||||
data.update(analytics) # type: ignore
|
||||
|
||||
results.append(data)
|
||||
|
||||
tasks = [get_one(symbol, **kwargs) for symbol in symbols]
|
||||
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
if not results:
|
||||
raise EmptyDataError("No data was returned.")
|
||||
|
||||
# Undo any formatting changes made to the symbols before sorting.
|
||||
symbols = query.symbol.replace(":US", "").split(",")
|
||||
|
||||
return sorted(
|
||||
results,
|
||||
key=(lambda item: (symbols.index(item.get("symbol", len(symbols))))),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def transform_data(
|
||||
query: IntrinioEtfPricePerformanceQueryParams,
|
||||
data: List[Dict],
|
||||
**kwargs: Any,
|
||||
) -> List[IntrinioEtfPricePerformanceData]:
|
||||
"""Transform data."""
|
||||
return [IntrinioEtfPricePerformanceData.model_validate(d) for d in data]
|
||||
@@ -64,6 +64,39 @@ ETF_EXCHANGES = Literal[
|
||||
]
|
||||
|
||||
|
||||
ETF_PERFORMANCE_MAP = {
|
||||
"trailing_one_month_return_split_and_dividend": "one_month",
|
||||
"trailing_one_month_return_split_only": "one_month",
|
||||
"trailing_one_year_return_split_and_dividend": "one_year",
|
||||
"trailing_one_year_return_split_only": "one_year",
|
||||
"trailing_one_year_volatility_annualized": "volatility_one_year",
|
||||
"trailing_three_year_annualized_return_split_and_dividend": "three_year",
|
||||
"trailing_three_year_annualized_return_split_only": "three_year",
|
||||
"trailing_three_year_volatility_annualized": "volatility_three_year",
|
||||
"trailing_five_year_annualized_return_split_and_dividend": "five_year",
|
||||
"trailing_five_year_annualized_return_split_only": "five_year",
|
||||
"trailing_five_year_volatility_annualized": "volatility_five_year",
|
||||
"trailing_ten_year_annualized_return_split_and_dividend": "ten_year",
|
||||
"trailing_ten_year_annualized_return_split_only": "ten_year",
|
||||
"inception_annualized_return_split_and_dividend": "max_annualized",
|
||||
"inception_annualized_return_split_only": "max_annualized",
|
||||
"calendar_year_5_return_split_and_dividend": "five_year",
|
||||
"calendar_year_5_return_split_only": "five_year",
|
||||
"calendar_year_4_return_split_and_dividend": "four_year",
|
||||
"calendar_year_4_return_split_only": "four_year",
|
||||
"calendar_year_3_return_split_and_dividend": "three_year",
|
||||
"calendar_year_3_return_split_only": "three_year",
|
||||
"calendar_year_2_return_split_and_dividend": "two_year",
|
||||
"calendar_year_2_return_split_only": "two_year",
|
||||
"calendar_year_1_return_split_and_dividend": "one_year",
|
||||
"calendar_year_1_return_split_only": "one_year",
|
||||
"calendar_year_to_date_return_split_and_dividend": "ytd",
|
||||
"calendar_year_to_date_return_split_only": "ytd",
|
||||
"net_asset_value": "nav",
|
||||
"beta_vs_spy": "beta",
|
||||
}
|
||||
|
||||
|
||||
class IntrinioCompany(Data):
|
||||
"""Intrinio Company Data."""
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
interactions:
|
||||
- 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/stats?api_key=MOCK_API_KEY
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAE9n82UAA5RVUW8aMQz+K9U9U2Q7cZzwNm3rc1daqdM2nW6Q0mjXo7s70Gi1/z4fXSkqlCsv
|
||||
QEK+z/6cz/FjdhebppjFJht9+zHIpkUbs1FGQPYUzCmabJBVsc2LptHPZVEu9G9GHgZwKDLIfsa2
|
||||
yJdN3tyvshEOYZC1dZHKVM3yeRXzu3nV3uZ1bBd1pWfKpFTVNJ+mZZrGapqNYAgUAqFhi5a9WLCu
|
||||
n2Nelat3YVexqA+HNxzIk1EsiID1vQTPsY3xgYI36C2zFeR9yOW8LFrda1cauFoUZXqI67BICI6Y
|
||||
nIgxwNvg9raO/+EvmMMiEMGTAHsmAGesHEe3KWewNgSL3hkkYXH7ad4WJSYEdAKA+oXebOFv0vJY
|
||||
UVZNFvRaDT5d7lFsz5rQgGUQQs/KJ8btZXlTEkEIWggExOAZeDuJNlZHKiItrAvsLPgQjJdjyDaC
|
||||
tPNMAGIwFmFtnVRN4n2b5tX7M9EGN+LYeW0fMGTfQ7KxiSeLol4TIW/VL4NsUpTKrNmvJXBPyyGR
|
||||
tp3VuwVWo5ke/HNc8l1Q1CqKA3b8GmZ7NHujTmIiVW2EQg98U2+Hjgw4fSf0pWDvX+PM4bCaNXmP
|
||||
wTlWDwu5HvxGrUD3sOk9oQS3UyM6FPW0U4uiWq0+UoBqO+kheArbAYP1qA5lFQx6R/QaiD16dTA4
|
||||
UMm8tgjsBMY39FryToKw18bQe9qpUzvPu/HUM028PsbqTkQhTR52st/L8uLsHXRsb7LRY5aUvfud
|
||||
P/wG8+W6G4vFXTcqx+efLk7G3xcA5M5PGODk8+XZyWW9aFo91KbJr1ivj33V5U2apXx7b3Q11u06
|
||||
TZ6Ww3NdpSZVurwai7eOzhAM6G4Tp/OyG83eAiHrTvwzuS2qmQ7INfzDxcfr7O/ffwAAAP//AwCV
|
||||
rhxr0gcAAA==
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Thu, 14 Mar 2024 21:08:31 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/analytics?api_key=MOCK_API_KEY
|
||||
response:
|
||||
body:
|
||||
string: !!binary |
|
||||
H4sIAE9n82UAA3RRy07DMBD8lcjnNFo7Dzu5IaDn0rRSESDLStzEah4QO31Q8e9sCqqQUOWLd2Zn
|
||||
xzs+k1ZbqyptSfby5pNSOU0ywoBFMwhnNCQ+2ZqtO0l36OVB652sTVWTLKYiYAzoP7rpDyQLRRhw
|
||||
5PZ9M7ZaukGVukRRTCECIQLwidrrAX1lqUxzkr+Nfadl23cODRIe85RFIohTwENvKFw96KuGJ2Ga
|
||||
JhELKKeCxzck1hyvgpSylAOgiYhYzHzSqmGnnSzUOz4XcBywRIQpCybS1mrQVvajs051pekqkqU8
|
||||
4YJRmkxLabcl2ZkY3HW6y88PCJ82mGGn2inXfPGw9PLXEXDqwosBvMfV3FsNo3XY5Eyx08Ol7fmS
|
||||
e2XkXyxb5wgPpvgpgwVWxpoOy3XORZSwOYUQELW67JvpH0UEjMaI6GNRqw6jaC/yu+X9hnx9fQMA
|
||||
AP//AwCMIK2E/wEAAA==
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Encoding:
|
||||
- gzip
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Thu, 14 Mar 2024 21:08:31 GMT
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Vary:
|
||||
- Origin,Accept-Encoding
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
version: 1
|
||||
@@ -14,6 +14,9 @@ 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_price_performance import (
|
||||
IntrinioEtfPricePerformanceFetcher,
|
||||
)
|
||||
from openbb_intrinio.models.etf_search import IntrinioEtfSearchFetcher
|
||||
from openbb_intrinio.models.financial_ratios import IntrinioFinancialRatiosFetcher
|
||||
from openbb_intrinio.models.fred_series import IntrinioFredSeriesFetcher
|
||||
@@ -382,3 +385,12 @@ def test_intrinio_etf_info_fetcher(credentials=test_credentials):
|
||||
fetcher = IntrinioEtfInfoFetcher()
|
||||
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"}
|
||||
|
||||
fetcher = IntrinioEtfPricePerformanceFetcher()
|
||||
result = fetcher.test(params, credentials)
|
||||
assert result is None
|
||||
|
||||
Reference in New Issue
Block a user