作者:viponedream ;来源:维恩的派论坛
针对懒人,打算挂上去就不管它,让它自己运行,一个星期,一个月,甚至更久。
目前想到的就是几个地方要改一下,欢迎大家探讨怎样用vnpy来做隔夜。
一,定时连接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()
二,历史持仓,即以前的老仓位。策略一开始要不要处理老仓位?目前是不管的,只管策略自己开的那些仓位。
这样中途停机造成问题。所以还是把老仓位一起赋给策略吧。
有人是把历史仓位存在一个文件中。我觉得没什么必要(不是单品种多策略的话)。
直接在策略中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
三,今仓,昨仓重置。
原来的系统是日内的,碰到换日就会出错。所以要重置一下。
这个要修改两个地方。
先在 CtpTdApi的 init 中加上
self.posBufferDict = {} # 缓存持仓数据的字典
self.symbolExchangeDict = {} # 保存合约代码和交易所的印射关系
self.symbolSizeDict = {} # 保存合约代码和合约大小的印射关系
# 加上下面这一行
self.posBufferDictShfe = {} # 缓存SHFE持仓数据的字典1,是在CTPGATEWAY.PY 修改这个回调。
def onRspQryInvestorPosition(self, data, error, n, last):
"""持仓查询回报"""
#print datetime.now(),u'持仓回报', data
# 更新持仓缓存,并获取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) # 不必 return
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)
2,在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)
以上修改,策略已经可以连续跑起来了。强调的是:一个品种只能一个策略,并且只能单方向,不能同时有多和有空。# 涉及到的变量,自己加的。
self.isPrePosHaved self.isAlreadyTraded 自己加在策略上或者ctaTemplate都行。
onTimer()也自己加上的。