diff --git a/pandas/io/data.py b/pandas/io/data.py index 67a841a27f992..13ced745b7b3f 100644 --- a/pandas/io/data.py +++ b/pandas/io/data.py @@ -661,31 +661,35 @@ def get_options_data(self, month=None, year=None, expiry=None): _OPTIONS_BASE_URL = 'http://finance.yahoo.com/q/op?s={sym}' - def _get_option_tables(self, month, year, expiry): + def _get_option_tables(self, expiry): + root = self._get_option_page_from_yahoo(expiry) + tables = self._parse_option_page_from_yahoo(root) + m1 = _two_char_month(expiry.month) + table_name = '_tables' + m1 + str(expiry.year)[-2:] + setattr(self, table_name, tables) + return tables - year, month, expiry = self._try_parse_dates(year, month, expiry) + def _get_option_page_from_yahoo(self, expiry): url = self._OPTIONS_BASE_URL.format(sym=self.symbol) - if month and year: # try to get specified month from yahoo finance - m1 = _two_char_month(month) + m1 = _two_char_month(expiry.month) - # if this month use other url - if month == CUR_MONTH and year == CUR_YEAR: - url += '+Options' - else: - url += '&m={year}-{m1}'.format(year=year, m1=m1) - else: # Default to current month + # if this month use other url + if expiry.month == CUR_MONTH and expiry.year == CUR_YEAR: url += '+Options' + else: + url += '&m={year}-{m1}'.format(year=expiry.year, m1=m1) root = self._parse_url(url) + return root + + def _parse_option_page_from_yahoo(self, root): + tables = root.xpath('.//table') ntables = len(tables) if ntables == 0: - raise RemoteDataError("No tables found at {0!r}".format(url)) - - table_name = '_tables' + m1 + str(year)[-2:] - setattr(self, table_name, tables) + raise RemoteDataError("No tables found") try: self.underlying_price, self.quote_time = self._get_underlying_price(root) @@ -723,7 +727,7 @@ def _get_option_data(self, month, year, expiry, name): try: tables = getattr(self, table_name) except AttributeError: - tables = self._get_option_tables(month, year, expiry) + tables = self._get_option_tables(expiry) ntables = len(tables) table_loc = self._TABLE_LOC[name] @@ -903,13 +907,14 @@ def get_near_stock_price(self, above_below=2, call=True, put=False, meth_name = 'get_{0}_data'.format(nam[:-1]) df = getattr(self, meth_name)(expiry=expiry) - start_index = np.where(df.index.get_level_values('Strike') + if self.underlying_price: + start_index = np.where(df.index.get_level_values('Strike') > self.underlying_price)[0][0] - get_range = slice(start_index - above_below, + get_range = slice(start_index - above_below, start_index + above_below + 1) - chop = df[get_range].dropna(how='all') - data[nam] = chop + chop = df[get_range].dropna(how='all') + data[nam] = chop return concat([data[nam] for nam in to_ret]).sortlevel() @@ -948,6 +953,8 @@ def _try_parse_dates(year, month, expiry): year = CUR_YEAR month = CUR_MONTH expiry = dt.date(year, month, 1) + else: + expiry = dt.date(year, month, 1) return year, month, expiry @@ -1127,7 +1134,11 @@ def _get_expiry_months(self): url = 'http://finance.yahoo.com/q/op?s={sym}'.format(sym=self.symbol) root = self._parse_url(url) - links = root.xpath('.//*[@id="yfncsumtab"]')[0].xpath('.//a') + try: + links = root.xpath('.//*[@id="yfncsumtab"]')[0].xpath('.//a') + except IndexError: + return RemoteDataError('Expiry months not available') + month_gen = (element.attrib['href'].split('=')[-1] for element in links if '/q/op?s=' in element.attrib['href'] diff --git a/pandas/io/tests/test_data.py b/pandas/io/tests/test_data.py index 5d2a8ef08c95b..8b5a81f050ced 100644 --- a/pandas/io/tests/test_data.py +++ b/pandas/io/tests/test_data.py @@ -334,7 +334,7 @@ def test_sample_page_price_quote_time2(self): @network def test_sample_page_chg_float(self): #Tests that numeric columns with comma's are appropriately dealt with - tables = self.root1.xpath('.//table') + tables = self.aapl._parse_option_page_from_yahoo(self.root1) data = web._parse_options_data(tables[self.aapl._TABLE_LOC['puts']]) option_data = self.aapl._process_data(data) self.assertEqual(option_data['Chg'].dtype, 'float64')