Skip to content

Commit

Permalink
feature/yfinance-multi-ticker: Adds support to openbb-yfinance for mu…
Browse files Browse the repository at this point in the history
…lti-ticker download. (#5845)

* yfinance multi-ticker support

* multi-ticker support for market indices

* crypto multi-ticker support

* recapture tests

* yfinance cache and tests

* currency historical multi-ticker support

* style things

* black

* missed a values

---------

Co-authored-by: James Maslek <[email protected]>
  • Loading branch information
deeleeramone and jmaslek authored Dec 7, 2023
1 parent 1604c78 commit d951dc0
Show file tree
Hide file tree
Showing 7 changed files with 2,594 additions and 2,319 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def transform_query(params: Dict[str, Any]) -> YFinanceCryptoHistoricalQueryPara
if params.get("end_date") is None:
transformed_params["end_date"] = now

return YFinanceCryptoHistoricalQueryParams(**params)
return YFinanceCryptoHistoricalQueryParams(**transformed_params)

@staticmethod
def extract_data(
Expand All @@ -72,12 +72,20 @@ def extract_data(
**kwargs: Any,
) -> List[Dict]:
"""Return the raw data from the Yahoo Finance endpoint."""
if "-" not in query.symbol:
position = len(query.symbol) - 3
query.symbol = query.symbol[:position] + "-" + query.symbol[position:]

tickers = query.symbol.split(",")
new_tickers = []
for ticker in tickers:
if "-" not in ticker:
new_ticker = ticker[:-3] + "-" + ticker[-3:]
if "-" in ticker:
new_ticker = ticker
new_tickers.append(new_ticker)

symbols = ",".join(new_tickers)

data = yf_download(
query.symbol,
symbols,
start=query.start_date,
end=query.end_date,
interval=query.interval,
Expand All @@ -99,12 +107,9 @@ def extract_data(
data.set_index("date", inplace=True)
data.index = to_datetime(data.index)

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.reset_index(inplace=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ def transform_query(
params: Dict[str, Any]
) -> YFinanceCurrencyHistoricalQueryParams:
"""Transform the query."""

transformed_params = params
transformed_params["symbol"] = (
f"{transformed_params['symbol'].upper()}=X"
if "=X" not in transformed_params["symbol"].upper()
else transformed_params["symbol"].upper()
)
symbols = params["symbol"].split(",")
new_symbols = [
f"{s.upper()}=X" if "=X" not in s.upper() else s.upper() for s in symbols
]
transformed_params["symbol"] = ",".join(new_symbols)

now = datetime.now().date()

if params.get("start_date") is None:
Expand Down Expand Up @@ -94,12 +96,9 @@ def extract_data(
data.set_index("date", inplace=True)
data.index = to_datetime(data.index)

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.reset_index(inplace=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,31 @@ def transform_query(params: Dict[str, Any]) -> YFinanceMarketIndicesQueryParams:
if params.get("end_date") is None:
transformed_params["end_date"] = now

tickers = params.get("symbol").lower().split(",")

new_tickers = []
for ticker in tickers:
_ticker = ""
indices = pd.DataFrame(INDICES).transpose().reset_index()
indices.columns = ["code", "name", "symbol"]

if ticker in indices["code"].values:
_ticker = indices[indices["code"] == ticker]["symbol"].values[0]

if ticker.title() in indices["name"].values:
_ticker = indices[indices["name"] == ticker.title()]["symbol"].values[0]

if "^" + ticker.upper() in indices["symbol"].values:
_ticker = "^" + ticker.upper()

if ticker.upper() in indices["symbol"].values:
_ticker = ticker.upper()

if _ticker != "":
new_tickers.append(_ticker)

transformed_params["symbol"] = ",".join(new_tickers)

return YFinanceMarketIndicesQueryParams(**params)

@staticmethod
Expand All @@ -67,21 +92,9 @@ def extract_data(
**kwargs: Any,
) -> List[dict]:
"""Return the raw data from the Yahoo Finance endpoint."""
symbol = query.symbol.lower()
indices = pd.DataFrame(INDICES).transpose().reset_index()
indices.columns = ["code", "name", "symbol"]

if symbol in indices["code"].to_list():
symbol = indices[indices["code"] == symbol]["symbol"].values[0]

if symbol.title() in indices["name"].to_list():
symbol = indices[indices["name"] == symbol.title()]["symbol"].values[0]

if "^" + symbol.upper() in indices["symbol"].to_list():
symbol = "^" + symbol.upper()

data = yf_download(
symbol=symbol,
symbol=query.symbol,
start_date=query.start_date,
end_date=query.end_date,
interval=query.interval,
Expand All @@ -104,12 +117,9 @@ def extract_data(
data.set_index("date", inplace=True)
data.index = to_datetime(data.index)

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.reset_index(inplace=True)
Expand Down
59 changes: 38 additions & 21 deletions openbb_platform/providers/yfinance/openbb_yfinance/utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import pandas as pd
import yfinance as yf
from dateutil.relativedelta import relativedelta
from openbb_core.provider.utils.errors import EmptyDataError
from openbb_yfinance.utils.references import MONTHS


Expand Down Expand Up @@ -91,7 +92,7 @@ def yf_download(
keepna: bool = False,
repair: bool = False,
rounding: bool = False,
group_by: Literal["symbol", "column"] = "column",
group_by: Literal["symbol", "column"] = "symbol",
adjusted: bool = False,
**kwargs: Any,
) -> pd.DataFrame:
Expand All @@ -115,22 +116,40 @@ def yf_download(
if adjusted is False:
kwargs = dict(auto_adjust=False, back_adjust=False)

data = yf.download(
tickers=symbol,
start=_start_date,
end=None,
interval=interval,
period=period,
prepost=prepost,
actions=actions,
progress=progress,
ignore_tz=ignore_tz,
keepna=keepna,
repair=repair,
rounding=rounding,
group_by=group_by,
**kwargs,
)
try:
data = yf.download(
tickers=symbol,
start=_start_date,
end=None,
interval=interval,
period=period,
prepost=prepost,
actions=actions,
progress=progress,
ignore_tz=ignore_tz,
keepna=keepna,
repair=repair,
rounding=rounding,
group_by=group_by,
**kwargs,
)
except ValueError:
raise EmptyDataError()

tickers = symbol.split(",")
if len(tickers) > 1:
_data = pd.DataFrame()
for ticker in tickers:
temp = data[ticker].copy().dropna(how="all")
for i in temp.index:
temp.loc[i, "symbol"] = ticker
temp = temp.reset_index().rename(
columns={"Date": "date", "Datetime": "date"}
)
_data = pd.concat([_data, temp])
_data = _data.set_index(["date", "symbol"]).sort_index()
data = _data

if not data.empty:
data = data.reset_index()
data = data.rename(columns={"Date": "date", "Datetime": "date"})
Expand Down Expand Up @@ -159,11 +178,9 @@ def yf_download(
"5y",
"10y",
]:
data["date"] = (
data["date"].dt.tz_localize(None).dt.strftime("%Y-%m-%d %H:%M:%S")
)
data["date"] = data["date"].dt.strftime("%Y-%m-%d %H:%M:%S")
if interval not in ["1m", "2m", "5m", "15m", "30m", "90m", "60m", "1h"]:
data["date"] = data["date"].dt.tz_localize(None).dt.strftime("%Y-%m-%d")
data["date"] = data["date"].dt.strftime("%Y-%m-%d")

if adjusted is False:
data = data.drop(columns=["Adj Close"])
Expand Down
Loading

0 comments on commit d951dc0

Please sign in to comment.