Skip to content

Commit 350de89

Browse files
Noah Stoffmanbashtage
authored andcommitted
Add dividends, splits, and currencies
Dividends and splits are now returned along with prices in a dict of DataFrames. Only one call needed per ticker. Currency pairs (e.g. CADUSD) can now be accessed with YahooFXReader.
1 parent e58896d commit 350de89

File tree

5 files changed

+214
-182
lines changed

5 files changed

+214
-182
lines changed

docs/source/whatsnew/v0.7.0.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,10 @@ Bug Fixes
5050

5151
- Added support for passing the API KEY to QuandlReader either directly or by
5252
setting the environmental variable QUANDL_API_KEY (:issue:`485`).
53-
- Added back support for Yahoo! price data
5453
- Handle Morningstar index volume data properly (:issue:`486`).
5554
- Added support for optionally passing a custom base_url to the EnigmaReader (:issue:`499`).
5655
- Fixed Morningstar 'retry' incrementation (:issue:`513`)
5756
- Updated Google Daily Price API to functional url (:issue:`502`)
5857
- Fix Yahoo! price data (:issue:`498`)
58+
- Added back support for Yahoo! price, dividends, and splits data for stocks
59+
and currency pairs (:issue:`487`).

pandas_datareader/data.py

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
RobinhoodQuoteReader
3333
from pandas_datareader.stooq import StooqDailyReader
3434
from pandas_datareader.tiingo import TiingoDailyReader, TiingoQuoteReader
35-
from pandas_datareader.yahoo.actions import (YahooActionReader, YahooDivReader)
3635
from pandas_datareader.yahoo.components import _get_data as \
3736
get_components_yahoo
3837
from pandas_datareader.yahoo.daily import YahooDailyReader
@@ -81,7 +80,6 @@ def get_quote_av(*args, **kwargs):
8180

8281
def get_data_yahoo_actions(*args, **kwargs):
8382
raise ImmediateDeprecationError(DEP_ERROR_MSG.format('Yahoo Actions'))
84-
return YahooActionReader(*args, **kwargs).read()
8583

8684

8785
def get_quote_yahoo(*args, **kwargs):
@@ -313,67 +311,6 @@ def DataReader(name, data_source=None, start=None, end=None,
313311
retry_count=retry_count, pause=pause,
314312
session=session).read()
315313

316-
elif data_source == "yahoo-actions":
317-
raise ImmediateDeprecationError(DEP_ERROR_MSG.format('Yahoo Actions'))
318-
return YahooActionReader(symbols=name, start=start, end=end,
319-
retry_count=retry_count, pause=pause,
320-
session=session).read()
321-
322-
elif data_source == "yahoo-dividends":
323-
comp = 'Yahoo Dividends'
324-
raise ImmediateDeprecationError(DEP_ERROR_MSG.format(comp))
325-
return YahooDivReader(symbols=name, start=start, end=end,
326-
adjust_price=False, chunksize=25,
327-
retry_count=retry_count, pause=pause,
328-
session=session, interval='d').read()
329-
330-
elif data_source == "av-forex":
331-
return AVForexReader(symbols=name, retry_count=retry_count,
332-
pause=pause, session=session,
333-
api_key=access_key).read()
334-
335-
elif data_source == "av-daily":
336-
return AVTimeSeriesReader(symbols=name,
337-
function="TIME_SERIES_DAILY", start=start,
338-
end=end, retry_count=retry_count,
339-
pause=pause, session=session,
340-
api_key=access_key).read()
341-
342-
elif data_source == "av-daily-adjusted":
343-
return AVTimeSeriesReader(symbols=name,
344-
function="TIME_SERIES_DAILY_ADJUSTED",
345-
start=start, end=end,
346-
retry_count=retry_count, pause=pause,
347-
session=session, api_key=access_key).read()
348-
349-
elif data_source == "av-weekly":
350-
return AVTimeSeriesReader(symbols=name,
351-
function="TIME_SERIES_WEEKLY", start=start,
352-
end=end, retry_count=retry_count,
353-
pause=pause, session=session,
354-
api_key=access_key).read()
355-
356-
elif data_source == "av-weekly-adjusted":
357-
return AVTimeSeriesReader(symbols=name,
358-
function="TIME_SERIES_WEEKLY_ADJUSTED",
359-
start=start, end=end,
360-
retry_count=retry_count, pause=pause,
361-
session=session, api_key=access_key).read()
362-
363-
elif data_source == "av-monthly":
364-
return AVTimeSeriesReader(symbols=name,
365-
function="TIME_SERIES_MONTHLY", start=start,
366-
end=end, retry_count=retry_count,
367-
pause=pause, session=session,
368-
api_key=access_key).read()
369-
370-
elif data_source == "av-monthly-adjusted":
371-
return AVTimeSeriesReader(symbols=name,
372-
function="TIME_SERIES_MONTHLY_ADJUSTED",
373-
start=start, end=end,
374-
retry_count=retry_count, pause=pause,
375-
session=session, api_key=access_key).read()
376-
377314
elif data_source == "google":
378315
return GoogleDailyReader(symbols=name, start=start, end=end,
379316
chunksize=25,

pandas_datareader/yahoo/FX.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import time
2+
import json
3+
import warnings
4+
from pandas import (DataFrame, Series, to_datetime, concat)
5+
from pandas_datareader.yahoo.daily import YahooDailyReader
6+
import pandas.compat as compat
7+
from pandas_datareader._utils import (RemoteDataError, SymbolWarning)
8+
from pandas.core.indexes.numeric import Int64Index
9+
10+
11+
class YahooFXReader(YahooDailyReader):
12+
"""
13+
Returns DataFrame of historical prices for currencies
14+
15+
Parameters
16+
----------
17+
symbols : string, array-like object (list, tuple, Series), or DataFrame
18+
Single stock symbol (ticker), array-like object of symbols or
19+
DataFrame with index containing stock symbols.
20+
start : string, (defaults to '1/1/2010')
21+
Starting date, timestamp. Parses many different kind of date
22+
representations (e.g., 'JAN-01-2010', '1/1/10', 'Jan, 1, 1980')
23+
end : string, (defaults to today)
24+
Ending date, timestamp. Same format as starting date.
25+
retry_count : int, default 3
26+
Number of times to retry query request.
27+
pause : int, default 0
28+
Time, in seconds, to pause between consecutive queries of chunks. If
29+
single value given for symbol, represents the pause between retries.
30+
session : Session, default None
31+
requests.sessions.Session instance to be used
32+
chunksize : int, default 25 (NOT IMPLEMENTED)
33+
Number of symbols to download consecutively before intiating pause.
34+
interval : string, default '1d'
35+
Valid values are '1d', '5d', '1mo', '3mo', '6mo', '1y', '2y', '5y',
36+
'10y', 'ytd', 'max'
37+
"""
38+
39+
def _get_params(self, symbol):
40+
unix_start = int(time.mktime(self.start.timetuple()))
41+
day_end = self.end.replace(hour=23, minute=59, second=59)
42+
unix_end = int(time.mktime(day_end.timetuple()))
43+
44+
params = {
45+
'symbol': symbol + '=X',
46+
'period1': unix_start,
47+
'period2': unix_end,
48+
'interval': self.interval, # deal with this
49+
'includePrePost': 'true',
50+
'events': 'div|split|earn',
51+
'corsDomain': 'finance.yahoo.com'
52+
}
53+
return params
54+
55+
def read(self):
56+
"""Read data"""
57+
try:
58+
# If a single symbol, (e.g., 'GOOG')
59+
if isinstance(self.symbols, (compat.string_types, int)):
60+
df = self._read_one_data(self.symbols)
61+
62+
# Or multiple symbols, (e.g., ['GOOG', 'AAPL', 'MSFT'])
63+
elif isinstance(self.symbols, DataFrame):
64+
df = self._dl_mult_symbols(self.symbols.index)
65+
else:
66+
df = self._dl_mult_symbols(self.symbols)
67+
68+
if isinstance(df.index, Int64Index):
69+
df = df.set_index('Date')
70+
71+
if 'Volume' in df:
72+
df = df.drop('Volume', axis=1)
73+
74+
return df.sort_index().dropna(how='all')
75+
finally:
76+
self.close()
77+
78+
def _read_one_data(self, symbol):
79+
""" read one data from specified URL """
80+
url = 'https://query1.finance.yahoo.com/v8/finance/chart/{}=X'\
81+
.format(symbol)
82+
params = self._get_params(symbol)
83+
84+
resp = self._get_response(url, params=params)
85+
jsn = json.loads(resp.text)
86+
87+
data = jsn['chart']['result'][0]
88+
df = DataFrame(data['indicators']['quote'][0])
89+
df.insert(0, 'date', to_datetime(Series(data['timestamp']),
90+
unit='s').dt.date)
91+
df.columns = map(str.capitalize, df.columns)
92+
return df
93+
94+
def _dl_mult_symbols(self, symbols):
95+
stocks = {}
96+
failed = []
97+
passed = []
98+
for sym in symbols:
99+
try:
100+
df = self._read_one_data(sym)
101+
df['PairCode'] = sym
102+
stocks[sym] = df
103+
passed.append(sym)
104+
except IOError:
105+
msg = 'Failed to read symbol: {0!r}, replacing with NaN.'
106+
warnings.warn(msg.format(sym), SymbolWarning)
107+
failed.append(sym)
108+
109+
if len(passed) == 0:
110+
msg = "No data fetched using {0!r}"
111+
raise RemoteDataError(msg.format(self.__class__.__name__))
112+
else:
113+
return concat(stocks).set_index(['PairCode', 'Date'])

pandas_datareader/yahoo/actions.py

Lines changed: 0 additions & 53 deletions
This file was deleted.

0 commit comments

Comments
 (0)