🚀 AI 一键生成 ptrade 策略代码

PTrade 进阶:如何使用 run_interval 实现多周期并发监控?

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

问题描述

如何在策略中同时运行多个不同频率的定时任务?

解决方案

在PTrade策略中,您可以非常方便地通过在 initialize 函数中多次调用 run_dailyrun_interval 函数来实现同时运行多个不同频率的定时任务。

核心实现逻辑

  1. 日内不同时刻的任务:多次调用 run_daily(context, func, time='HH:MM'),设置不同的 time 参数。
  2. 高频/秒级间隔任务:多次调用 run_interval(context, func, seconds=N),设置不同的 seconds 间隔(注意:run_interval 仅在交易/实盘模式下可用,回测中不可用)。
  3. 混合使用:可以同时结合使用上述两种函数。

策略代码示例

以下是一个完整的策略示例,展示了如何设置:

  1. 每天上午 10:30 执行一次选股。
  2. 每天下午 14:50 执行一次尾盘处理。
  3. (仅实盘)每隔 10 秒执行一次行情监控。
def initialize(context):
    """
    初始化函数,设置股票池和定时任务
    """
    # 1. 设置股票池(示例:平安银行)
    g.security = '000001.SZ'
    set_universe(g.security)
    
    # 2. 设置定时任务 A:每天上午 10:30 运行
    # 适用于:盘中选股、早盘数据更新
    run_daily(context, morning_task, time='10:30')
    
    # 3. 设置定时任务 B:每天下午 14:50 运行
    # 适用于:尾盘清仓、收盘前信号确认
    run_daily(context, tail_task, time='14:50')
    
    # 4. 设置定时任务 C:每隔 10 秒运行一次
    # 注意:run_interval 仅在【交易/实盘】模式下生效,回测中不会触发
    # 适用于:高频监控、条件单触发、风控扫描
    run_interval(context, monitor_task, seconds=10)

def handle_data(context, data):
    """
    必须实现的函数,按策略频率(分钟或日线)运行
    """
    # 这里是默认的主循环,可以留空,也可以写常规逻辑
    pass

def morning_task(context):
    """
    上午 10:30 执行的任务
    """
    log.info("【定时任务A】现在是上午 10:30,开始执行早盘选股逻辑...")
    # 示例逻辑:获取当前价格
    # snapshot = get_snapshot(g.security) # 注意:回测不支持get_snapshot
    # log.info(snapshot)

def tail_task(context):
    """
    下午 14:50 执行的任务
    """
    log.info("【定时任务B】现在是下午 14:50,开始执行尾盘处理逻辑...")
    # 示例逻辑:检查持仓
    position = get_position(g.security)
    if position.amount > 0:
        log.info("当前持有 %s,数量:%s" % (g.security, position.amount))

def monitor_task(context):
    """
    每 10 秒执行一次的任务(仅实盘有效)
    """
    # 注意:此函数在回测中不会被调用
    log.info("【定时任务C】高频监控运行中...")
    
    # 实盘中获取快照示例
    # snapshot = get_snapshot(g.security)
    # if snapshot:
    #     current_price = snapshot[g.security].get('last_px')
    #     log.info("当前 %s 价格: %s" % (g.security, current_price))

注意事项

  1. 回测与实盘的区别
    • run_daily:在回测和实盘中均可使用。但在日线级别回测中,无论 time 设置为几点,它通常都会在当天的 bar 结束时(即 15:00)统一执行逻辑(除非是分钟级回测)。
    • run_interval仅在交易(实盘)模块可用。如果在回测中使用,该代码不会报错,但对应的函数永远不会被触发。
  2. 并发与线程
    • run_interval 在实盘中是以多线程方式并行运行的。如果多个定时任务操作同一个全局变量(如 g.count),需要注意线程安全问题,或者确保逻辑互不冲突。
  3. 时间精度
    • run_interval 的最小间隔为 3秒。如果设置小于3秒,系统默认按3秒执行。
  4. 函数定义
    • 被调用的任务函数(如上例中的 morning_task)必须接收 context 作为第一个参数。

Q&A

Q: 在回测模式下,我设置了 run_daily(..., time='10:00'),为什么日志显示是在 15:00 打印的?
A: 这取决于您的回测频率。如果您选择的是日线级别回测,策略每天只运行一次(通常是收盘后),因此所有 run_daily 任务都会在那个时间点触发。如果您选择分钟级别回测,run_daily 就会在指定的 10:00 准时触发。

Q: run_interval 可以设置多个不同的间隔吗?
A: 可以。例如,您可以设置一个 run_interval(..., seconds=3) 用于极速监控价格,同时设置另一个 run_interval(..., seconds=60) 用于每分钟检查一次账户风控状态。它们会独立运行。

Q: 如果定时任务执行时间超过了间隔时间怎么办?
A: 对于 run_interval,如果函数逻辑非常复杂,执行时间超过了设定的间隔(例如设定3秒,但执行了5秒),下一次触发可能会顺延或在当前执行完毕后立即触发。建议保持 run_interval 中的逻辑尽可能轻量高效。