I am trying to write basic code that continues when a valid ticker (stock symbol) is input and restarts if the ticker is invalid. I thought I would try a while True / try / except
method. This works fine with valid tickers but does not loop when an invalid ticker is input - rather, the error is displayed and the code continues anyways.
Code:
while True:
tickerInput = input("What ticker would you like to test? Please do not use quotes. \n")
ticker = tickerInput.upper()
try:
def closing_price(ticker):
Asset = pd.DataFrame(yf.download(ticker, start=startDate, end=endDate)['Adj Close'])
return Asset
closing_price(ticker).head()
break
except:
print("Invalid ticker! Please try again.")
This is what a valid ticker looks like:
What ticker would you like to test? Please do not use quotes.
spy
[*********************100%***********************] 1 of 1 completed
What type of moving average would you like to test?
[1] Exponential
[2] Simple
And this is what happens when an invalid ticker is input:
What ticker would you like to test? Please do not use quotes.
fake
[*********************100%***********************] 1 of 1 completed
1 Failed download:
['FAKE']: YFTzMissingError('$%ticker%: possibly delisted; no timezone found')
What type of moving average would you like to test?
[1] Exponential
[2] Simple
Unfortunately yfinance
doesn't trigger errors if it can't find the ticker. Instead it is listing all errors in logs. Workaround is to create custom YFinance log handler and raise errors when processing missing ticker logs.
import pandas as pd
import yfinance as yf
import logging
import re
class YFMissingError(Exception):
"""
Basic exception that gives shows an error if a ticker with the given name is missing.
"""
pass
class ErrorCatcher(logging.Handler):
"""
Additional processing of logs from YFinance
"""
def emit(self, record: logging.LogRecord) -> None:
msg = record.getMessage()
# search for wrong ticker error
if "YFTzMissingError" in msg:
# Extract ticker name from the log message
# Example of input:
# msg = "['FAKE']: YFTzMissingError('$%ticker%: possibly delisted; no timezone found')"
matches = re.search("\['(.*?)'\]", msg)
ticker_name = matches.group(1)
# finally raise an error
raise YFMissingError(f"Missing ticker {ticker_name}")
# And finally add our logging handler to default YF handlers
logger = yf.utils.get_yf_logger()
yf_handler = ErrorCatcher(logging.ERROR)
logger.addHandler(yf_handler)
while True:
tickerInput = input("What ticker would you like to test? Please do not use quotes. \n")
ticker = tickerInput.upper()
try:
def closing_price(ticker):
Asset = pd.DataFrame(yf.download(ticker,
start='2020-01-01',
end='2021-01-01')['Adj Close'])
return Asset
closing_price(ticker).head()
break
except YFMissingError as err:
# ticker with given name is missing
raise err
except:
print("Other error during processing")