这里主要针对vnpy吧,因为我在用这个平台,说到这里还是非常感谢作者,给新手们真的减少了好多的时间。
Github上的Issue
- tick合成分钟线。在ctp的tick流中,有一些tick只是快照数据,并没有真正成交,也就是成交量为0的tick。这些tick现在是全部用作了分钟线的合成计算,我比较过一些数据,mc,tb的,他们的数据逻辑从我的逆向分析来讲应该是过滤掉了成交量为0的tick了的。
- tick合成分钟线。只判断了Minute,这样会导致一个问题,就是今天23:00:00和明天的09:00:00的tick数据会统一当做今天23:00的分钟线,其实这这分钟的tick里面只包含了一根23:00的tick,其余的全部是明天9点的。
- 分钟线合成多分钟线。KkStrategy里面是合成的5分钟线。我做了一个测试,比如:09:00:00,09:01:00,09:02:00,09:03:00,09:04:00,09:05:00,09:06:00 这个序列,09:00:00不会参与计算,09:01:00-09:05:00会参与一个5分钟线的计算。我比较过文华的数据,他们是09:00:00-09:04:00参与的计算。
解决方案:
- 过滤掉没有成交量的tick就行。代码:
def onTick(self, tick):
"""收到行情TICK推送(必须由用户继承实现)"""
# print str(tick.__dict__)
# 过滤掉没有成交量的tick Issue411-1
if self.preTick is not None and self.preTick.volume == tick.volume:
return
# 计算分钟线
"""
在原有逻辑的基础上增加了对小时的判断,为什么呢?因为前一天的23:00:00和第二天的09:00:00的minute都是0
但是其实是在不同的小时里面了,按原有的逻辑的话,今天早上09:00:00~09:01:00的走势会作为昨天23:00的K线展示
Issue411-2
TODO:
1. 但是要考虑增加这个逻辑的性能消耗和实盘的一个权衡
2. 还有23:00这分钟里面一般只有两个tick,可以根据实际情况去掉
"""
tick_hour = tick.datetime.hour
tick_minute = tick.datetime.minute
if tick_minute != self.barMinute or tick_hour != self.barHour:
if self.minBar:
if self.preTick.volume - self.minBar.volume < 0:
print self.minBar.__dict__
print self.preTick.__dict__
print tick.__dict__
raise ValueError('bar volume less than 0')
self.minBar.volume = self.preTick.volume - self.minBar.volume
self.onMinBar(self.minBar)
bar = CtaBarData()
bar.vtSymbol = tick.vtSymbol
bar.symbol = tick.symbol
bar.exchange = tick.exchange
bar.open = tick.lastPrice
bar.high = tick.lastPrice
bar.low = tick.lastPrice
bar.close = tick.lastPrice
bar.date = tick.date
bar.time = tick.time[:8]
bar.datetime = tick.datetime.replace(second=0, microsecond=0) # K线的时间设为第一个Tick的时间
# 实盘中用不到的数据可以选择不算,从而加快速度
if self.preTick is None:
bar.volume = 0
else:
if tick.datetime.time() > self.tickVolumeSplitTime:
if not self.tickVolumeResetSwitch:
bar.volume = 0
self.tickVolumeResetSwitch = True
else:
bar.volume = self.preTick.volume
else:
# 真坑,通过逆向分析发现上海期货的tick合成规则是21开始,如果前一个交易日没有夜市,则今天重新计算volume
if (tick.datetime - self.preTick.datetime).total_seconds() > (3600*12) and self.preTick.datetime.hour < 21:
bar.volume = 0
else:
bar.volume = self.preTick.volume
self.tickVolumeResetSwitch = False
# bar.openInterest = tick.openInterest
self.minBar = bar # 这种写法为了减少一层访问,加快速度
self.barMinute = tick_minute # 更新当前的分钟
self.barHour = tick_hour # 更新当前的小时
else: # 否则继续累加新的K线
bar = self.minBar # 写法同样为了加快速度
bar.high = max(bar.high, tick.lastPrice)
bar.low = min(bar.low, tick.lastPrice)
bar.close = tick.lastPrice
self.preTick = tick
- 加上Hour的过滤就行,可以参考上面的代码。
- 改了一些逻辑,看代码:
def onMinBar(self, bar):
"""收到Bar推送(必须由用户继承实现)"""
self.dtMinBarCount += 1
# 特殊处理分钟线,减少后面处理时间
# TODO: 实盘时一定要精简代码,不要太多if else,减少处理时间
if self.multiFramePeriod == 1:
self.onMultiFrameBar(bar)
return
# 如果当前是一个K线周期走完
# TODO:这时的计算逻辑比较简单,计算正确的前提是每个小时的开始是从0分开始,
# TODO:否则就会出错,也就是要保证该品种的活跃度要达到每分钟内必须有成交量
if bar.datetime.minute % self.multiFramePeriod == 0:
# 如果已经有聚合5分钟K线
if self.multiFrameBar:
mmBar = self.multiFrameBar
# 推送5分钟线数据
self.onMultiFrameBar(mmBar)
# 清空5分钟线数据缓存
self.multiFrameBar = None
# clark add 建立缓存,不应该在下一分钟建立缓存
# print 'init 5 bar ' + str(bar.datetime)
mmBar = CtaBarData()
mmBar.vtSymbol = bar.vtSymbol
mmBar.symbol = bar.symbol
mmBar.exchange = bar.exchange
mmBar.open = bar.open
mmBar.high = bar.high
mmBar.low = bar.low
mmBar.close = bar.close
mmBar.date = bar.date
mmBar.time = bar.time
mmBar.datetime = bar.datetime
mmBar.volume = bar.volume
self.multiFrameBar = mmBar
else:
# 如果没有缓存则新建
if not self.multiFrameBar:
mmBar = CtaBarData()
mmBar.vtSymbol = bar.vtSymbol
mmBar.symbol = bar.symbol
mmBar.exchange = bar.exchange
mmBar.open = bar.open
mmBar.high = bar.high
mmBar.low = bar.low
mmBar.close = bar.close
mmBar.date = bar.date
mmBar.time = bar.time
mmBar.datetime = bar.datetime
mmBar.volume = bar.volume
self.multiFrameBar = mmBar
else:
mmBar = self.multiFrameBar
mmBar.high = max(mmBar.high, bar.high)
mmBar.low = min(mmBar.low, bar.low)
mmBar.close = bar.close
mmBar.volume += bar.volume
Comments
comments powered by Disqus