一只债券被从 BBB- 下调到 BB+,市场称之为「堕落天使」(Fallen Angel)。大家盯着评级的动作看信用,但真正把这只有机体砸出超额跌幅的,往往是评级档案里那几条自动触发的条款——指数基金必须在 N 个交易日内把它踢出投资级指数、受限账户一旦持仓评级跌破阈值就强制减仓、风控模型里把”非投资级”映射成更高的折扣率与更低的敞口上限。
结论先放这:堕落天使的跌幅 = 真实信用恶化 + 机械性抛压,且后者在窗口期可以占到观测利差的 20%–40%,并留下约 30% 的永久残留。本文用一只合成堕落天使债券,把价格路径拆成「基本面公允价」与「实际指数价」,用 Kyle 式价格冲击把机械卖压翻译成可观测的超额利差,再用一个流动性深度敏感性图说明为什么在压力市里同样的评级事件,跌幅能差一个数量级。附完整 Python 与四张真实计算图(高阶)。

一、堕落天使为什么”跌过头”:两个互相叠加的机制#
先定义清楚我们要拆的两块。设债券净价 、期权调整利差 、久期 ,近似有
当评级从投资级下调到高收益,OAS 会跳升。但这个跳升里有两块性质完全不同的成分:
- 基本面成分(fundamental):公司真实信用状况恶化,违约概率上升,理应享受更高利差。这部分是”对的”,发行人自己活该。
- 机械成分(mechanical):因为债券不再满足指数纳入标准、不再满足账户的评级约束,一批持有人在窗口期内被动地、与基本面无关地把它卖掉。这批卖盘不关心价格,只关心”在截止日前清仓”,于是制造出额外的、暂时性的价格冲击。
关键是:基本面成分最终会稳定在新的均衡利差上,而机械成分本应在窗口结束后随流动性恢复而回落——但它往往留一部分永久残留。原因在于,机械抛售把债券压到低价后,反而可能触发第二批技术性卖盘(折扣率上调→杠杆账户被迫减仓),形成二阶伤害。
二、构造一只合成堕落天使:把路径拆成两行#
我们用受控模拟造出一只债券在事件前 30 个交易日(投资级,OAS=130bp)到事件后 30 个交易日(高收益,基本面 OAS=380bp)的完整路径。核心是把”观测 OAS”写成两行之和:
其中 只跟随真实信用状态演化,下调当日从 130bp 跳到 380bp; 只在强制抛售窗口内非零。设窗口长度 个交易日,进入窗口时持有该债的受约束账户需在窗口内清掉占流通盘 的仓位,于是每日机械抛压为 。
import numpy as np
rng = np.random.default_rng(20260827)
N = 60 # 事件前后共 60 个交易日
t_dg = 30 # 第 30 日发生评级下调
duration = 7.0 # 债券久期(年)
OAS_pre = 130.0 # 下调前 IG 利差(bp)
OAS_fund_post = 380.0 # 下调后"真实"信用状态对应的 HY 合理利差(bp)
window = 5
forced_frac = 0.35 # 必须卖出的持仓占流通盘比例
depth_stress = 0.18 # 压力期每日可吸收流动性(占流通盘比例)
lambda_m = 60.0 # 机械冲击系数
rebound = 0.70 # 窗口结束后机械折价的均值回复比例
daily_forced = forced_frac / window
oas = np.zeros(N)
oas_fund = np.zeros(N)
oas[0] = oas_fund[0] = OAS_pre
for t in range(1, t_dg):
oas[t] = oas[t-1] + rng.normal(0, 3.0)
oas_fund[t] = oas[t]
oas[t_dg] = oas_fund[t_dg] = OAS_fund_post
cum_mech = 0.0
for t in range(t_dg + 1, t_dg + 1 + window):
oas_fund[t] = oas_fund[t-1] + rng.normal(0, 2.0)
# 机械冲击 = 系数 × (抛压 / 可吸收深度)
imp = lambda_m * (daily_forced / depth_stress)
cum_mech += imp
oas[t] = oas_fund[t] + cum_mechpython注意一个细节: 在窗口期内也继续随机演化,所以图里”基本面公允价”并不是一条直线,而是带着自身波动的真实信用轨迹。我们要看的超额,始终是”实际观测”减”基本面公允”的差,不是减一个常数。
三、Kyle 式冲击:把”被动卖盘”翻译成超额利差#
机械抛压为什么会产生超额利差?因为卖盘是价格不敏感的。指数基金不在乎这几天是 98 还是 95,它只在乎第 5 天收盘前仓位归零。这类流动性驱动的交易,其价格冲击服从 Kyle (1985) 的经典形式:永久价格影响正比于订单的信息无关成分。
我们把它简化成一行可复现的公式:
分母”可吸收流动性”是压力期每天真正能接住这波卖盘的交易量。当市场平静、做市商愿意接货时,分母大,冲击小;当全市场都在去杠杆时,分母塌到 18%,同样的抛压制造出数倍的超额利差。把窗口内每日冲击累加,就得到峰值机械超额利差。

在我们的参数下,窗口期每日抛压 7.0% 流通盘、可吸收深度 18%,单日冲击约 23bp,5 日累计峰值机械超额利差 ≈117bp。把久期 7.0 代回去,这相当于债券净价被额外打掉约 8.17 元——而这不是因为公司变差了,纯粹是因为”有人被规定要卖”。
四、把利差拆开看:多少是真实信用,多少是被迫卖出#
下图把观测 OAS(蓝)、基本面公允 OAS(灰虚线)、两者之差(橙填充)并列。可以清楚看到:下调当日基本面从 130bp 跳到 380bp(这是真实信用恶化的 +250bp),但观测值紧接着被机械成分再顶高一段,峰值观测 OAS 达到约 491bp——其中 380bp 是”该得的”,117bp 是”被砸出来的”。

# 窗口结束后,机械折价的均值回复(不是完全归零)
post_start = t_dg + 1 + window
for i, t in enumerate(range(post_start, N)):
oas_fund[t] = oas_fund[t-1] + rng.normal(0, 2.0)
progress = (i + 1) / (N - post_start)
oas[t] = oas_fund[t] + cum_mech * (1 - rebound * progress)
peak_mech = cum_mech # 117 bp
resid_mech = cum_mech * (1 - rebound) # 窗口结束后的永久残留:35 bppython最值得记住的是残留:我们设回复比例 70%,意味着窗口结束后机械折价的 30% 永久留下,即约 35bp。这不是模型随便设的数字,而是对应现实里”低价触发了第二批技术性卖盘、或买方趁机要求更高补偿才肯接”的二阶效应。如果完全归零,等于假设市场瞬时有效、没有任何遗留伤口——这反而是一个更不现实的安慰剂。
五、流动性是坠落的引擎:深度敏感性#
同一笔评级事件,为什么 2008 年能砸出 40% 的跌幅,2021 年同类事件只跌 5%?答案几乎全在分母。下图固定抛压 7%/日,把每日可吸收流动性从 5% 扫到 60%,看峰值机械利差怎么变:

- 可吸收深度 = 5%(极端压力):峰值机械利差 ≈420bp
- 可吸收深度 = 18%(基准压力):峰值机械利差 ≈117bp
- 可吸收深度 = 60%(平静市):峰值机械利差 ≈35bp
深度从 18% 掉到 5%,机械利差涨了 3.6 倍。这正是堕落天使策略的核心矛盾:你赚的是”错杀后均值回归”的钱,但错杀的深度由你完全控制不了的流动性决定。在流动性最好的时候,错杀最浅,你能赚的也最少;在流动性最差的时候,错杀最深,但你可能根本没现金去接,或者接了之后它还能再跌。
六、实务监测框架:怎么在事前嗅到机械卖压#
把上面的机制变成一个可运行的监测器。输入是一只刚被下调(或即将被下调)的债券,输出是它的”机械卖压温度计”:
def mechanical_stress(index_weight, float_shares, window_days,
daily_absorption, lambda_m=60.0):
"""估算一只堕落天使在窗口期内的峰值机械性超额利差。"""
forced_frac = index_weight * float_shares # 必须卖掉的占流通盘比例
daily_forced = forced_frac / window_days
if daily_absorption <= 0:
return float("inf") # 没人接盘 → 冲击发散
peak_mech = window_days * lambda_m * (daily_forced / daily_absorption)
return {
"daily_forced_pct": daily_forced * 100,
"peak_mech_bp": peak_mech,
"price_hit": peak_mech * 7.0 / 10000.0 * 100.0, # 按 7 年久期
}
# 例:某堕落天使占某 IG 指数 0.12%,受限账户合计持有 35% 流通盘
print(mechanical_stress(index_weight=0.0012, float_shares=0.35,
window_days=5, daily_absorption=0.18))
# {'daily_forced_pct': 7.0, 'peak_mech_bp': 116.7, 'price_hit': 8.17}python监测要点,按重要性排序:
- 窗口长度与日历:指数剔除是 T+5 还是 T+10?季度再平衡日前后,多个堕落天使会被同时抛,互相挤占流动性。
- 可吸收深度的代理变量:用同评级、同板块债券的中介买卖价差、成交量集中度、ETF 折溢价来近似”现在每天能接多少”。
- 二阶触发器的距离:当前净价离”会触发折扣率上调/保证金追补”的价位还有多远?离得近,说明残留会更大。
- 错杀深度 ≠ 买入信号:机械利差越大,回归空间越大,但回归需要流动性。最深的错杀往往发生在流动性最枯竭时——你的买入价可能还不是底。
七、能做与不能做的:从”知道会跌”到”赚到钱”#
堕落天使策略(买入被错杀的高收益新晋债券,赌均值回归)长期有正期望,但本文的拆解剖开了它的两个隐形约束:
- 你赌的是流动性会回来,不是公司会变好。基本面那 250bp 是永久的,机械那 117bp(峰值)里只有约 82bp 会回来,35bp 永久留下。所以”跌过头→涨回来”只成立在机械部分,且回来需要时间。
- 错杀最深时你最没子弹。这和经验法则”别人恐惧时我贪婪”冲突——因为恐惧最盛、错杀最深的那天,正是你的保证金最紧、申购最冷、没人愿意接货的那天。
能做的:把机械卖压温度计接进风控,在窗口期内分批、不抢跑地接,且只在可吸收深度开始回升(价差收窄、成交量恢复)后才加仓。不能做的:把”评级下调”当成无脑买入信号,或假设窗口结束日就是最低点——本文的残留机制说明,最低点常常在窗口结束后才被二阶触发确认。
八、小结与可复现#
本文用一个受控的、完全可复现的信用事件模型,把堕落天使的下跌拆成了”该跌的”和”被砸的”两块。关键数字(种子 20260827):
- 基本面跳跃:OAS 从 130bp → 380bp(+250bp,真实信用恶化)
- 机械峰值:窗口期累计 ≈117bp 超额利差,对应净价额外打掉 ≈8.17 元
- 永久残留:窗口结束后约 35bp 不回来(二阶伤害)
- 流动性杠杆:深度从 18% 掉到 5%,机械利差从 117bp 涨到 420bp(3.6 倍)
一句话收尾:堕落天使的伤口,评级只划了第一刀,真正让它血流不止的,是那些写在基金合同和风控模型里、与基本面无关的自动抛售条款——而它们的杀伤力,由当时市场愿不愿意接盘决定。 完整代码与四张图均来自本文脚本,欢迎改参数复现。
本文图表均由 Python(numpy + matplotlib)实时计算生成,非占位图。模型为教学用合成数据,参数可改;真实落地时请用实际指数权重、持仓约束与流动性代理变量替换文中的受控假设。