def _parse_historical_data(symbol, expiration, data, db_name=None): """Parses historical (EOD) quotes from CBOE and saves them to database. Args: symbol (str): Symbol. expiration (date): Expiration. data (str): Raw quotes for the symbol. db_name (str): Optional database name. Returns: int: Number of quotes fetched. """ assert symbol == 'VX' lines = 0 with database.connect_db(db_name) as db: for line in data.splitlines(): values = line.strip().split(',') if len(values) != 11: continue if values[0] == 'Trade Date': continue date = datetime.strptime(values[0], '%m/%d/%Y').date() settle = utils.to_float(values[6]) quote = FutureQuote(symbol, expiration, date, None, settle) save_quote(db, quote) lines += 1 return lines
def _parse_realtime_data(symbol, data, db_name=None): """Parses realtime (delayed) futures quotes from CBOE website and saves them to database. Args: symbol (str): Symbol. data (str): Raw quotes for the symbol. db_name (str): Optional database name. Returns: list: List of FutureQuote objects. """ assert symbol == 'VX' logger = logging.getLogger(__name__) timestamp = dates.get_database_timestamp() date = timestamp.date() time = timestamp.time() base_symbol = _future_to_base_symbol(symbol) quotes = [] with database.connect_db(db_name) as db: try: soup = BeautifulSoup(data, 'html5lib') table = soup.find('a', {'name': symbol}).parent.parent.find('table') for row in table.find_all('tr'): cols = row.find_all('td') if len(cols) != 9: continue row_symbol = cols[0].text.strip().split('/')[0] if row_symbol != base_symbol: continue expiration = datetime.strptime( cols[1].text.strip(), '%m/%d/%Y').date() last = utils.to_float(cols[2].text.strip()) if last is None: continue quote = FutureQuote(symbol, expiration, date, time, last) save_quote(db, quote) quotes.append(quote) except AttributeError: logger.error('Cannot parse futures quotes from CBOE for %s ...', symbol) return quotes
def test_valid_integer_string(self): self.assertEqual(utils.to_float('1'), 1.0)
def test_invalid_string(self): self.assertIsNone(utils.to_float('abc'))
def test_valid_float_string(self): self.assertEqual(utils.to_float('1.1'), 1.1)
def _parse_data(symbol, data, is_eod, db_name=None, timestamp=None): """Parses realtime (delayed) options quotes from CBOE and saves to database. Args: symbol (str): Symbol. data (str): Raw quotes for the symbol. is_eod (bool): If True: mark received quotes as EOD (time=None), if False: store actual time. db_name (str): Optional database name. timestamp (datetime): Optional datetime for the data. Returns: list: List of OptionQuote objects. """ logger = logging.getLogger(__name__) if timestamp is None: timestamp = dates.get_database_timestamp() date = timestamp.date() time = None if is_eod else timestamp.time() quotes = [] stock_price = None expirations = dates.get_expirations(symbol) with database.connect_db(db_name) as db: for line in data.splitlines(): values = line.strip().split(',') if (len(values) == 4) and (stock_price is None): stock_price = utils.to_float(values[1]) continue if len(values) != 15: continue if values[0] == 'Calls' or values[0].find('-') >= 0: continue code_values = values[0].split(' ') if len(code_values) != 4: continue position = code_values[3].find(code_values[0]) if code_values[3][1:position] in SKIP_SYMBOLS: continue expiration_year = 2000 + int(code_values[0]) expiration_month = MONTHS[code_values[1]] expiration_day = int(code_values[3][position + 2:position + 4]) expiration = datetime(expiration_year, expiration_month, expiration_day).date() if expiration not in expirations: continue strike = utils.to_float(code_values[2]) for type_, bid, ask in [ (consts.CALL, values[3], values[4]), (consts.PUT, values[10], values[11]), ]: bid = utils.to_float(bid) ask = utils.to_float(ask) quote = OptionQuote( symbol, type_, expiration, strike, date, time, bid, ask, stock_price, None, None) iv_bid = math.calc_iv(quote, bid) * 100 iv_ask = math.calc_iv(quote, ask) * 100 quote = OptionQuote( symbol, type_, expiration, strike, date, time, bid, ask, stock_price, iv_bid, iv_ask) save_quote(db, quote) quotes.append(quote) logger.info('... quotes parsed: %d', len(quotes)) return quotes