🚀 AI 一键生成 joinquant 策略代码

JoinQuant 策略编写:如何正确设置 end_date 获取前一交易日以避免未来函数?

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

问题描述

请问end_date的取值问题?

enddate = (context.current_dt - datetime.timedelta(days=1)).date()
roll_days = 90
stdev_up = 2
stdev_dn = 2
table = finance.STK_ML_QUOTA
q = query(
table.day, func.sum(table.buy_amount - table.sell_amount).label('net_amount')
).filter(
table.link_id.in(['310001', '310002']),
table.day >= end_date - datetime.timedelta(days=2 * roll_days),
table.day < = end_date
).group_by(
table.day
).order_by(table.day)

以上为代码一

end_date = context.current_dt.date()
roll_days = 90
stdev_up = 2
stdev_dn = 2
table = finance.STK_ML_QUOTA
q = query(
table.day, func.sum(table.buy_amount - table.sell_amount).label('net_amount')
).filter(
table.link_id.in_(['310001', '310002']),
table.day >= end_date - datetime.timedelta(days=2 * roll_days),
table.day < = end_date
).group_by(
table.day
).order_by(table.day)
以上代码二

以上两个代码片段只是在第一句有不同,代码一和代码二回测收益差了很多很多,

end_date 哪种写法可以确认为交易时/模拟时/回测时的前一交易日?

主要是为了避免未来函数的影响。

解决方案

核心解答:推荐使用 context.previous_date

在 JoinQuant 平台中,为了严谨地获取前一交易日并彻底避免未来函数,您提供的代码一和代码二都不是最佳选择。官方 API 提供了一个专门的属性来解决这个问题:context.previous_date

为什么您的两段代码回测结果差异巨大?

您查询的表 finance.STK_ML_QUOTA 是沪深港通的日度额度数据。这类日频统计数据通常在当天收盘后才能确定最终数值。

  1. 代码二 (end_date = context.current_dt.date()) 引入了未来函数
    如果您在盘中(例如 09:30)运行策略,context.current_dt.date() 获取的是当天的日期。此时您去数据库查询当天的汇总数据,在回测引擎中可能会提前拿到当天收盘后才有的数据。这就引入了未来函数,导致回测收益看起来异常好,但实盘中根本无法实现。

  2. 代码一 (end_date = (context.current_dt - datetime.timedelta(days=1)).date()) 避免了未来函数,但不严谨
    减去 1 天确实避免了拿到当天的数据,但它只是自然日的前一天。如果今天是周一,减去 1 天是周日(非交易日),这可能会导致您在某些逻辑计算或数据对齐时出现空值或错误。

正确的写法

为了确保获取的是前一个有效的交易日,请直接使用 context.previous_date。修改后的代码如下:

# 正确写法:使用 context.previous_date 获取前一交易日
end_date = context.previous_date
roll_days = 90
stdev_up = 2
stdev_dn = 2
table = finance.STK_ML_QUOTA

q = query(
    table.day, func.sum(table.buy_amount - table.sell_amount).label('net_amount')
).filter(
    table.link_id.in_(['310001', '310002']),
    table.day >= end_date - datetime.timedelta(days=2 * roll_days),
    table.day <= end_date
).group_by(
    table.day
).order_by(table.day)

进阶建议:开启避免未来函数模式

为了在编写策略时更好地防范未来函数,建议在 initialize 函数中开启 JoinQuant 提供的避免未来数据选项:

def initialize(context):
    # 开启避免未来数据模式
    set_option("avoid_future_data", True)

开启此功能后,如果您在策略中尝试通过 API 获取未来数据(例如在盘中获取当天的收盘价或盘后财务数据),系统会抛出 FutureDataError 异常或自动剔除未来数据,从而帮助您及时发现代码中的漏洞。