Skip to content

Commit 1c947a2

Browse files
committed
Adding Tiingo IEX historical data reader. Tiingo serves cached IEX historical data in excess of IEx's default time frame.
1 parent b9f809f commit 1c947a2

File tree

4 files changed

+106
-4
lines changed

4 files changed

+106
-4
lines changed

pandas_datareader/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
get_nasdaq_symbols,
99
get_quote_google, get_quote_yahoo, get_recent_iex,
1010
get_records_iex, get_summary_iex, get_tops_iex,
11-
get_data_tiingo, get_data_alphavantage)
11+
get_data_tiingo, get_iex_data_tiingo, get_data_alphavantage)
1212

1313
__version__ = get_versions()['version']
1414
del get_versions
@@ -22,4 +22,4 @@
2222
'get_nasdaq_symbols', 'get_data_quandl', 'get_data_moex',
2323
'get_data_fred', 'get_dailysummary_iex', 'get_data_morningstar',
2424
'get_data_stooq', 'DataReader', 'Options',
25-
'get_data_tiingo', 'get_data_alphavantage']
25+
'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
@@ -30,7 +30,7 @@
3030
from pandas_datareader.robinhood import RobinhoodHistoricalReader, \
3131
RobinhoodQuoteReader
3232
from pandas_datareader.stooq import StooqDailyReader
33-
from pandas_datareader.tiingo import TiingoDailyReader, TiingoQuoteReader
33+
from pandas_datareader.tiingo import TiingoDailyReader, TiingoQuoteReader, TiingoIEXHistoricalReader
3434
from pandas_datareader.yahoo.actions import (YahooActionReader, YahooDivReader)
3535
from pandas_datareader.yahoo.components import _get_data as \
3636
get_components_yahoo
@@ -127,6 +127,10 @@ def get_data_tiingo(*args, **kwargs):
127127
return TiingoDailyReader(*args, **kwargs).read()
128128

129129

130+
def get_iex_data_tiingo(*args, **kwargs):
131+
return TiingoIEXHistoricalReader(*args, **kwargs).read()
132+
133+
130134
def get_quotes_tiingo(*args, **kwargs):
131135
return TiingoQuoteReader(*args, **kwargs).read()
132136

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

0 commit comments

Comments
 (0)