3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在聚宽(JoinQuant)平台上进行回测时,系统本身不会“自动”或“恶意”地加入未来函数,但由于日线级别回测的底层数据结构以及API调用方式的特殊性,开发者在编写代码时非常容易不小心引入未来数据。
针对你描述的现象(9:26计算收益低,9:30计算收益极高),这几乎可以断定是在9:30的逻辑中引入了未来函数。以下是导致这种巨大差异的核心原因分析及排查建议:
如果你使用的是按天回测(日频),在 handle_data 或 run_daily(..., time='09:30') 中获取当天的“实时价格”时,极易踩中以下几个“未来函数”陷阱:
data[security].price 或 data[security].avg 获取价格,根据聚宽API文档,日频下的 avg 代表的是该股票全天的成交均价(成交额/成交量)。在早上9:30使用全天均价来判断是否止损,等于提前知道了全天的走势。get_price 或 attribute_history,且没有严格限制时间戳,可能会直接取到包含当天 close、low、high 的整根日K线。用当天的最低价(low)或收盘价(close)来计算回撤,意味着你的策略在9:30就已经“预知”了今天盘中会跌到多少,从而精准逃顶或止损,这会导致年化收益率出现极其夸张的飙升。在 9:26(通常在 before_trading_start 或 run_daily(..., time='09:26') 中运行),当天的日K线尚未生成。此时你只能通过 get_current_data().day_open 获取到集合竞价产生的开盘价,或者使用昨天的收盘价。
low 或 close,因此计算出的亏损/回撤是基于真实的开盘价,没有任何未来数据。为了验证并修复你的策略,建议采取以下几个步骤:
在策略的 initialize 函数中,强制开启聚宽提供的防未来函数选项。如果你的9:30逻辑确实用到了未来数据,系统会直接报错抛出 FutureDataError:
def initialize(context):
# 开启避免未来数据模式
set_option("avoid_future_data", True)
仔细检查你在9:30获取“实时价格”的代码:
current_price = data[security].price 或 current_price = data[security].closeget_current_data() 获取。current_data = get_current_data()
current_price = current_data[security].last_price # 9:30时通常等于开盘价
如果你希望在盘中(如跌破阈值的瞬间)实时止损,绝对不能使用按天回测。日频回测只能在每天的一个固定时间点(通常是开盘)做一次决策。
data[security].close 代表的是上一分钟的收盘价,这样你在 9:30 或盘中任何一分钟计算回撤时,使用的数据都是严格截止到上一分钟的,彻底杜绝了日内未来函数。你所观察到的“9:30收益极高”,99%是因为在日频回测的9:30调用了包含当天全天信息的字段(如日均价、日最低价、日收盘价)作为止损依据。请开启 avoid_future_data 选项,并确保日内止损逻辑在分钟级回测下运行,以获得具有实盘指导意义的真实收益率。