1from datetime import datetime, timedelta 2 3import pandas as pd 4 5from pandas_datareader.exceptions import UnstableAPIWarning 6from pandas_datareader.iex import IEX 7 8# Data provided for free by IEX 9# Data is furnished in compliance with the guidelines promulgated in the IEX 10# API terms of service and manual 11# See https://iextrading.com/api-exhibit-a/ for additional information 12# and conditions of use 13 14 15class DailySummaryReader(IEX): 16 """ 17 Daily statistics from IEX for a day or month 18 """ 19 20 def __init__( 21 self, symbols=None, start=None, end=None, retry_count=3, pause=0.1, session=None 22 ): 23 import warnings 24 25 warnings.warn( 26 "Daily statistics is not working due to issues with the " "IEX API", 27 UnstableAPIWarning, 28 ) 29 self.curr_date = start 30 super(DailySummaryReader, self).__init__( 31 symbols=symbols, 32 start=start, 33 end=end, 34 retry_count=retry_count, 35 pause=pause, 36 session=session, 37 ) 38 39 @property 40 def service(self): 41 """Service endpoint""" 42 return "stats/historical/daily" 43 44 def _get_params(self, symbols): 45 p = {} 46 47 if self.curr_date is not None: 48 p["date"] = self.curr_date.strftime("%Y%m%d") 49 50 return p 51 52 def read(self): 53 """Unfortunately, IEX's API can only retrieve data one day or one month 54 at a time. Rather than specifying a date range, we will have to run 55 the read function for each date provided. 56 57 :return: DataFrame 58 """ 59 tlen = self.end - self.start 60 dfs = [] 61 for date in (self.start + timedelta(n) for n in range(tlen.days)): 62 self.curr_date = date 63 tdf = super(DailySummaryReader, self).read() 64 dfs.append(tdf) 65 return pd.concat(dfs) 66 67 68class MonthlySummaryReader(IEX): 69 """Monthly statistics from IEX""" 70 71 def __init__( 72 self, symbols=None, start=None, end=None, retry_count=3, pause=0.1, session=None 73 ): 74 self.curr_date = start 75 self.date_format = "%Y%m" 76 77 super(MonthlySummaryReader, self).__init__( 78 symbols=symbols, 79 start=start, 80 end=end, 81 retry_count=retry_count, 82 pause=pause, 83 session=session, 84 ) 85 86 @property 87 def service(self): 88 """Service endpoint""" 89 return "stats/historical" 90 91 def _get_params(self, symbols): 92 p = {} 93 94 if self.curr_date is not None: 95 p["date"] = self.curr_date.strftime(self.date_format) 96 97 return p 98 99 def read(self): 100 """Unfortunately, IEX's API can only retrieve data one day or one month 101 at a time. Rather than specifying a date range, we will have to run 102 the read function for each date provided. 103 104 :return: DataFrame 105 """ 106 tlen = self.end - self.start 107 dfs = [] 108 109 # Build list of all dates within the given range 110 lrange = [x for x in (self.start + timedelta(n) for n in range(tlen.days))] 111 112 mrange = [] 113 for dt in lrange: 114 if datetime(dt.year, dt.month, 1) not in mrange: 115 mrange.append(datetime(dt.year, dt.month, 1)) 116 lrange = mrange 117 118 for date in lrange: 119 self.curr_date = date 120 tdf = super(MonthlySummaryReader, self).read() 121 122 # We may not return data if this was a weekend/holiday: 123 if not tdf.empty: 124 tdf["date"] = date.strftime(self.date_format) 125 dfs.append(tdf) 126 127 # We may not return any data if we failed to specify useful parameters: 128 return pd.concat(dfs) if len(dfs) > 0 else pd.DataFrame() 129 130 131class RecordsReader(IEX): 132 """ 133 Total matched volume information from IEX 134 """ 135 136 def __init__( 137 self, symbols=None, start=None, end=None, retry_count=3, pause=0.1, session=None 138 ): 139 super(RecordsReader, self).__init__( 140 symbols=symbols, 141 start=start, 142 end=end, 143 retry_count=retry_count, 144 pause=pause, 145 session=session, 146 ) 147 148 @property 149 def service(self): 150 """Service endpoint""" 151 return "stats/records" 152 153 def _get_params(self, symbols): 154 # Record Stats API does not take any parameters, returning empty dict 155 return {} 156 157 158class RecentReader(IEX): 159 """Recent trading volume from IEX 160 161 Notes 162 ----- 163 Returns 6 fields for each day: 164 165 * date: refers to the trading day. 166 * volume: refers to executions received from order routed to away 167 trading centers. 168 * routedVolume: refers to single counted shares matched from executions 169 on IEX. 170 * marketShare: refers to IEX's percentage of total US Equity market 171 volume. 172 * isHalfday: will be true if the trading day is a half day. 173 * litVolume: refers to the number of lit shares traded on IEX 174 (single-counted). 175 """ 176 177 def __init__( 178 self, symbols=None, start=None, end=None, retry_count=3, pause=0.1, session=None 179 ): 180 super(RecentReader, self).__init__( 181 symbols=symbols, 182 start=start, 183 end=end, 184 retry_count=retry_count, 185 pause=pause, 186 session=session, 187 ) 188 189 @property 190 def service(self): 191 """Service endpoint""" 192 return "stats/recent" 193 194 def _get_params(self, symbols): 195 # Record Stats API does not take any parameters, returning empty dict 196 return {} 197