Skip to content

Commit

Permalink
fast_info: Fix previousClose & yearChange
Browse files Browse the repository at this point in the history
  • Loading branch information
ValueRaider committed Jan 30, 2023
1 parent 5b0feb3 commit eb749c2
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 13 deletions.
20 changes: 14 additions & 6 deletions tests/ticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,7 @@ def setUp(self):
self.symbols += ["ESLT.TA", "BP.L", "GOOGL"]
self.symbols.append("QCSTIX") # good for testing, doesn't trade
self.symbols += ["BTC-USD", "IWO", "VFINX", "^GSPC"]
self.symbols += ["SOKE.IS", "ADS.DE"] # detected bugs
self.tickers = [yf.Ticker(s, session=self.session) for s in self.symbols]

def tearDown(self):
Expand Down Expand Up @@ -776,12 +777,19 @@ def test_fast_info(self):
if k in ["market_cap","marketCap"] and ticker.fast_info["currency"] in ["GBp", "ILA"]:
# Adjust for currency to match Yahoo:
test *= 0.01
if correct is None:
self.assertTrue(test is None or (not np.isnan(test)), f"{k}: {test} must be None or real value because correct={correct}")
elif isinstance(test, float) or isinstance(correct, int):
self.assertTrue(np.isclose(test, correct, rtol=rtol), f"{k}: {test} != {correct}")
else:
self.assertEqual(test, correct, f"{k}: {test} != {correct}")
try:
if correct is None:
self.assertTrue(test is None or (not np.isnan(test)), f"{k}: {test} must be None or real value because correct={correct}")
elif isinstance(test, float) or isinstance(correct, int):
self.assertTrue(np.isclose(test, correct, rtol=rtol), f"{ticker.ticker} {k}: {test} != {correct}")
else:
self.assertEqual(test, correct, f"{k}: {test} != {correct}")
except:
if k in ["regularMarketPreviousClose"] and ticker.ticker in ["ADS.DE"]:
# Yahoo is wrong, is returning post-market close not regular
continue
else:
raise



Expand Down
37 changes: 30 additions & 7 deletions yfinance/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ def __init__(self, tickerBaseObject):
self._tkr = tickerBaseObject

self._prices_1y = None
self._prices_1wk_1h_prepost = None
self._prices_1wk_1h_reg = None
self._md = None

self._currency = None
Expand All @@ -71,7 +73,6 @@ def __init__(self, tickerBaseObject):
self._last_volume = None

self._prev_close = None

self._reg_prev_close = None

self._50d_day_average = None
Expand Down Expand Up @@ -161,12 +162,23 @@ def _get_1y_prices(self, fullDaysOnly=False):

dnow = pd.Timestamp.utcnow().tz_convert(self.timezone).date()
d1 = dnow
d0 = (d1 + _datetime.timedelta(days=1)) - utils._interval_to_timedelta("1y")
if fullDaysOnly and self._exchange_open_now():
# Exclude today
d1 -= utils._interval_to_timedelta("1d")
d0 = d1 - utils._interval_to_timedelta("1y")
# d0 = d1 - utils._interval_to_timedelta("1y")
return self._prices_1y.loc[str(d0):str(d1)]

def _get_1wk_1h_prepost_prices(self):
if self._prices_1wk_1h_prepost is None:
self._prices_1wk_1h_prepost = self._tkr.history(period="1wk", interval="1h", auto_adjust=False, prepost=True, debug=False)
return self._prices_1wk_1h_prepost

def _get_1wk_1h_reg_prices(self):
if self._prices_1wk_1h_reg is None:
self._prices_1wk_1h_reg = self._tkr.history(period="1wk", interval="1h", auto_adjust=False, prepost=False, debug=False)
return self._prices_1wk_1h_reg

def _get_exchange_metadata(self):
if self._md is not None:
return self._md
Expand Down Expand Up @@ -255,8 +267,9 @@ def last_price(self):
def previous_close(self):
if self._prev_close is not None:
return self._prev_close
prices = self._get_1y_prices()
if prices.empty:
prices = self._get_1wk_1h_prepost_prices()
prices = prices[["Close"]].groupby(prices.index.date).last()
if prices.shape[0] < 2:
# Very few symbols have previousClose despite no
# no trading data. E.g. 'QCSTIX'.
# So fallback to original info[] if available.
Expand All @@ -272,7 +285,12 @@ def regular_market_previous_close(self):
if self._reg_prev_close is not None:
return self._reg_prev_close
prices = self._get_1y_prices()
if prices.empty:
if prices.shape[0] == 1:
# Tiny % of tickers don't return daily history before last trading day,
# so backup option is hourly history:
prices = self._get_1wk_1h_reg_prices()
prices = prices[["Close"]].groupby(prices.index.date).last()
if prices.shape[0] < 2:
# Very few symbols have regularMarketPreviousClose despite no
# no trading data. E.g. 'QCSTIX'.
# So fallback to original info[] if available.
Expand Down Expand Up @@ -391,6 +409,8 @@ def year_high(self):
return self._year_high

prices = self._get_1y_prices(fullDaysOnly=True)
if prices.empty:
prices = self._get_1y_prices(fullDaysOnly=False)
self._year_high = float(prices["High"].max())
return self._year_high

Expand All @@ -400,6 +420,8 @@ def year_low(self):
return self._year_low

prices = self._get_1y_prices(fullDaysOnly=True)
if prices.empty:
prices = self._get_1y_prices(fullDaysOnly=False)
self._year_low = float(prices["Low"].min())
return self._year_low

Expand All @@ -409,8 +431,9 @@ def year_change(self):
return self._year_change

prices = self._get_1y_prices(fullDaysOnly=True)
self._year_change = (prices["Close"].iloc[-1] - prices["Close"].iloc[0]) / prices["Close"].iloc[0]
self._year_change = float(self._year_change)
if prices.shape[0] >= 2:
self._year_change = (prices["Close"].iloc[-1] - prices["Close"].iloc[0]) / prices["Close"].iloc[0]
self._year_change = float(self._year_change)
return self._year_change

@property
Expand Down

0 comments on commit eb749c2

Please sign in to comment.