diff --git a/openbb_platform/extensions/derivatives/integration/test_derivatives_api.py b/openbb_platform/extensions/derivatives/integration/test_derivatives_api.py index 421cb41c3124..9132ab861382 100644 --- a/openbb_platform/extensions/derivatives/integration/test_derivatives_api.py +++ b/openbb_platform/extensions/derivatives/integration/test_derivatives_api.py @@ -60,27 +60,14 @@ def test_derivatives_options_unusual(params, headers): @parametrize( "params", [ - ( - { - "provider": "yfinance", - "symbol": "ES", - "start_date": "2023-01-01", - "end_date": "2023-06-06", - "expiration": "2024-06", - } - ), ( { "provider": "yfinance", "interval": "1d", - "period": "max", - "prepost": True, - "adjust": True, - "back_adjust": True, - "symbol": "ES", + "symbol": "CL,BZ", "start_date": "2023-01-01", "end_date": "2023-06-06", - "expiration": "2024-06", + "expiration": "2025-12", } ), ], diff --git a/openbb_platform/extensions/derivatives/integration/test_derivatives_python.py b/openbb_platform/extensions/derivatives/integration/test_derivatives_python.py index 02d0ee4bc782..ed967cbc5cc8 100644 --- a/openbb_platform/extensions/derivatives/integration/test_derivatives_python.py +++ b/openbb_platform/extensions/derivatives/integration/test_derivatives_python.py @@ -52,26 +52,14 @@ def test_derivatives_options_unusual(params, obb): @parametrize( "params", [ - ( - { - "symbol": "ES", - "start_date": "2023-01-01", - "end_date": "2023-06-06", - "expiration": "2024-06", - } - ), ( { "provider": "yfinance", "interval": "1d", - "period": "max", - "prepost": True, - "adjust": True, - "back_adjust": True, - "symbol": "ES", - "start_date": "2023-05-05", + "symbol": "CL,BZ", + "start_date": "2023-01-01", "end_date": "2023-06-06", - "expiration": "2024-06", + "expiration": "2025-12", } ), ], diff --git a/openbb_platform/providers/yfinance/openbb_yfinance/models/equity_historical.py b/openbb_platform/providers/yfinance/openbb_yfinance/models/equity_historical.py index b56c0ffd60c5..f42e043ec393 100644 --- a/openbb_platform/providers/yfinance/openbb_yfinance/models/equity_historical.py +++ b/openbb_platform/providers/yfinance/openbb_yfinance/models/equity_historical.py @@ -1,4 +1,5 @@ """Yahoo Finance Equity Historical Price Model.""" +# pylint: disable=unused-argument # ruff: noqa: SIM105 from datetime import datetime, timedelta @@ -112,7 +113,9 @@ def extract_data( query.interval = "1mo" elif query.interval == "3M": query.interval = "3mo" - + kwargs = ( + {"auto_adjust": True, "back_adjust": True} if query.adjusted is True else {} + ) # pylint: disable=protected-access data = yf_download( symbol=query.symbol, @@ -129,6 +132,7 @@ def extract_data( rounding=query._rounding, group_by=query._group_by, adjusted=query.adjusted, + **kwargs, ) if data.empty: diff --git a/openbb_platform/providers/yfinance/openbb_yfinance/models/futures_historical.py b/openbb_platform/providers/yfinance/openbb_yfinance/models/futures_historical.py index 72213843e69c..3a877ef992bb 100644 --- a/openbb_platform/providers/yfinance/openbb_yfinance/models/futures_historical.py +++ b/openbb_platform/providers/yfinance/openbb_yfinance/models/futures_historical.py @@ -1,7 +1,7 @@ """Yahoo Finance Futures Historical Price Model.""" +# pylint: disable=unused-argument # ruff: noqa: SIM105 - from datetime import datetime, timedelta from typing import Any, Dict, List, Optional @@ -13,11 +13,10 @@ ) from openbb_core.provider.utils.descriptions import QUERY_DESCRIPTIONS from openbb_core.provider.utils.errors import EmptyDataError -from openbb_yfinance.utils.helpers import get_futures_data +from openbb_yfinance.utils.helpers import get_futures_data, yf_download from openbb_yfinance.utils.references import INTERVALS, MONTHS, PERIODS from pandas import Timestamp, to_datetime from pydantic import Field, field_validator -from yfinance import Ticker class YFinanceFuturesHistoricalQueryParams(FuturesHistoricalQueryParams): @@ -30,13 +29,6 @@ class YFinanceFuturesHistoricalQueryParams(FuturesHistoricalQueryParams): period: Optional[PERIODS] = Field( default=None, description=QUERY_DESCRIPTIONS.get("period", "") ) - prepost: bool = Field( - default=False, description="Include Pre and Post market data." - ) - adjust: bool = Field(default=True, description="Adjust all the data automatically.") - back_adjust: bool = Field( - default=False, description="Back-adjusted data to mimic true historical prices." - ) class YFinanceFuturesHistoricalData(FuturesHistoricalData): @@ -62,94 +54,88 @@ class YFinanceFuturesHistoricalFetcher( @staticmethod def transform_query(params: Dict[str, Any]) -> YFinanceFuturesHistoricalQueryParams: """Transform the query. Setting the start and end dates for a 1 year period.""" - if params.get("period") is None: - transformed_params = params - - now = datetime.now().date() - if params.get("start_date") is None: - transformed_params["start_date"] = now - relativedelta(years=1) - - if params.get("end_date") is None: - transformed_params["end_date"] = now + transformed_params = params.copy() + + symbols = params["symbol"].split(",") + new_symbols = [] + futures_data = get_futures_data() + for symbol in symbols: + if params.get("expiration"): + expiry_date = datetime.strptime( + transformed_params["expiration"], "%Y-%m" + ) + if "." not in symbol: + exchange = futures_data[futures_data["Ticker"] == symbol][ + "Exchange" + ].values[0] + new_symbol = ( + f"{symbol}{MONTHS[expiry_date.month]}{str(expiry_date.year)[-2:]}.{exchange}" + if "." not in symbol + else symbol + ) + new_symbols.append(new_symbol) + else: + new_symbols.append(symbol) + formatted_symbols = [ + f"{s.upper()}=F" if "." not in s.upper() else s.upper() for s in new_symbols + ] + transformed_params["symbol"] = ",".join(formatted_symbols) + + now = datetime.now() + + if params.get("start_date") is None: + transformed_params["start_date"] = (now - relativedelta(years=1)).strftime( + "%Y-%m-%d" + ) - else: - transformed_params = params + if params.get("end_date") is None: + transformed_params["end_date"] = now.strftime("%Y-%m-%d") return YFinanceFuturesHistoricalQueryParams(**transformed_params) @staticmethod def extract_data( - query: YFinanceFuturesHistoricalQueryParams, # pylint: disable=unused-argument + query: YFinanceFuturesHistoricalQueryParams, credentials: Optional[Dict[str, str]], **kwargs: Any, - ) -> dict: + ) -> List[Dict]: """Return the raw data from the Yahoo Finance endpoint.""" - symbol = "" - - if query.expiration: - expiry_date = datetime.strptime(query.expiration, "%Y-%m") - futures_data = get_futures_data() - exchange = futures_data[futures_data["Ticker"] == query.symbol][ - "Exchange" - ].values[0] - symbol = f"{query.symbol}{MONTHS[expiry_date.month]}{str(expiry_date.year)[-2:]}.{exchange}" - - query_symbol = symbol if symbol else f"{query.symbol}=F" - - if query.period: - data = Ticker(query_symbol).history( - interval=query.interval, - period=query.period, - prepost=query.prepost, - auto_adjust=query.adjust, - back_adjust=query.back_adjust, - actions=False, - raise_errors=True, - ) - else: - data = Ticker(query_symbol).history( - interval=query.interval, - start=query.start_date, - end=query.end_date, - prepost=query.prepost, - auto_adjust=query.adjust, - back_adjust=query.back_adjust, - actions=False, - raise_errors=True, - ) + data = yf_download( + query.symbol, + start=query.start_date, + end=query.end_date, + interval=query.interval, # type: ignore + prepost=True, + auto_adjust=False, + actions=False, + ) if data.empty: raise EmptyDataError() - query.end_date = ( - datetime.now().date() if query.end_date is None else query.end_date - ) days = ( 1 if query.interval in ["1m", "2m", "5m", "15m", "30m", "60m", "1h", "90m"] else 0 ) + if "date" in data.columns: + data.set_index("date", inplace=True) + data.index = to_datetime(data.index) if query.start_date: - data.index = to_datetime(data.index).tz_convert(None) - - start_date_dt = datetime.combine(query.start_date, datetime.min.time()) - end_date_dt = datetime.combine(query.end_date, datetime.min.time()) - data = data[ - (data.index >= start_date_dt + timedelta(days=days)) - & (data.index <= end_date_dt) + (data.index >= to_datetime(query.start_date)) + & (data.index <= to_datetime(query.end_date + timedelta(days=days))) ] - data = data.reset_index().rename( - columns={"index": "Date", "Datetime": "Date"}, errors="ignore" - ) - data.columns = data.columns.str.lower() + data.reset_index(inplace=True) + data.rename(columns={"index": "date"}, inplace=True) + return data.to_dict("records") @staticmethod def transform_data( - query: YFinanceFuturesHistoricalQueryParams, # pylint: disable=unused-argument - data: dict, + query: YFinanceFuturesHistoricalQueryParams, + data: List[Dict], **kwargs: Any, ) -> List[YFinanceFuturesHistoricalData]: """Transform the data to the standard format.""" diff --git a/openbb_platform/providers/yfinance/openbb_yfinance/utils/futures.csv b/openbb_platform/providers/yfinance/openbb_yfinance/utils/futures.csv index 8dc4c5a86fd6..91907e511532 100644 --- a/openbb_platform/providers/yfinance/openbb_yfinance/utils/futures.csv +++ b/openbb_platform/providers/yfinance/openbb_yfinance/utils/futures.csv @@ -183,6 +183,7 @@ SF,Sugar No. 16 Futures,NYB,agriculture SB,Sugar No. 11 Futures,NYB,agriculture OJ,Orange Juice Futures,NYB,agriculture NG,Natural Gas Futures,NYM,hydrocarbon +HO,Heating Oil Futures,NYM,hydrocarbon RB,RBOB Gasoline Futures,NYM,hydrocarbon CL,WTI Crude Oil Futures,NYM,hydrocarbon TRM,ICE TRY/USD Futures,NYB,currency diff --git a/openbb_platform/providers/yfinance/openbb_yfinance/utils/helpers.py b/openbb_platform/providers/yfinance/openbb_yfinance/utils/helpers.py index d89c08478274..a46d6afb2069 100644 --- a/openbb_platform/providers/yfinance/openbb_yfinance/utils/helpers.py +++ b/openbb_platform/providers/yfinance/openbb_yfinance/utils/helpers.py @@ -1,5 +1,5 @@ """Yahoo Finance helpers module.""" - +# pylint: disable=unused-argument from datetime import ( date as dateType, datetime, @@ -134,8 +134,8 @@ def yf_download( threads=False, **kwargs, ) - except ValueError: - raise EmptyDataError() + except ValueError as exc: + raise EmptyDataError() from exc tickers = symbol.split(",") if len(tickers) > 1: @@ -148,7 +148,8 @@ def yf_download( columns={"Date": "date", "Datetime": "date"} ) _data = pd.concat([_data, temp]) - _data = _data.set_index(["date", "symbol"]).sort_index() + index_keys = ["date", "symbol"] if "symbol" in _data.columns else ["date"] + _data = _data.set_index(index_keys).sort_index() data = _data if not data.empty: data = data.reset_index()