I am working on a stock analysis application in Python and I have the need to determine whether an input ticker symbol is an Exchange Traded Fund (ETF) or not. First I need to determine if the given ticker is even valid. Second I need to determine if it is an ETF or a company stock. So, I have some simple functions to request info from Yahoo! Finance (modified from ystockquote)
from urllib.request import Request, urlopen def _yahoo_request(symbol, tag): """ Retrieve stock data from Yahoo! Finance. Args: symbol (str): Stock ticker symbol for company of interest. tag (str): Yahoo! finance tag for a given property. Returns: str: The property requested. """ url = 'http://finance.yahoo.com/d/quotes.csv?s=%s&f=%s' % (symbol, tag) request = Request(url) response = urlopen(request) content = response.read().decode().strip().strip('"') return content
So to determine if a stock is valid, I check to see if it's name exists in Yahoo! Finance. Getting the name:
def get_name(symbol): """ Retrieve company name for given ticker. Args: symbol (str): Ticker symbol for a given company's stock. Returns: str: The company name. Returns 'N/A' if ticker not in Yahoo! Finance. """ return _yahoo_request(symbol, 'n')
and checking if it is a valid ticker:
def valid_ticker(ticker): """ Check whether given ticker is a valid stock symbol. NOTE: Assumes that a stock is valid IF Yahoo! Finance returns a name for the given ticker. Args: ticker (str): Ticker symbol in question. Returns: bool: True if valid ticker (returned name != 'N/A'), otherwise False. """ ticker = ticker.upper() return True if get_name(ticker) != 'N/A' else False
Finally, to determine if a given ticker is for an ETF or not, I will check the number of shares outstanding.
def get_shares_outstanding(symbol): """ Retrieve number of shares outstanding for given stock ticker. Args: symbol (str): Ticker symbol for a given company's stock. Returns: str: The company name. """ return _yahoo_request(symbol, 'j2')
This is not a valid data point for ETF's, so again, Yahoo! will return 'N/A'. So, if the response can be cast as an integer, the ticker is not an ETF.
def is_etf(ticker): """ Determine whether a given ticker symbol is for an Exchange Traded Fund (ETF). NOTE: Assumes that ticker is an ETF IF it is a valid ticker AND Yahoo! Finance does not return a numeric value for 'shares outstanding.' Args: ticker (str): Ticker symbol in question. Returns: bool: None if not a valid ticker, True if an etf (ticker is valid and returned shares outstanding cannot be converted to an int), otherwise False. """ ticker = ticker.upper() if valid_ticker(ticker): try: int(get_shares_outstanding(ticker)) return False except ValueError: return True else: return None
Code is working as expected. Does this seem a reasonable way to check this? In particular the last function. Should I just use
if get_shares_outstanding(ticker) == 'N/A': return True ?