halo 的技术博客

返回

核心结论:你以为你买了一只久期 6.34 年的债券,其实你买了一只久期在 3.08 到 7.58 年之间反复横跳的债券——而且它总是朝对你不利的方向跳。 本文构造一个 30 年 pass-through MBS:WAC 6.00%、投资人净票息 5.50%、贴现率取 5.50%,基准价格精确等于 100.0000(这是引擎正确性的第一道校验)。它的有效久期 6.34 年、有效凸性 -313.2、WAL 9.20 年。再拿一支久期几乎完全匹配的 7.79 年国债(久期 6.35、凸性 +46.5)做对照。结果:利率下行 300bp,国债涨 +21.32%,MBS 只涨 +9.70%,上行捕获率 45.5%;利率上行 300bp,国债跌 -17.12%,MBS 跌 -19.86%,多亏 2.74 个百分点。所有数字均由脚本真实计算,stats.json 保留全部原始值。

MBS 与久期匹配国债的价格曲线对比:-300bp 时国债 +21.32% 而 MBS 仅 +9.70%(只吃到 45.5% 涨幅),+300bp 时 MBS -19.86% 比国债 -17.12% 多亏 2.74 个百分点

一、你不是债主,你是期权的卖方#

买一支普通国债,你只承担利率风险。买一支 MBS,你额外免费送给了借款人一份美式看涨期权:任何时候,只要再融资划算,他可以按面值 100 把贷款还给你,然后去别处借更便宜的钱。

这笔交易的不对称性是致命的:

  • 利率跌 → 借款人行权,你收回一堆现金,只能按更低的利率再投资(收缩风险
  • 利率涨 → 借款人绝不提前还款,你手里的低息资产被锁死,错过高息(展期风险

两个方向你都输。用凸性的语言说:普通债券的价格-利率曲线向上凸(凸性为正,利率两边跑你都占便宜);MBS 的曲线在票面附近被压平甚至向下凹。凸性为正是白送的礼物,凸性为负是你在替别人交期权费。

二、S 曲线:提前偿付对利率高度非线性#

建模的核心是把「再融资激励」映射成 CPR(年化提前偿付率)。激励定义为 refi incentive = WAC − 当前市场按揭利率,用一个有界的 arctan S 曲线拟合:

CPR_MIN, CPR_MAX = 0.04, 0.55   # 自然周转地板 / 再融资潮饱和
K_STEEP, X0_INCEN = 3.0, 0.70   # 陡度 / 触发阈值(百分点)
BURN_BETA, BURN_FLOOR = 2.2, 0.40

def scurve_cpr(incentive_pp, burnout=0.0, k=K_STEEP, x0=X0_INCEN):
    s = 0.5 + np.arctan(k * (incentive_pp - x0)) / np.pi   # ∈ (0,1)
    cpr_fresh = CPR_MIN + (CPR_MAX - CPR_MIN) * s
    # 燃尽只削弱「再融资超额部分」,不削弱自然周转地板
    mult = BURN_FLOOR + (1.0 - BURN_FLOOR) * np.exp(-BURN_BETA * burnout)
    return CPR_MIN + (cpr_fresh - CPR_MIN) * mult
python

三个细节决定了模型是否像真的:

  1. 地板不为零。就算利率涨到天上,仍有 4% CPR 来自换房、离婚、违约——这部分与利率无关。
  2. 有触发阈值。激励小于约 70bp 时借款人懒得动(手续费、时间成本),CPR 几乎不变。
  3. Burnout(燃尽)。该走的人早走了,剩下的是对利率不敏感的「钉子户」。这里用 burnout = 1 − 实际余额 / 计划余额 度量,燃尽后再融资敏感度最低衰减到 40%。

左图 S 曲线:基准点 CPR=11.2%,激励超过 70bp 阈值后急剧陡峭、深度燃尽后整条曲线被压低;右图实际路径显示 seasoning 爬坡→峰值→burnout 衰减,-300bp 情景首年均值 10.8% CPR

三、现金流引擎:一个循环讲完 30 年#

pass-through 的月度现金流只有三块:净票息利息、计划本金、提前偿付本金。计划本金用沉基金公式(剩余期数 rem 会随时间递减):

for i in range(TERM_M):                       # TERM_M = 360
    rem = TERM_M - i
    factor = wac_m / ((1.0 + wac_m) ** rem - 1.0)   # 当期计划本金占比
    sched_prin = min(bal * factor, bal)

    burn = max(0.0, 1.0 - bal / sched_bal)          # 燃尽程度
    cpr  = scurve_cpr(incentive, burnout=burn) * min(1.0, (i + 1) / SEASON_M)
    smm  = 1.0 - (1.0 - cpr) ** (1.0 / 12.0)        # 年化 CPR → 单月死亡率
    pp   = (bal - sched_prin) * smm                 # 提前偿付本金

    cf[i] = bal * NET_CPN / 12.0 + sched_prin + pp  # 投资人拿净票息
    bal  -= (sched_prin + pp)
python

sched_bal 是一条平行跑的「无提前偿付」轨道,专门用来度量燃尽。注意 SMM 作用在扣除计划本金之后的余额上——顺序搞反会系统性高估提前偿付。

正确性校验:因为贴现率取得与净票息相同(5.50%),而所有本金都按面值 100 收回,基准价格必须精确等于 100。脚本实际输出 100.0000,引擎没有漏钱也没有多算。

四、现金流被利率来回撕扯:3.47 年 vs 12.18 年#

同一个池子,在不同利率情景下的本金回收时间分布完全是两个东西:

情景首年平均 CPRWAL有效久期
-300bp10.76%3.47 年3.08 年
0bp2.41%9.20 年6.34 年
+300bp1.18%12.18 年7.19 年

WAL 被拉伸了 3.51 倍。你以为自己持有的是一个久期 6.34 年的资产,实际上它在 3.47 年和 12.18 年这两个完全不同的资产之间摇摆——而切换开关握在别人手里。

左图不同情景的年度本金回收分布:-300bp 本金在前 5 年集中回流,+300bp 则摊到 30 年;右图 WAL 从 3.47 年拉伸到 12.18 年(3.51 倍),左侧为收缩风险、右侧为展期风险

五、久期反转:你的对冲比率一直在错#

有效久期和有效凸性用中心差分算——关键是按揭利率和贴现率必须同步冲击,只动贴现率算出来的是错的:

def eff_dur_conv(shift_bp, h=25.0, **kw):
    p0 = price_pool(shift_bp,     **kw)
    pu = price_pool(shift_bp + h, **kw)     # 按揭利率与贴现率一起 +h
    pd = price_pool(shift_bp - h, **kw)
    dy = h / 10000.0
    return (pd - pu) / (2 * p0 * dy), (pd + pu - 2 * p0) / (p0 * dy * dy), p0
python

结果非常反直觉:MBS 的有效久期在 +125bp 处见顶 7.58 年,然后随着利率下行一路塌缩,到 -300bp 只剩 3.08 年(缩短 59.4%)。也就是说,利率跌得越多,你能赚钱的「杠杆」自动变得越小;利率涨得越多,你亏钱的杠杆自动变大。

局部有效凸性最深处是 -839.5(出现在 -50bp,即期权最贴价的位置),基准点 -313.2。有意思的是负凸性只在 [-75bp, +50bp] 这个窄带里成立(25 个格点里 6 个),因为深度实值/虚值时 S 曲线两端都趋平、期权 gamma 消失。

左图有效凸性:MBS 在 -75bp 至 +50bp 区间转负、谷底 -839.5,而 CPR≡0 安慰剂(最小 +143.8)与 CPR≡10% 对照(最小 +44.7)全区间为正;右图久期反转,峰值 7.58 年在 +125bp、-300bp 塌到 3.08 年

六、对冲残差:两个方向都亏,这就是空 gamma#

用国债做 DV01 中性对冲,比率算出来是 0.9977(几乎 1:1,因为久期和价格都匹配)。理论上如果两者凸性相同,任何平行移动都该完美对冲。实际残差:

情景-300bp-100bp+100bp+300bp
残差 P&L(每 100 面值)-11.57-3.02-0.88-2.78

24 个非零格点,残差全部为负。 这不是运气不好,这是空 gamma 的定义:无论利率往哪边走、走多远,你都在向对手方支付时间价值。绝对残差合计 86.12

还有一个更该被警惕的发现:用基准点凸性做二阶泰勒展开去预测残差,全区间 R² = -0.90(比直接用均值预测还差),只有在 ±100bp 以内 R² 才有 0.54。原因是 MBS 的凸性本身极度局部——反解出的「路径平均凸性」在 -100bp 是 -555.9,到 -300bp 却只有 -206.9,在 +300bp 更是只剩 -18.8。拿单点凸性去做大幅移动的风险预算,会系统性高估亏损、给你虚假的安全感。

左图 DV01 中性对冲残差在四个情景全为负(-300bp 亏 11.57、+300bp 亏 2.78);右图局部凸性谷底 -839.5 与路径平均凸性(-300bp 仅 -206.9)差距巨大,二阶泰勒全区间 R²=-0.90

七、三个安慰剂:负凸性 100% 来自提前偿付期权#

光看到负凸性不够,得证明它来自提前偿付的利率敏感性,而不是别的什么。

安慰剂 1:关掉提前偿付(CPR≡0)。 只剩纯计划摊销。有效凸性全区间为正,最小值 +143.8、基准 +192.2(久期 11.19 年、WAL 19.31 年)。负凸性精确消失

对照 2:恒定 CPR=10%(有提前偿付,但与利率无关)。 最小凸性 +44.7、基准 +57.7、久期缩到 5.55 年。回款确实变快了,但凸性依然全为正。这一条最关键:它排除了「因为回款快所以凸性负」这个错误归因——负凸性来自 CPR 对利率的导数,不是 CPR 的水平

敏感性 3:S 曲线陡度 k 扫描。 让借款人的「行权效率」从零变到极高:

k0.00.251.03.0(基准)8.0
最小有效凸性+25.6-32.9-245.6-839.5-2427.5
-300bp 上行捕获率66.1%56.4%48.2%45.5%44.7%

k=0(CPR 完全不随利率变)时凸性转正,单调、连续、无跳跃。负凸性的强度就是借款人行权效率的单调函数。

左图安慰剂对比:CPR≡0 与 CPR≡10% 的价格曲线重新「向上凸」;右图 k 从 0 扫到 8,最小凸性从 +25.6 单调塌到 -2427.5,-300bp 捕获率从 66.1% 降到 44.7%

检验 4:差分步长收敛性。 凸性会不会是数值噪声?h 从 5bp 扫到 100bp,凸性分别是 -298.1 / -300.0 / -313.2 / -355.6 / -343.6,极差仅 57.4恒为负。结论不靠调参。(但要注意久期本身对步长敏感得多:从 6.44 年掉到 5.28 年——这本身就是负凸性的另一个表现。)

检验 5:Burnout 开关。 关掉燃尽后基准凸性从 -313.2 恶化到 -415.7,-300bp 捕获率从 45.5% 掉到 34.0%。燃尽是负凸性的安全气囊:老池子没那么毒,新发行的当期票面池最危险。(一个诚实的反例:关掉燃尽后的最小凸性是 -808.2,反而比含燃尽的 -839.5 略浅——因为燃尽把期权 gamma 从贴价区推开了。看负凸性不能只看谷底,要看你实际持仓的那个点。)

左图步长收敛:h 从 5bp 到 100bp 凸性极差仅 57.4 且恒为负;右图关掉 burnout 后基准凸性从 -313.2 恶化到 -415.7

八、陷阱与局限(诚实版)#

1. 标题里的「不涨反跌」在本模型里没有字面发生。 -300bp 时 MBS 仍然是 +9.70%,只是相对久期匹配国债少赚一半多。真正出现绝对下跌,需要叠加 OAS 走阔(危机中 MBS 利差与利率往往同向恶化)或负凸性驱动的凸性对冲踩踏——本模型用的是固定静态利差,没有建模 OAS 动态,因此低估了真实世界的下行。

2. 平行移动是最温和的假设。 现实中曲线会陡峭化/平坦化,而提前偿付看的是长端按揭利率、贴现看的是整条曲线。单因子平行冲击既算不出关键利率久期,也算不出曲线形变带来的损益。

3. 确定性路径 ≠ OAS。 真正的 MBS 定价要在几百条蒙特卡洛利率路径上跑现金流再取均值,才能捕捉期权的路径依赖(尤其 burnout 依赖历史最低利率,而非当期利率)。本文的单路径静态贴现会低估期权价值、从而低估负凸性绝对值。

4. S 曲线参数是构造的,不是拟合的。 k=3.0x0=0.70CPR_MAX=0.55 都是我设的。好消息是敏感性扫描显示:结论的符号在 k>0.25 的整个区间稳健,只有量级依赖参数。

5. 没有建模违约、修改、政策干预。 大规模再融资项目、贷款服务商行为、信贷标准收紧都会让 S 曲线整体平移或变形。

九、实践 Checklist#

  1. 永远不要用票面久期(coupon duration)给 MBS 做对冲,用有效久期,且必须让按揭利率与贴现率同步冲击。
  2. 对冲比率要动态重算。本例久期从 7.58 年到 3.08 年跨度 59.4%,静态对冲在大幅移动中必然失效。
  3. 别用单点凸性做大幅位移的风险预算。二阶泰勒在 ±100bp 内 R² 只有 0.54,全区间是 -0.90;要压力测试就直接重定价,别外推。
  4. 区分「速度」与「敏感度」。CPR 高不等于负凸性;CPR 对利率的斜率才是。恒定 CPR=10% 的对照凸性是 +44.7
  5. 优先看池子的燃尽状态。深度折价/深度燃尽的老池子负凸性弱得多;当期票面(at-the-money)的新池子凸性谷底 -839.5,最危险。
  6. 在风险报告里同时列出局部凸性和路径平均凸性。-839.5 和 -206.9 讲的是完全不同的故事,只报一个都是误导。
  7. 把负凸性当成一个已卖出的期权仓位来管理,不是当成一个债券的二阶修正项——它的对冲成本(本例绝对残差合计 86.12/100 面值)应该被明确定价,而不是被摊进「跟踪误差」。
MBS 提前偿付与负凸性:为什么利率下行时你的债券不涨反跌
https://blog.halo26812.eu.org/blog/mbs-prepayment-negative-convexity
Author halo
Published at 2026年8月6日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨