Coerce into a list of uppercase strings like "GOOG", "$SPX, "XOM"

    Flattens nested lists in `symbols` and converts all list elements to strings

    Arguments:
      symbols (str or list of str): list of market ticker symbols to normalize
        If `symbols` is a str a get_symbols_from_list() call is used to retrieve the list of symbols
      postrprocess (func): function to apply to strings after they've been stripped
        default = str.upper

    FIXME:
      - list(set(list(symbols))) and `args` separately so symbols may be duplicated in symbols and args
      - `postprocess` should be a method to facilitate monkey-patching

    Returns:
      list of str: list of cananical ticker symbol strings (typically after .upper().strip())

    Examples:
      >> normalize_symbols("Goog,AAPL")
      ['GOOG', 'AAPL']
      >> normalize_symbols("  $SPX   ", " aaPL ")
      ['$SPX', 'AAPL']
      >> normalize_symbols("  $SPX   ", " aaPL ", postprocess=str)
      ['$SPX', 'aaPL']
      >> normalize_symbols(["$SPX", ["GOOG", "AAPL"]])
      ['GOOG', 'AAPL', '$SPX']
      >> normalize_symbols("$spy", ["GOOGL", "Apple"], postprocess=str)
      ['$spy', 'GOOGL', 'Apple']

def normalize_symbols(symbols, *args, **kwargs):
    """Coerce into a list of uppercase strings like "GOOG", "$SPX, "XOM"

    Flattens nested lists in `symbols` and converts all list elements to strings

    Arguments:
      symbols (str or list of str): list of market ticker symbols to normalize
        If `symbols` is a str a get_symbols_from_list() call is used to retrieve the list of symbols
      postrprocess (func): function to apply to strings after they've been stripped
        default = str.upper

    FIXME:
      - list(set(list(symbols))) and `args` separately so symbols may be duplicated in symbols and args
      - `postprocess` should be a method to facilitate monkey-patching

    Returns:
      list of str: list of cananical ticker symbol strings (typically after .upper().strip())

    Examples:
      >> normalize_symbols("Goog,AAPL")
      ['GOOG', 'AAPL']
      >> normalize_symbols("  $SPX   ", " aaPL ")
      ['$SPX', 'AAPL']
      >> normalize_symbols("  $SPX   ", " aaPL ", postprocess=str)
      ['$SPX', 'aaPL']
      >> normalize_symbols(["$SPX", ["GOOG", "AAPL"]])
      ['GOOG', 'AAPL', '$SPX']
      >> normalize_symbols("$spy", ["GOOGL", "Apple"], postprocess=str)
      ['$spy', 'GOOGL', 'Apple']
    """
    postprocess = kwargs.get('postprocess', None) or str.upper
    if (      (hasattr(symbols, '__iter__') and not any(symbols))
        or (isinstance(symbols, (list, tuple, Mapping)) and (not symbols or not any(symbols)))):
        return []
    args = normalize_symbols(args, postprocess=postprocess)
    if isinstance(symbols, basestring):
        try:
            return list(set(get_symbols_from_list(symbols))) + args
        except:
            return [postprocess(s.strip()) for s in symbols.split(',')] + args
    else:
        ans = []
        for sym in list(symbols):
            ans += normalize_symbols(sym, postprocess=postprocess)
        return list(set(ans))