diff --git a/.github/labeler.yml b/.github/labeler.yml index c785bb7c01e..d48d518f4fc 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -23,4 +23,8 @@ labels: - label: "excel" files: - - "website/content/excel/.*" \ No newline at end of file + - "website/content/excel/.*" + + - label: "breaking_change" + files: + - "openbb_platform/core/openbb_core/provider/standard_models/.*" diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 296b6e15ba7..eab4af1c80a 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -8,6 +8,9 @@ categories: - title: 🐛 OpenBB Platform Bug Fixes labels: - 'bug' + - title: 🚨 OpenBB Platform Breaking Changes + labels: + - 'breaking_change' - title: 📚 OpenBB Documentation Changes labels: - 'docs' diff --git a/build/pypi/openbb_platform/publish.py b/build/pypi/openbb_platform/publish.py index 4abe874b7be..3d6fb6bf83e 100644 --- a/build/pypi/openbb_platform/publish.py +++ b/build/pypi/openbb_platform/publish.py @@ -51,6 +51,7 @@ def update_extension_dependencies(path: Path): def bump_version(path: Path): """Bump the version of the package""" + print(f"\n> {path.parent.stem}") # noqa: T201 subprocess.run(CMD + VERSION_BUMP_CMD, cwd=path.parent, check=True) # noqa: S603 @@ -77,7 +78,9 @@ def publish(dry_run: bool = False, core: bool = False, extensions: bool = False) # Publish (if not dry run) if not dry_run: subprocess.run( - CMD + PUBLISH_CMD, cwd=path.parent, check=True # noqa: S603 + CMD + PUBLISH_CMD, # noqa: S603 + cwd=path.parent, + check=True, # noqa: S603 ) except Exception as e: print(f"Error publishing {path.parent}:\n{e}") # noqa: T201 diff --git a/openbb_platform/README.md b/openbb_platform/README.md index 23c0a5acb96..40bf3f7fc74 100644 --- a/openbb_platform/README.md +++ b/openbb_platform/README.md @@ -4,9 +4,9 @@ [![LatestRelease](https://badge.fury.io/py/openbb.svg)](https://github.com/OpenBB-finance/OpenBBTerminal) | OpenBB is committed to build the future of investment research by focusing on an open source infrastructure accessible to everyone, everywhere. | -|:--:| -| ![OpenBBLogo](https://user-images.githubusercontent.com/25267873/218899768-1f0964b8-326c-4f35-af6f-ea0946ac970b.png) | -| Check our website at [openbb.co](www.openbb.co) | +| :---------------------------------------------------------------------------------------------------------------------------------------------: | +| ![OpenBBLogo](https://user-images.githubusercontent.com/25267873/218899768-1f0964b8-326c-4f35-af6f-ea0946ac970b.png) | +| Check our website at [openbb.co](www.openbb.co) | ## Overview @@ -22,21 +22,19 @@ pip install openbb This will install the following data providers: -| Extension Name | Description | Installation Command | Minimum Subscription Type Required | -|----------------|-------------|----------------------|------------------------------------| -| openbb-benzinga | [Benzinga](https://www.benzinga.com/apis/en-ca/) data connector | pip install openbb-benzinga | Paid | -| openbb-biztoc | [Biztoc](https://api.biztoc.com/#biztoc-default) News data connector | pip install openbb-biztoc | Free | -| openbb-ecb | [ECB](https://data.ecb.europa.eu/) data connector | pip install openbb-ecb | Free | -| openbb-finra | [FINRA](https://www.finra.org/finra-data) data connector | pip install openbb-finra | Free | -| openbb-finviz | [Finviz](https://finviz.com) data connector | pip install openbb-finra | Free | -| openbb-fmp | [FMP](https://site.financialmodelingprep.com/developer/) data connector | pip install openbb-fmp | Free | -| openbb-fred | [FRED](https://fred.stlouisfed.org/) data connector | pip install openbb-fred | Free | -| openbb-intrinio | [Intrinio](https://intrinio.com/pricing) data connector | pip install openbb-intrinio | Paid | -| openbb-oecd | [OECD](https://data.oecd.org/) data connector | pip install openbb-oecd | Free | -| openbb-polygon | [Polygon](https://polygon.io/) data connector | pip install openbb-polygon | Free | -| openbb-sec | [SEC](https://www.sec.gov/edgar/sec-api-documentation) data connector | pip install openbb-sec | Free | -| openbb-tiingo | [Tiingo](https://www.tiingo.com/about/pricing) data connector | pip install openbb-tiingo | Free | -| openbb-tradingeconomics | [TradingEconomics](https://tradingeconomics.com/api) data connector | pip install openbb-tradingeconomics | Paid | +| Extension Name | Description | Installation Command | Minimum Subscription Type Required | +| ----------------------- | ------------------------------------------------------------------------- | ----------------------------------- | ---------------------------------- | +| openbb-benzinga | [Benzinga](https://www.benzinga.com/apis/en-ca/) data connector | pip install openbb-benzinga | Paid | +| openbb-federal-reserve | [FederalReserve](https://www.federalreserve.gov/data.html) data connector | pip install openbb-federal-reserve | Free | +| openbb-fmp | [FMP](https://site.financialmodelingprep.com/developer/) data connector | pip install openbb-fmp | Free | +| openbb-fred | [FRED](https://fred.stlouisfed.org/) data connector | pip install openbb-fred | Free | +| openbb-intrinio | [Intrinio](https://intrinio.com/pricing) data connector | pip install openbb-intrinio | Paid | +| openbb-oecd | [OECD](https://data.oecd.org/) data connector | pip install openbb-oecd | Free | +| openbb-polygon | [Polygon](https://polygon.io/) data connector | pip install openbb-polygon | Free | +| openbb-sec | [SEC](https://www.sec.gov/edgar/sec-api-documentation) data connector | pip install openbb-sec | Free | +| openbb-tiingo | [Tiingo](https://www.tiingo.com/about/pricing) data connector | pip install openbb-tiingo | Free | +| openbb-tradingeconomics | [TradingEconomics](https://tradingeconomics.com/api) data connector | pip install openbb-tradingeconomics | Paid | +| openbb-yahoo-finance | [Yahoo Finance](https://finance.yahoo.com/) data connector | pip install openbb-yfinance | Free | To install extensions that expand the core functionalities specify the extension name or use `all` to install all. diff --git a/openbb_platform/core/openbb_core/provider/standard_models/key_metrics.py b/openbb_platform/core/openbb_core/provider/standard_models/key_metrics.py index 80158688dc8..d2580e481cf 100644 --- a/openbb_platform/core/openbb_core/provider/standard_models/key_metrics.py +++ b/openbb_platform/core/openbb_core/provider/standard_models/key_metrics.py @@ -1,6 +1,6 @@ """Key Metrics Standard Model.""" -from typing import List, Literal, Optional, Set, Union +from typing import Literal, Optional from pydantic import Field, field_validator @@ -48,11 +48,3 @@ class KeyMetricsData(Data): pe_ratio: Optional[float] = Field( default=None, description="Price-to-earnings ratio (P/E ratio)" ) - - @field_validator("symbol", mode="before", check_fields=False) - @classmethod - def to_upper(cls, v: Union[str, List[str], Set[str]]): - """Convert field to uppercase.""" - if isinstance(v, str): - return v.upper() - return ",".join([symbol.upper() for symbol in list(v)]) if v else None diff --git a/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py b/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py index e420fdde63b..f4c8f48386e 100644 --- a/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py +++ b/openbb_platform/extensions/econometrics/openbb_econometrics/econometrics_router.py @@ -346,12 +346,6 @@ def residual_autocorrelation( 'obb.econometrics.cointegration(data=stock_data, columns=["open", "close"])', ], ), - APIEx( - parameters={ - "columns": ["open", "close"], - "data": APIEx.mock_data("timeseries"), - } - ), ], ) def cointegration( diff --git a/openbb_platform/extensions/etf/integration/test_etf_api.py b/openbb_platform/extensions/etf/integration/test_etf_api.py index 1e3271ae6b1..0baccbd72b0 100644 --- a/openbb_platform/extensions/etf/integration/test_etf_api.py +++ b/openbb_platform/extensions/etf/integration/test_etf_api.py @@ -189,7 +189,7 @@ def test_etf_search(params, headers): ( { "provider": "tradier", - "symbol": "AAPL,MSFT", + "symbol": "SPY", "start_date": "2023-01-01", "end_date": "2023-06-06", "interval": "1M", @@ -199,7 +199,7 @@ def test_etf_search(params, headers): ( { "provider": "tradier", - "symbol": "AAPL,MSFT", + "symbol": "SPY,DJIA", "start_date": None, "end_date": None, "interval": "15m", diff --git a/openbb_platform/extensions/etf/integration/test_etf_python.py b/openbb_platform/extensions/etf/integration/test_etf_python.py index 0498e2e2f72..9329a1cdada 100644 --- a/openbb_platform/extensions/etf/integration/test_etf_python.py +++ b/openbb_platform/extensions/etf/integration/test_etf_python.py @@ -187,7 +187,7 @@ def test_etf_search(params, obb): ( { "provider": "tradier", - "symbol": "AAPL,MSFT", + "symbol": "SPY", "start_date": "2023-01-01", "end_date": "2023-06-06", "interval": "1M", @@ -197,7 +197,7 @@ def test_etf_search(params, obb): ( { "provider": "tradier", - "symbol": "AAPL,MSFT", + "symbol": "SPY,DJIA", "start_date": None, "end_date": None, "interval": "15m", diff --git a/openbb_platform/extensions/quantitative/integration/test_quantitative_api.py b/openbb_platform/extensions/quantitative/integration/test_quantitative_api.py index e42c06c24ad..57782126fc7 100644 --- a/openbb_platform/extensions/quantitative/integration/test_quantitative_api.py +++ b/openbb_platform/extensions/quantitative/integration/test_quantitative_api.py @@ -206,7 +206,13 @@ def test_quantitative_unitroot_test(params, data_type): "params, data_type", [ ( - {"data": "", "target": "close", "rfr": "", "window": "", "index": "date"}, + { + "data": "", + "target": "close", + "rfr": "", + "window": "100", + "index": "date", + }, "equity", ), ( @@ -214,7 +220,7 @@ def test_quantitative_unitroot_test(params, data_type): "data": "", "target": "high", "rfr": "0.5", - "window": "250", + "window": "150", "index": "date", }, "crypto", @@ -243,7 +249,7 @@ def test_quantitative_performance_sharpe_ratio(params, data_type): "data": "", "target": "close", "target_return": "", - "window": "", + "window": "100", "adjusted": "", "index": "date", }, diff --git a/openbb_platform/extensions/quantitative/integration/test_quantitative_python.py b/openbb_platform/extensions/quantitative/integration/test_quantitative_python.py index d84c6981d61..f9fd73b832d 100644 --- a/openbb_platform/extensions/quantitative/integration/test_quantitative_python.py +++ b/openbb_platform/extensions/quantitative/integration/test_quantitative_python.py @@ -327,7 +327,6 @@ def test_quantitative_summary(params, data_type, obb): "data": "", "target": "close", "window": "10", - "quantile_pct": "", "index": "date", }, "equity", @@ -337,7 +336,6 @@ def test_quantitative_summary(params, data_type, obb): "data": "", "target": "high", "window": "50", - "quantile_pct": "0.6", "index": "date", }, "crypto", @@ -363,7 +361,6 @@ def test_quantitative_rolling_stdev(params, data_type, obb): "data": "", "target": "close", "window": "10", - "quantile_pct": "", "index": "date", }, "equity", @@ -373,7 +370,6 @@ def test_quantitative_rolling_stdev(params, data_type, obb): "data": "", "target": "high", "window": "50", - "quantile_pct": "0.6", "index": "date", }, "crypto", @@ -399,7 +395,6 @@ def test_quantitative_rolling_mean(params, data_type, obb): "data": "", "target": "close", "window": "10", - "quantile_pct": "", "index": "date", }, "equity", @@ -409,7 +404,6 @@ def test_quantitative_rolling_mean(params, data_type, obb): "data": "", "target": "high", "window": "50", - "quantile_pct": "0.6", "index": "date", }, "crypto", diff --git a/openbb_platform/extensions/technical/openbb_technical/technical_router.py b/openbb_platform/extensions/technical/openbb_technical/technical_router.py index 24ca12139f6..69405a3e3fe 100644 --- a/openbb_platform/extensions/technical/openbb_technical/technical_router.py +++ b/openbb_platform/extensions/technical/openbb_technical/technical_router.py @@ -931,7 +931,6 @@ def donchian( "ichimoku_data = obb.technical.ichimoku(data=stock_data.results, conversion=9, base=26, lookahead=False)", ], ), - APIEx(parameters={"data": APIEx.mock_data("timeseries")}), ], ) def ichimoku( @@ -973,6 +972,7 @@ def ichimoku( OBBject[List[Data]] The calculated data. """ + validate_data(data, [conversion, base, lagging]) df = basemodel_to_df(data, index=index) df_target = get_target_columns(df, ["high", "low", "close"]) df_ichimoku, df_span = df_target.ta.ichimoku( diff --git a/openbb_platform/extensions/tests/conftest.py b/openbb_platform/extensions/tests/conftest.py index bf9c9b65b10..01de5e65d3f 100644 --- a/openbb_platform/extensions/tests/conftest.py +++ b/openbb_platform/extensions/tests/conftest.py @@ -1,6 +1,6 @@ """Custom pytest configuration for the extensions.""" -from typing import Dict, List +from typing import Any, Dict, List, Tuple import pytest from openbb_core.app.router import CommandMap @@ -13,7 +13,7 @@ commands = list(cm.map.keys()) # ruff: noqa: SIM114 -def parametrize(argnames: str, argvalues: List[Dict], **kwargs): +def parametrize(argnames: str, argvalues: List[Tuple[Any, ...]], **kwargs): """Custom parametrize decorator that filters test cases based on the environment.""" routers, providers, obbject_ext = list_openbb_extensions() diff --git a/openbb_platform/openbb/package/equity_fundamental.py b/openbb_platform/openbb/package/equity_fundamental.py index c0c6f810ecb..862cb291ef4 100644 --- a/openbb_platform/openbb/package/equity_fundamental.py +++ b/openbb_platform/openbb/package/equity_fundamental.py @@ -2412,7 +2412,7 @@ class ROUTER_equity_fundamental(Container): symbol: Annotated[ Union[str, List[str]], OpenBBCustomParameter( - description="Symbol to get data for. Multiple items allowed for provider(s): fmp, yfinance." + description="Symbol to get data for. Multiple items allowed for provider(s): fmp, intrinio, yfinance." ), ], period: Annotated[ @@ -2436,7 +2436,7 @@ class ROUTER_equity_fundamental(Container): Parameters ---------- symbol : Union[str, List[str]] - Symbol to get data for. Multiple items allowed for provider(s): fmp, yfinance. + Symbol to get data for. Multiple items allowed for provider(s): fmp, intrinio, yfinance. period : Optional[Literal['annual', 'quarter']] Time period of the data to return. limit : Optional[int] @@ -2451,7 +2451,7 @@ class ROUTER_equity_fundamental(Container): Returns ------- OBBject - results : Union[List[KeyMetrics], KeyMetrics] + results : List[KeyMetrics] Serializable results. provider : Optional[Literal['fmp', 'intrinio', 'yfinance']] Provider name. @@ -2494,8 +2494,8 @@ class ROUTER_equity_fundamental(Container): Shareholders equity per share (provider: fmp) interest_debt_per_share : Optional[float] Interest debt per share (provider: fmp) - enterprise_value : Optional[Union[float, int]] - Enterprise value (provider: fmp, yfinance) + enterprise_value : Optional[int] + Enterprise value (provider: fmp, intrinio, yfinance) price_to_sales_ratio : Optional[float] Price-to-sales ratio (provider: fmp) pocf_ratio : Optional[float] @@ -2515,7 +2515,8 @@ class ROUTER_equity_fundamental(Container): ev_to_free_cash_flow : Optional[float] Enterprise value-to-free cash flow ratio (provider: fmp) earnings_yield : Optional[float] - Earnings yield (provider: fmp) + Earnings yield (provider: fmp); + Earnings yield, as a normalized percent. (provider: intrinio) free_cash_flow_yield : Optional[float] Free cash flow yield (provider: fmp) debt_to_equity : Optional[float] @@ -2586,15 +2587,73 @@ class ROUTER_equity_fundamental(Container): Return on equity (provider: fmp) capex_per_share : Optional[float] Capital expenditures per share (provider: fmp) + price_to_book : Optional[float] + Price to book ratio. (provider: intrinio, yfinance) + price_to_tangible_book : Optional[float] + Price to tangible book ratio. (provider: intrinio) + price_to_revenue : Optional[float] + Price to revenue ratio. (provider: intrinio) + quick_ratio : Optional[float] + Quick ratio. (provider: intrinio, yfinance) + gross_margin : Optional[float] + Gross margin, as a normalized percent. (provider: intrinio, yfinance) + ebit_margin : Optional[float] + EBIT margin, as a normalized percent. (provider: intrinio) + profit_margin : Optional[float] + Profit margin, as a normalized percent. (provider: intrinio, yfinance) + eps : Optional[float] + Basic earnings per share. (provider: intrinio) + eps_growth : Optional[float] + EPS growth, as a normalized percent. (provider: intrinio) + revenue_growth : Optional[float] + Revenue growth, as a normalized percent. (provider: intrinio, yfinance) + ebitda_growth : Optional[float] + EBITDA growth, as a normalized percent. (provider: intrinio) + ebit_growth : Optional[float] + EBIT growth, as a normalized percent. (provider: intrinio) + net_income_growth : Optional[float] + Net income growth, as a normalized percent. (provider: intrinio) + free_cash_flow_to_firm_growth : Optional[float] + Free cash flow to firm growth, as a normalized percent. (provider: intrinio) + invested_capital_growth : Optional[float] + Invested capital growth, as a normalized percent. (provider: intrinio) + return_on_assets : Optional[float] + Return on assets, as a normalized percent. (provider: intrinio, yfinance) + return_on_equity : Optional[float] + Return on equity, as a normalized percent. (provider: intrinio, yfinance) + return_on_invested_capital : Optional[float] + Return on invested capital, as a normalized percent. (provider: intrinio) + ebitda : Optional[int] + Earnings before interest, taxes, depreciation, and amortization. (provider: intrinio) + ebit : Optional[int] + Earnings before interest and taxes. (provider: intrinio) + long_term_debt : Optional[int] + Long-term debt. (provider: intrinio) + total_debt : Optional[int] + Total debt. (provider: intrinio) + total_capital : Optional[int] + The sum of long-term debt and total shareholder equity. (provider: intrinio) + free_cash_flow_to_firm : Optional[int] + Free cash flow to firm. (provider: intrinio) + altman_z_score : Optional[float] + Altman Z-score. (provider: intrinio) beta : Optional[float] - Beta relative to the broad market calculated on a rolling three-year basis. (provider: intrinio); + Beta relative to the broad market (rolling three-year). (provider: intrinio); Beta relative to the broad market (5-year monthly). (provider: yfinance) - volume : Optional[float] - Volume (provider: intrinio) - fifty_two_week_high : Optional[float] + last_price : Optional[float] + Last price of the stock. (provider: intrinio) + year_high : Optional[float] 52 week high (provider: intrinio) - fifty_two_week_low : Optional[float] + year_low : Optional[float] 52 week low (provider: intrinio) + volume_avg : Optional[int] + Average daily volume. (provider: intrinio) + short_interest : Optional[int] + Number of shares reported as sold short. (provider: intrinio) + shares_outstanding : Optional[int] + Weighted average shares outstanding (TTM). (provider: intrinio) + days_to_cover : Optional[float] + Days to cover short interest, based on average daily volume. (provider: intrinio) forward_pe : Optional[float] Forward price-to-earnings ratio. (provider: yfinance) peg_ratio : Optional[float] @@ -2611,30 +2670,16 @@ class ROUTER_equity_fundamental(Container): Earnings growth (Year Over Year), as a normalized percent. (provider: yfinance) earnings_growth_quarterly : Optional[float] Quarterly earnings growth (Year Over Year), as a normalized percent. (provider: yfinance) - revenue_growth : Optional[float] - Revenue growth (Year Over Year), as a normalized percent. (provider: yfinance) enterprise_to_revenue : Optional[float] Enterprise value to revenue ratio. (provider: yfinance) - quick_ratio : Optional[float] - Quick ratio. (provider: yfinance) - gross_margin : Optional[float] - Gross margin, as a normalized percent. (provider: yfinance) operating_margin : Optional[float] Operating margin, as a normalized percent. (provider: yfinance) ebitda_margin : Optional[float] EBITDA margin, as a normalized percent. (provider: yfinance) - profit_margin : Optional[float] - Profit margin, as a normalized percent. (provider: yfinance) - return_on_assets : Optional[float] - Return on assets, as a normalized percent. (provider: yfinance) - return_on_equity : Optional[float] - Return on equity, as a normalized percent. (provider: yfinance) dividend_yield_5y_avg : Optional[float] 5-year average dividend yield, as a normalized percent. (provider: yfinance) book_value : Optional[float] Book value per share. (provider: yfinance) - price_to_book : Optional[float] - Price-to-book ratio. (provider: yfinance) overall_risk : Optional[float] Overall risk score. (provider: yfinance) audit_risk : Optional[float] @@ -2673,7 +2718,11 @@ class ROUTER_equity_fundamental(Container): "limit": limit, }, extra_params=kwargs, - extra_info={"symbol": {"multiple_items_allowed": ["fmp", "yfinance"]}}, + extra_info={ + "symbol": { + "multiple_items_allowed": ["fmp", "intrinio", "yfinance"] + } + }, ) ) diff --git a/openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/models/equity_historical.py b/openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/models/equity_historical.py index 766551251ac..b4e18ad1b9f 100644 --- a/openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/models/equity_historical.py +++ b/openbb_platform/providers/alpha_vantage/openbb_alpha_vantage/models/equity_historical.py @@ -3,6 +3,7 @@ # pylint: disable=unused-argument import asyncio +import json from datetime import datetime from io import BytesIO from typing import Any, Dict, List, Literal, Optional @@ -213,70 +214,84 @@ class AVEquityHistoricalFetcher( if result: data = read_csv(BytesIO(result)) # type: ignore if len(data) > 0: - data.rename( - columns={ - "timestamp": "date", - "dividend_amount": "dividend", - "adjusted close": "adj_close", - "dividend amount": "dividend", - "adjusted_close": "adj_close", - "split_coefficient": "split_factor", - }, - inplace=True, - ) - data["date"] = data["date"].apply(to_datetime) - data.set_index("date", inplace=True) - # The returned data when 'adjusted=true' from the API does not return a usable OHLCV data set. - # We need to calculate the adjusted prices manually. - if query.adjustment != "unadjusted": - temp = data.copy() - temp["dividend_factor"] = ( - temp["close"] - temp["dividend"] - ) / temp["close"] - temp["volume_factor"] = temp["split_factor"] - temp["split_factor"] = 1 / temp["split_factor"] - adj_cols = ["open", "high", "low", "close", "volume"] - divs = query.adjustment == "splits_and_dividends" - for col in adj_cols: - divs = False if col == "volume" else divs - if col in temp.columns: - temp = calculate_adjusted_prices(temp, col, divs) - temp["adj_dividend"] = ( - temp["adj_close"] * (1 - temp["dividend_factor"]) - if query.adjustment == "splits_only" - else temp["close"] * (1 - temp["dividend_factor"]) + if all( + col in data.columns + for col in [ + "timestamp", + "dividend_amount", + "adjusted close", + "split_coefficient", + ] + ): + data.rename( + columns={ + "timestamp": "date", + "dividend_amount": "dividend", + "adjusted close": "adj_close", + "split_coefficient": "split_factor", + }, + inplace=True, ) - data["open"] = round(temp["adj_open"], 4) - data["high"] = round(temp["adj_high"], 4) - data["low"] = round(temp["adj_low"], 4) - data["close"] = round(temp["adj_close"], 4) - data["volume"] = round(temp["adj_volume"]).astype(int) - data["dividend"] = round(temp["adj_dividend"], 4) - data.drop(columns=["adj_close"], inplace=True) - # Resample the daily data for the interval requested. - freq = "" - agg_dict = { - "open": "first", - "high": "max", - "low": "min", - "close": "last", - "volume": "sum", - "dividend": "sum", - "split_factor": "prod", - } - if query.adjustment == "unadjusted": - agg_dict.pop("dividend") - agg_dict.pop("split_factor") - if query.interval == "1M": - freq = "M" - if query.interval == "1W": - freq = "W-FRI" - if freq in ["M", "W-FRI"]: - data = data.resample(freq).agg({**agg_dict}) - if len(query.symbol.split(",")) > 1: - data.loc[:, "symbol"] = symbol + data["date"] = data["date"].apply(to_datetime) + data.set_index("date", inplace=True) + # The returned data when 'adjusted=true' from the API does not return a usable OHLCV data set. + # We need to calculate the adjusted prices manually. + if query.adjustment != "unadjusted": + temp = data.copy() + temp["dividend_factor"] = ( + temp["close"] - temp["dividend"] + ) / temp["close"] + temp["volume_factor"] = temp["split_factor"] + temp["split_factor"] = 1 / temp["split_factor"] + adj_cols = ["open", "high", "low", "close", "volume"] + divs = query.adjustment == "splits_and_dividends" + for col in adj_cols: + divs = False if col == "volume" else divs + if col in temp.columns: + temp = calculate_adjusted_prices(temp, col, divs) + temp["adj_dividend"] = ( + temp["adj_close"] * (1 - temp["dividend_factor"]) + if query.adjustment == "splits_only" + else temp["close"] * (1 - temp["dividend_factor"]) + ) + data["open"] = round(temp["adj_open"], 4) + data["high"] = round(temp["adj_high"], 4) + data["low"] = round(temp["adj_low"], 4) + data["close"] = round(temp["adj_close"], 4) + data["volume"] = round(temp["adj_volume"]).astype(int) + data["dividend"] = round(temp["adj_dividend"], 4) + data.drop(columns=["adj_close"], inplace=True) + # Resample the daily data for the interval requested. + freq = "" + agg_dict = { + "open": "first", + "high": "max", + "low": "min", + "close": "last", + "volume": "sum", + "dividend": "sum", + "split_factor": "prod", + } + if query.adjustment == "unadjusted": + agg_dict.pop("dividend") + agg_dict.pop("split_factor") + if query.interval == "1M": + freq = "M" + if query.interval == "1W": + freq = "W-FRI" + if freq in ["M", "W-FRI"]: + data = data.resample(freq).agg({**agg_dict}) + if len(query.symbol.split(",")) > 1: + data.loc[:, "symbol"] = symbol - results.extend(data.reset_index().to_dict("records")) + results.extend(data.reset_index().to_dict("records")) + else: + try: + data = json.loads(result.decode()) + if "Information" in data: + warn(f"{data['Information']}") + except json.JSONDecodeError: + warn(f"Failed to parse data for {symbol}.") return results 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.""" -from typing import Any, Dict, List, Optional +# 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,15 +21,13 @@ 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): @@ -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.", ) - 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( + 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.", + ) + 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.""" - async def callback(response: ClientResponse, _: Any) -> Dict: - """Return the response.""" - return {response.url.parts[-1]: await response.json()} + _urls = [ + f"https://api-v2.intrinio.com/companies/{symbol}/data_point/{tag}?api_key={api_key}" + for tag in tags + ] + urls.extend(_urls) - data: Dict = {"symbol": query.symbol} - for result in await amake_requests(urls, callback, **kwargs): - data.update(result) + async def callback(response: ClientResponse, _: Any) -> Dict: + """Return the response.""" + return {response.url.parts[-1]: await response.json()} - return data + data = {} + for result in await amake_requests(urls, callback, **kwargs): + data.update(result) + if data: + data["symbol"] = symbol + results.append(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 diff --git a/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_key_metrics_fetcher.yaml b/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_key_metrics_fetcher.yaml index 0d78efe2d31..c15e55ea5bb 100644 --- a/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_key_metrics_fetcher.yaml +++ b/openbb_platform/providers/intrinio/tests/record/http/test_intrinio_fetchers/test_intrinio_key_metrics_fetcher.yaml @@ -3,17 +3,17 @@ interactions: body: null headers: Accept: - - '*/*' + - application/json Accept-Encoding: - - gzip, deflate, br + - gzip, deflate Connection: - keep-alive method: GET - uri: https://api-v2.intrinio.com/companies/AAPL/data_point/beta?api_key=MOCK_API_KEY + uri: https://api-v2.intrinio.com/companies/AAPL/data_point/days_to_cover?api_key=MOCK_API_KEY response: body: string: !!binary | - H4sIAKN4X2UAAzLUMzI2MAYAAAD//wMAyNiMHAYAAAA= + H4sIAEyP7mUAAzLSM7GwAAAAAP//AwDfjdFBBQAAAA== headers: Connection: - keep-alive @@ -22,7 +22,7 @@ interactions: Content-Type: - application/json Date: - - Thu, 23 Nov 2023 16:06:59 GMT + - Mon, 11 Mar 2024 04:57:48 GMT Transfer-Encoding: - chunked Vary: @@ -34,17 +34,17 @@ interactions: body: null headers: Accept: - - '*/*' + - application/json Accept-Encoding: - - gzip, deflate, br + - gzip, deflate Connection: - keep-alive method: GET - uri: https://api-v2.intrinio.com/companies/AAPL/data_point/volume?api_key=MOCK_API_KEY + uri: https://api-v2.intrinio.com/companies/AAPL/data_point/last_price?api_key=MOCK_API_KEY response: body: string: !!binary | - H4sIAKR4X2UAAzK2NDM2MDA01DMAAAAA//8DADlUTt0KAAAA + H4sIAEyP7mUAAzI0N9AzMbe0tDQ1NzI3NbY0MAMAAAD//wMAPZhnjRIAAAA= headers: Connection: - keep-alive @@ -53,7 +53,7 @@ interactions: Content-Type: - application/json Date: - - Thu, 23 Nov 2023 16:07:00 GMT + - Mon, 11 Mar 2024 04:57:48 GMT Transfer-Encoding: - chunked Vary: @@ -65,17 +65,17 @@ interactions: body: null headers: Accept: - - '*/*' + - application/json Accept-Encoding: - - gzip, deflate, br + - gzip, deflate Connection: - keep-alive method: GET - uri: https://api-v2.intrinio.com/companies/AAPL/data_point/marketcap?api_key=MOCK_API_KEY + uri: https://api-v2.intrinio.com/companies/AAPL/data_point/enterprisevalue?api_key=MOCK_API_KEY response: body: string: !!binary | - H4sIAKZ4X2UAAzI2MDI1sLQwNjMzNTfQMwAAAAD//wMAFx5PfA8AAAA= + H4sIAEyP7mUAAzIytTSxMDOxNDS3NDbQMwAAAAD//wMAN5ouRQ8AAAA= headers: Connection: - keep-alive @@ -84,7 +84,7 @@ interactions: Content-Type: - application/json Date: - - Thu, 23 Nov 2023 16:07:02 GMT + - Mon, 11 Mar 2024 04:57:48 GMT Transfer-Encoding: - chunked Vary: @@ -96,17 +96,17 @@ interactions: body: null headers: Accept: - - '*/*' + - application/json Accept-Encoding: - - gzip, deflate, br + - gzip, deflate Connection: - keep-alive method: GET - uri: https://api-v2.intrinio.com/companies/AAPL/data_point/52_week_high?api_key=MOCK_API_KEY + uri: https://api-v2.intrinio.com/companies/AAPL/data_point/earningsyield?api_key=MOCK_API_KEY response: body: string: !!binary | - H4sIAKd4X2UAAzK0NNczBwAAAP//AwA2jt5FBQAAAA== + H4sIAEyP7mUAAzLQMzA2tzQxAwAAAP//AwBHc0CvCAAAAA== headers: Connection: - keep-alive @@ -115,7 +115,7 @@ interactions: Content-Type: - application/json Date: - - Thu, 23 Nov 2023 16:07:03 GMT + - Mon, 11 Mar 2024 04:57:48 GMT Transfer-Encoding: - chunked Vary: @@ -127,17 +127,17 @@ interactions: body: null headers: Accept: - - '*/*' + - application/json Accept-Encoding: - - gzip, deflate, br + - gzip, deflate Connection: - keep-alive method: GET - uri: https://api-v2.intrinio.com/companies/AAPL/data_point/52_week_low?api_key=MOCK_API_KEY + uri: https://api-v2.intrinio.com/companies/AAPL/data_point/quickratio?api_key=MOCK_API_KEY response: body: string: !!binary | - H4sIAKh4X2UAAzI0MtYzsQAAAAD//wMAgelg5gYAAAA= + H4sIAEyP7mUAAzLQszS0NAMAAAD//wMAxBf9ogYAAAA= headers: Connection: - keep-alive @@ -146,7 +146,7 @@ interactions: Content-Type: - application/json Date: - - Thu, 23 Nov 2023 16:07:04 GMT + - Mon, 11 Mar 2024 04:57:48 GMT Transfer-Encoding: - chunked Vary: @@ -158,17 +158,17 @@ interactions: body: null headers: Accept: - - '*/*' + - application/json Accept-Encoding: - - gzip, deflate, br + - gzip, deflate Connection: - keep-alive method: GET - uri: https://api-v2.intrinio.com/companies/AAPL/data_point/dividendyield?api_key=MOCK_API_KEY + uri: https://api-v2.intrinio.com/companies/AAPL/data_point/average_daily_volume?api_key=MOCK_API_KEY response: body: string: !!binary | - H4sIAKl4X2UAAzLQMzAwtTA2BwAAAP//AwB6DW17CAAAAA== + H4sIAEyP7mUAAzIyNTEwMDKw1DMAAAAA//8DAE60GmsKAAAA headers: Connection: - keep-alive @@ -177,7 +177,7 @@ interactions: Content-Type: - application/json Date: - - Thu, 23 Nov 2023 16:07:05 GMT + - Mon, 11 Mar 2024 04:57:48 GMT Transfer-Encoding: - chunked Vary: @@ -189,9 +189,9 @@ interactions: body: null headers: Accept: - - '*/*' + - application/json Accept-Encoding: - - gzip, deflate, br + - gzip, deflate Connection: - keep-alive method: GET @@ -199,7 +199,7 @@ interactions: response: body: string: !!binary | - H4sIAKp4X2UAAzI21DO0sDACAAAA//8DAEvjlwgHAAAA + H4sIAEyP7mUAAzIy0zM2NTYBAAAA//8DAGH/oxsHAAAA headers: Connection: - keep-alive @@ -208,7 +208,968 @@ interactions: Content-Type: - application/json Date: - - Thu, 23 Nov 2023 16:07:06 GMT + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/beta?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLUMzIwMwUAAAD//wMAImTzoQYAAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/short_interest?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzIzNrQ0NTUx1DMAAAAA//8DAEWtD68KAAAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/dividendyield?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLQMzAwNTMyBgAAAP//AwAo1YVvCAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/debt?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzI0sDAwMYAAPQMAAAAA//8DAOm1FuQOAAAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/pricetobook?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzI21bOwsDQGAAAA//8DAADvEoAHAAAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/roe?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLUMzUxMrM0AQAAAP//AwAUliXmCAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/pricetorevenue?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLTs7A0sQQAAAD//wMA2KEa5wYAAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/ebitgrowth?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLQMzAxNjMyBwAAAP//AwAt6AO4CAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/basiceps?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLTMzEDAAAA//8DAOV1R7IEAAAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/pricetotangiblebook?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzI21bOwsDQGAAAA//8DAADvEoAHAAAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/epsgrowth?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLQMzA3NjE1AwAAAP//AwDC4GHECAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/marketcap?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzIyM7U0trS0NDS3NDbQMwAAAAD//wMAZzw/Hg8AAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/ltdebtandcapleases?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAA7I0NbCwMAADPQMAAAAA//8DAP5m3rQNAAAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/grossmargin?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLQMzE1MDKzAAAAAP//AwAsXJ3/CAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/fcffgrowth?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLQMzQwsDC2BAAAAP//AwDqA1dgCAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/roa?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLQM7KwMDI0BQAAAP//AwAVuRAlCAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/altmanzscore?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAA7LQM7M0tgQAAAD//wMAXCGOcgYAAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/totalcapital?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzK0MDI0MYAAPQMAAAAA//8DACVRrJUOAAAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/52_week_low?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzI0MdOzMAYAAAD//wMAl3qZZQYAAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/profitmargin?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLQMzIzNDM2AgAAAP//AwADF3NMCAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/netincomegrowth?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLQMzAzMDY2AQAAAP//AwCztq9WCAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/ebitdagrowth?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLQMzAxMLM0BQAAAP//AwAk/0ynCAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/freecashflow?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAA7I0tjQyMTQ1MTYz1LMAAAAA//8DAGA0abkNAAAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/revenuegrowth?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAA9I10DMwMDE3MgUAAAD//wMAfNMNzwkAAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/ebitda?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzI0srSwMDcAAz0DAAAAAP//AwDPIHHbDgAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/investedcapitalgrowth?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLWMzAwNzQyAgAAAP//AwBTPEs5CAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/adjweightedavebasicsharesos?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzI0NTWwNDczNjAw0DMAAAAA//8DAOsDp3QNAAAA + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/roic?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzI007M0tDAwNgQAAAD//wMAg08WCAkAAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/ebit?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzI0tDAxNjMAAz0DAAAAAP//AwAdfZ8YDgAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/52_week_high?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzK0tNQzNgcAAAD//wMAorPzIQYAAAA= + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 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/companies/AAPL/data_point/ebitmargin?api_key=MOCK_API_KEY + response: + body: + string: !!binary | + H4sIAEyP7mUAAzLQMzYwNzAzBgAAAP//AwC71vkjCAAAAA== + headers: + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Mon, 11 Mar 2024 04:57:48 GMT Transfer-Encoding: - chunked Vary: diff --git a/openbb_platform/providers/tmx/openbb_tmx/models/equity_historical.py b/openbb_platform/providers/tmx/openbb_tmx/models/equity_historical.py index 17531db149c..acc66c79449 100644 --- a/openbb_platform/providers/tmx/openbb_tmx/models/equity_historical.py +++ b/openbb_platform/providers/tmx/openbb_tmx/models/equity_historical.py @@ -2,9 +2,12 @@ # pylint: disable=unused-argument import asyncio -import warnings -from datetime import datetime +from datetime import ( + date as dateType, + datetime, +) from typing import Any, Dict, List, Literal, Optional, Union +from warnings import warn import pytz from openbb_core.provider.abstract.fetcher import Fetcher @@ -24,8 +27,6 @@ from openbb_tmx.utils.helpers import ( from pandas import DataFrame, to_datetime from pydantic import Field, field_validator -_warn = warnings.warn - class TmxEquityHistoricalQueryParams(EquityHistoricalQueryParams): """ @@ -112,6 +113,8 @@ class TmxEquityHistoricalData(EquityHistoricalData): @classmethod def date_validate(cls, v): # pylint: disable=W0221 """Validate the datetime format.""" + if isinstance(v, (datetime, dateType)): + return v if v.hour != 0 and v.minute != 0 and v.second != 0 else v.date() # type: ignore try: dt = datetime.strptime(v, "%Y-%m-%d %H:%M:%S%z") return dt.astimezone(pytz.timezone("America/New_York")) @@ -133,7 +136,7 @@ class TmxEquityHistoricalFetcher( and adjustment != "splits_only" and params.get("interval") not in ["day", "1d"] ): - _warn("Adjustment parameter is only available for daily data.") + warn("Adjustment parameter is only available for daily data.") return TmxEquityHistoricalQueryParams(**params) @staticmethod @@ -179,7 +182,7 @@ class TmxEquityHistoricalFetcher( results.extend(data) if data == []: - _warn(f"No data found for {symbol}.") + warn(f"No data found for {symbol}.") return results diff --git a/openbb_platform/providers/tmx/pyproject.toml b/openbb_platform/providers/tmx/pyproject.toml index c0e9e95f30a..bb09185b99e 100644 --- a/openbb_platform/providers/tmx/pyproject.toml +++ b/openbb_platform/providers/tmx/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "openbb-tmx" -version = "1.0.0" +version = "1.0.0b" description = "Unofficial TMX data provider extension for the OpenBB Platform - Public Canadian markets data for Python and Fast API." authors = ["OpenBB "] readme = "README.md" diff --git a/openbb_platform/providers/tradier/openbb_tradier/__init__.py b/openbb_platform/providers/tradier/openbb_tradier/__init__.py index 625d489b276..fea8c5e819a 100644 --- a/openbb_platform/providers/tradier/openbb_tradier/__init__.py +++ b/openbb_platform/providers/tradier/openbb_tradier/__init__.py @@ -20,6 +20,7 @@ tradier_provider = Provider( ], # account_type is either "sandbox" or "live" fetcher_dict={ "EquityHistorical": TradierEquityHistoricalFetcher, + "EtfHistorical": TradierEquityHistoricalFetcher, "EquityQuote": TradierEquityQuoteFetcher, "EquitySearch": TradierEquitySearchFetcher, "OptionsChains": TradierOptionsChainsFetcher, diff --git a/openbb_platform/providers/tradier/pyproject.toml b/openbb_platform/providers/tradier/pyproject.toml index 1e4499a6490..2c052e91430 100644 --- a/openbb_platform/providers/tradier/pyproject.toml +++ b/openbb_platform/providers/tradier/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "openbb-tradier" -version = "1.0.0" +version = "1.0.0b" description = "Tradier Provider Extension for the OpenBB Platform" authors = ["OpenBB "] readme = "README.md" diff --git a/openbb_platform/pyproject.toml b/openbb_platform/pyproject.toml index 02ca57505bd..af4ec64b10a 100644 --- a/openbb_platform/pyproject.toml +++ b/openbb_platform/pyproject.toml @@ -45,8 +45,8 @@ openbb-government-us = { version = "^1.1.2", optional = true } openbb-nasdaq = { version = "^1.1.3", optional = true } openbb-seeking-alpha = { version = "^1.1.2", optional = true } openbb-stockgrid = { version = "^1.1.2", optional = true } -openbb-tmx = { version = "^1.0.0", optional = true } -openbb-tradier = { version = "^1.0.0", optional = true } +openbb-tmx = { version = "^1.0.0b", optional = true } +openbb-tradier = { version = "^1.0.0b", optional = true } openbb-wsj = { version = "^1.1.2", optional = true } openbb-charting = { version = "^2.0.0", optional = true }