3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在聚宽(JoinQuant)平台的回测中,自动检查和避免使用未来数据(Look-ahead Bias)最直接且有效的方法是使用策略设置函数 set_option 开启防未来数据模式。
以下是具体的实现方法和详细说明:
avoid_future_data在策略的初始化函数 initialize(context) 中,调用 set_option 函数并将 avoid_future_data 选项设置为 True。
# -*- coding: utf-8 -*-
def initialize(context):
# 开启避免未来数据模式
# 默认为 False,设置为 True 后,系统会自动检测并拦截未来数据的获取
set_option('avoid_future_data', True)
# 其他初始化代码...
g.security = '000001.XSHE'
set_benchmark('000300.XSHG')
开启该选项后,回测引擎会从以下两个层面进行严格检查:
抛出异常(针对带时间参数的API):
如果策略代码中使用了包含时间参数的 API(例如 get_price, get_bars 等),并且请求的时间范围超过了当前回测的时间点(context.current_dt),系统会直接抛出 FutureDataError 异常,终止回测。
自动剔除(针对不带时间参数的API):
对于用户无法通过参数主动规避未来数据的 API(例如 get_call_auction 等),系统会自动过滤掉返回结果中的未来数据,只返回当前时刻已知的数据,而不会抛出异常。
即使开启了上述选项,理解未来数据的来源对于编写健壮的策略依然至关重要。以下是常见的未来数据类型:
before_trading_start)或盘中使用了当天的收盘价(close)、最高价(high)或最低价(low)进行决策。before_trading_start 中,只能使用前一个交易日及之前的数据。history 或 attribute_history 时,注意 skip_paused 和数据长度,确保不包含当日未发生的数据。get_fundamentals 查询财务数据时,不要直接指定 statDate(统计期),而是指定 date(查询日期)。date 返回该日期之前已经公告的最新财报数据,从而自动避免未来函数。get_current_data()[security].paused 判断停牌状态。get_index_stocks 获取指数成分股时,务必传入 date 参数(如 date=context.current_dt),以获取当时真实的成分股列表。虽然 set_option('avoid_future_data', True) 功能强大,但它无法检测以下情况:
if context.current_dt == datetime(2015, 6, 12): sell_all()),这种逻辑性未来函数无法被检测。Q1: 开启 avoid_future_data 会影响回测速度吗?
A1: 会有轻微的影响,因为系统需要在每次数据请求时增加额外的时间戳校验逻辑,但为了策略的严谨性,这种性能损耗通常是值得的。
Q2: 为什么我在 before_trading_start 获取当天的 open 价报错了?
A2: before_trading_start 运行在 09:00~09:30 之间(通常逻辑时间为 09:00),此时交易所尚未产生当天的开盘价(09:25 集合竞价产生)。如果在此时获取当日数据,属于未来数据。
Q3: 如果我不开启这个选项,回测结果一定不可信吗?
A3: 不一定,经验丰富的开发者可以通过严谨的代码逻辑避免未来数据。但开启此选项可以作为一道强制的保险,防止无意中引入未来数据,强烈建议在开发阶段始终开启。
Q4: get_fundamentals 查询财务数据时,传入 statDate 一定会导致未来数据吗?
A4: 是的,在回测中极大概率会导致未来数据。因为 statDate 是按财报统计周期(如 '2023q1')查询,系统会直接返回该季度的最终数据,忽略了该数据的实际发布日期(PubDate)。在回测中应始终使用 date 参数查询。