python 程序化交易_IB+python实现程序化交易 - 小众知识

001xeyYegy6JySk4PWP6b&690

最近有点儿忙,只能每周一更了。

建立好python环境后运行tws客户端。注意要去configuration里面把api的功能开启。另外建议把127.0.0.1加为信任ip,免得每次tws都会弹个对话框跟你确认。(本来想截个图方便读者,可是tws这会儿登不了--周六凌晨)

首先是建立链接,

需要引用 connection或者是ibConnection。后者封装了前者,用起来更方便些。

from ib.opt import ibConnection

有了上面的引用后,下面两行就链接到了tws:

con = ibConnection()

con.connect()

因为我们需要从tws接受信息,所以实际上两行之间还要加点东西,用来告诉系统谁负责处理什么信息。

from ib.opt import ibConnection, message

con = ibConnection()

con.register(printData, message.historicalData)

con.connect()

注意增加的内容:1、多引入了一个message模块,里面有一个message类。historicalData是它的属性(这个不知道我理解的正确与否,我在message.py里找不到这个属性的定义)。总之

con.register(printData, message.historicalData)

这句就是告诉系统,如果收到关于historicalData的消息,由printData这个函数处理。注意你有可能会遇到一些sample代码,里面用的HistoricalData。这是版本问题。最新的0.8版是用的historicalData。

有时候你还需要定义一些其它的函数处理其他的消息类型,见下面的例子。

下一个步骤是定义contract。又得引用:

from ib.ext.Contract import Contract

引入contact这个类,创建一个对象:

newContract = Contract()

修改里面的属性

newContract.m_symbol = 'TSLA'

newContract.m_secType = 'STK'

newContract.m_exchange = 'SMART'

newContract.m_currency = 'USD'

以下期权才用得到,对于股票就是如下设定:

newContract.m_expiry = ''

newContract.m_strike = 0.0

newContract.m_right = ''

准备工作好了以后,读取历史数据的关键函数是

reqHistoricalData(tickerId, contract,

endDateTime, # last requested bar date/time

durationStr, # quote duration, units: S,D,W,M,Y

barSizeSetting, # bar length

whatToShow, # what to show

useRTH, formatDate )

注意同一个ibConnection对象,tickerId不能重复,所以每次调用记得tickerId+1。如果close之后重新connect则tickerId清零。

下面用到的CSV文件读写我就不特别说明了,特别简单。

以下是我的代码。改编自Merlinson 的request historical data example.py。主要改动为两点:

1、时间计算:原来的代码bar length改成1天之后运行出错。

2、新读取数据与旧数据的合并:原来的版本如果今天白天运行过一次,在收盘后再运行一次,如果收盘后ask, bid, last任何一项出现变动,CSV文件里就会出现两条当日记录。这个问题相信已经得到解决。另外我的版本新数据在底,老数据在顶。

另外我加了简单50日均线和200日均线,偷懒作为返回函数值了……

欢迎测试和提供修改意见。

=============================

#!/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]

print '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

print '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()

print '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()

print 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')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值