Skip to content

Commit 429013f

Browse files
committed
Implements HTTP requests for IEX DEEP API, see: https://www.iextrading.com/developer/docs/#deep
1 parent a554cf6 commit 429013f

File tree

4 files changed

+140
-1
lines changed

4 files changed

+140
-1
lines changed

pandas_datareader/__init__.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
__version__ = version = '0.4.0'
22

33
from .data import (get_components_yahoo, get_data_famafrench, get_data_google, get_data_yahoo, get_data_enigma, # noqa
4-
get_data_yahoo_actions, get_quote_google, get_quote_yahoo, DataReader, Options) # noqa
4+
get_data_yahoo_actions, get_quote_google, get_quote_yahoo, get_tops_iex, get_last_iex, get_markets_iex, # noqa
5+
get_data_iex, get_summary_iex, get_records_iex, get_recent_iex, get_iex_symbols, get_iex_book, # noqa
6+
DataReader, Options) # noqa

pandas_datareader/data.py

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from pandas_datareader.iex.stats import DailySummaryReader as IEXHistorical
1818
from pandas_datareader.iex.stats import MonthlySummaryReader as IEXMonthSummary
19+
from pandas_datareader.iex.deep import Deep as IEXDeep
1920
from pandas_datareader.iex.stats import RecentReader as IEXRecents
2021
from pandas_datareader.iex.stats import RecordsReader as IEXRecords
2122
from pandas_datareader.iex.market import MarketReader as IEXMarkets
@@ -97,6 +98,10 @@ def get_iex_symbols(*args, **kwargs):
9798
return IEXSymbols(*args, **kwargs).read()
9899

99100

101+
def get_iex_book(*args, **kwargs):
102+
return IEXDeep(*args, **kwargs).read()
103+
104+
100105
def DataReader(name, data_source=None, start=None, end=None,
101106
retry_count=3, pause=0.001, session=None, access_key=None):
102107
"""
@@ -182,6 +187,11 @@ def DataReader(name, data_source=None, start=None, end=None,
182187
retry_count=retry_count, pause=pause,
183188
session=session).read()
184189

190+
elif data_source == "iex-book":
191+
return IEXDeep(symbols=name, service="book", start=start, end=end,
192+
retry_count=retry_count, pause=pause,
193+
session=session).read()
194+
185195
elif data_source == "enigma":
186196
return EnigmaReader(datapath=name, api_key=access_key).read()
187197

pandas_datareader/iex/deep.py

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
from pandas_datareader.iex import IEX
2+
from datetime import datetime
3+
4+
# Data provided for free by IEX
5+
# Data is furnished in compliance with the guidelines promulgated in the IEX
6+
# API terms of service and manual
7+
# See https://iextrading.com/api-exhibit-a/ for additional information
8+
# and conditions of use
9+
10+
11+
class Deep(IEX):
12+
def __init__(self, symbols=None, service=None, start=None, end=None,
13+
retry_count=3, pause=0.001, session=None):
14+
super(Deep, self).__init__(symbols=symbols,
15+
start=start, end=end,
16+
retry_count=retry_count,
17+
pause=pause, session=session)
18+
self.sub = service
19+
20+
@property
21+
def service(self):
22+
ss = "/" + self.sub if self.sub is not None else ""
23+
return "deep{}".format(ss)
24+
25+
def _read_lines(self, out):
26+
"""
27+
IEX depth of book data varies and shouldn't always be returned in a DF
28+
29+
:param out: Raw HTTP Output
30+
:return: DataFrame
31+
"""
32+
33+
# Runs appropriate output functions per the service being accessed.
34+
fmap = {
35+
'book': '_pass',
36+
'op-halt-status': '_convert_tstamp',
37+
'security-event': '_convert_tstamp',
38+
'ssr-status': '_convert_tstamp',
39+
'system-event': '_read_system_event',
40+
'trades': '_pass',
41+
'trade-breaks': '_convert_tstamp',
42+
'trading-status': '_read_trading_status',
43+
None: '_pass',
44+
}
45+
46+
if self.sub in fmap:
47+
return getattr(self, fmap[self.sub])(out)
48+
else:
49+
raise "Invalid service specified: {}.".format(self.sub)
50+
51+
def _read_system_event(self, out):
52+
# Map the response code to a string output per the API docs.
53+
# Per: https://www.iextrading.com/developer/docs/#system-event-message
54+
smap = {
55+
'O': 'Start of messages',
56+
'S': 'Start of system hours',
57+
'R': 'Start of regular market hours',
58+
'M': 'End of regular market hours',
59+
'E': 'End of system hours',
60+
'C': 'End of messages'
61+
}
62+
tid = out["systemEvent"]
63+
out["eventResponse"] = smap[tid]
64+
65+
return self._convert_tstamp(out)
66+
67+
@staticmethod
68+
def _pass(out):
69+
return out
70+
71+
def _read_trading_status(self, out):
72+
# Reference: https://www.iextrading.com/developer/docs/#trading-status
73+
smap = {
74+
'H': 'Trading halted across all US equity markets',
75+
'O': 'Trading halt released into an Order Acceptance Period '
76+
'(IEX-listed securities only)',
77+
'P': 'Trading paused and Order Acceptance Period on IEX '
78+
'(IEX-listed securities only)',
79+
'T': 'Trading on IEX'
80+
}
81+
rmap = {
82+
# Trading Halt Reasons
83+
'T1': 'Halt News Pending',
84+
'IPO1': 'IPO/New Issue Not Yet Trading',
85+
'IPOD': 'IPO/New Issue Deferred',
86+
'MCB3': 'Market-Wide Circuit Breaker Level 3 - Breached',
87+
'NA': 'Reason Not Available',
88+
89+
# Order Acceptance Period Reasons
90+
'T2': 'Halt News Dissemination',
91+
'IPO2': 'IPO/New Issue Order Acceptance Period',
92+
'IPO3': 'IPO Pre-Launch Period',
93+
'MCB1': 'Market-Wide Circuit Breaker Level 1 - Breached',
94+
'MCB2': 'Market-Wide Circuit Breaker Level 2 - Breached'
95+
}
96+
for ticker, data in out.items():
97+
if data['status'] in smap:
98+
data['statusText'] = smap[data['status']]
99+
100+
if data['reason'] in rmap:
101+
data['reasonText'] = rmap[data['reason']]
102+
103+
out[ticker] = data
104+
105+
return self._convert_tstamp(out)
106+
107+
@staticmethod
108+
def _convert_tstamp(out):
109+
# Searches for top-level timestamp attributes or within dictionaries
110+
if 'timestamp' in out:
111+
# Convert UNIX to datetime object
112+
f = float(out["timestamp"])
113+
out["timestamp"] = datetime.fromtimestamp(f/1000)
114+
else:
115+
for ticker, data in out.items():
116+
if 'timestamp' in data:
117+
f = float(data["timestamp"])
118+
data["timestamp"] = datetime.fromtimestamp(f/1000)
119+
out[ticker] = data
120+
121+
return out

pandas_datareader/tests/test_iex.py

+6
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,9 @@ def test_live_prices(self):
3939
tickers = dftickers[:5].symbol.values
4040
df = get_last_iex(tickers[:5])
4141
assert df["price"].mean() > 0
42+
43+
def test_deep(self):
44+
dob = DataReader('GS', 'iex-book')
45+
assert 'GS' in dob
46+
assert 'asks' in dob['GS']
47+
assert dob['GS']['bids'][0]['price'] > 0

0 commit comments

Comments
 (0)