🚀 AI 一键生成 joinquant 策略代码

JoinQuant 平台如何自定义 handle_tick 的执行频率以加速回测?

joinquant | 发布时间: 2026/5/27
以下内容由 EasyQuant 生成。

问题描述

如何减少tick回测调用handle_tick的次数?

实际回测中发现如果每个tick都调用handle_tick()函数,会导致时间开销巨大,可不可以通过添加一些代码使得2秒或者其它时间调用handle_tick()函数,而不是每个tick都调用?

解决方案

在 JoinQuant (聚宽) 平台进行 Tick 级别回测时,由于 Tick 数据量极其庞大(例如期货每 0.5 秒一个 Tick,股票每 3 秒一个 Tick),如果每个 Tick 都执行复杂的逻辑,确实会导致回测时间开销巨大。

虽然 JoinQuant 的 API 底层在订阅 Tick 后会在每个 Tick 到来时触发 handle_tick,但我们可以通过在策略代码中引入时间戳记录与比对机制,来主动过滤掉不需要处理的 Tick,从而达到“每隔 N 秒执行一次核心逻辑”的目的。

解决方案思路

  1. initialize 函数中定义一个全局变量(如 g.last_tick_time)用于记录上一次执行核心逻辑的时间,并定义一个时间间隔(如 g.interval)。
  2. handle_tick 函数的开头,获取当前 Tick 的时间。
  3. 计算当前时间与上一次执行时间的差值,如果差值大于或等于设定的时间间隔,则执行核心逻辑并更新 g.last_tick_time;否则,直接 return 跳过本次处理。

Python 代码示例

以下是一个完整的代码框架示例,演示如何将 handle_tick 的实际处理频率限制为每 2 秒一次:

import datetime

def initialize(context):
    # 设定基准和复权模式
    set_benchmark('000300.XSHG')
    set_option('use_real_price', True)
    
    # 订阅标的(以某期货为例)
    g.security = 'RB9999.XSGE'
    
    # 初始化上次执行时间为空
    g.last_tick_time = None
    # 设置期望的执行间隔,例如 2 秒
    g.interval = datetime.timedelta(seconds=2)
    
    # 每天开盘前订阅 tick
    run_daily(before_market_open, time='08:30', reference_security='RB9999.XSGE')

def before_market_open(context):
    # 订阅 tick 事件
    subscribe(g.security, 'tick')

def handle_tick(context, tick):
    # 获取当前 tick 的时间
    # 注意:tick.datetime 是 datetime.datetime 对象
    current_time = tick.datetime
    
    # 判断是否满足执行条件:
    # 1. 第一次执行 (g.last_tick_time is None)
    # 2. 当前时间距离上次执行时间已经超过或等于设定的间隔
    if g.last_tick_time is None or (current_time - g.last_tick_time) >= g.interval:
        # 更新上次执行时间
        g.last_tick_time = current_time
        
        # ==========================================
        # 在这里编写你的核心交易逻辑,例如计算指标、下单等
        # ==========================================
        # log.info("执行核心逻辑,当前时间: %s, 最新价: %s", current_time, tick.current)
        
        # 示例:获取最新价
        price = tick.current
        # ... 你的策略代码 ...
        
    else:
        # 如果时间间隔不足 2 秒,直接跳过,不执行任何耗时操作
        pass

注意事项与优化建议

  1. 标的原始频率限制:请注意,股票的 Tick 快照频率本身是 3 秒一次,期货是 0.5 秒一次。如果你设置的间隔是 2 秒,对于股票而言,它依然是每 3 秒触发一次(因为底层数据就是 3 秒来的);对于期货,则会过滤掉中间的 3 个 Tick,大约每 2 秒执行一次。
  2. 避免在过滤逻辑前进行耗时操作:确保时间判断逻辑放在 handle_tick 的最前面。在判断通过之前,不要调用 get_current_tickhistory 等耗时的 API。
  3. 多标的处理:如果你同时订阅了多个标的,且希望它们独立计算时间间隔,可以将 g.last_tick_time 设计为一个字典,以标的代码为 Key 分别记录时间:g.last_tick_time[tick.code] = current_time
  4. 开启性能分析:如果过滤后回测依然很慢,可以在代码最上方加入 enable_profile(),运行一段短时间的回测,查看具体的耗时瓶颈在哪里。