pythontry-exceptyfinance

Yahoo Finance YFTzMissingError not being recognized in try except


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

Solution

  • 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")