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

JoinQuant回测中get_bars获取到未来数据的原因及解决方法

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

问题描述

获取的数据的日期超过了运行时间,请问是哪里出问题了?

如图,这段是主程序,其他程序已经一一排查没有问题了。
设置的运行时间是2021-01-01至2021-01-15,
在2021-01-04时运行,却获取到了2021-04-23的数据,
后面每一天的运行结果皆如此。
请问是get_bars()中的问题吗,比如end_dt的设置?

解决方案

是的,您遇到的问题非常典型,这正是 get_bars() 函数中 end_dt 参数设置不当导致的“未来函数”问题

问题原因分析

在 JoinQuant 平台中,get_bars 函数用于获取历史 K 线数据。关于它的 end_dt(查询截止时间)参数,官方文档有明确的说明:

  • 默认值 (None):在回测/模拟环境下,如果不传入 end_dt,它默认等于 context.current_dt(即回测引擎当前运行到的逻辑时间)。
  • 常见错误:很多开发者在编写策略时,习惯性地将 end_dt 设置为 datetime.datetime.now()datetime.now() 获取的是现实世界中的当前系统时间(比如您运行代码时的 2021-04-23),而不是回测引擎的逻辑时间(2021-01-04)。

因此,当您在 2021-01-04 的回测逻辑中,要求获取截止到现实当前时间(2021-04-23)的数据时,系统就会把未来的数据返回给您,导致策略“偷看”了未来。

解决方法

要解决这个问题,您只需要修改 get_bars 的调用方式:

1. 推荐做法:不传入 end_dt 参数
让系统自动使用回测的当前逻辑时间,这是最安全、最简洁的做法。

# 正确写法:不写 end_dt,系统默认使用 context.current_dt
df = get_bars(security, count=5, unit='1d', fields=['date', 'open', 'close'])

2. 备选做法:显式传入 context.current_dt
如果您出于某种原因必须显式指定截止时间,请务必使用 context.current_dt

# 正确写法:显式指定为回测逻辑时间
df = get_bars(security, count=5, unit='1d', fields=['date', 'open', 'close'], end_dt=context.current_dt)

错误示例(请检查您的代码是否是这样写的):

import datetime
# 错误写法:使用了现实世界的当前时间,引入了未来数据!
df = get_bars(security, count=5, unit='1d', fields=['date', 'open', 'close'], end_dt=datetime.datetime.now())

进阶建议:开启防未来数据模式

为了防止在编写策略时无意中引入未来数据,JoinQuant 提供了一个非常实用的设置项。建议您在 initialize 函数中开启它:

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

开启此功能后,如果您在策略中尝试通过 API 获取 current_dt 之后的数据,系统会直接抛出 FutureDataError 异常,从而帮助您在早期发现并定位代码中的未来函数问题。