1import os 2 3import pandas as pd 4 5from pandas_datareader.base import _BaseReader 6 7 8def get_tiingo_symbols(): 9 """ 10 Get the set of stock symbols supported by Tiingo 11 12 Returns 13 ------- 14 symbols : DataFrame 15 DataFrame with symbols (ticker), exchange, asset type, currency and 16 start and end dates 17 18 Notes 19 ----- 20 Reads https://apimedia.tiingo.com/docs/tiingo/daily/supported_tickers.zip 21 """ 22 url = "https://apimedia.tiingo.com/docs/tiingo/daily/supported_tickers.zip" 23 return pd.read_csv(url) 24 25 26class 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 or list of symbols 37 start : string, int, date, datetime, Timestamp 38 Starting date. Parses many different kind of date 39 representations (e.g., 'JAN-01-2010', '1/1/10', 'Jan, 1, 1980'). Defaults to 40 20 years before current date. 41 end : string, int, date, datetime, Timestamp 42 Ending date 43 retry_count : int, default 3 44 Number of times to retry query request. 45 pause : float, default 0.1 46 Time, in seconds, of the pause between retries. 47 session : Session, default None 48 requests.sessions.Session instance to be used 49 freq : {str, None} 50 Re-sample frequency. Format is # + (min/hour); e.g. "15min" or "4hour". 51 If no value is provided, defaults to 5min. The minimum value is "1min". 52 Units in minutes (min) and hours (hour) are accepted. 53 api_key : str, optional 54 Tiingo API key . If not provided the environmental variable 55 TIINGO_API_KEY is read. The API key is *required*. 56 """ 57 58 def __init__( 59 self, 60 symbols, 61 start=None, 62 end=None, 63 retry_count=3, 64 pause=0.1, 65 timeout=30, 66 session=None, 67 freq=None, 68 api_key=None, 69 ): 70 super().__init__( 71 symbols, start, end, retry_count, pause, timeout, session, freq 72 ) 73 74 if isinstance(self.symbols, str): 75 self.symbols = [self.symbols] 76 self._symbol = "" 77 if api_key is None: 78 api_key = os.getenv("TIINGO_API_KEY") 79 if not api_key or not isinstance(api_key, str): 80 raise ValueError( 81 "The tiingo API key must be provided either " 82 "through the api_key variable or through the " 83 "environmental variable TIINGO_API_KEY." 84 ) 85 self.api_key = api_key 86 self._concat_axis = 0 87 88 @property 89 def url(self): 90 """API URL""" 91 _url = "https://api.tiingo.com/iex/{ticker}/prices" 92 return _url.format(ticker=self._symbol) 93 94 @property 95 def params(self): 96 """Parameters to use in API calls""" 97 return { 98 "startDate": self.start.strftime("%Y-%m-%d"), 99 "endDate": self.end.strftime("%Y-%m-%d"), 100 "resampleFreq": self.freq, 101 "format": "json", 102 } 103 104 def _get_crumb(self, *args): 105 pass 106 107 def _read_one_data(self, url, params): 108 """ read one data from specified URL """ 109 headers = { 110 "Content-Type": "application/json", 111 "Authorization": "Token " + self.api_key, 112 } 113 out = self._get_response(url, params=params, headers=headers).json() 114 return self._read_lines(out) 115 116 def _read_lines(self, out): 117 df = pd.DataFrame(out) 118 df["symbol"] = self._symbol 119 df["date"] = pd.to_datetime(df["date"]) 120 df = df.set_index(["symbol", "date"]) 121 return df 122 123 def read(self): 124 """Read data from connector""" 125 dfs = [] 126 for symbol in self.symbols: 127 self._symbol = symbol 128 try: 129 dfs.append(self._read_one_data(self.url, self.params)) 130 finally: 131 self.close() 132 return pd.concat(dfs, self._concat_axis) 133 134 135class TiingoDailyReader(_BaseReader): 136 """ 137 Historical daily data from Tiingo on equities, ETFs and mutual funds 138 139 Parameters 140 ---------- 141 symbols : {str, List[str]} 142 String symbol or list of symbols 143 start : string, int, date, datetime, Timestamp 144 Starting date, timestamp. Parses many different kind of date 145 representations (e.g., 'JAN-01-2010', '1/1/10', 'Jan, 1, 1980'). 146 Default starting date is 5 years before current date. 147 end : string, int, date, datetime, Timestamp 148 Ending date, timestamp. Same format as starting date. 149 retry_count : int, default 3 150 Number of times to retry query request. 151 pause : float, default 0.1 152 Time, in seconds, of the pause between retries. 153 session : Session, default None 154 requests.sessions.Session instance to be used 155 freq : {str, None} 156 Not used. 157 api_key : str, optional 158 Tiingo API key . If not provided the environmental variable 159 TIINGO_API_KEY is read. The API key is *required*. 160 """ 161 162 def __init__( 163 self, 164 symbols, 165 start=None, 166 end=None, 167 retry_count=3, 168 pause=0.1, 169 timeout=30, 170 session=None, 171 freq=None, 172 api_key=None, 173 ): 174 super(TiingoDailyReader, self).__init__( 175 symbols, start, end, retry_count, pause, timeout, session, freq 176 ) 177 if isinstance(self.symbols, str): 178 self.symbols = [self.symbols] 179 self._symbol = "" 180 if api_key is None: 181 api_key = os.getenv("TIINGO_API_KEY") 182 if not api_key or not isinstance(api_key, str): 183 raise ValueError( 184 "The tiingo API key must be provided either " 185 "through the api_key variable or through the " 186 "environmental variable TIINGO_API_KEY." 187 ) 188 self.api_key = api_key 189 self._concat_axis = 0 190 191 @property 192 def url(self): 193 """API URL""" 194 _url = "https://api.tiingo.com/tiingo/daily/{ticker}/prices" 195 return _url.format(ticker=self._symbol) 196 197 @property 198 def params(self): 199 """Parameters to use in API calls""" 200 return { 201 "startDate": self.start.strftime("%Y-%m-%d"), 202 "endDate": self.end.strftime("%Y-%m-%d"), 203 "format": "json", 204 } 205 206 def _get_crumb(self, *args): 207 pass 208 209 def _read_one_data(self, url, params): 210 """ read one data from specified URL """ 211 headers = { 212 "Content-Type": "application/json", 213 "Authorization": "Token " + self.api_key, 214 } 215 out = self._get_response(url, params=params, headers=headers).json() 216 return self._read_lines(out) 217 218 def _read_lines(self, out): 219 df = pd.DataFrame(out) 220 df["symbol"] = self._symbol 221 df["date"] = pd.to_datetime(df["date"]) 222 df = df.set_index(["symbol", "date"]) 223 return df 224 225 def read(self): 226 """Read data from connector""" 227 dfs = [] 228 for symbol in self.symbols: 229 self._symbol = symbol 230 try: 231 dfs.append(self._read_one_data(self.url, self.params)) 232 finally: 233 self.close() 234 return pd.concat(dfs, self._concat_axis) 235 236 237class TiingoMetaDataReader(TiingoDailyReader): 238 """ 239 Read metadata about symbols from Tiingo 240 241 Parameters 242 ---------- 243 symbols : {str, List[str]} 244 String symbol or list of symbols 245 start : string, int, date, datetime, Timestamp 246 Not used. 247 end : string, int, date, datetime, Timestamp 248 Not used. 249 retry_count : int, default 3 250 Number of times to retry query request. 251 pause : float, default 0.1 252 Time, in seconds, of the pause between retries. 253 session : Session, default None 254 requests.sessions.Session instance to be used 255 freq : {str, None} 256 Not used. 257 api_key : str, optional 258 Tiingo API key . If not provided the environmental variable 259 TIINGO_API_KEY is read. The API key is *required*. 260 """ 261 262 def __init__( 263 self, 264 symbols, 265 start=None, 266 end=None, 267 retry_count=3, 268 pause=0.1, 269 timeout=30, 270 session=None, 271 freq=None, 272 api_key=None, 273 ): 274 super(TiingoMetaDataReader, self).__init__( 275 symbols, start, end, retry_count, pause, timeout, session, freq, api_key 276 ) 277 self._concat_axis = 1 278 279 @property 280 def url(self): 281 """API URL""" 282 _url = "https://api.tiingo.com/tiingo/daily/{ticker}" 283 return _url.format(ticker=self._symbol) 284 285 @property 286 def params(self): 287 return None 288 289 def _read_lines(self, out): 290 s = pd.Series(out) 291 s.name = self._symbol 292 return s 293 294 295class TiingoQuoteReader(TiingoDailyReader): 296 """ 297 Read quotes (latest prices) from Tiingo 298 299 Parameters 300 ---------- 301 symbols : {str, List[str]} 302 String symbol or list of symbols 303 start : string, int, date, datetime, Timestamp 304 Not used. 305 end : string, int, date, datetime, Timestamp 306 Not used. 307 retry_count : int, default 3 308 Number of times to retry query request. 309 pause : float, default 0.1 310 Time, in seconds, of the pause between retries. 311 session : Session, default None 312 requests.sessions.Session instance to be used 313 freq : {str, None} 314 Not used. 315 api_key : str, optional 316 Tiingo API key . If not provided the environmental variable 317 TIINGO_API_KEY is read. The API key is *required*. 318 319 Notes 320 ----- 321 This is a special case of the daily reader which automatically selected 322 the latest data available for each symbol. 323 """ 324 325 @property 326 def params(self): 327 return None 328