Python functions to determine if a given ticker symbol is an ETF 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&amp;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 ?
Any time you're dealing with structured data, use a proper parser for it. 

url = 'http://finance.yahoo.com/d/quotes.csv?s=%s&amp;f=%s' % (symbol, tag)


In this case, you want urllib.parse.

Please use a context manager for:

request = Request(url)
response = urlopen(request)


eg.

with urlopen(Request(url)) as response:
    ...


Context managers are good. It's a shame they're so under-used. On older Pythons, you should use contextlib.closing instead.

I would generally merge these lines into a long return:

content = response.read().decode().strip().strip('"')
return content


Consider that in

ticker = ticker.upper()
return True if get_name(ticker) != 'N/A' else False


True if some_bool else False is just some_bool, so write

return get_name(ticker.upper()) != 'N/A'


instead.