Date Tags Quant

这里主要针对vnpy吧,因为我在用这个平台,说到这里还是非常感谢作者,给新手们真的减少了好多的时间。

Github上的Issue

  1. tick合成分钟线。在ctp的tick流中,有一些tick只是快照数据,并没有真正成交,也就是成交量为0的tick。这些tick现在是全部用作了分钟线的合成计算,我比较过一些数据,mc,tb的,他们的数据逻辑从我的逆向分析来讲应该是过滤掉了成交量为0的tick了的。
  2. tick合成分钟线。只判断了Minute,这样会导致一个问题,就是今天23:00:00和明天的09:00:00的tick数据会统一当做今天23:00的分钟线,其实这这分钟的tick里面只包含了一根23:00的tick,其余的全部是明天9点的。
  3. 分钟线合成多分钟线。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参与的计算。

解决方案:

  1. 过滤掉没有成交量的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
  1. 加上Hour的过滤就行,可以参考上面的代码。
  2. 改了一些逻辑,看代码:
    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