4、事件窗口定义:事件日确定、窗口期(事前、事后)设置、参数优化方法
做事件驱动策略,最核心的一步是什么?
我个人觉得,就是定义好「事件窗口」。
窗口没定好,后面算出来的超额收益全是噪音。我刚开始做量化那会儿,就吃过这个亏——把窗口拉得太长,结果把市场自然波动也算成了事件影响,回测曲线漂亮得不行,实盘一跑就露馅。
说白了,事件窗口就是你要盯着的那段「关键时间」。它决定了你什么时候买入、什么时候卖出,以及你的收益到底是不是事件带来的。
4.1 事件日(T=0)的确定
事件日,就是公告正式发布的那一天。但这里有个坑——你得搞清楚,到底是「公告日」还是「生效日」?
举个例子:
- 业绩预增公告:以上交所/深交所官网披露日期为准
- 分红预案:以股东大会通过后的公告日为准
- 重大合同:以公司签署并公告的日期为准
我习惯的做法是,从Wind或聚宽接口拉数据时,直接取 ann_date 字段。但要注意,如果公告是在收盘后发布的,那事件日应该顺延到下一个交易日。
# 伪代码示例:事件日调整逻辑
if 公告时间 > 15:00:
事件日 = 下一个交易日
else:
事件日 = 当前交易日
4.2 窗口期设置:事前与事后
窗口期分为两段:事前窗口和事后窗口。
事前窗口([-T, -1]):用来观察事件前有没有信息泄露。你想想看,A股市场经常有「提前反应」的现象——公告还没出,股价先涨了5个点。这就是内幕消息在作祟。
事后窗口([+1, +N]):用来捕捉事件后的持续效应。有些利好是「见光死」,当天涨停第二天就跌停;有些则是「慢牛」,能涨好几天。
但具体怎么设?我列个表给你参考:
| 事件类型 | 事前窗口 | 事后窗口 | 说明 |
|---|---|---|---|
| 业绩预增 | [-3, -1] | [+1, +5] | 市场反应快,窗口不宜过长 |
| 重大合同 | [-5, -1] | [+1, +10] | 需要时间消化信息 |
| 分红送转 | [-10, -1] | [+1, +3] | 提前炒作明显,事后容易回落 |
| 资产重组 | [-20, -1] | [+1, +20] | 停牌复牌类,窗口要拉长 |
嗯,这里要注意:窗口不是越长越好。拉太长,会把其他事件的干扰也装进来。我曾经试过把事后窗口设到30天,结果发现收益里混进了季报效应,根本分不清是哪个事件贡献的。
4.3 参数优化方法
窗口参数怎么定?拍脑袋肯定不行。我一般用三种方法:
4.3.1 网格搜索法
说白了,就是暴力枚举。把事前窗口从 [-1, -1] 试到 [-10, -1],事后窗口从 [+1, +1] 试到 [+1, +20],看哪组参数的回测夏普比最高。
# 网格搜索伪代码
best_sharpe = -999
best_pre = 0
best_post = 0
for pre in range(1, 11):
for post in range(1, 21):
sharpe = backtest(event_list, pre_window=pre, post_window=post)
if sharpe > best_sharpe:
best_sharpe = sharpe
best_pre = pre
best_post = post
print(f"最优窗口:事前{best_pre}天,事后{best_post}天")
4.3.2 累计异常收益(CAR)曲线法
这个方法更直观。你把所有事件的平均累计异常收益画出来,看曲线什么时候趋于平稳。
举个例子:
- 如果CAR在 [+1, +5] 持续上升,但 [+6, +10] 开始横盘——那事后窗口设5天就够了
- 如果CAR在 [-3, -1] 就开始拉升——说明事前窗口至少需要3天
我习惯用这个方法做「初筛」,再用网格搜索做「精调」。
4.3.3 交叉验证法
这个是为了防止过拟合。你把样本分成训练集和测试集,在训练集上找最优参数,在测试集上验证。
我曾经犯过一个错误:用全量数据做网格搜索,找到一组参数回测夏普比2.5,结果在样本外测试只有0.8。后来用了交叉验证,才找到真正稳定的参数。
4.4 知识体系总览
下面这张图,把事件窗口的核心逻辑串起来了:
这张图把整个流程串起来了:从事件日出发,向左是事前窗口(捕捉信息泄露),向右是事后窗口(捕捉持续效应),底部是三种参数优化方法。你想想看,是不是一下子就清晰了?
最后说一句:窗口参数没有「万能解」。不同市场、不同板块、不同事件类型,最优参数都不一样。我的建议是——先按经验设一组默认值,再用数据去验证和调整。别偷懒,该跑的回测一定要跑。
公众号:蓝海资料掘金营,微信deep3321