🚀 AI 一键生成 joinquant 策略代码
立即体验
👉 AI 生成代码 👈

解决 JoinQuant 策略中 time='every_bar' 每天只运行一次的问题

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

问题描述

time='every_bar',为什么每天只运行一次?

设置了每个bar运行一次:run_daily(market_open, time='every_bar', reference_security='RB9999.XSGE')
订阅的是30分钟K线:bar_data = get_bars(IF_current_month, count=context.long_extend,
unit='30m', fields=['close'])["close"]
按理说应该每30分钟运行一遍,但看日志,每天就开盘的时候运行了一遍,就结束了,这是为啥?

解决方案

出现这个问题的原因在于您对 time='every_bar' 的理解与 JoinQuant 引擎的实际运行机制存在偏差。

为什么每天只运行了一次?

在 JoinQuant 平台中,time='every_bar' 的触发频率完全取决于您在回测/模拟交易界面(右上方)设置的“运行频率”(按天或按分钟),而不取决于您在代码中使用 get_bars 获取数据的周期(如 unit='30m')。

根据 JoinQuant API 文档的说明:

  • 如果您在界面上选择了“按天”回测time='every_bar' 会在每天开盘时调用一次(即每天只运行一次)。
  • 如果您在界面上选择了“按分钟”回测time='every_bar' 会在交易时间内每分钟调用一次。

JoinQuant 引擎底层只支持“天”、“分钟”和“Tick”三种基础驱动频率,并不存在原生的“按 30 分钟”驱动频率。因此,即使您获取了 30 分钟的 K 线数据,只要您的回测频率选的是“按天”,策略就只会每天开盘运行一次。


如何实现每 30 分钟运行一次策略?

要在 JoinQuant 中实现每 30 分钟执行一次交易逻辑,您需要将回测频率设置为“按分钟”,然后通过以下两种方案之一来实现:

方案一:在分钟回调中进行时间判断(推荐)

将回测频率设置为“按分钟”,every_bar 会每分钟触发一次。我们在函数内部通过 context.current_dt 判断当前分钟数,只有在符合 30 分钟节点时才执行核心逻辑。

def initialize(context):
    # 必须在回测界面将频率设置为“按分钟”
    run_daily(market_open, time='every_bar', reference_security='RB9999.XSGE')

def market_open(context):
    # 获取当前时间
    current_minute = context.current_dt.minute
    
    # 判断是否是 30 分钟的节点 (例如 09:30, 10:00, 10:30 等)
    # 注意:期货夜盘和白盘的时间节点可能需要根据具体品种交易时间微调
    if current_minute % 30 == 0:
        # 在这里获取 30 分钟 K 线并执行交易逻辑
        bar_data = get_bars('IF9999.CCFX', count=context.long_extend, unit='30m', fields=['close'])
        close_price = bar_data['close'][-1]
        
        log.info(f"当前时间 {context.current_dt},执行 30 分钟策略逻辑")
        # 您的下单逻辑...

方案二:使用多个 run_daily 定时触发

如果您不想每分钟都触发函数,可以使用多个 run_daily 明确指定每天需要运行的具体时间点。这种方法比较死板,但对于交易时间固定的品种很有效。

def initialize(context):
    # 明确指定每天的 30 分钟节点运行
    # 注意:这里的时间需要根据您交易品种的实际交易时间来设定
    run_daily(market_open, time='09:30', reference_security='RB9999.XSGE')
    run_daily(market_open, time='10:00', reference_security='RB9999.XSGE')
    run_daily(market_open, time='10:30', reference_security='RB9999.XSGE')
    run_daily(market_open, time='11:00', reference_security='RB9999.XSGE')
    run_daily(market_open, time='11:30', reference_security='RB9999.XSGE')
    run_daily(market_open, time='13:30', reference_security='RB9999.XSGE')
    run_daily(market_open, time='14:00', reference_security='RB9999.XSGE')
    run_daily(market_open, time='14:30', reference_security='RB9999.XSGE')
    run_daily(market_open, time='15:00', reference_security='RB9999.XSGE')
    # 如果有夜盘,还需要继续添加夜盘的时间节点

def market_open(context):
    # 获取 30 分钟 K 线并执行交易逻辑
    bar_data = get_bars('IF9999.CCFX', count=context.long_extend, unit='30m', fields=['close'])
    log.info(f"当前时间 {context.current_dt},执行策略")

总结

  1. 检查您的回测/模拟设置,确保运行频率选的是**“按分钟”**。
  2. get_barsunit='30m' 只是决定了您获取的数据切片是 30 分钟一根,它不能改变策略引擎的驱动频率。
  3. 结合分钟级回测和代码内的时间判断,是实现自定义周期(如 5m, 15m, 30m, 60m)策略的标准做法。