import arrow from ...assets import asset_factory, Option from ...quotes import OptionQuote, Quote from .QuoteAdapter import QuoteAdapter from googlefinance import getQuotes """ Get current prices from Google Finance """ class GoogleFinanceQuoteAdapter(QuoteAdapter): def __init__(self): self._cache = {} def _set_cache(self, quote): self._cache[quote.asset.symbol] = quote return quote def get_quote(self, asset): asset = asset_factory(asset) if self._cache.get(asset.symbol) is not None: return self._cache.get(asset.symbol) if isinstance(asset, Option): options = self.get_options(asset.underlying, asset.expiration_date) matches = [_ for _ in options if _.asset == asset] if len(matches) == 0: raise Exception("GoogleFinanceAdapter.get_quote: No quote found for {}".format(asset.symbol)) return matches[0] else: google_quotes = getQuotes(asset.symbol) if google_quotes is None or len(google_quotes) == 0: raise Exception("GoogleFinanceAdapter.get_quote: No quote found for {}".format(asset.symbol)) last_trade = google_quotes[0].get('LastTradeWithCurrency', None) if last_trade is None or last_trade == '' or last_trade == '-': raise Exception("GoogleFinanceAdapter.get_quote: No quote found for {}".format(asset.symbol)) return Quote(quote_date=arrow.now().format('YYYY-MM-DD'), asset=asset, bid=float(last_trade)-0.01, ask=float(last_trade)+0.01) def get_expiration_dates(self, underlying_asset=None): oc = OptionChain('NASDAQ:' + asset_factory(underlying_asset).symbol) return sorted(list(set([asset_factory(_['s']).expiration_date for _ in (oc.calls + oc.puts)]))) def get_options(self, underlying_asset=None, expiration_date=None): oc = OptionChain('NASDAQ:' + asset_factory(underlying_asset).symbol) underlying_quote = self.get_quote(underlying_asset) out = [] for option in (oc.calls + oc.puts): if arrow.get(expiration_date).format('YYMMDD') in option['s']: quote = OptionQuote(quote_date=arrow.now().format('YYYY-MM-DD'), asset=option['s'], bid=float(option['b']) if option['b'] != '-' else None, ask=float(option['a']) if option['a'] != '-' else None, underlying_price = underlying_quote.price) self._set_cache(quote) out.append(quote) return out # the code below is from https://github.com/makmac213/python-google-option-chain import requests OPTION_CHAIN_URL = 'https://www.google.com/finance/option_chain' class OptionChain(object): def __init__(self, q): """ Usage: from optionchain import OptionChain oc = OptionChain('NASDAQ:AAPL') # oc.calls # oc.puts """ params = { 'q': q, 'output': 'json' } data = self._get_content(OPTION_CHAIN_URL, params) # get first calls and puts calls = data['calls'] puts = data['puts'] for (ctr, exp) in enumerate(data['expirations']): # we already got the first put and call # skip first if ctr: params['expd'] = exp['d'] params['expm'] = exp['m'] params['expy'] = exp['y'] new_data = self._get_content(OPTION_CHAIN_URL, params) if new_data.get('calls') is not None: calls += new_data.get('calls') if new_data.get('puts') is not None: puts += new_data.get('puts') self.calls = calls self.puts = puts def _get_content(self, url, params): response = requests.get(url, params=params) if response.status_code == 200: content_json = response.content data = json_decode(content_json) return data import json import token, tokenize from io import StringIO # using below solution fixes the json output from google # http://stackoverflow.com/questions/4033633/handling-lazy-json-in-python-expecting-property-name def fixLazyJson (in_text): tokengen = tokenize.generate_tokens(StringIO(in_text.decode('ascii')).readline) result = [] for tokid, tokval, _, _, _ in tokengen: # fix unquoted strings if (tokid == token.NAME): if tokval not in ['true', 'false', 'null', '-Infinity', 'Infinity', 'NaN']: tokid = token.STRING tokval = u'"%s"' % tokval # fix single-quoted strings elif (tokid == token.STRING): if tokval.startswith ("'"): tokval = u'"%s"' % tokval[1:-1].replace ('"', '\\"') # remove invalid commas elif (tokid == token.OP) and ((tokval == '}') or (tokval == ']')): if (len(result) > 0) and (result[-1][1] == ','): result.pop() # fix single-quoted strings elif (tokid == token.STRING): if tokval.startswith ("'"): tokval = u'"%s"' % tokval[1:-1].replace ('"', '\\"') result.append((tokid, tokval)) return tokenize.untokenize(result) def json_decode(json_string): try: ret = json.loads(json_string) except: json_string = fixLazyJson(json_string) ret = json.loads(json_string) return ret