summaryrefslogtreecommitdiffstats
path: root/openbb_platform/providers/intrinio/openbb_intrinio/models/key_metrics.py
diff options
context:
space:
mode:
Diffstat (limited to 'openbb_platform/providers/intrinio/openbb_intrinio/models/key_metrics.py')
-rw-r--r--openbb_platform/providers/intrinio/openbb_intrinio/models/key_metrics.py332
1 files changed, 297 insertions, 35 deletions
diff --git a/openbb_platform/providers/intrinio/openbb_intrinio/models/key_metrics.py b/openbb_platform/providers/intrinio/openbb_intrinio/models/key_metrics.py
index 478bb9c6008..2dbecc4a0e3 100644
--- a/openbb_platform/providers/intrinio/openbb_intrinio/models/key_metrics.py
+++ b/openbb_platform/providers/intrinio/openbb_intrinio/models/key_metrics.py
@@ -1,12 +1,18 @@
"""Intrinio Key Metrics Model."""
+# pylint: disable=unused-argument
+
+import asyncio
from typing import Any, Dict, List, Optional
+from warnings import warn
+from openbb_core.provider.abstract.data import ForceInt
from openbb_core.provider.abstract.fetcher import Fetcher
from openbb_core.provider.standard_models.key_metrics import (
KeyMetricsData,
KeyMetricsQueryParams,
)
+from openbb_core.provider.utils.errors import EmptyDataError
from openbb_core.provider.utils.helpers import (
ClientResponse,
amake_requests,
@@ -15,16 +21,14 @@ from pydantic import Field
class IntrinioKeyMetricsQueryParams(KeyMetricsQueryParams):
- """Intrinio Key Metrics Query.
-
- Source: https://data.intrinio.com/data-tag/beta
- https://data.intrinio.com/data-tag/volume
- https://data.intrinio.com/data-tag/52_week_high
- https://data.intrinio.com/data-tag/52_week_low
- https://data.intrinio.com/data-tag/dividendyield
- https://data.intrinio.com/data-tag/pricetoearnings
+ """
+ Intrinio Key Metrics Query.
+
+ Source: https://data.intrinio.com/data-tags/
"""
+ __json_schema_extra__ = {"symbol": ["multiple_items_allowed"]}
+
class IntrinioKeyMetricsData(KeyMetricsData):
"""Intrinio Key Metrics Data."""
@@ -32,26 +36,200 @@ class IntrinioKeyMetricsData(KeyMetricsData):
__alias_dict__ = {
"market_cap": "marketcap",
"pe_ratio": "pricetoearnings",
+ "price_to_book": "pricetobook",
+ "price_to_tangible_book": "pricetotangiblebook",
+ "price_to_revenue": "pricetorevenue",
+ "long_term_debt": "ltdebtandcapleases",
+ "total_debt": "debt",
+ "total_capital": "totalcapital",
+ "enterprise_value": "enterprisevalue",
+ "eps_growth": "epsgrowth",
+ "ebit_growth": "ebitgrowth",
+ "ebitda_growth": "ebitdagrowth",
+ "revenue_growth": "revenuegrowth",
+ "net_income_growth": "netincomegrowth",
+ "free_cash_flow_to_firm_growth": "fcffgrowth",
+ "invested_capital_growth": "investedcapitalgrowth",
+ "quick_ratio": "quickratio",
+ "gross_margin": "grossmargin",
+ "ebit_margin": "ebitmargin",
+ "profit_margin": "profitmargin",
+ "return_on_assets": "roa",
+ "return_on_equity": "roe",
+ "return_on_invested_capital": "roic",
+ "free_cash_flow_to_firm": "freecashflow",
+ "altman_z_score": "altmanzscore",
+ "earnings_yield": "earningsyield",
+ "dividend_yield": "dividendyield",
+ "year_high": "52_week_high",
+ "year_low": "52_week_low",
+ "volume_avg": "average_daily_volume",
+ "shares_outstanding": "adjweightedavebasicsharesos",
+ "eps": "basiceps",
}
- beta: float = Field(
- description="Beta relative to the broad market calculated on a rolling three-year basis."
+ price_to_book: Optional[float] = Field(
+ default=None,
+ description="Price to book ratio.",
+ )
+ price_to_tangible_book: Optional[float] = Field(
+ default=None,
+ description="Price to tangible book ratio.",
+ )
+ price_to_revenue: Optional[float] = Field(
+ default=None,
+ description="Price to revenue ratio.",
+ )
+ quick_ratio: Optional[float] = Field(
+ default=None,
+ description="Quick ratio.",
+ )
+ gross_margin: Optional[float] = Field(
+ default=None,
+ description="Gross margin, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ ebit_margin: Optional[float] = Field(
+ default=None,
+ description="EBIT margin, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ profit_margin: Optional[float] = Field(
+ default=None,
+ description="Profit margin, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ eps: Optional[float] = Field(
+ default=None,
+ description="Basic earnings per share.",
+ )
+ eps_growth: Optional[float] = Field(
+ default=None,
+ description="EPS growth, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ revenue_growth: Optional[float] = Field(
+ default=None,
+ description="Revenue growth, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ ebitda_growth: Optional[float] = Field(
+ default=None,
+ description="EBITDA growth, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ ebit_growth: Optional[float] = Field(
+ default=None,
+ description="EBIT growth, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ net_income_growth: Optional[float] = Field(
+ default=None,
+ description="Net income growth, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ free_cash_flow_to_firm_growth: Optional[float] = Field(
+ default=None,
+ description="Free cash flow to firm growth, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ invested_capital_growth: Optional[float] = Field(
+ default=None,
+ description="Invested capital growth, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ return_on_assets: Optional[float] = Field(
+ default=None,
+ description="Return on assets, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ return_on_equity: Optional[float] = Field(
+ default=None,
+ description="Return on equity, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ return_on_invested_capital: Optional[float] = Field(
+ default=None,
+ description="Return on invested capital, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ ebitda: Optional[ForceInt] = Field(
+ default=None,
+ description="Earnings before interest, taxes, depreciation, and amortization.",
+ )
+ ebit: Optional[ForceInt] = Field(
+ default=None,
+ description="Earnings before interest and taxes.",
+ )
+ long_term_debt: Optional[ForceInt] = Field(
+ default=None,
+ description="Long-term debt.",
+ )
+ total_debt: Optional[ForceInt] = Field(
+ default=None,
+ description="Total debt.",
+ )
+ total_capital: Optional[ForceInt] = Field(
+ default=None,
+ description="The sum of long-term debt and total shareholder equity.",
+ )
+ enterprise_value: Optional[ForceInt] = Field(
+ default=None,
+ description="Enterprise value.",
+ )
+ free_cash_flow_to_firm: Optional[ForceInt] = Field(
+ default=None,
+ description="Free cash flow to firm.",
)
- volume: float = Field(description="Volume")
- fifty_two_week_high: float = Field(description="52 week high", alias="52_week_high")
- fifty_two_week_low: float = Field(description="52 week low", alias="52_week_low")
- dividend_yield: float = Field(
+ altman_z_score: Optional[float] = Field(
+ default=None,
+ description="Altman Z-score.",
+ )
+ beta: Optional[float] = Field(
+ default=None,
+ description="Beta relative to the broad market (rolling three-year).",
+ )
+ dividend_yield: Optional[float] = Field(
default=None,
description="Dividend yield, as a normalized percent.",
- json_schema_extra={"unit_measurement": "percent", "frontend_multiply": 100},
- alias="dividendyield",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ earnings_yield: Optional[float] = Field(
+ default=None,
+ description="Earnings yield, as a normalized percent.",
+ json_schema_extra={"x-unit_measurement": "percent", "x-frontend_multiply": 100},
+ )
+ last_price: Optional[float] = Field(
+ default=None,
+ description="Last price of the stock.",
+ )
+ year_high: Optional[float] = Field(
+ default=None,
+ description="52 week high",
+ )
+ year_low: float = Field(default=None, description="52 week low")
+ volume_avg: Optional[ForceInt] = Field(
+ default=None,
+ description="Average daily volume.",
+ )
+ short_interest: Optional[ForceInt] = Field(
+ default=None,
+ description="Number of shares reported as sold short.",
+ )
+ shares_outstanding: Optional[ForceInt] = Field(
+ default=None,
+ description="Weighted average shares outstanding (TTM).",
+ )
+ days_to_cover: Optional[float] = Field(
+ default=None,
+ description="Days to cover short interest, based on average daily volume.",
)
class IntrinioKeyMetricsFetcher(
Fetcher[
IntrinioKeyMetricsQueryParams,
- IntrinioKeyMetricsData,
+ List[IntrinioKeyMetricsData],
]
):
"""Transform the query, extract and transform the data from the Intrinio endpoints."""
@@ -59,44 +237,128 @@ class IntrinioKeyMetricsFetcher(
@staticmethod
def transform_query(params: Dict[str, Any]) -> IntrinioKeyMetricsQueryParams:
"""Transform the query params."""
+
+ if params.get("period") is not None and params.get("period") != "annual":
+ warn(
+ "The period parameter is not available for this Intrinio endpoint, it will be ignored."
+ )
return IntrinioKeyMetricsQueryParams(**params)
@staticmethod
async def aextract_data(
- query: IntrinioKeyMetricsQueryParams, # pylint: disable=unused-argument
+ query: IntrinioKeyMetricsQueryParams,
credentials: Optional[Dict[str, str]],
**kwargs: Any,
- ) -> Dict:
+ ) -> List[Dict]:
"""Return the raw data from the Intrinio endpoint."""
api_key = credentials.get("intrinio_api_key") if credentials else ""
tags = [
"beta",
- "volume",
+ "average_daily_volume",
+ "basiceps",
+ "basicdilutedeps",
"marketcap",
+ "last_price",
"52_week_high",
"52_week_low",
"dividendyield",
"pricetoearnings",
+ "pricetorevenue",
+ "pricetobook",
+ "pricetotangiblebook",
+ "grossmargin",
+ "ebitmargin",
+ "profitmargin",
+ "roa",
+ "roe",
+ "roic",
+ "earningsyield",
+ "days_to_cover",
+ "short_interest",
+ "revenuegrowth",
+ "ebitgrowth",
+ "ebitdagrowth",
+ "epsgrowth",
+ "netincomegrowth",
+ "investedcapitalgrowth",
+ "debt",
+ "totalcapital",
+ "enterprisevalue",
+ "freecashflow",
+ "fcffgrowth",
+ "ltdebtandcapleases",
+ "altmanzscore",
+ "quickratio",
+ "ebit",
+ "ebitda",
+ "adjweightedavebasicsharesos",
]
+ results = []
+ urls = []
+ symbols = query.symbol.split(",")
- urls = [
- f"https://api-v2.intrinio.com/companies/{query.symbol}/data_point/{tag}?api_key={api_key}"
- for tag in tags
- ]
+ async def get_one(symbol: str):
+ """Get data for one symbol."""
+
+ _urls = [
+ f"https://api-v2.intrinio.com/companies/{symbol}/data_point/{tag}?api_key={api_key}"
+ for tag in tags
+ ]
+ urls.extend(_urls)
- async def callback(response: ClientResponse, _: Any) -> Dict:
- """Return the response."""
- return {response.url.parts[-1]: await response.json()}
+ async def callback(response: ClientResponse, _: Any) -> Dict:
+ """Return the response."""
+ return {response.url.parts[-1]: await response.json()}
- data: Dict = {"symbol": query.symbol}
- for result in await amake_requests(urls, callback, **kwargs):
- data.update(result)
+ data = {}
+ for result in await amake_requests(urls, callback, **kwargs):
+ data.update(result)
+ if data:
+ data["symbol"] = symbol
+ results.append(data)
- return data
+ tasks = [get_one(symbol) for symbol in symbols]
+
+ await asyncio.gather(*tasks)
+
+ if not results:
+ raise EmptyDataError()
+
+ return results
@staticmethod
def transform_data(
- query: IntrinioKeyMetricsQueryParams, data: List[Dict], **kwargs: Any
- ) -> IntrinioKeyMetricsData:
- """Return the transformed data."""
- return IntrinioKeyMetricsData.model_validate(data)
+ query: IntrinioKeyMetricsQueryParams,
+ data: List[Dict],
+ **kwargs: Any,
+ ) -> List[IntrinioKeyMetricsData]:
+ """Validate and transform the data."""
+
+ # Sort the results by the order of the symbols in the query.
+ symbols = query.symbol.split(",")
+ data = sorted(
+ data,
+ key=(
+ lambda item: (
+ symbols.index(item["symbol"])
+ if item["symbol"] in symbols
+ else len(symbols)
+ )
+ ),
+ )
+
+ results: List[IntrinioKeyMetricsData] = []
+ for item in data:
+
+ if item.get("marketcap") is None or isinstance(item.get("marketcap"), dict):
+ warn(f"Symbol Error: No data found for {item.get('symbol')}")
+ continue
+
+ for key, value in item.copy().items():
+ # A bad response in a field will return a dict here, so we remove it.
+ if isinstance(value, dict):
+ _ = item.pop(key)
+
+ results.append(IntrinioKeyMetricsData.model_validate(item))
+
+ return results