1
+ import datetime
2
+ import json
3
+
4
+ import pandas as pd
5
+
6
+ from dateutil .relativedelta import relativedelta
7
+ from pandas_datareader .base import _DailyBaseReader
8
+
9
+ # Data provided for free by IEX
10
+ # Data is furnished in compliance with the guidelines promulgated in the IEX
11
+ # API terms of service and manual
12
+ # See https://iextrading.com/api-exhibit-a/ for additional information
13
+ # and conditions of use
14
+
15
+
16
+ class IEXDailyReader (_DailyBaseReader ):
17
+
18
+ """
19
+ Returns DataFrame/Panel of historical stock prices from symbols, over date
20
+ range, start to end. To avoid being penalized by Google Finance servers,
21
+ pauses between downloading 'chunks' of symbols can be specified.
22
+
23
+ Parameters
24
+ ----------
25
+ symbols : string, array-like object (list, tuple, Series), or DataFrame
26
+ Single stock symbol (ticker), array-like object of symbols or
27
+ DataFrame with index containing stock symbols.
28
+ start : string, (defaults to '1/1/2010')
29
+ Starting date, timestamp. Parses many different kind of date
30
+ representations (e.g., 'JAN-01-2010', '1/1/10', 'Jan, 1, 1980')
31
+ end : string, (defaults to today)
32
+ Ending date, timestamp. Same format as starting date.
33
+ retry_count : int, default 3
34
+ Number of times to retry query request.
35
+ pause : int, default 0
36
+ Time, in seconds, to pause between consecutive queries of chunks. If
37
+ single value given for symbol, represents the pause between retries.
38
+ chunksize : int, default 25
39
+ Number of symbols to download consecutively before intiating pause.
40
+ session : Session, default None
41
+ requests.sessions.Session instance to be used
42
+ """
43
+
44
+ def __init__ (self , symbols = None , start = None , end = None , retry_count = 3 ,
45
+ pause = 0.35 , session = None , chunksize = 25 ):
46
+ super (IEXDailyReader , self ).__init__ (symbols = symbols , start = start , end = end ,
47
+ retry_count = retry_count , pause = pause , session = session , chunksize = chunksize )
48
+
49
+ @property
50
+ def url (self ):
51
+ return 'https://api.iextrading.com/1.0/stock/market/batch'
52
+
53
+ @property
54
+ def endpoint (self ):
55
+ return "chart"
56
+
57
+ def _get_params (self , symbol ):
58
+ chart_range = self ._range_string_from_date ()
59
+ print (chart_range )
60
+ if isinstance (symbol , list ):
61
+ symbolList = ',' .join (symbol )
62
+ else :
63
+ symbolList = symbol
64
+ params = {
65
+ "symbols" : symbolList ,
66
+ "types" : self .endpoint ,
67
+ "range" : chart_range ,
68
+ }
69
+ return params
70
+
71
+ def _range_string_from_date (self ):
72
+ delta = relativedelta (self .start , datetime .datetime .now ())
73
+ if 2 <= (delta .years * - 1 ) <= 5 :
74
+ return "5y"
75
+ elif 1 <= (delta .years * - 1 ) <= 2 :
76
+ return "2y"
77
+ elif 0 <= (delta .years * - 1 ) < 1 :
78
+ return "1y"
79
+ else :
80
+ raise ValueError (
81
+ "Invalid date specified. Must be within past 5 years." )
82
+
83
+ def read (self ):
84
+ """read data"""
85
+ try :
86
+ return self ._read_one_data (self .url , self ._get_params (self .symbols ))
87
+ finally :
88
+ self .close ()
89
+
90
+ def _read_lines (self , out ):
91
+ data = out .read ()
92
+ json_data = json .loads (data )
93
+ result = {}
94
+ if type (self .symbols ) is str :
95
+ syms = [self .symbols ]
96
+ else :
97
+ syms = self .symbols
98
+ for symbol in syms :
99
+ d = json_data .pop (symbol )["chart" ]
100
+ df = pd .DataFrame (d )
101
+ df .set_index ("date" , inplace = True )
102
+ values = ["open" , "high" , "low" , "close" , "volume" ]
103
+ df = df [values ]
104
+ sstart = self .start .strftime ('%Y-%m-%d' )
105
+ send = self .end .strftime ('%Y-%m-%d' )
106
+ df = df .loc [sstart :send ]
107
+ result .update ({symbol :df })
108
+ if len (result ) > 1 :
109
+ return result
110
+ return result [self .symbols ]
0 commit comments