1 import numpy as np
2 import dircache
3 from sets import Set
4 import time
5 import tables as pt
6 import sys
7 import time
8 import os
9 from optparse import OptionParser
10
12 timestamp = pt.Time64Col()
13
14
16 symbol = pt.StringCol(30)
17 exchange = pt.StringCol(10)
18 adj_high = pt.Float32Col()
19 adj_low = pt.Float32Col()
20 adj_open = pt.Float32Col()
21 adj_close = pt.Float32Col()
22 close = pt.Float32Col()
23 volume = pt.Float32Col()
24 timestamp = pt.Time64Col()
25 date = pt.Int32Col()
26 interval = pt.Time64Col()
27
28
31 self.filt_list=[]
32 self.timestamps=[]
33
34 - def getSymbols(self, listOfPaths, fileExtensionToRemove):
35 '''
36 @bug: This might not work if the path contains a folder whose name has .csv, or is some random file that has a .csv in it..
37 So, lets assume that whoever is using this is not going to "cheat" us
38 '''
39 listOflistOfStocks=list()
40 for path in listOfPaths:
41 stocksAtThisPath=list ()
42 stocksAtThisPath= dircache.listdir(str(path))
43
44 stocksAtThisPath = filter (lambda x:(str(x).find(str(fileExtensionToRemove)) > -1), stocksAtThisPath)
45
46 stocksAtThisPath = map(lambda x:(x.partition(str(fileExtensionToRemove))[0]),stocksAtThisPath)
47
48
49 listOflistOfStocks.append(stocksAtThisPath)
50 return listOflistOfStocks
51
52
53
54 - def getData(self, listOfListOfStocks, listOfInputPaths, startDate, endDate, listOfOutputPaths):
55 '''
56 @summary: This is where all the work happens
57 @attention: Assumption here is that past data never changes
58 @bug: The exchange is currently set pretty randomly
59 '''
60
61
62 noOfStocks=0
63 for stock_list in listOfListOfStocks:
64 noOfStocks+= len (stock_list)
65
66
67
68 print "No. of stocks: " + str(noOfStocks)
69 print "No. of timestamps: " + str(len(self.timestamps))
70
71
72 listIndex=-1
73 ctr=1;
74 for inputFileFolder in listOfInputPaths:
75 listIndex+=1
76 outputFileFolder= str(listOfOutputPaths[listIndex])
77 stocks_list= listOfListOfStocks[listIndex]
78 for i in range(0, len(stocks_list)):
79 print str(stocks_list[i]) +" "+str(ctr)+" of "+ str(noOfStocks)+" "+ str(time.strftime("%H:%M:%S"))
80 ctr= ctr+1
81
82 beginTS= startDate
83
84
85 if (os.path.exists(str(outputFileFolder) + str(stocks_list[i]+".h5"))):
86
87
88 h5f=pt.openFile(outputFileFolder + str(stocks_list[i]+".h5"), mode = "a")
89 print "Updating " +str(outputFileFolder + str(stocks_list[i]+".h5"))
90 table= h5f.getNode('/StrategyData', 'StrategyData')
91 beginTS= int(time.strftime("%Y%m%d", time.gmtime(table[table.nrows-1]['timestamp'])))
92 if (str(beginTS) >= self.timestamps[len(self.timestamps)-1]):
93
94 print str(stocks_list[i])+".h5 already is up to date. "+ str(time.strftime("%H:%M:%S"))
95 h5f.close()
96 continue
97 else:
98
99 beginTS= int(time.strftime("%Y%m%d", time.gmtime(table[table.nrows-1]['timestamp'])))
100 else:
101
102 print "Creating file: " + str(outputFileFolder) + str(stocks_list[i]+".h5")+" "+ str(time.strftime("%H:%M:%S"))
103
104 h5f = pt.openFile(str(outputFileFolder) + str(stocks_list[i]+".h5"), mode = "w")
105 group = h5f.createGroup("/", 'StrategyData')
106 table = h5f.createTable(group, 'StrategyData', StrategyDataModel)
107 beginTS= startDate
108
109
110 f=open(str(inputFileFolder)+str(stocks_list[i]+str(".CSV")))
111 jk=f.readlines()
112 f.close()
113 jk.pop(0)
114
115 self.filt_list=list()
116 filt_list_temp=filter(lambda x: (int(x.split(',')[1])> int(beginTS)) ,jk)
117 filt_list_temp=filter(lambda x: (int(x.split(',')[1])<= int(endDate)) ,filt_list_temp)
118 filt_list_temp=map(lambda x:(x.split(',')[0],x.split(',')[1],x.split(',')[2],x.split(',')[3],x.split(',')[4],x.split(',')[5],x.split(',')[6],(x.split(',')[7]).strip()),filt_list_temp)
119
120 self.filt_list.append(filt_list_temp)
121
122 if (table.nrows > 0):
123
124
125 tsStartIndex= np.array(self.timestamps).searchsorted(beginTS) +1
126
127 else:
128
129 tsStartIndex =0
130
131
132 k = 0
133 for j in range(tsStartIndex, len(self.timestamps)):
134 if (k< len(self.filt_list[0])):
135
136 if((self.timestamps[j])< (self.filt_list[0][k][1])):
137 row=table.row
138 row['exchange'] = 'NYSE'
139 row['symbol'] = self.filt_list[0][k][0]
140 row['adj_open'] = np.NaN
141 row['adj_close'] = np.NaN
142 row['adj_high'] = np.NaN
143 row['adj_low'] = np.NaN
144 row['close'] = np.NaN
145 row['volume'] = np.NaN
146 parseddate = time.strptime(self.timestamps[j],'%Y%m%d')
147
148 row['timestamp'] = time.mktime(parseddate)
149 row.append()
150
151 elif(self.timestamps[j]==self.filt_list[0][k][1]):
152 row=table.row
153 row['exchange'] = 'NASDAQ'
154 row['symbol'] = self.filt_list[0][k][0]
155 row['adj_open'] = float(self.filt_list[0][k][2])
156 row['adj_close'] = float(self.filt_list[0][k][5])
157 row['adj_high'] = float(self.filt_list[0][k][3])
158 row['adj_low'] = float(self.filt_list[0][k][4])
159 row['close'] = float(self.filt_list[0][k][7])
160 row['volume'] = int(self.filt_list[0][k][6])
161 parseddate = time.strptime(self.timestamps[j],'%Y%m%d')
162
163 row['timestamp'] = time.mktime(parseddate)
164 row.append()
165
166 k=k+1
167 else:
168 print"###############Something has gone wrong. A stock had a timestamp which was not in the timestamp list..."
169 print "TS: " + str(self.timestamps[j]) + ", Stock: " + str (self.filt_list[0][k][1])
170 k=k+1
171
172
173
174 else:
175 row=table.row
176 row['exchange'] = 'NYSE'
177 row['symbol'] = stocks_list[i]
178 row['adj_open'] = np.NaN
179 row['adj_close'] = np.NaN
180 row['adj_high'] = np.NaN
181 row['adj_low'] = np.NaN
182 row['close'] = np.NaN
183 row['volume'] = np.NaN
184 parseddate = time.strptime(self.timestamps[j],'%Y%m%d')
185
186 row['timestamp'] = time.mktime(parseddate)
187
188 row.append()
189
190
191 table.flush()
192 h5f.close()
193
194
195 print "Writing data done. "+ str(time.strftime("%H:%M:%S"))
196
197
199 '''
200 @bug: Formerly did not take care of DST
201 @attention: fixed DST bug. No known DST problems now.
202 '''
203
204 DAY=86400
205
206 if (os.path.exists(fileName)):
207 print "Updating timestamps"
208 h5f = pt.openFile(str(fileName), mode = "a")
209 table=h5f.getNode('/timestamps','timestamps')
210
211 lastTSFromFile= str(time.strftime("%Y%m%d", time.gmtime(table[table.nrows-1]['timestamp'])))
212
213 if (str(startDate)<= lastTSFromFile):
214 startDate=str(time.strftime("%Y%m%d", time.gmtime(table[table.nrows-1]['timestamp'])))
215
216 else:
217 print "Creating new timestamp file"
218 h5f = pt.openFile(str(fileName), mode = "w")
219 group = h5f.createGroup("/", 'timestamps')
220 table = h5f.createTable(group, 'timestamps', TimestampsModel)
221
222 print "start: " + str(startDate)+", end: "+ str(endDate)
223
224 tslist=list()
225 ctr=1
226 if (str(startDate) <= str(endDate)):
227 listIndex=-1
228 for path in listOfInputPaths:
229 listIndex+=1
230 for stock in listOflistOfStocks[listIndex]:
231
232 ctr+=1
233
234 f=open(str(path)+str(stock+str(".CSV")))
235 j=f.readlines()
236 j.pop(0)
237 f.close()
238
239 filt_list_temp=filter(lambda x: (int(x.split(',')[1])> int(startDate)) ,j)
240 filt_list_temp=filter(lambda x: (int(x.split(',')[1])<= int(endDate)) ,filt_list_temp)
241
242 if not (filt_list_temp):
243 print str(stock.split('.')[0]) + " didn't exist in this period\n"
244
245
246 else:
247
248 filt_list_temp=map(lambda x:(x.split(',')[1]),filt_list_temp)
249 filt_list_temp= map(lambda item:(time.mktime(time.strptime(item,'%Y%m%d'))), filt_list_temp)
250
251 for item in filt_list_temp:
252 try:
253 tslist.index(int(item))
254 except:
255 tslist.append(int(item))
256
257
258 if (len(tslist)>0):
259 if (self.continueChecking(tslist, startDate, endDate)== False):
260 break
261
262
263
264 tslist.sort()
265
266 for ts in tslist:
267 row= table.row
268 row['timestamp']= ts
269
270 row.append()
271
272
273 table.flush()
274 h5f.close()
275
276
277
278
280 '''
281 @summary: This function basically checks if a day that we haven't found any trades on is a weekend. If so- we don't need to keep looking. The converter will work just fine even without this function- but it will take more time- because it will keep looking for timestamps that it is not going to find.
282 @bug: There is a Daylight savings time bug here too- but it won't adversely affect anything because DST always happens over the weekends! Though if the time change happens on a weekday sometime in the distant past/future this function may break.
283 '''
284
285 index=1
286 DAY=86400
287
288 while (index < len(tsList)):
289 if (int(tsList[index])- int(tsList[index -1]) > DAY):
290 tempTS= tsList[index-1] + DAY
291 while (tempTS< tsList[index]):
292 timeStruct= time.gmtime(tempTS)
293 if not ((timeStruct[6] == 5) or (timeStruct[6] == 6)):
294
295 return True
296 tempTS+=DAY
297
298 index+=1
299
300
301 tempTS=time.mktime(time.strptime(str(beginTS),'%Y%m%d'))
302
303 while (int(tsList[0])- int(tempTS) > DAY):
304 timeStruct= time.gmtime((tempTS))
305 if not ((timeStruct[6] == 5) or (timeStruct[6] == 6)):
306 return True
307
308 tempTS+=DAY
309
310
311 tempTS=time.mktime(time.strptime(str(endTS),'%Y%m%d'))
312
313 while (int(tempTS)- int(tsList[len(tsList)-1]) > DAY):
314 timeStruct= time.gmtime(tempTS)
315 if not ((timeStruct[6] == 5) or (timeStruct[6] == 6)):
316 return True
317
318 tempTS+=DAY
319
320
321 print "Smartly figured out that we don't need to continue"
322 return False
323
324
325
326
328 h5f = pt.openFile(str(fileName), mode = "a")
329 fileIterator= h5f.root.timestamps.timestamps
330
331 tslist=[]
332 for row in fileIterator.iterrows():
333 temp= str(time.strftime("%Y%m%d", time.gmtime(row['timestamp'])))
334
335 if (temp>= str(beginTS)) and (temp <= str(endTS)):
336 tslist.append(temp)
337
338 if (temp > str(endTS)):
339 break
340
341 h5f.close()
342
343 self.timestamps=tslist
344
345
347 '''
348 @summary: This function removes HDF files that correspond to CSV files that existed in the past- but don't exist anymore. Possibly because the stock was delisted or something like that.
349 '''
350 print "Removing HDF files for which there is no corresponding CSV file"
351 listOfListOfHdfFiles=self.getSymbols(listOfOutputPaths, ".h5")
352 listOfListOfCsvFiles=self.getSymbols(listOfInputPaths, ".csv")
353
354 ctr=-1
355 for listofHDFFiles in listOfListOfHdfFiles:
356 ctr+=1
357 for hdfFile in listofHDFFiles:
358 try:
359
360 listOfListOfCsvFiles[ctr].index(hdfFile)
361 except:
362 print "Removing "+str(listOfOutputPaths[ctr]) + str(hdfFile)+".h5"
363 os.remove(str(listOfOutputPaths[ctr]) + str(hdfFile)+".h5")
364
365
366
367
368 print "Done removing HDF files (if any)"
369
370
371
372
373 if __name__ == "__main__":
374 '''
375 @attention: The HDF file containing the timestamps should not be in any of the output paths because, if it is, then it will be deleted at the end.
376 '''
377
378 print "Starting..."+ str(time.strftime("%H:%M:%S"))
379
380 parser = OptionParser()
381 args = parser.parse_args()[1]
382 endDate= args[0]
383 print "End date is: " + str (endDate)
384
385
386
387 startDate = 19840101
388
389
390
391
392
393 timestampsFile="C:\\generated data files\\timestamp files\\timestamps.h5"
394
395
396 spd = StockPriceData()
397
398
399 listOfInputPaths= list()
400 listOfInputPaths.append("C:\\Trading data text\\Stocks\\Delisted Securities\\US Recent\\")
401 listOfInputPaths.append ("C:\\Trading data text\\Stocks\\US\\AMEX\\")
402 listOfInputPaths.append ("C:\\Trading data text\\Stocks\\US\\Delisted Securities\\")
403 listOfInputPaths.append ("C:\\Trading data text\\Stocks\\US\OTC\\")
404 listOfInputPaths.append ("C:\\Trading data text\\Stocks\\US\\NASDAQ\\")
405 listOfInputPaths.append ("C:\\Trading data text\\Stocks\\US\NYSE\\")
406 listOfInputPaths.append ("C:\\Trading data text\\Stocks\\US\\NYSE Arca\\")
407
408 listOfOutputPaths= list()
409 listOfOutputPaths.append("C:\\generated data files\\one stock per file\\maintain folder structure\\Delisted_US_Recent\\")
410 listOfOutputPaths.append("C:\\generated data files\\one stock per file\\maintain folder structure\\US_AMEX\\")
411 listOfOutputPaths.append("C:\\generated data files\\one stock per file\\maintain folder structure\\US_Delisted\\")
412 listOfOutputPaths.append("C:\\generated data files\\one stock per file\\maintain folder structure\OTC\\")
413 listOfOutputPaths.append("C:\\generated data files\\one stock per file\\maintain folder structure\\US_NASDAQ\\")
414 listOfOutputPaths.append("C:\\generated data files\\one stock per file\\maintain folder structure\\US_NYSE\\")
415 listOfOutputPaths.append("C:\\generated data files\\one stock per file\\maintain folder structure\\US_NYSE Arca\\")
416
417
418 for path in listOfOutputPaths:
419 if not (os.access(path, os.F_OK)):
420
421 os.makedirs(path)
422
423
424 if (len(listOfInputPaths)!= len(listOfOutputPaths)):
425 print "No. of input paths not equal to the number of output paths.. quitting"
426 sys.exit("FAILURE")
427 listOfListOfStocks=spd.getSymbols(listOfInputPaths, ".csv")
428
429
430 if(endDate<startDate):
431 print "Error: enddate earlier than startdate"
432 sys.exit(0)
433
434 spd.makeOrUpdateTimestampsFile(timestampsFile, listOfListOfStocks, listOfInputPaths, startDate, endDate)
435 spd.readTimestampsFromFile(timestampsFile, startDate, endDate)
436 spd.getData(listOfListOfStocks, listOfInputPaths, startDate, endDate, listOfOutputPaths)
437 spd.keepHDFFilesInSyncWithCSV(listOfInputPaths, listOfOutputPaths)
438
439 print "All Done. Conversion from CSV to HDF5 is complete."
440