Skip to content

Commit 4ff9a3e

Browse files
authored
Merge pull request #619 from boingaon/tiingo-add-iex
Tiingo add IEX Historical Reader
2 parents c714918 + 308d2e2 commit 4ff9a3e

File tree

5 files changed

+111
-4
lines changed

5 files changed

+111
-4
lines changed

docs/source/whatsnew/v0.8.0.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Highlights include:
2323
Enhancements
2424
~~~~~~~~~~~~
2525

26+
- Added Tiingo IEX Historical reader.
2627

2728
.. _whatsnew_080.api_breaking:
2829

pandas_datareader/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
get_iex_book, get_iex_symbols, get_last_iex,
77
get_markets_iex, get_nasdaq_symbols, get_quote_yahoo,
88
get_recent_iex, get_records_iex, get_summary_iex,
9-
get_tops_iex, get_data_tiingo, get_data_alphavantage)
9+
get_tops_iex, get_data_tiingo, get_iex_data_tiingo,
10+
get_data_alphavantage)
1011

1112
__version__ = get_versions()['version']
1213
del get_versions
@@ -20,4 +21,4 @@
2021
'get_nasdaq_symbols', 'get_data_quandl', 'get_data_moex',
2122
'get_data_fred', 'get_dailysummary_iex',
2223
'get_data_stooq', 'DataReader', 'Options',
23-
'get_data_tiingo', 'get_data_alphavantage']
24+
'get_data_tiingo', 'get_iex_data_tiingo', 'get_data_alphavantage']

pandas_datareader/data.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from pandas_datareader.robinhood import RobinhoodHistoricalReader, \
2828
RobinhoodQuoteReader
2929
from pandas_datareader.stooq import StooqDailyReader
30-
from pandas_datareader.tiingo import TiingoDailyReader, TiingoQuoteReader
30+
from pandas_datareader.tiingo import TiingoDailyReader, TiingoQuoteReader, TiingoIEXHistoricalReader
3131
from pandas_datareader.yahoo.actions import (YahooActionReader, YahooDivReader)
3232
from pandas_datareader.yahoo.components import _get_data as \
3333
get_components_yahoo
@@ -110,6 +110,10 @@ def get_data_tiingo(*args, **kwargs):
110110
return TiingoDailyReader(*args, **kwargs).read()
111111

112112

113+
def get_iex_data_tiingo(*args, **kwargs):
114+
return TiingoIEXHistoricalReader(*args, **kwargs).read()
115+
116+
113117
def get_quotes_tiingo(*args, **kwargs):
114118
return TiingoQuoteReader(*args, **kwargs).read()
115119

pandas_datareader/tests/test_tiingo.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from pandas_datareader.compat import PY3
77
from pandas_datareader.tiingo import TiingoDailyReader, TiingoMetaDataReader, \
8-
TiingoQuoteReader, get_tiingo_symbols
8+
TiingoQuoteReader, TiingoIEXHistoricalReader, get_tiingo_symbols
99

1010
TEST_API_KEY = os.getenv('TIINGO_API_KEY')
1111
# Ensure blank TEST_API_KEY not used in pull request
@@ -38,6 +38,16 @@ def test_tiingo_historical(symbols):
3838
assert df.index.levels[0].shape[0] == len(symbols)
3939

4040

41+
@pytest.mark.skipif(TEST_API_KEY is None, reason="TIINGO_API_KEY not set")
42+
def test_tiingo_iex_historical(symbols):
43+
df = TiingoIEXHistoricalReader(symbols=symbols).read()
44+
df.head()
45+
assert isinstance(df, pd.DataFrame)
46+
if isinstance(symbols, str):
47+
symbols = [symbols]
48+
assert df.index.levels[0].shape[0] == len(symbols)
49+
50+
4151
@pytest.mark.skipif(TEST_API_KEY is None, reason="TIINGO_API_KEY not set")
4252
def test_tiingo_metadata(symbols):
4353
df = TiingoMetaDataReader(symbols=symbols).read()

pandas_datareader/tiingo.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,97 @@ def get_tiingo_symbols():
2323
return pd.read_csv(url)
2424

2525

26+
class TiingoIEXHistoricalReader(_BaseReader):
27+
"""
28+
Historical data from Tiingo on equities, ETFs and mutual funds,
29+
with re-sampling capability. This query is limited to the last
30+
1,000 bars based in the endDate. So the startDate is moved if
31+
it goes past the limit.
32+
33+
Parameters
34+
----------
35+
symbols : {str, List[str]}
36+
String symbol of like of symbols
37+
start : str, (defaults to '1/1/2010')
38+
Starting date, timestamp. Parses many different kind of date
39+
representations (e.g., 'JAN-01-2010', '1/1/10', 'Jan, 1, 1980')
40+
end : str, (defaults to today)
41+
Ending date, timestamp. Same format as starting date.
42+
retry_count : int, default 3
43+
Number of times to retry query request.
44+
pause : float, default 0.1
45+
Time, in seconds, of the pause between retries.
46+
session : Session, default None
47+
requests.sessions.Session instance to be used
48+
freq : {str, None}
49+
Re-sample frequency. Format is # + (min/hour); e.g. "15min" or "4hour".
50+
If no value is provided, defaults to 5min. The minimum value is "1min".
51+
Units in minutes (min) and hours (hour) are accepted.
52+
api_key : str, optional
53+
Tiingo API key . If not provided the environmental variable
54+
TIINGO_API_KEY is read. The API key is *required*.
55+
"""
56+
57+
def __init__(self, symbols, start=None, end=None, retry_count=3, pause=0.1,
58+
timeout=30, session=None, freq=None, api_key=None):
59+
super().__init__(symbols, start, end, retry_count, pause, timeout,
60+
session, freq)
61+
62+
if isinstance(self.symbols, str):
63+
self.symbols = [self.symbols]
64+
self._symbol = ''
65+
if api_key is None:
66+
api_key = os.getenv('TIINGO_API_KEY')
67+
if not api_key or not isinstance(api_key, str):
68+
raise ValueError('The tiingo API key must be provided either '
69+
'through the api_key variable or through the '
70+
'environmental variable TIINGO_API_KEY.')
71+
self.api_key = api_key
72+
self._concat_axis = 0
73+
74+
@property
75+
def url(self):
76+
"""API URL"""
77+
_url = 'https://api.tiingo.com/iex/{ticker}/prices'
78+
return _url.format(ticker=self._symbol)
79+
80+
@property
81+
def params(self):
82+
"""Parameters to use in API calls"""
83+
return {'startDate': self.start.strftime('%Y-%m-%d'),
84+
'endDate': self.end.strftime('%Y-%m-%d'),
85+
'resampleFreq': self.freq,
86+
'format': 'json'}
87+
88+
def _get_crumb(self, *args):
89+
pass
90+
91+
def _read_one_data(self, url, params):
92+
""" read one data from specified URL """
93+
headers = {'Content-Type': 'application/json',
94+
'Authorization': 'Token ' + self.api_key}
95+
out = self._get_response(url, params=params, headers=headers).json()
96+
return self._read_lines(out)
97+
98+
def _read_lines(self, out):
99+
df = pd.DataFrame(out)
100+
df['symbol'] = self._symbol
101+
df['date'] = pd.to_datetime(df['date'])
102+
df = df.set_index(['symbol', 'date'])
103+
return df
104+
105+
def read(self):
106+
"""Read data from connector"""
107+
dfs = []
108+
for symbol in self.symbols:
109+
self._symbol = symbol
110+
try:
111+
dfs.append(self._read_one_data(self.url, self.params))
112+
finally:
113+
self.close()
114+
return pd.concat(dfs, self._concat_axis)
115+
116+
26117
class TiingoDailyReader(_BaseReader):
27118
"""
28119
Historical daily data from Tiingo on equities, ETFs and mutual funds

0 commit comments

Comments
 (0)