写均线、波动率这类滚动因子时,代码很短,回测也很少报错。但我最近复查一个收盘前选股策略,发现当天信号使用了当天完整收盘价,相当于提前知道了收盘结果。
pandas 的 rolling(20).mean() 会把当前行放进窗口。若策略要求当天收盘前下单,最终收盘价此时还不存在,算出的均线就含有未来信息。如果改成收盘后计算、下一交易日开盘执行,同样的写法则可能合理。因此,是否使用 shift,取决于信号和订单的时间。
对“开盘前生成信号”的日线策略,我会先排序、分组,再把因子后移一行:
df = df.sort_values(["symbol", "trade_date"])
df["ma20"] = (
df.groupby("symbol")["close"]
.transform(lambda s: s.rolling(20, min_periods=20)
.mean().shift(1))
)
df["signal"] = df["open"] > df["ma20"]这里 shift(1) 表示当天只使用截至前一交易日的数据。分组不能省,否则不同股票的数据可能串在一起;min_periods=20 要求窗口完整,也避免用两三天数据冒充 20 日均线。
滚动标准差、最高价和成交量均值也要检查。我习惯保留 factor_asof 和 order_time,再抽查几个信号:因子截止到哪天,订单最早何时进入市场。这比只看净值更容易发现“公式正确、时点错误”的穿越。
判断标准其实很简单:在模拟下单的那个时刻,这个数值是否已经完整产生,并且策略确实能够获得。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。