3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在量化交易中,回测结果异常优异(如收益率暴增、回撤极小)往往并非因为策略本身完美,而是由于引入了未来函数或产生了订单撮合幻觉。以下是使用聚宽(JoinQuant)回测系统排查这些问题的完整指南:
未来函数是指在历史某个时间点,策略使用了该时间点之后(未来)才发生的数据。这会导致回测时“未卜先知”,实盘时却大幅亏损。
聚宽提供了实验性的安全设置,可以在初始化中开启:
def initialize(context):
# 开启避免未来数据模式(默认关闭)
set_option("avoid_future_data", True)
context.current_dt)之后的数据,系统会直接抛出 FutureDataError 异常,强行中断并提醒开发者。get_price 与 get_bars:在使用这些 API 获取历史数据时,必须确保 end_date 或 end_dt 参数不要大于当前逻辑时间 context.current_dt。推荐不传 end_date(默认即为当前时间)或显式传入 context.current_dt。get_fundamentals:财务数据极易引入未来函数。在回测中,如果不传入 date 参数,默认会取 context.current_dt 的前一天,这是安全的。如果手动传入 statDate(如指定季度 2023q1),由于上市公司财报披露存在滞后性,极易引入未来数据。建议在盘后(15:00后)或使用 date 参数查询当时已披露的最新数据。initialize 中开启真实价格(动态复权)模式:set_option('use_real_price', True)
传统前复权模式在回测历史时刻时,使用的是基于未来的复权因子计算的价格,天然带有未来函数属性。开启真实价格模式能有效避免这一问题。撮合幻觉是指回测系统在不合理的价位或超大成交量下,判定你的订单“完美成交”,而实际市场中根本无法实现。
如果不设置滑点,系统默认使用 PriceRelatedSlippage(0.00246)。为了更贴近实盘,应根据标的流动性主动设置滑点:
# 为股票设置百分比滑点(双边)
set_slippage(PriceRelatedSlippage(0.00246), type='stock')
# 为特定期货合约设置跳数滑点
set_slippage(StepRelatedSlippage(2), type='futures', ref='RB')
在真实市场中,你的买卖盘会冲击市场。如果你的下单量超过当时市场成交量的很大比例,是不可能按现价全部成交的。聚宽提供了成交量比例限制:
def initialize(context):
# 限制单笔订单成交量不超过本日该股票总成交量的 25%
set_option('order_volume_ratio', 0.25)
开启后,无论是市价单还是限价单,撮合时都会严格受到全市场实际成交量的比例限制,超出部分市价单会撤单,限价单会挂单等待。
| 检查维度 | 常见症状 | 排查与解决方法 |
|---|---|---|
| 未来函数 | 回测收益率曲线呈完美的45度角上升,无明显回撤。 | 1. 开启 set_option("avoid_future_data", True)。2. 检查 history、get_price 是否取到了当天收盘后的数据。3. 检查是否使用了未来的复权因子。 |
| 撮合幻觉 | 策略频繁在极小成交量的垃圾股或分时图异动点上满仓进出。 | 1. 限制 order_volume_ratio 为 0.1 ~ 0.25。2. 调大滑点参数进行压力测试。 3. 过滤掉日成交额过低(如低于1000万)的个股。 |
| 过度拟合 | 改变回测时间段(如从2018-2020移到2021-2023),策略收益瞬间崩溃。 | 1. 进行样本外测试(Out-of-Sample Test)。 2. 减少策略参数数量,避免使用超过3个以上的核心优化参数。 |
| 风控不足 | 遇到极端行情(如大盘暴跌、个股停牌/退市)时,回测直接报错中断或账户穿仓。 | 1. 在代码中加入 current_data[security].paused 停牌判断。2. 期货策略中,使用 context.subportfolios[i].is_dangerous(margin_rate) 监控保证金安全。 |