#!/usr/bin/env python
# -*- coding: utf-8 -*-
# requests historical data from TWS and can save to a CSV file
# bar length is set to 15 minute bars
# legal bar lengths: 1 secs, 5 secs, 10 secs, 15 secs, 30 secs, 1
min,
# 2 mins, 3 mins, 5 mins, 10
mins, 15 mins, 20 mins, 30 mins, 1 hour,
# 2 hours, 3 hours, 4 hours,
8 hours, 1 day, 1 week, 1 month
# the data duration is set to 1 year (28800 seconds)
# can read/write a CSV OHLC file
# if the file exists, the first file date/time
becomes the inital request
# so earlier historical data is requested and
put at the front of the file
# uses Eastern Standard Time for data requests and writing
date/time to CSV
from ib.ext.Contract
import Contract
from ib.opt import ibConnection, message
import os.path, time
from collections import OrderedDict
def
contract(contractTuple):
newContract = Contract()
newContract.m_symbol =
contractTuple[0]
newContract.m_secType =
contractTuple[1]
newContract.m_exchange =
contractTuple[2]
newContract.m_currency =
contractTuple[3]
newContract.m_expiry =
contractTuple[4]
newContract.m_strike =
contractTuple[5]
newContract.m_right =
contractTuple[6]
'Contract Parameters: [%s,%s,%s,%s,%s,%s,%s]' % contractTuple
return newContract
def cleanMerge(seq1,seq2):
seen = set(seq1)
if seq1[0].split(',')[3:6]==[0,0,0]:
seen={x[0:10]
for x in seen}
seq1.extend([ x for x in seq2 if x[0:10]
not in seen])
else:
seq1.extend([ x for x in seq2 if x not in
seen])
return seq1
def SMA200(seq):
sum=0
for i in range(1,201):
sum+=float(seq[-i])
return sum/200
def SMA50(seq):
sum=0
for i in range(1,51):
sum+=float(seq[-i])
return sum/50
# convert UTC to New York EST timezone
def ESTtime(msg):
return time.gmtime(int(msg.date) -
(5 -
time.daylight)*3600)
def strDatetime(dt):
return dt[0:4]+','+dt[4:6]+','+dt[6:8]+','+dt[10:12]+','+dt[13:15]+','+dt[16:18]
def printData(msg):
if int(msg.high) > 0:
dataStr = '%s,%s,%s,%s,%s,%s' %
(strDatetime(msg.date),
msg.open,
msg.high,
msg.low,
msg.close,
msg.volume)
#print dataStr
if
printData.write2file:
printData.newRowData.append(dataStr+'\n')
else: printData.finished = True
def watchAll(msg):
print msg
def getIbHistData(sym,
sec='STK', exch='SMART', barLength='1 day', duration='1 Y'):
con = ibConnection()
con.registerAll(watchAll)
con.unregister(watchAll,
message.historicalData)
con.register(printData,
message.historicalData)
con.connect()
time.sleep(1)
contractTuple = (sym, sec,
exch, 'USD', '', 0.0, '')
endSecs =
time.time()-(5-time.daylight)*60*60 # to NY EST via gmtime
NYtime =
time.gmtime(endSecs)
# combined dateStr+timeStr format is
'YYYYMMDD hh:mm:ss TMZ'
dateStr =
time.strftime('%Y%m%d',
NYtime)
timeStr =
time.strftime(' %H:%M:%S EST',
NYtime)
# write2file=True to write data to:
fileName in the default directory
printData.write2file =
True
if printData.write2file:
directory="HistData"
if
not
os.path.exists(directory):os.makedirs(directory)
barLengthStr = barLength.replace(" ","_") # add the
bar length to the file name
fileName = directory+'/'+contractTuple[0]+'_'+contractTuple[1]+'_'+dateStr+'_'+barLengthStr+'.csv'
if
os.path.isfile(fileName): # found a
previous version
file =
open(fileName, 'r')
oldRowData
= file.readlines()
file.close()
prevRec=len(oldRowData)
if prevRec > 1:
#
get the new end date and time from the last data line of the
file
lastRow =
oldRowData[-1]
lastRowData=lastRow.split(",")
endtimeStr = ' %s:%s:%s EST' % (lastRowData[3],lastRowData[4],lastRowData[5])
if endtimeStr.find('::') :
if
barLength=='1 day':
duration=str((int(dateStr[0:4])-int(lastRow[0:4]))*366+(int(dateStr[4:6])-int(lastRow[5:7]))*31+int(dateStr[6:8])-int(lastRow[8:10]))+'
D'
print duration
else:
print "barlength too short"
#barlength is in mins and previous data has time
elif barLength.find('min')>0:
duration=str((int(dateStr[6:8])-int(lastRow[8:10]))*24*60+(int(timeStr[1:3])-int(lastRow[11:13]))*60+int(timeStr[4:6])-int(lastRow[14:16]))+'
D'
else:
print "other unit of time need more
work"
else:
oldRowData
= [] # and use default end
date
prevRec=0
oldRowData.append('Year,Month,Day,Hour,Minute,Second,Open,High,Low,Close,Volume\n')
printData.newRowData = []
printData.finished = False # true when historical data is
done
'End Date/Time String: [%s]' %
(dateStr+timeStr)
con.reqHistoricalData(0,
contract(contractTuple),
dateStr+timeStr, #
last requested bar date/time
duration, # quote duration, units: S,D,W,M,Y
barLength, # bar length
'TRADES', # what to show
0,
1 )
countSecs = 0
while not printData.finished and countSecs < 20: # wait up
to 20 seconds
time.sleep(1)
countSecs += 1
con.disconnect()
'CSV format:
year,month,day,hour,minute,second,open,high,low,close,volume'
if printData.write2file:
Data=cleanMerge(oldRowData,printData.newRowData)
file = open(fileName, 'w')
file.writelines(Data)
file.close()
len(Data)-prevRec,' of CSV data
appended to file: ', fileName
prices=[rec.split(",")[9]
for rec in Data]
return [SMA200(prices),SMA50(prices)]
if __name__ == "__main__":
#getIbHistData('COMP',sec='IND', exch='NASDAQ', duration='1 Y')
getIbHistData('TSLA',duration='1 Y')