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

JoinQuant 聚宽平台 run_daily(time='every_bar') 无法每分钟运行的原因及解决方法

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

问题描述

run_daily 如何每分钟运行一次?

every_bar 我使用的有问题,看了api文档和社区的说明文章,仍然没弄懂为什么不能每分钟运行一次,有知道原因的大神麻烦留言指导我一下,多谢

日志截图:
Img

代码如下:


# 初始化函数,设定基准等等
def initialize(context):
run_daily(stop_loss, time='every_bar', reference_security='000300.XSHG')

# 设置止损:跌幅大于8 止损
def stop_loss(context):
log.info('函数运行时间(market_open):'+str(context.current_dt.time()))

# 遍历可卖出的持仓股票
for stock in context.portfolio.positions:
if context.portfolio.positions[stock].closeable_amount > 0:
current_date = context.current_dt.strftime('%Y-%m-%d')

pre_close = g.position_dict[stock][0]

# 获取当前时间价格
close_data = get_bars(stock, count=1, unit='1m', fields=['close'], fq_ref_date=None)['close'][0]

#-8个点止损
if pre_close * 0.92 > float(close_data):
log.info("止损卖出 %s" % (stock))
order_target(stock, 0)

解决方案

在 JoinQuant (聚宽) 平台中,使用 run_daily(func, time='every_bar') 却发现没有每分钟运行,最根本的原因是:你的回测或模拟交易的“运行频率”设置成了“天”,而不是“分钟”。

原因解析

根据 JoinQuant API 文档的说明:

time="every_bar" 只能在 run_daily 中调用,运行时间和您设置的频率(回测页面右上方设置)一致。按天会在交易日的开盘时调用一次,按分钟会在交易时间每分钟运行。

也就是说,every_bar 里的 bar 指的是你当前策略的 K 线周期。如果你选了日线(天频率),一个 bar 就是一天,它就每天跑一次;如果你选了分钟线(分钟频率),一个 bar 就是一分钟,它才会每分钟跑一次。

解决方法

步骤 1:修改回测/模拟交易频率
在聚宽策略编写页面的右上方(或者创建模拟交易的设置页面),找到**“运行频率”选项,将其从“天”修改为“分钟”**。

步骤 2:检查代码逻辑
你的代码逻辑基本是正确的,只要频率设置对了,stop_loss 函数就会每分钟被调用一次。以下是优化后的代码示例:

# 导入聚宽函数库
import jqdata

def initialize(context):
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 注册定时运行函数,time='every_bar' 依赖于全局频率设置
    # 必须在界面上将频率设置为“分钟”!
    run_daily(stop_loss, time='every_bar', reference_security='000300.XSHG')

# 设置止损:跌幅大于8% 止损
def stop_loss(context):
    # 打印当前时间,如果是分钟频率,这里会每分钟打印一次
    log.info('函数运行时间: ' + str(context.current_dt))

    # 遍历可卖出的持仓股票
    for stock in context.portfolio.positions:
        if context.portfolio.positions[stock].closeable_amount > 0:
            # 假设 g.position_dict 已经在其他地方正确维护了昨收价
            # 这里为了演示,直接获取昨收价
            pre_close = attribute_history(stock, 1, '1d', ['close'])['close'][0]

            # 获取当前分钟的最新价格
            # 注意:在分钟频率下,可以直接使用 data[stock].close 或 get_current_data()
            current_data = get_current_data()
            current_price = current_data[stock].last_price

            # -8个点止损 (即当前价低于昨收价的 92%)
            if current_price < pre_close * 0.92:
                log.info("触发止损,卖出 %s, 当前价: %f, 昨收价: %f" % (stock, current_price, pre_close))
                order_target(stock, 0)

替代方案:使用 handle_data

除了 run_daily 配合 every_bar,你也可以直接使用 handle_data 函数。handle_data 的触发机制同样依赖于全局频率设置。只要设置为分钟频率,handle_data 就会每分钟执行一次。

def initialize(context):
    set_benchmark('000300.XSHG')
    set_option('use_real_price', True)

# 如果回测频率设置为“分钟”,此函数每分钟运行一次
def handle_data(context, data):
    for stock in context.portfolio.positions:
        if context.portfolio.positions[stock].closeable_amount > 0:
            current_price = data[stock].close
            pre_close = data[stock].pre_close
            
            if current_price < pre_close * 0.92:
                log.info("止损卖出 %s" % stock)
                order_target(stock, 0)

总结与注意事项

  1. 频率设置是关键:代码里的 every_bar 只是声明“跟随全局频率”,真正的控制开关在界面的频率下拉菜单里。
  2. 性能优化:在分钟频率下,策略每天会运行 240 次。尽量避免在每分钟的循环里调用耗时的 API(如大范围的 get_barshistory),推荐使用 get_current_data() 获取最新价,以提高回测速度。
  3. 避免混用:官方文档建议,一个策略中尽量不要同时使用 run_dailyhandle_data,选择其中一种方式实现即可。