Skip to content

Commit 2750110

Browse files
committed
Merge branch 'master' of https://github.com/dstephens99/pandas into dstephens99-master
2 parents de2e7cc + 54454bc commit 2750110

File tree

2 files changed

+35
-24
lines changed

2 files changed

+35
-24
lines changed

pandas/io/data.py

+24-20
Original file line numberDiff line numberDiff line change
@@ -736,9 +736,8 @@ def _get_option_data(self, month, year, expiry, name):
736736
" found".format(table_loc, ntables))
737737

738738
option_data = _parse_options_data(tables[table_loc])
739-
option_data = self._process_data(option_data)
740739
option_data['Type'] = name[:-1]
741-
option_data.set_index(['Strike', 'Expiry', 'Type', 'Symbol'], inplace=True)
740+
option_data = self._process_data(option_data, name[:-1])
742741

743742
if month == CUR_MONTH and year == CUR_YEAR:
744743
setattr(self, name, option_data)
@@ -859,8 +858,7 @@ def get_near_stock_price(self, above_below=2, call=True, put=False,
859858
month=None, year=None, expiry=None):
860859
"""
861860
***Experimental***
862-
Cuts the data frame opt_df that is passed in to only take
863-
options that are near the current stock price.
861+
Returns a data frame of options that are near the current stock price.
864862
865863
Parameters
866864
----------
@@ -889,34 +887,38 @@ def get_near_stock_price(self, above_below=2, call=True, put=False,
889887
Note: Format of returned data frame is dependent on Yahoo and may change.
890888
891889
"""
892-
year, month, expiry = self._try_parse_dates(year, month, expiry)
893890

894891
to_ret = Series({'calls': call, 'puts': put})
895892
to_ret = to_ret[to_ret].index
896893

897894
data = {}
898895

899896
for nam in to_ret:
900-
if month:
901-
m1 = _two_char_month(month)
902-
name = nam + m1 + str(year)[2:]
897+
df = self._get_option_data(month, year, expiry, nam)
898+
data[nam] = self.chop_data(df, above_below, self.underlying_price)
899+
900+
return concat([data[nam] for nam in to_ret]).sortlevel()
901+
902+
def chop_data(self, df, above_below=2, underlying_price=None):
903+
"""Returns a data frame only options that are near the current stock price."""
903904

905+
if not underlying_price:
904906
try:
905-
df = getattr(self, name)
907+
underlying_price = self.underlying_price
906908
except AttributeError:
907-
meth_name = 'get_{0}_data'.format(nam[:-1])
908-
df = getattr(self, meth_name)(expiry=expiry)
909+
underlying_price = np.nan
909910

910-
if self.underlying_price:
911-
start_index = np.where(df.index.get_level_values('Strike')
912-
> self.underlying_price)[0][0]
911+
if not np.isnan(underlying_price):
912+
start_index = np.where(df.index.get_level_values('Strike')
913+
> underlying_price)[0][0]
913914

914-
get_range = slice(start_index - above_below,
915+
get_range = slice(start_index - above_below,
915916
start_index + above_below + 1)
916-
chop = df[get_range].dropna(how='all')
917-
data[nam] = chop
917+
df = df[get_range].dropna(how='all')
918+
919+
return df
920+
918921

919-
return concat([data[nam] for nam in to_ret]).sortlevel()
920922

921923
@staticmethod
922924
def _try_parse_dates(year, month, expiry):
@@ -1048,7 +1050,7 @@ def get_forward_data(self, months, call=True, put=False, near=False,
10481050
frame = self.get_near_stock_price(call=call, put=put,
10491051
above_below=above_below,
10501052
month=m2, year=y2)
1051-
frame = self._process_data(frame)
1053+
frame = self._process_data(frame, name[:-1])
10521054

10531055
all_data.append(frame)
10541056

@@ -1178,7 +1180,7 @@ def _parse_url(self, url):
11781180
return root
11791181

11801182

1181-
def _process_data(self, frame):
1183+
def _process_data(self, frame, type):
11821184
"""
11831185
Adds columns for Expiry, IsNonstandard (ie: deliverable is not 100 shares)
11841186
and Tag (the tag indicating what is actually deliverable, None if standard).
@@ -1195,5 +1197,7 @@ def _process_data(self, frame):
11951197
frame['Underlying_Price'] = self.underlying_price
11961198
frame["Quote_Time"] = self.quote_time
11971199
frame.rename(columns={'Open Int': 'Open_Int'}, inplace=True)
1200+
frame['Type'] = type
1201+
frame.set_index(['Strike', 'Expiry', 'Type', 'Symbol'], inplace=True)
11981202

11991203
return frame

pandas/io/tests/test_data.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ def setUpClass(cls):
250250
cls.html2 = os.path.join(cls.dirpath, 'yahoo_options2.html')
251251
cls.root1 = cls.aapl._parse_url(cls.html1)
252252
cls.root2 = cls.aapl._parse_url(cls.html2)
253+
cls.tables1 = cls.aapl._parse_option_page_from_yahoo(cls.root1)
254+
cls.unprocessed_data1 = web._parse_options_data(cls.tables1[cls.aapl._TABLE_LOC['puts']])
255+
cls.data1 = cls.aapl._process_data(cls.unprocessed_data1, 'put')
253256

254257
@classmethod
255258
def tearDownClass(cls):
@@ -324,6 +327,13 @@ def test_sample_page_price_quote_time1(self):
324327
self.assertIsInstance(price, (int, float, complex))
325328
self.assertIsInstance(quote_time, (datetime, Timestamp))
326329

330+
def test_chop(self):
331+
#regression test for #7625
332+
self.aapl.chop_data(self.data1, above_below=2, underlying_price=np.nan)
333+
chopped = self.aapl.chop_data(self.data1, above_below=2, underlying_price=300)
334+
self.assertIsInstance(chopped, DataFrame)
335+
self.assertTrue(len(chopped) > 1)
336+
327337
@network
328338
def test_sample_page_price_quote_time2(self):
329339
#Tests the weekday quote time format
@@ -334,10 +344,7 @@ def test_sample_page_price_quote_time2(self):
334344
@network
335345
def test_sample_page_chg_float(self):
336346
#Tests that numeric columns with comma's are appropriately dealt with
337-
tables = self.aapl._parse_option_page_from_yahoo(self.root1)
338-
data = web._parse_options_data(tables[self.aapl._TABLE_LOC['puts']])
339-
option_data = self.aapl._process_data(data)
340-
self.assertEqual(option_data['Chg'].dtype, 'float64')
347+
self.assertEqual(self.data1['Chg'].dtype, 'float64')
341348

342349

343350
class TestOptionsWarnings(tm.TestCase):

0 commit comments

Comments
 (0)