vn.py官网
开源量化社区
Member
avatar
加入于:
帖子: 58
声望: 0

先看一下原版的 on_tick 逻辑以及问题点:

def on_tick(self, tick: TickData):
    """
    Callback of new tick data update.
    """
    if (
        self.last_tick_time
        and self.last_tick_time.minute != tick.datetime.minute
    ):
        bars = {}
        for vt_symbol, bg in self.bgs.items():
            bars[vt_symbol] = bg.generate()
        self.on_bars(bars)

    bg: BarGenerator = self.bgs[tick.vt_symbol]
    bg.update_tick(tick)

    self.last_tick_time = tick.datetime

问题1:在订阅多个品种的时候,无法保证多品种的 tick 推送到 on_tick 里面的先后顺序,进而会出现 前一个 tick时间戳是第59秒, 后一个 tick时间戳变为了第0秒,然后再下一个时间戳又变为了第59秒的问题。每当tick的时间戳反复跨越第0秒时,会导致 bg.generate() 在很短的时间内,被多次被调用,每次被调用 bg.generate() 后,bg,bar 就会被清空为 None值了,进而导致第二次推到 on_bars 里面的 bars 大部分为None,因为在很短的时间内,几乎没有任何新的tick数据 调用了 bg.update_tick(tick)。

问题2:self.last_tick_time = tick.datetime, 这个写法在多合约订阅的时候,问题如上,这个写法不能保证,tick.datetime 的时间戳就一定比 self.last_tick_time 更晚。

问题3: 某些不活跃的合约,特别是期权合约,会存在一分钟之内没有新的tick过来的情况,如果直接调用 bg.generate() 的话,同样得到的Bar数据会为None

改进版的写法:

def on_tick(self, tick: TickData):
   """
   Callback of new tick data update.
   """

    if (
            self.last_tick_time and tick.datetime > self.last_tick_time
            and self.last_tick_time.minute != tick.datetime.minute
    ):

        bars = {}
        for vt_symbol, bg in self.bgs.items():

            if bg.bar is not None:
                bars[vt_symbol] = bg.generate()  
                bg.last_bar = bars[vt_symbol]
            elif bg.last_bar is not None:
                bars[vt_symbol] = bg.last_bar
            else:
                bars[vt_symbol] = None

        self.on_bars(bars)

    bg: BarGenerator = self.bgs[tick.vt_symbol]
    bg.update_tick(tick)

    if self.last_tick_time is None:
        self.last_tick_time = tick.datetime
    elif self.last_tick_time and self.last_tick_time < tick.datetime:
        self.last_tick_time = tick.datetime

改进点1: 保证了 缓存中的 last_tick_time 时间戳,一定晚于 新来的 tick的时间戳,并且只有当 tick的时间戳 晚于 last_tick_time 时间戳时,才会合成 bars
改进点2: 每个品种的 bar里面,都缓存了 last_bar的属性,用于某些不活跃的品种 一分钟内没有新tick过来而无法合成 bars的情况。这个情况下,直接用上一个非None 的last_bar 推到 on_bars()里面

改完之后,on_bars里面已经很少会出现 bar 为 None的情况了。 如果还有什么考虑不周的地方,欢迎大家来指正共同改进~~

Member
avatar
加入于:
帖子: 58
声望: 0

改完之后,我有个疑问就是,为什么多合约推到 on_tick 函数里面时,tick 时间戳的先后顺序无法得到保证了? 如果可以保证 tick 时间戳是按照时间顺序的话,那么很多相关的问题都可以得到解决了

Member
avatar
加入于:
帖子: 13
声望: 0

痛并快乐着 wrote:

先看一下原版的 on_tick 逻辑以及问题点:

def on_tick(self, tick: TickData):
    """
    Callback of new tick data update.
    """
    if (
        self.last_tick_time
        and self.last_tick_time.minute != tick.datetime.minute
    ):
        bars = {}
        for vt_symbol, bg in self.bgs.items():
            bars[vt_symbol] = bg.generate()
        self.on_bars(bars)

    bg: BarGenerator = self.bgs[tick.vt_symbol]
    bg.update_tick(tick)

    self.last_tick_time = tick.datetime

问题1:在订阅多个品种的时候,无法保证多品种的 tick 推送到 on_tick 里面的先后顺序,进而会出现 前一个 tick时间戳是第59秒, 后一个 tick时间戳变为了第0秒,然后再下一个时间戳又变为了第59秒的问题。每当tick的时间戳反复跨越第0秒时,会导致 bg.generate() 在很短的时间内,被多次被调用,每次被调用 bg.generate() 后,bg,bar 就会被清空为 None值了,进而导致第二次推到 on_bars 里面的 bars 大部分为None,因为在很短的时间内,几乎没有任何新的tick数据 调用了 bg.update_tick(tick)。

问题2:self.last_tick_time = tick.datetime, 这个写法在多合约订阅的时候,问题如上,这个写法不能保证,tick.datetime 的时间戳就一定比 self.last_tick_time 更晚。

问题3: 某些不活跃的合约,特别是期权合约,会存在一分钟之内没有新的tick过来的情况,如果直接调用 bg.generate() 的话,同样得到的Bar数据会为None

改进版的写法:

def on_tick(self, tick: TickData):
   """
   Callback of new tick data update.
   """
    
    if (
            self.last_tick_time and tick.datetime > self.last_tick_time
            and self.last_tick_time.minute != tick.datetime.minute
    ):

        bars = {}
        for vt_symbol, bg in self.bgs.items():

            if bg.bar is not None:
                bars[vt_symbol] = bg.generate()  
                bg.last_bar = bars[vt_symbol]
            elif bg.last_bar is not None:
                bars[vt_symbol] = bg.last_bar
            else:
                bars[vt_symbol] = None

        self.on_bars(bars)

    bg: BarGenerator = self.bgs[tick.vt_symbol]
    bg.update_tick(tick)

    if self.last_tick_time is None:
        self.last_tick_time = tick.datetime
    elif self.last_tick_time and self.last_tick_time < tick.datetime:
        self.last_tick_time = tick.datetime

改进点1: 保证了 缓存中的 last_tick_time 时间戳,一定晚于 新来的 tick的时间戳,并且只有当 tick的时间戳 晚于 last_tick_time 时间戳时,才会合成 bars
改进点2: 每个品种的 bar里面,都缓存了 last_bar的属性,用于某些不活跃的品种 一分钟内没有新tick过来而无法合成 bars的情况。这个情况下,直接用上一个非None 的last_bar 推到 on_bars()里面

改完之后,on_bars里面已经很少会出现 bar 为 None的情况了。 如果还有什么考虑不周的地方,欢迎大家来指正共同改进~~

请问您在修改完此模块后是否能正常收到bars?我也遇到相同问题

Member
avatar
加入于:
帖子: 58
声望: 0

改完之后,基本上都可以正常收到bars了

© 2015-2019 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号-3

沪公网安备 31011502017034号