本文提供了一个每个交易日开盘前不用重连CTP的方法。如果不是特殊需求,强烈建议每天盘前重启程序。感谢viponedream在维恩的派论坛里的分享!
设计初衷
针对懒人,打算挂上去就不管它,让它自己运行,一个星期,一个月,甚至更久。
设计思路
主要需要解决以下几个问题:
1. 定时连接CTP。在uiMainWindow.py中的 updateStatusBar中,增加时间判断,到点了自动重连CTP。
# 计时器 # 晚上21:00是夜盘时间,提前20分钟连接 CTP dt = datetime.now() if dt.hour == 20 or dt.hour == 8: if dt.minute == 40 and dt.second == 0: self.connectCtp()
2. 历史持仓,即以前的老仓位。策略一开始要不要处理老仓位?如果只管策略自己开的那些仓位,这样中途停机会造成问题,所以还是把老仓位一起赋给策略吧。有人是把历史仓位存在一个文件中。我觉得没什么必要(不是单品种多策略的话)。直接在策略中onPosition中读取历史持仓了。(要先在ctaEngine中增加一个处理函数,把onPosition推到相应的策略去)
def onPosition(self, pos):
# 还没有开过仓,或,还没有获取历史仓位
if self.isPrePosHaved or self.isAlreadyTraded:
return elif pos.position != 0: if pos.direction == DIRECTION_LONG: self.pos = pos.position else: self.pos = -pos.position self.lastEntryPrice = pos.price self.isPrePosHaved = True print (u'{0} {1} 历史持仓 {2} 开仓均价{3}'.format(datetime.now(), self.vtSymbol, self.pos, pos.price)) pass
3. 今仓,昨仓重置。原来的系统是日内的,碰到换日就会出错,所以要重置一下。这个要修改几个地方:
1)CtpTdApi中的 init:
# 缓存持仓数据的字典
self.posBufferDict = {}
# 保存合约代码和交易所的印射关系
self.symbolExchangeDict = {}
# 保存合约代码和合约大小的印射关系
self.symbolSizeDict = {} # 缓存SHFE持仓数据的字典
self.posBufferDictShfe = {}
2)ctpGateway.py修改回调函数:
def onRspQryInvestorPosition(self, data, error, n, last): """持仓查询回报"""
# 更新持仓缓存,并获取VT系统中持仓对象的返回值 exchange = self.symbolExchangeDict.get(data['InstrumentID'], EXCHANGE_UNKNOWN) size = self.symbolSizeDict.get(data['InstrumentID'], 1) # 获取缓存字典中的持仓缓存,若无则创建并初始化 positionName = '.'.join([data['InstrumentID'], data['PosiDirection']]) if exchange == EXCHANGE_SHFE:
#上期所的专门一个 dict
if positionName in self.posBufferDictShfe: posBuffer = self.posBufferDictShfe[positionName] else: posBuffer = PositionBuffer(data, self.gatewayName) self.posBufferDictShfe[positionName] = posBuffer else:
# 其它交易所 if positionName in self.posBufferDict: posBuffer = self.posBufferDict[positionName] else: posBuffer = PositionBuffer(data, self.gatewayName) self.posBufferDict[positionName] = posBuffer
# 缓存持仓信息,上期所的只有最后一个才全部返回持仓信息 ,其它交易所直接返回 if exchange == EXCHANGE_SHFE:
posBuffer.updateShfeBuffer(data, size) if last: for positionName in self.posBufferDictShfe: pos = self.posBufferDictShfe[positionName].pos self.gateway.onPosition(pos) self.posBufferDictShfe = {} else: pos = posBuffer.updateBuffer(data, size) self.gateway.onPosition(pos)
3)在ctaEngine中增加两个事件处理函数。
def registerEvent(self): # 加上以下两个 self.eventEngine.register(EVENT_POSITION, self.processExchangePositionEvent) self.eventEngine.register(EVENT_TIMER, self.onTimer)
def onTimer(self, event): dt = datetime.now() if dt.hour == 21 and dt.minute==0 and dt.second==1:
# 夜盘开盘第一时间重置,清空则默认使用平昨
self.posBufferDict = {} if self.tickStrategyDict: for key in self.tickStrategyDict: for strategy in self.tickStrategyDict[key]: strategy.onTimer() pass
def processExchangePositionEvent(self, event): pos = event.dict_['data'] if pos.vtSymbol in self.tickStrategyDict: for strategy in self.tickStrategyDict[pos.vtSymbol]: if pos.direction == DIRECTION_LONG: strategy.exchangePos = pos.position else: strategy.exchangePos = -pos.position strategy.onPosition(pos)
以上修改,策略已经可以连续跑起来了。
强调的是:一个品种只能一个策略,并且只能单方向,不能同时有多和有空。
基于python的开源交易平台开发框架。截止目前,vn.py项目在Github上的Star已经达到5787,量化交易类开源项目第1,量化类项目第3(1、2依旧分别是Zipline和TuShare)。
项目官网:http://www.vnpy.org
论坛地址:www.vnpie.com
知乎专栏:https://zhuanlan.zhihu.com/vn-py
Developed by Traders,
for Traders