Skip to content

Commit

Permalink
Improve handling delisted tickers
Browse files Browse the repository at this point in the history
  • Loading branch information
ValueRaider committed Nov 3, 2022
1 parent 66af308 commit d261237
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 11 deletions.
66 changes: 62 additions & 4 deletions test_yfinance.py
Expand Up @@ -15,22 +15,52 @@

import yfinance as yf
import unittest
import datetime

session = None
import requests_cache ; session = requests_cache.CachedSession("yfinance.cache", expire_after=24*60*60)

symbols = ['MSFT', 'IWO', 'VFINX', '^GSPC', 'BTC-USD']
tickers = [yf.Ticker(symbol) for symbol in symbols]
tickers = [yf.Ticker(symbol, session=session) for symbol in symbols]
delisted_symbols = ["BRK.B", "SDLP"]
delisted_tickers = [yf.Ticker(symbol, session=session) for symbol in delisted_symbols]


class TestTicker(unittest.TestCase):
def setUp(self):
d_today = datetime.date.today()
d_today -= datetime.timedelta(days=30)
self.start_d = datetime.date(d_today.year, d_today.month, 1)

def test_info_history(self):
# always should have info and history for valid symbols
for ticker in tickers:
# always should have info and history for valid symbols
assert(ticker.info is not None and ticker.info != {})
history = ticker.history(period="max")
history = ticker.history(period="1mo")
assert(history.empty is False and history is not None)
histories = yf.download(symbols, period="1mo", session=session)
assert(histories.empty is False and histories is not None)

histories = yf.download(symbols, period="1yr")
for ticker in tickers:
assert(ticker.info is not None and ticker.info != {})
history = ticker.history(start=self.start_d)
assert(history.empty is False and history is not None)
histories = yf.download(symbols, start=self.start_d, session=session)
assert(histories.empty is False and histories is not None)

def test_info_history_nofail(self):
# should not throw Exception for delisted tickers, just print a message
for ticker in delisted_tickers:
history = ticker.history(period="1mo")
histories = yf.download(delisted_symbols, period="1mo", session=session)
histories = yf.download(delisted_symbols[0], period="1mo", session=session)
histories = yf.download(delisted_symbols[1], period="1mo")#, session=session)
for ticker in delisted_tickers:
history = ticker.history(start=self.start_d)
histories = yf.download(delisted_symbols, start=self.start_d, session=session)
histories = yf.download(delisted_symbols[0], start=self.start_d, session=session)
histories = yf.download(delisted_symbols[1], start=self.start_d, session=session)

def test_attributes(self):
for ticker in tickers:
ticker.isin
Expand Down Expand Up @@ -58,6 +88,34 @@ def test_attributes(self):
ticker.earnings_history
ticker.earnings_dates

def test_attributes_nofail(self):
# should not throw Exception for delisted tickers, just print a message
for ticker in delisted_tickers:
ticker.isin
ticker.major_holders
ticker.institutional_holders
ticker.mutualfund_holders
ticker.dividends
ticker.splits
ticker.actions
ticker.info
ticker.calendar
ticker.recommendations
ticker.earnings
ticker.quarterly_earnings
ticker.financials
ticker.quarterly_financials
ticker.balance_sheet
ticker.quarterly_balance_sheet
ticker.cashflow
ticker.quarterly_cashflow
ticker.sustainability
ticker.options
ticker.news
ticker.shares
ticker.earnings_history
ticker.earnings_dates

def test_holders(self):
for ticker in tickers:
assert(ticker.info is not None and ticker.info != {})
Expand Down
21 changes: 14 additions & 7 deletions yfinance/base.py
Expand Up @@ -349,11 +349,12 @@ def _get_ticker_tz(self, debug_mode, proxy, timeout):
if tkr_tz is None:
tkr_tz = self._fetch_ticker_tz(debug_mode, proxy, timeout)

try:
utils.cache_store_tkr_tz(self.ticker, tkr_tz)
except PermissionError:
# System probably read-only, so cannot cache
pass
if tkr_tz is not None:
try:
utils.cache_store_tkr_tz(self.ticker, tkr_tz)
except PermissionError:
# System probably read-only, so cannot cache
pass

self._tz = tkr_tz
return tkr_tz
Expand Down Expand Up @@ -858,6 +859,10 @@ def get_isin(self, proxy=None):
self.get_info(proxy=proxy)
if "shortName" in self._info:
q = self._info['shortName']
if q is None:
err_msg = "Cannot map to ISIN code, symbol may be delisted"
print('- %s: %s' % (self.ticker, err_msg))
return None

url = 'https://markets.businessinsider.com/ajax/' \
'SearchController_Suggest?max_results=25&query=%s' \
Expand Down Expand Up @@ -956,8 +961,10 @@ def get_earnings_dates(self, proxy=None):
dates = _pd.concat([dates, data], axis=0)
page_offset += page_size

if dates is None:
raise Exception("No data found, symbol may be delisted")
if (dates is None) or dates.shape[0]==0:
err_msg = "No earnings dates found, symbol may be delisted"
print('- %s: %s' % (self.ticker, err_msg))
return None
dates = dates.reset_index(drop=True)

# Drop redundant columns
Expand Down

0 comments on commit d261237

Please sign in to comment.