MCM520 ← 资料站首页 事件驱动策略的参数网格与稳健性全景:阈值高原、组合稀释与表现面(优秀范文三) 打开交互阅读器 →

事件驱动策略的参数网格与稳健性全景:阈值高原、组合稀释与表现面(优秀范文三)

摘要

范文一证明了"事件驱动策略能赚钱"(+35.5%、夏普 4.03),范文二解剖了"超额从哪来、有多脆"(Top5 占 32.4%、强度不单调、HOLD=8 更优、市场前跌更有效)。但投资策略真正落地前,还有一个更尖锐的问题:这套参数换一组还灵不灵?最佳配置是一片高原还是一根尖峰? 本文把范文一的"筛类型→回测"流程放进参数网格里做全景扫描——训练阈值、类型组合、持有期、事件窗、样本切分、最佳事件剔除六个维度——得到四个被"单点 +35.5%"掩盖的事实:第一,训练阈值存在大平原:τ∈[0,1.5] 全部选出业绩预增+并购落地,样本外回报恒定 +35.5%,τ 直到 2.0 才把并购落地之外的信号筛掉(+17.0%)、3.0 全部清零——类型筛选对阈值高度耐变,不是"碰巧调出来的尖峰";第二,类型组合有明确稀释规律:业绩预增+并购落地最优(+35.5%),把被排除的政策扶持硬加回去反而跌到 +30.2%,单类表现分三级(业绩预增 +22.8% > 并购落地 +17.0% > 政策扶持 +6.7%),说明范文一的排除是有效信号而非过拟合;第三,真正敏感的旋钮是持有期与样本切分:HOLD×τ 网格显示 τ≤1.5 整列回报恒定,而 HOLD=8 是最优脊(+37.6%);训练/测试比例 60/40 最优(+35.5%),训练过少(52%)或过多(68%)都明显回落(+15.7%/+23.2%)——60/40 是数据效率与过拟合的平衡点;第四,策略对最佳事件有一定依赖但不脆弱:剔除训练期回报最高的 5/10/15 条事件后,策略从 +35.5% 退化到 +17.0%(只留下并购落地),20 条才归零——"去头"会显著削弱但不致崩塌。这些发现把"参数是调出来的"改成了"参数是验证过的、平原与脊都清楚"的稳健策略画像。

一、问题重述与数据

赛题要求在 60 只股票×500 交易日三因子合成市场、238 条五类公告事件库上构建事件驱动投资策略。范文一用训练期(前 300 日)事件研究筛出正 CAR 且 t>1.5 的类型(业绩预增、并购落地),在样本外 200 日回测 CAR 策略,总回报 +35.5%、夏普 4.03。范文二从构成与风险剖面解剖同一策略。

本文不改行情、不改事件库,只把范文一的决策链路参数化后做网格扫描,逐格重训、重筛、重测,回答四个问题:

  • 筛选阈值 τ 从 0 到 3 变化,选出的类型与回报如何变?
  • 三种多头类型的所有组合,谁最优、谁稀释?
  • 持有期 HOLD 与阈值 τ 的二维网格,表现面是高原还是尖峰?
  • 事件窗、样本切分、最佳事件剔除,策略对它们敏不敏感?

二、符号与核心方法

沿用范文一的全部定义(估计窗市场模型 OLS、CAR[-1,+10] 筛选口径、逐日回测、perf 指标),并定义参数化的决策链路:

  • 筛选规则:类型 kk 入选当且仅当训练期 μk>0\mu_k>0 且 tk>τt_k>\tau,其中 τ\tau 为阈值参数(范文一取 1.5);
  • 类型集合:S(τ)={k:μk>0, tk>τ}S(\tau)=\{k:\mu_k>0,\ t_k>\tau\},样本外策略 P(S(τ))P(S(\tau)) 在选中事件次日买入、持有 HOLD 天;
  • 表现面:R(HOLD,τ)R(\text{HOLD},\tau) = 在 HOLD×τ 网格每个格点上重训重测得到的总回报;
  • 剔除鲁棒性:从训练期按 CAR 降序剔除前 nn 条事件后重筛,观察策略退化曲线。

三、结果 I:训练阈值——筛选的大平原

图1 训练阈值 τ 扫描:类型选择与回测总回报

图 1 把筛选阈值 τ 从 0.0 扫到 3.0:τ∈[0,1.5] 时全部选出 {业绩预增, 并购落地},样本外回报恒定 +35.5%(46 笔、夏普 4.03、回撤 2.8%);τ=2.0/2.5 时只剩并购落地(+17.0%、24 笔);τ=3.0 无类型入选(0 笔、0%)。

这条曲线把"筛选阈值是重要参数吗"回答得很清楚:在 0~1.5 的宽区间内,结论完全不变。业绩预增与并购落地的 t 值都远超 1.5(前者 1.92、后者 2.91),使它们对阈值有充足余量;只有阈值逼近 3.0 的极端值时信号才被全筛掉。这说明范文一选 1.5 不是"在某根针尖上碰巧成功",而是落在决定结论的大平原内——这是策略可靠性的第一块基石。

四、结果 II:类型组合——稀释规律清晰

图2 类型组合遍历:样本外总回报排序

图 2 枚举三种多头类型的全部非空组合(2³−1=7 种)并回测:业绩预增+并购落地 +35.5%(最优)> 三者全加 +30.2% > 业绩预增+政策扶持 +26.8% > 业绩预增 +22.8% > 并购落地+政策扶持 +17.1% > 并购落地 +17.0% > 政策扶持 +6.7%。

两个发现:其一,单类表现严格分三级(业绩预增 > 并购落地 > 政策扶持),与训练期 t 排序(2.91/1.92/负值)一致,训练信号在样本外保持成立;其二,把被排除的政策扶持加回去会稀释回报(35.5%→30.2%),证明范文一"排除政策扶持"是剔除噪音而非过拟合——差策略的边际价值是负的。这解释了为何筛选是策略的收益来源之一:不是"多买类型多赚钱",而是"少买错误类型"。

五、结果 III:HOLD×τ 网格——平原与脊

图3 HOLD x τ 网格:总回报百分比

图 3 是持有期 HOLD∈{5,8,10,12,15} × 阈值 τ∈{0,1,1.5,2,3} 的二维回报网格。看整张表:每一行的 τ≤1.5 三格回报完全相同(如 HOLD=8 行为 +37.6/+37.6/+37.6,HOLD=10 行 +35.5/+35.5/+35.5),τ=2 时各行都降到 12~17%,τ=3 全 0;而沿 HOLD 方向,8 天是全局最优脊(+37.6%),向两边 5 天(+24.9%)与 12/15 天(+30.9%/+29.6%)平滑下降。

这张网格把策略的"参数性格"彻底说透:阈值方向是平原(不敏感)、持有期方向是缓脊(HOLD=8 最优但邻域不塌)。没有任何格点是孤立尖峰——最佳格 (8, 0) 的相邻格仍普遍 +30% 左右。这为参数选择提供了充分底气:即便实现细节略有偏差(多持一天、阈值调半点),策略都不会从 +35% 掉到负值。

六、结果 IV:单类型子策略——三级分化

图4 单类型子策略的样本外表现

图 4 单独持有每一类事件的样本外表现:业绩预增 +22.8%(26 笔、夏普 3.57)、并购落地 +17.0%(24 笔、夏普 2.66)、政策扶持 +6.7%(26 笔、夏普 1.17)。

单类策略全部为正,但梯度清晰:业绩预增的独立 alpha 几乎是政策扶持的 3.4 倍。这说明组合里的贡献不是平均分配——业绩预增承担主力,并购落地提供补充,政策扶持的 +6.7% 更像市场 beta 而非事件 alpha(与范文一"零效应陷阱"一致)。对组合构建的启示:权重分配应按单类 alpha 而非事件数量;范文一等权持有两类是稳健做法,但若追求极致可对业绩预增倾斜。

七、结果 V:事件窗长度敏感性

图5 事件窗长度敏感性

图 5 把筛选用的事件窗上界从 +5 扫到 +10:+5 天窗口只选出并购落地(+17.0%),+8 与 +10 天都选出两类型(+35.5%)。

事件窗不是无关紧要的:+5 天的窗口太短,业绩预增的完整脉冲尚未展开(范文一的平均 CAR 曲线显示其正 CAR 在 +5 天后仍在爬升),t 检验不足 1.5 被漏选;而 +8 天后信号成熟,结论与 +10 完全一致。启示:事件窗上界应覆盖信号的主要兑现期,过窄会漏掉慢热类型;但在信号成熟后(≥+8),结论对窗长稳健——这再次印证"平原而非尖峰"的基调。

八、结果 VI:训练/测试样本量平衡

图6 训练/测试样本量比例对回报的影响

图 6 把训练/测试分界 SPLIT 从 260 移到 340(训练占比 52%~68%):SPLIT=300(60/40)时回报最高 +35.5%;训练不足(52%/56%)只有 +15.7%/+15.5%;训练过多(64%/68%)回落 +27.8%/+23.2%。

这是一条典型的"过拟合-欠拟合权衡"曲线:训练太少,类型统计噪声大、筛选不稳定;训练太多,样本外测试期被压缩,且训练期覆盖的行情结构可能与剩余测试期错位。60/40 恰好是平衡点——它与范文一默认的 SPLIT=300 一致,且两侧都单调下降,说明该切分选择是"谷底最优"而非偶然。策略部署时若数据量变化,应重估这个比例而非死守 60/40。

九、结果 VII:最佳事件剔除鲁棒性

图7 剔除训练期最佳事件后的策略退化

图 7 从训练期按 CAR 降序剔除前 0/5/10/15/20 条最佳事件后重筛重测:0 条 +35.5%、5/10/15 条都降到 +17.0%(只剩并购落地仍过筛)、20 条归零。

策略对"去掉最好事件"有一定依赖但不至崩塌:剔除 15 条(训练期事件的约 12%)后,业绩预增因 t 跌破阈值出局,但并购落地仍独立贡献 +17.0%。这说明策略的 alpha 不是建立在少数几只"神之一手"上,而是类型级别的系统性信号;若连 20 条都剔除,训练期信号被掏空,策略归零。对回测可信度的启示:若真实市场里未来不会再出现与训练期最佳事件同类的行情,策略会损失业绩预增这条主线,但并购落地仍提供缓冲——这是策略韧性的体现。

十、结果 VIII:表现面梯度——平原非尖峰

图8 最佳参数区 vs 邻域稳健性

图 8 取全局最佳格点(HOLD=8, τ=0)回报 +37.6%,并统计其曼哈顿距离≤2 的全部邻域格点:均值约 +31.5%、标准差约 9.3(相对波动约 25%)。

量化结论:最佳点周围的邻域回报普遍在 +30% 上下,没有"最佳格 +37.6%、邻格全负"的尖峰形态。相对波动 25% 说明邻域确实有梯度(8 天比 5 天好),但方向平滑、幅度温和。这是全套稳健性分析收束的结论:该策略的参数空间是一片带缓坡的高原,最优配置周围有充足的安全带。任何"换参数就崩"的担忧,都被这张图否定。

十一、结论

四个被"单点 +35.5%"掩盖的事实重塑了策略的可靠画像:

  1. 训练阈值是大平原:τ∈[0,1.5] 结论恒定,筛选不是针尖上的成功;
  2. 类型组合稀释规律清晰:加回被排除的政策扶持反而 -5.3%,"少买错误类型"是收益来源;
  3. 真正敏感的旋钮是持有期(HOLD=8 脊)与样本切分(60/40 平衡点),但都是缓坡非悬崖;
  4. 剔除最佳事件 15 条仍保留 +17.0% 的并购落地缓冲,策略有韧性不脆弱。

这些结论共同指向一个可放心的工程结论:范文一的策略不是"在某个参数点恰好成立的巧合",而是被六个维度的网格扫描验证过的、带平原与安全带的可复制策略。

十二、模型验证(四路一致)

本文正文、配图、附录代码、真源 tools/gen_tidy2026c_3.py 四路数字完全一致。附录代码块可在 tools/ 目录下独立运行复现全部关键数字(τ 扫描、类型组合、HOLD×τ 网格、单类型、事件窗、SPLIT、剔除鲁棒、表现面梯度),所有结果由固定随机种子确定,双跑字节一致。

参考文献

[1] MacKinlay A C. Event studies in economics and finance. Journal of Economic Literature, 1997.
[2] Bailey D H, et al. The probability of backtest overfitting. Journal of Computational Finance, 2017.
[3] 泰迪杯 2026 C 赛题组委会. 事件驱动型股市投资策略赛题数据说明.

附录:核心 Python 实现

import sys, os
_HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.abspath(os.path.join(_HERE, "..", "..", "..", "tools")))
import gen_tidy2026c_3 as SRC
import gen_tidy2026c as G

r = SRC.gen_tidy2026c_3()
b = r["base"]
print("基准 τ=1.5 HOLD=10:", [G.EVENT_TYPES[k][0] for k in b["sel"]],
      "总回报%+.1f%%" % b["perf"]["total"])
# E1 τ 扫描
for tau, d in r["e1"].items():
    print("E1 τ=%.1f %s 总回报%+.1f%% 笔数%d" % (tau, d["sel"], d["total"], d["n"]))
# E2 类型组合
for nm, (tot, sh, n) in sorted(r["e2"].items(), key=lambda x: -x[1][0]):
    print("E2 %-12s 总回报%+.1f%% 夏普%.2f 笔数%d" % (nm, tot, sh, n))
# E3 HOLD x τ 网格
taus = sorted(next(iter(r["e3"].values())).keys())
for h, row in sorted(r["e3"].items()):
    print("E3 HOLD=%d " % h + " ".join("%+.1f" % row[t] for t in taus))
# E4 单类型
for nm, (tot, sh, n) in r["e4"].items():
    print("E4 %-6s 总回报%+.1f%% 夏普%.2f 笔数%d" % (nm, tot, sh, n))
# E5 事件窗
for hi, (sel, tot) in r["e5"].items():
    print("E5 +%d %s 总回报%+.1f%%" % (hi, sel, tot))
# E6 SPLIT
for split, (tot, n) in r["e6"].items():
    print("E6 SPLIT=%d 总回报%+.1f%% 笔数%d" % (split, tot, n))
# E7 剔除鲁棒
for nd, (tot, n) in r["e7"].items():
    print("E7 剔除%d条 总回报%+.1f%% 笔数%d" % (nd, tot, n))
# E8 表现面
e8 = r["e8"]
nb = e8["neighbors"]
mn = sum(nb) / len(nb); sd = (sum((x - mn) ** 2 for x in nb) / len(nb)) ** 0.5
print("E8 最佳(H=%d,τ=%.1f)=%+.1f%% 邻域均值%+.1f%%±%.1f" % (
    e8["best_h"], e8["best_tau"], e8["best_v"], mn, sd))