🚀 AI 一键生成 joinquant 策略代码

JoinQuant 策略高级调度:如何使用 run_daily 在盘中不同时间点执行不同任务?

joinquant | 发布时间: 2025/12/16
以下内容由 EasyQuant 生成。

问题描述

怎样才能让我的策略在每天的 9:30、10:30 和 14:50 执行不同的操作?

解决方案

在聚宽(JoinQuant)平台中,要实现每天在不同特定时间点(如 9:30、10:30、14:50)执行不同的操作,最推荐的方法是在 initialize 函数中使用 run_daily API 进行定时任务注册。

这种方法比在 handle_data 中判断时间更高效,代码结构也更清晰。

以下是完整的策略代码示例:

# -*- coding: utf-8 -*-
import jqdata

def initialize(context):
    """
    初始化函数,设定基准、复权模式,并注册定时运行函数
    """
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    # 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')

    # 注册定时任务
    # 任务1:每天 9:30 执行
    run_daily(market_open_job, time='9:30')
    
    # 任务2:每天 10:30 执行
    run_daily(mid_day_job, time='10:30')
    
    # 任务3:每天 14:50 执行
    run_daily(market_close_job, time='14:50')

def market_open_job(context):
    """
    9:30 执行的操作
    """
    log.info("当前时间: %s,执行 9:30 的开盘操作" % context.current_dt)
    # 在这里编写 9:30 需要执行的逻辑,例如获取开盘价、判断高开低开等
    # 示例:打印平安银行的开盘价
    current_data = get_current_data()
    p = current_data['000001.XSHE'].day_open
    log.info("平安银行今日开盘价: %s" % p)

def mid_day_job(context):
    """
    10:30 执行的操作
    """
    log.info("当前时间: %s,执行 10:30 的盘中操作" % context.current_dt)
    # 在这里编写 10:30 需要执行的逻辑,例如盘中调整仓位

def market_close_job(context):
    """
    14:50 执行的操作
    """
    log.info("当前时间: %s,执行 14:50 的尾盘操作" % context.current_dt)
    # 在这里编写 14:50 需要执行的逻辑,例如尾盘选股、清仓或调仓
    # 示例:获取当前持仓并打印
    positions = context.portfolio.positions
    if len(positions) > 0:
        log.info("当前持仓标的: %s" % list(positions.keys()))
    else:
        log.info("当前为空仓")

# 注意:如果使用了 run_daily 注册了所有需要的逻辑,handle_data 可以省略
# 或者仅用于处理 tick 级别的实时风控
# def handle_data(context, data):
#     pass

代码解析

  1. run_daily(func, time='HH:MM'):

    • 这是实现定时任务的核心函数。
    • func: 你自定义的函数名(如 market_open_job),该函数必须接收 context 作为参数。
    • time: 指定执行的时间字符串,格式为 'HH:MM'(24小时制)。
    • 注意run_daily 必须在 initialize 中调用。
  2. 执行逻辑:

    • 9:30: 策略会在每天 9:30 调用 market_open_job。如果是按分钟回测,会在 9:30 这一分钟的 bar 开始时触发。
    • 10:30: 策略会在每天 10:30 调用 mid_day_job
    • 14:50: 策略会在每天 14:50 调用 market_close_job
  3. 优势:

    • 相比于在 handle_data 中每分钟去 if 判断当前时间,使用 run_daily 效率更高,且逻辑解耦,便于维护。

常见问题 (Q&A)

Q: run_daily 设置的时间如果是 9:30,在按天回测和按分钟回测中有什么区别?
A:

  • 按分钟回测:会在 9:30:00 准时触发。
  • 按天回测:由于按天回测只有一根日线 Bar,run_daily 设置为 '9:30' 时,通常会在策略逻辑上的开盘时刻(9:30)运行,但实际上是在处理当天的日线数据之前。

Q: 我可以在 run_daily 调用的函数里下单吗?
A: 可以。所有的交易函数(如 order, order_target 等)都可以在 run_daily 调用的自定义函数中使用。

Q: 如果我想在收盘后(例如 15:30)处理数据怎么办?
A: 可以使用 run_daily(func, time='15:30'),或者直接使用系统内置的回调函数 after_trading_end(context),它固定在每天交易结束后(15:30)运行。

Q: run_daily 可以设置多个相同时间的任务吗?
A: 可以。你可以写多行 run_daily(funcA, time='10:00')run_daily(funcB, time='10:00'),它们会按注册顺序依次执行。