🚀 AI 一键生成 joinquant 策略代码

JoinQuant 策略时间管理:context.current_dt 与 previous_date 应用详解

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

问题描述

如何在策略中精确地进行日期和时间的判断?

解决方案

在 JoinQuant(聚宽)策略开发中,精确的日期和时间判断主要依赖于 context.current_dt 属性。这是一个 Python 的 standard datetime.datetime 对象,代表了回测或模拟交易当前的逻辑时间

以下是关于如何在策略中进行精确日期和时间判断的详细指南。

核心对象:context.current_dt

无论是在 handle_databefore_trading_start 还是定时运行的函数中,context.current_dt 都是获取当前时间的最标准方式。

它包含以下常用属性:

  • context.current_dt.year:年
  • context.current_dt.month:月
  • context.current_dt.day:日
  • context.current_dt.hour:时(24小时制)
  • context.current_dt.minute:分
  • context.current_dt.second:秒
  • context.current_dt.isoweekday():星期几(1是周一,7是周日)

1. 日期判断(年、月、日、星期)

适用于日频和分钟频策略,常用于判断调仓日、节假日或特定日期逻辑。

判断特定日期

def handle_data(context, data):
    # 获取当前日期字符串
    current_date = context.current_dt.strftime("%Y-%m-%d")
    
    # 判断是否为 2023年1月5日
    if current_date == '2023-01-05':
        log.info("到达指定日期,执行操作")

判断星期几

def handle_data(context, data):
    # isoweekday() 返回 1-7,代表周一到周日
    weekday = context.current_dt.isoweekday()
    
    # 如果是周五 (5)
    if weekday == 5:
        log.info("今天是周五,准备收盘操作")

判断月初或年末

def handle_data(context, data):
    # 判断是否是1月份
    if context.current_dt.month == 1:
        pass
        
    # 判断是否是每月1号 (注意:回测中1号可能是非交易日,通常配合 get_trade_days 使用更准确)
    if context.current_dt.day == 1:
        pass

2. 时间判断(时、分、秒)

主要用于分钟频(Minute)或 Tick 频策略,用于控制日内交易时机,如早盘抢筹、尾盘平仓等。

判断具体时间点

def handle_data(context, data):
    hour = context.current_dt.hour
    minute = context.current_dt.minute
    
    # 判断是否在 14:50 之后 (尾盘)
    if hour == 14 and minute >= 50:
        log.info("进入尾盘阶段")
        
    # 判断是否在早盘 10:00 之前
    if (hour == 9 and minute >= 30) or (hour < 10):
        # 注意:9:30 开盘
        pass

避开午休时间

A股交易时间包含 11:30 - 13:00 的午休,分钟回测中通常不会触发这段时间的 handle_data,但在编写通用逻辑时可以显式过滤。

import datetime

def handle_data(context, data):
    # 获取当前时间部分
    current_time = context.current_dt.time()
    
    # 定义午休时间段
    lunch_break_start = datetime.time(11, 30)
    lunch_break_end = datetime.time(13, 0)
    
    if lunch_break_start <= current_time < lunch_break_end:
        return # 午休时间不操作

3. 高级应用:判断交易日逻辑

结合 get_trade_days 函数,可以判断当前是否为月初第一个交易日、月末最后一个交易日等复杂逻辑。

判断是否为当月第一个交易日

from jqdata import *

def handle_data(context, data):
    # 获取当前日期
    current_date = context.current_dt.date()
    
    # 获取本月的所有交易日
    # 获取范围:本月1号到下个月1号之间
    start_of_month = datetime.date(current_date.year, current_date.month, 1)
    # 简单处理:取当前日期往后32天内的交易日,然后筛选本月的
    trade_days = get_trade_days(start_date=start_of_month, count=30)
    
    # 过滤出本月的交易日
    this_month_days = [d for d in trade_days if d.month == current_date.month]
    
    if len(this_month_days) > 0:
        first_day = this_month_days[0]
        last_day = this_month_days[-1]
        
        if current_date == first_day:
            log.info("今天是本月第一个交易日")
        elif current_date == last_day:
            log.info("今天是本月最后一个交易日")

4. 时间差计算(Timedelta)

使用 Python 的 datetime.timedelta 计算时间间隔,例如判断持仓是否超过 N 天。

import datetime

def handle_data(context, data):
    security = '000001.XSHE'
    position = context.portfolio.positions[security]
    
    # 如果有持仓
    if position.total_amount > 0:
        # position.init_time 是建仓时间 (datetime对象)
        # 计算持仓时长
        duration = context.current_dt - position.init_time
        
        # 如果持仓超过 5 天 (5 * 24小时)
        if duration > datetime.timedelta(days=5):
            log.info(f"{security} 持仓已超过5天")

总结与注意事项

  1. 对象类型context.current_dtdatetime.datetime 对象,context.current_dt.date() 返回的是 datetime.date 对象。比较时类型必须一致。
  2. 回测频率
    • 按天回测handle_data 中的 context.current_dt 通常显示为当天的 09:30:0000:00:00(取决于具体设置),无法进行分钟级的精确判断。
    • 按分钟回测context.current_dt 会随每分钟变化(如 09:31, 09:32...),可以进行精确的时间判断。
  3. 时区:JoinQuant 平台统一使用北京时间。
  4. 库导入:进行复杂时间运算时,建议在代码开头导入 import datetime

Q&A

Q: 如何在策略中只在每天收盘前5分钟交易?
A: 可以在 initialize 中使用 run_daily(func, time='14:55') 定时运行,或者在分钟回测的 handle_data 中判断 if context.current_dt.hour == 14 and context.current_dt.minute == 55:

Q: context.current_dtdatetime.datetime.now() 有什么区别?
A: context.current_dt 是回测系统的逻辑时间(即回测进行到的那个历史时刻),而 datetime.datetime.now() 是服务器的物理时间(当前现实世界的时间)。在回测中必须使用 context.current_dt,否则会引入未来函数或导致逻辑错误。

Q: 如何判断当前是否是交易时间?
A: 在分钟回测中,handle_data 只在交易时间触发,因此不需要额外判断。如果在 run_daily 或其他逻辑中需要判断,可以检查时间是否在 9:30-11:30 或 13:00-15:00 之间。