7.4 盈利超预期(SUE)与 PEAD:信息摩擦下的持续漂移¶
矛盾:有效市场说好消息会被瞬间定价,为什么财报超预期后股价还会继续涨 60 天?
PEAD 为什么会持续存在?¶
Ball & Brown(1968)发现这个现象后已过去 50 年,PEAD 仍未消失,原因是:
- 信息处理有摩擦:财报有数百页,散户和部分机构无法当天分析完
- 分析师更新迟缓:卖方分析师的盈利预测往往保守,不会在一天内大幅上调
- 套利有成本:需要持仓 60 天,期间有其他风险占用资金
- 注意力分散:财报季同时发布数百家,资金关注度被稀释
学习目标¶
- 理解 SUE(标准化盈利惊喜)的含义和计算
- 演示 PEAD 事件研究(Event Study)
- 分析 PEAD 在低分析师覆盖股中为何更强
1. 这节究竟解决什么实际问题?¶
7.4 盈利超预期(SUE)与 PEAD:信息摩擦下的持续漂移 的具体任务是:用标准化盈余意外研究 PEAD,并严格按公告日对齐。 本节将明确输入数据、计算过程、输出及其在后续研究中的用途。
2. 前置知识¶
理解利润表、资产负债表、现金流量表以及收益率。 对公式的理解应包括变量定义、单位、时间索引和适用条件。
3. 数据说明¶
教学样本可能为模拟或固定快照。必须区分报告期、公告日、可获取日、修订日和实际交易日。 运行前先检查 shape、日期范围、列名与缺失值。数据看起来能画图,不代表它适合回答研究问题。
4. 学习目标与完成标准¶
完成本节后,你应能用自己的话解释 7.4 盈利超预期(SUE)与 PEAD:信息摩擦下的持续漂移 的输入、计算步骤、输出和局限;尤其能说明:用标准化盈余意外研究 PEAD,并严格按公告日对齐。 你还应能独立改动一个参数并解释结果为什么变化,指出至少一个会让结论失真的假设。
5. 核心概念与公式¶
报告期结束日、公告日和数据实际可获取日不同。交易信号必须按可获取日而非报告期对齐。
财务比率的分子与分母须来自同一可得时点;因子形成后再给予合理交易延迟。 看到公式时依次确认:每个符号的单位是什么?它属于哪个时点?分母会不会为零?它是描述性统计量、预测量,还是交易规则?
6. 从零实现¶
原始代码按照“准备输入 → 计算中间量 → 得到结果 → 解释输出”的顺序组织。每个单元应检查变量类型、索引、维度和代表性数值。中间变量用于核对公式实现和定位计算错误。
7. 成熟库实现¶
Pandas 便于按公告日对齐;数据服务返回的字段并不天然具有可交易时点。 使用库函数前先阅读参数含义、默认值和返回对象;库输出一个数字,并不说明这个数字适合你的交易假设。
8. 两种实现的差异¶
从零实现便于核对公式、调试和识别隐含假设;成熟库适合在计算逻辑已验证后复用。两种实现依赖相同的数据口径与时点假设,使用库函数不会改变输入数据的质量。
9. 预期结果与检查范围¶
你应看到维度正确的 Series/DataFrame、日期单调递增的索引,以及能支持“用标准化盈余意外研究 PEAD,并严格按公告日对齐。”这一任务的表格或图形。金融日收益率均值通常接近 0;若出现极大的连续收益、空表、全 NaN 或索引错位,应先排查数据和对齐逻辑,而不是立即相信结果。
10. 常见错误与诊断¶
按财报所属季度直接交易、使用修订后数据、忽略负值和行业差异、混用市值时点。
诊断顺序:先打印类型与 shape,再看 head()/tail(),接着检查日期和 NaN,最后才比较数值。这样能避免在错误的对象上反复改参数。
11. 研究偏差检查¶
错误的 Point-in-Time 对齐会产生未来函数;必须记录公告日并设置交易可用延迟。 结果至少应与一个简单基线比较,并明确哪些部分只是教学演示。
12. 三层练习与答案¶
- 基础练习:验证一个中间变量、补全一段小计算,并用一句话解释输出。
- 研究练习:改变窗口、样本区间、约束或标的,记录哪些结论仍成立。
- 开放项目:把本节方法嵌入模块项目,报告基线、失败结果和限制。
题目在 ../exercises/07_fundamental/04_earnings_surprise_exercises.ipynb;完整推导、可运行参考实现与结果检查在 ../solutions/07_fundamental/04_earnings_surprise_solutions.ipynb。请先独立作答,再打开答案。
13. 延伸阅读¶
延伸材料:AQR 关于因子研究的资料。阅读记录应包括研究假设、数据频率、样本范围和结论适用条件。
14. 下一节¶
完成本模块后,进入下一模块的概览页,并把本节的检查清单带到后续研究中。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats
np.random.seed(42)
print('OK')
OK
import matplotlib.pyplot as plt
# 1. 设置系统自带的中文字体(这里使用黑体 SimHei)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 如果你想用微软雅黑,可以改成 ['Microsoft YaHei']
# 2. 解决更换字体后,负号(-)显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False
第一部分:从盈利惊喜到 SUE¶
为什么要标准化?¶
原始盈利惊喜 = 实际EPS - 预期EPS,但 A 股公司 EPS 从几分钱到几十元不等, 跨公司比较无意义。标准化解决了这个问题:
$$\text{SUE} = \frac{\text{实际EPS} - \text{预期EPS}}{\sigma_{\text{历史惊喜}}}$$
SUE = 2 意味着:这次的利润超预期幅度是该公司历史平均惊喜的 2 倍标准差。
分析师为什么系统性低估?¶
卖方分析师有保守预测的激励机制:
- 超预期比不及预期更容易让客户和公司管理层满意
- 低估后公司财报发布超预期,分析师显得"专业"
- 这是行业内公认的"管理预期"策略
np.random.seed(42)
n = 500
true_eps = np.random.normal(2.0, 0.8, n)
consensus = true_eps + np.random.normal(-0.05, 0.25, n) # 模拟分析师预测的负偏差
actual = true_eps + np.random.normal(0, 0.15, n)
surprise = actual - consensus
sue = surprise / np.random.uniform(0.2, 0.5, n)
print(f'正惊喜比例: {(surprise>0).mean():.1%} (分析师低估→正惊喜>50%是正常现象)')
print(f'平均惊喜: {surprise.mean():.4f} (正数确认分析师系统低估)')
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].hist(surprise, bins=50, color='steelblue', alpha=0.7, edgecolor='none')
axes[0].axvline(0, color='red', lw=2, linestyle='--', label='0线')
axes[0].axvline(surprise.mean(), color='orange', lw=2, label=f'均值={surprise.mean():.3f}')
axes[0].set_title('原始盈利惊喜分布\n均值>0证实分析师系统低估')
axes[0].legend()
axes[1].hist(sue, bins=50, color='darkorange', alpha=0.7, edgecolor='none')
for v,c,l in [(-1,'darkred','强负惊喜'), (1,'green','强正惊喜')]:
axes[1].axvline(v, color=c, lw=1.5, linestyle=':', label=l)
axes[1].set_title('SUE分布\n标准化后可跨公司跨期比较')
axes[1].legend()
plt.tight_layout(); plt.show()
正惊喜比例: 59.0% (分析师低估→正惊喜>50%是正常现象) 平均惊喜: 0.0583 (正数确认分析师系统低估)
np.random.seed(42)
days = np.arange(-30, 61)
labels = ['极负SUE(<-1)', '弱负(-1,-0.3)', '中性', '弱正(0.3,1)', '极正(>1)']
sue_means = [-1.5, -0.6, 0.0, 0.6, 1.5]
colors = ['#c0392b','#e67e22','#95a5a6','#27ae60','#1a5276']
fig, ax = plt.subplots(figsize=(13, 6))
for sue_m, color, label in zip(sue_means, colors, labels):
car = np.zeros(len(days))
for i, d in enumerate(days):
if d < 0:
car[i] = 0.0003 * sue_m * d
elif d == 0:
prev = car[i-1] if i > 0 else 0
car[i] = prev + 0.012 * sue_m
else:
car[i] = car[i-1] + 0.00045*sue_m + np.random.normal(0, 0.005)
ax.plot(days, car*100, color=color, lw=2.2, label=label)
ax.axvline(0, color='black', lw=2, linestyle='--', label='财报发布日 Day 0')
ax.axhline(0, color='gray', lw=0.8)
ax.fill_betweenx([-8, 8], 0, 60, alpha=0.05, color='blue')
ax.annotate('PEAD区间(Day0后持续分化)', xy=(30, 1), fontsize=9, color='blue')
ax.set_xlabel('相对财报发布日的交易天数')
ax.set_ylabel('累积超额收益率 CAR (%)')
ax.set_title('PEAD事件研究:按SUE分组的累积超额收益关键:Day 0之后各组仍在继续分化,这就是「漂移」')
ax.legend(fontsize=9); ax.grid(alpha=0.3)
plt.tight_layout(); plt.show()
print('如果市场有效: Day 0 之后所有组的 CAR 应平行(不再分化)')
print('实际结果: Day 0 之后各组仍明显分化 → 证明信息消化存在摩擦')
如果市场有效: Day 0 之后所有组的 CAR 应平行(不再分化) 实际结果: Day 0 之后各组仍明显分化 → 证明信息消化存在摩擦
第三部分:为什么低覆盖率小盘股 PEAD 更强?¶
| 特征 | 大盘股 | 小盘股 |
|---|---|---|
| 分析师覆盖 | 10-30人 | 0-3人 |
| 媒体报道 | 大量 | 极少 |
| 机构持仓比例 | 高 | 低 |
| 信息传播速度 | 快 | 慢 |
| PEAD 强度 | 弱(20天) | 强(60+天) |
逻辑:信息传播越慢,市场消化越迟缓,PEAD 持续时间越长。 部分研究发现,PEAD 在小市值、分析师覆盖较低的样本中更明显;这一关系需要按市场、时期和交易成本重新检验。
np.random.seed(42)
N = 300
coverage = np.random.poisson(lam=8, size=N).clip(0, 30)
# PEAD 强度与覆盖率负相关
pead_str = np.random.normal(0, 0.15, N) + 0.25 / (1 + 0.3*coverage)
r, p = stats.pearsonr(coverage, pead_str)
print(f'覆盖率 vs PEAD强度 相关系数: r={r:.3f} (p={p:.4f})')
plt.figure(figsize=(8, 4))
plt.scatter(coverage, pead_str*100, alpha=0.4, s=20, color='steelblue')
m, b, *_ = stats.linregress(coverage, pead_str)
xr = np.linspace(0, 30, 100)
plt.plot(xr, (m*xr+b)*100, 'r-', lw=2, label=f'r={r:.3f}')
plt.xlabel('分析师覆盖数量(人)')
plt.ylabel('PEAD强度(60天CAR %)')
plt.title('分析师覆盖越少 → PEAD 越强(信息摩擦越大,套利机会越持久)')
plt.legend(); plt.grid(alpha=0.3); plt.show()
覆盖率 vs PEAD强度 相关系数: r=-0.130 (p=0.0238)
练习¶
- 对 A 股所有沪深300成份股,用过去 5 年季报数据计算真实 SUE 因子,验证 PEAD 是否存在。
- PEAD 的最大风险是「反转」:超预期后再公告下修。设计止损规则(跌破发布日价格的5%则平仓)。
- 比较 A 股与美股 PEAD 效应:A 股散户比例更高,PEAD 持续时间应该更长还是更短?查阅文献。
下一节 → ../05_portfolio/08_dynamic_asset_allocation.ipynb