halo 的技术博客

返回

基金每季度要披露持仓。这意味着在季末最后几天,基金经理面对一个不对称的激励:买入本季表现好的股票,让持仓报表看起来像是早就抓住了它们;卖出表现差的,让失误从名单上消失

这就是 window dressing(粉饰橱窗)。它有个很干净的可检验预测——如果这是真的价格压力而非信息,那么季末被推高的部分应该在新季度开盘后吐回去。

12 年 48 个季度、300 只股票的模拟给出的答案:季末最后 3 天赢家减输家 53.16bp(t=6.02),新季度前 3 天反转 -55.90bp(t=-7.17),反转覆盖 105.2%

季末价差与新季反转

左图直接画多空价差(已剔除市场漂移),反转看得很清楚:涨到峰值 0.47%,然后几乎全部吐回。右图是分组原始路径——两条线在事件窗口里同向上行,那是市场收益,如果只看右图会误以为”输家也在涨、哪来的压力”。这是分组事件研究最常见的读图错误:必须看价差,不能看分组绝对水平。

一、机制设定:把压力写成可审查的公式#

模拟的核心是让粉饰压力同时依赖三个变量,这样后面才能做横截面识别:

# 季内表现排名(只用粉饰窗口之前的数据,避免用未来信息选样)
qtd  = ret[s:e - DRESS_DAYS].sum(axis=0)
rank = pd.Series(qtd).rank(pct=True).values
tilt = 2 * (rank - 0.5)                       # -1(最差) ~ +1(最好)

# 流动性越差,同样资金推动幅度越大
liq_amp = (adv.mean() / adv) ** 0.35
liq_amp = liq_amp / liq_amp.mean()

# 压力 ∝ 季内表现 × 机构持股比例 × 流动性放大
push = DRESS_STRENGTH * tilt * inst_own / inst_own.max() * liq_amp
push *= (1 + 0.25 * rng.standard_normal(N_STOCK))    # 每季强度有噪音
python

压力按 [0.2, 0.3, 0.5] 的权重分配到最后 3 天(越接近季末越猛),然后在新季度前 3 天按 [0.5, 0.3, 0.2] 释放 85%。

DRESS_STRENGTH = 0.007,即顶格机构持仓的赢家被推高 0.7%。这个量级参考了 Carhart 等人对季末价格模式的实证区间——不是拟合出来的,是先设定后检验。

一个会静默毁掉整份研究的 bug#

第一版代码我把”生成常规收益”和”注入粉饰压力”写在同一个季度循环里:

for q in range(QUARTERS):
    s, e = q*DAYS_Q, (q+1)*DAYS_Q
    ret[s:e] = 生成常规收益(...)      # ← 这一行
    ...
    ret[e:e+3] += 反转压力             # ← 写到了下一季的区间
python

问题在于:第 q 季写入 ret[e:e+3] 的反转压力,会被第 q+1 季的 ret[s:e] = ... 整段覆盖掉。注意这是赋值 = 不是累加 +=

后果是反转消失。第一版跑出来 H2 是 +13.04bp(t=1.49)——方向反了,还不显著。如果我当时没有交叉验证”反转覆盖比例应该接近 1”这个先验,很可能就写成”粉饰效应存在但不反转,说明它包含真实信息”这种完全错误的结论。

修复方法是拆成两遍:

# 第一遍:先生成全部常规收益
for q in range(QUARTERS):
    ret[s:e] = 生成常规收益(...)

# 第二遍:再叠加压力与反转(用 += )
for q in range(QUARTERS):
    ret[e-3:e] += push * w_d
    ret[e:e+3] += -push * 0.85 * w_r
python

修复后 H2 变成 -55.90bp(t=-7.17),反转覆盖比例 105.2%。

这类 bug 的可怕之处在于它不报错、不产生 NaN、结果看起来还挺”有意思”。唯一能抓住它的是先验:如果这是价格压力,它必须反转。当数据说”不反转”时,第一反应应该是查代码,而不是编故事。

二、三个对照:这到底是不是季末特有的?#

单看 53.16bp 和 t=6.02 说明不了什么。至少有三个替代解释需要排除。

对照一:会不会是月度再平衡流?#

很多机构每月末调仓。如果非季末的月末也有同样效应,那抓到的就不是”季末披露压力”,而是”月度资金流”。

用完全相同的算法跑季内第 1、2 个月末(96 个样本):

窗口赢家−输家 3 日价差t 值
季末53.16bp6.02
非季末月末5.92bp0.95

非季末月末不显著。 效应确实集中在季末,与”披露驱动”的假说一致。

安慰剂对照与横截面识别

对照二:会不会只是短期动量?#

“季内涨得多的股票在接下来 3 天继续涨”——这可能只是动量,跟季末没关系。用随机日期安慰剂检验:在季内随机挑一个日期,用同样的方法排名并测算之后 3 天的价差。

结果:14.29bp(t=1.94)

这个数字很关键,它没有归零。t=1.94 刚好卡在 5% 显著性的边缘。诚实的读法是:53.16bp 里大约有 14bp 来自短期动量本身,真正归因于季末的增量约 39bp,而不是全部 53bp。

如果只做对照一就收工,会把动量的贡献算进粉饰效应,高估约 27%。

对照三:引擎会不会自己造信号?#

生成一个完全没有粉饰压力的纯净市场,跑同一套策略:

-7.22bp(t=-0.85),不显著。引擎不造假信号。

三、横截面识别:压力应该随机构持仓放大#

时序对照能排除日历解释,但最有力的证据来自横截面。如果这真是基金行为驱动的,那么同样是赢家,机构持股比例高的应该被推得更猛

把赢家组按机构持股比例再切两半:

分组季末 3 日收益
高机构持仓赢家+5.21bp
低机构持仓赢家-8.20bp

方向和单调性都对上了,而且低机构持仓组是负的——它们没有被粉饰,只表现出正常的短期反转。

这个检验比时序对照更难被替代解释攻破:任何”市场整体在季末上涨”的说法都无法解释为什么涨幅系统性地依赖机构持股比例

四、稳定性:81% 的季度为正,但离散度很大#

逐季度稳定性

48 个季度里 39 个为正(81.3%),但柱子高低差异极大——最好的季度接近 200bp,最差的接近 -120bp。

这是日历效应策略的典型形态:统计上稳健,单季度上不可靠。t=6.02 是 48 个季度累积出来的,任何单一季度都可能大幅偏离。用它做实盘意味着必须容忍连续几个季度的回撤,而每年只有 4 次机会——样本累积速度极慢,10 年才 40 个观测。这也意味着,即使效应真实存在,你也很难在有生之年用实盘业绩把它和运气区分开。

五、可交易性:成本容忍度很低#

前面都是毛收益。加上成本:

单边成本全市场 Sharpe高机构持仓过滤 Sharpe
0bp1.741.69
5bp1.411.45
10bp1.081.20
15bp0.760.96
20bp0.430.71
30bp-0.220.22
40bp-0.88-0.28

成本敏感性与容量墙

盈亏平衡成本约 26bp(全市场)。 A 股卖出印花税 5bp + 双边佣金 + 冲击,机构口径下 15-25bp 是现实区间——也就是说这个策略在扣完成本后剩不下多少。

注意一个反直觉的现象:在低成本区,高机构持仓过滤反而略差(0bp 时 1.69 vs 1.74)。因为过滤后股票池从 300 缩到约 150,每边只能选 30 只,分散度下降、波动上升。但成本一旦超过 10bp,过滤组就全面胜出(30bp 时 0.22 vs -0.22)——信号密度的价值只在成本足够高时才体现出来

六、容量墙#

加上平方根冲击成本和成交量约束(单只不超过窗口成交额的 8%):

策略规模成交完成率冲击成本每季净收益Sharpe
0.1 亿100%3.48bp+19.68bp0.64
0.5 亿100%7.78bp+15.38bp0.50
1 亿100%11.01bp+12.15bp0.40
5 亿100%24.61bp-1.45bp-0.05
10 亿99.1%34.60bp-11.93bp-0.39
30 亿60.4%42.90bp-40.91bp-2.20

5 亿元是临界规模。 更值得注意的是失效的顺序:在 5 亿时成交完成率还是 100%,杀死策略的是冲击成本;要到 30 亿成交完成率才掉到 60.4%。

“买得进”和”买得划算”是两个不同的约束,前者远比后者宽松。只检查持仓上限而不建模冲击,会把容量高估一个数量级。

还有一层现实约束模型没有覆盖:这个策略要在季末最后 3 天集中调仓,而这正是粉饰资金自己在抢的时间窗口。你的对手盘是一群有强制披露约束、对价格不敏感的买家——听起来像好事,但同时意味着流动性在这 3 天被大量消耗,实际冲击很可能高于平方根律的估计。

七、总结:真实、可识别、但基本不可交易#

三层结论分开说:

统计层面成立。 53.16bp(t=6.02),81.3% 的季度为正,反转覆盖 105.2%——涨出来的全吐回去,这是价格压力而非信息的判定性特征。

因果识别成立。 非季末月末不显著(t=0.95)排除月度再平衡;横截面上压力随机构持股比例单调放大(+5.21bp vs -8.20bp)排除市场整体解释;纯净市场对照(t=-0.85)排除引擎伪影。

交易层面基本不成立。 盈亏平衡成本约 26bp,容量约 5 亿元,且随机日期安慰剂(14.29bp,t=1.94)说明其中约四分之一其实是普通短期动量。扣掉这部分、扣掉成本,剩下的空间对绝大多数资金规模都不值得占用一条策略线。

它更适合的用途是风险管理而非 alpha:如果你的组合恰好重仓了一批本季大涨、机构持仓集中的股票,那么季末最后 3 天的账面浮盈里有一部分是借来的,新季度开盘会还回去。知道这一点,比试图去交易它更有价值。


局限与偏差#

这是结构模拟不是历史回测。 压力强度、反转比例、衰减权重全部外生设定。它能验证”如果机制成立,能观测到什么、能否交易”,但不能证明真实市场中该效应的具体幅度。真实检验需要基金持仓披露数据 + 逐笔成交数据。

监管环境在变。 各主要市场近年都加强了对季末异常交易的监控,部分司法辖区将刻意抬价列为操纵。历史上存在的效应强度不能外推到当下,且效应本身可能因为被广泛研究而衰减。

冲击成本模型偏乐观。 平方根律的系数取自常态市场,而季末最后 3 天流动性被粉饰资金大量消耗,真实冲击很可能更高。5 亿容量应视为上界。

A 股的实施约束未建模。 空头端需要融券,而季末赢家往往券源紧张、费率高企;T+1 制度也限制了调仓灵活性。本文的多空框架在 A 股更接近理论构造,实盘更可行的形态是单边规避(季末减持高机构持仓的本季赢家)而非双边套利。

季末粉饰橱窗效应:基金排名压力如何扭曲最后三天的价格
https://blog.halo26812.eu.org/blog/window-dressing-quarter-end
Author halo
Published at 2026年7月31日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨