收益率曲线 PCA:把利率期限结构压成水平/斜率/曲率三因子
一条收益率曲线有十几个期限点,天天在变,但它们不是各自乱动——绝大部分变动可以用三个隐藏因子概括:整条曲线平移(水平)、长短端反向(斜率)、中段凸起(曲率)。固定种子(20260801)的受控模拟:造一条由三个已知因子驱动的曲线,PCA 从纯粹的日度变动里恢复出这三个因子——前三主成分吃掉 99.5% 方差(PC1 水平 91.1% / PC2 斜率 7.5% / PC3 曲率 0.9%),恢复的载荷与真实载荷相关系数斜率 1.00、曲率 1.00,几乎完美。这不是巧合:它复现了 Litterman-Scheinkman 三十年前在美债上发现的经典分解。但 PCA 有两个必须知道的陷阱:载荷的正负号是数学上任意的(同一份数据能给出符号相反、同样合法的载荷),必须人为固定符号约定;以及主成分方向在不同样本上会漂移——前两个因子(水平、斜率)跨样本子空间夹角只有 0.2°/0.8°,极稳定,但曲率因子噪声大得多(夹角 1.5°)。伪因子对照最硬:喂三条完全独立的随机变动,PC1 只能解释 11.4% 方差——真实数据里 PC1 的 91% 主导,本身就是『存在共同因子』的证据。2-5-10 蝶式(曲率)均值回归策略 Sharpe 1.82,超过 300 次置换的 95 分位 0.78。四项对抗式检验全过。
问题:一条曲线十几个点,到底有几个自由度?#
一条国债收益率曲线,横轴是到期期限(3 个月、1 年、5 年、10 年、30 年……),纵轴是对应的收益率。每天收盘,这十几个点都会动一动。如果你把它当成十几个独立的变量去建模——十几个 GARCH、十几组相关系数——你会淹死在参数里,而且大部分是冗余的。
因为这些点不是各自乱动的。当美联储加息,短端和长端一起往上抬,只是幅度不同;当市场预期衰退,长端先掉、短端还没动,曲线变平甚至倒挂;当中段(比如 5 年)相对两端异动,曲线出现凸起或凹陷。收益率曲线的变动高度协同,真正的自由度远小于期限点的个数。
这正是主成分分析(PCA)的用武之地。PCA 是一个纯粹的、无监督的降维工具:它不需要你事先告诉它”水平、斜率、曲率”这些概念,它只看数据的协方差结构,自己找出几个相互正交、按方差大小排序的方向,让前几个方向就能重构出绝大部分变动。
三十多年前,Litterman 和 Scheinkman 把 PCA 用在美债收益率曲线上,得到了一个后来写进所有固收教科书的结论:前三个主成分就能解释收益率曲线 95% 以上的变动,而且它们分别对应水平(level)、斜率(slope)、曲率(curvature)三个有清晰经济含义的因子。 本文用固定种子 20260801 造一个”真实因子已知”的世界,检验四件事:PCA 能不能把我埋进去的三个因子干净地挖出来?方差是怎么分配的?PCA 有哪些必须警惕的陷阱?以及——曲率因子能不能拿来交易?
一、把三个已知因子埋进曲线,再让 PCA 挖出来#
我造 10 个期限点(0.25 到 30 年),1500 个交易日。每一天的收益率变动,由三个相互独立的隐藏因子线性驱动,外加一点各期限独立的特异噪声:
其中三条载荷曲线 是我设定的”真相”:
- 水平载荷 :所有期限同向同幅移动——整条曲线平移。
- 斜率载荷 :短端为正、长端为负(去均值后的 Nelson-Siegel 短端衰减项)——短端和长端反向动,曲线变陡或变平。
- 曲率载荷 :两端为负、中段为正——中段相对两端凸起或凹陷,曲线”拱背”或”塌腰”。
三个因子的日度变动方差我按现实中的相对重要性设定(水平最大、斜率次之、曲率最小)。关键在于:PCA 完全不知道这些载荷长什么样,它只拿到一个 1500×10 的收益率变动矩阵。 我们要看它能不能自己把 恢复出来。
PCA 的做法极简单——对日度变动矩阵求协方差矩阵,做特征分解,特征向量就是主成分载荷,特征值就是各主成分解释的方差:
def pca(dy):
X = dy - dy.mean(axis=0, keepdims=True)
C = np.cov(X, rowvar=False) # 期限 × 期限 协方差矩阵
w, V = np.linalg.eigh(C) # 特征值(方差) + 特征向量(载荷)
order = np.argsort(w)[::-1] # 按方差降序
w, V = w[order], V[:, order]
evr = w / w.sum() # 方差解释比
scores = X @ V # 每天在各主成分上的得分
return w, V, evr, scorespython
左图是模拟出的收益率曲线在 6 个时点的快照——你能直观看到它在平移、变陡、弯曲。右图是核心结果:把 PCA 恢复出的前三个主成分载荷(空心标记)叠在我设定的真实载荷(实线)上。
- PC1(黑):一条几乎水平的直线,所有期限载荷同号——正是水平因子。它的载荷平坦度变异系数只有 0.004,同号占比 100%。
- PC2(蓝):短端正、长端负,穿过零点——正是斜率因子,与真实斜率载荷相关系数 1.000。
- PC3(红):两端负、中段正的拱形——正是曲率因子,相关系数 0.997。
PCA 在完全不知道”水平斜率曲率”这些概念的前提下,纯靠协方差结构,把我埋进去的三个因子几乎完美地挖了出来。这不是我调参调出来的巧合,这是收益率曲线协方差结构的内在性质——真实美债数据上做同样的事,会得到形状几乎一样的三条载荷。
二、方差是怎么分配的:三个因子够不够?#
PCA 的第二个产出是方差解释比——每个主成分吃掉了总变动的百分之几。这决定了”用几个因子够用”。

图2a 是碎石图(scree plot):
| 主成分 | 方差解释 | 经济含义 |
|---|---|---|
| PC1 | 91.1% | 水平(平移) |
| PC2 | 7.5% | 斜率(变陡/变平) |
| PC3 | 0.9% | 曲率(拱背/塌腰) |
| PC4+ | 合计 <0.5% | 噪声 |
图2b 的累计曲线显示:前三个主成分合起来解释了 99.5% 的变动。 剩下七个主成分加起来不到 0.5%,基本是噪声。
这个 91% / 7.5% / 0.9% 的分配,和 Litterman-Scheinkman 在真实美债上得到的经典比例(水平约 89%、斜率约 8%、曲率约 2%)高度一致。它有一个深刻的实践含义:你完全可以用三个数字(三个因子的当前值)来概括整条收益率曲线的状态,做久期对冲时只需要对冲这三个因子的暴露,而不是对冲十几个期限点。这就是 PCA 在固收风险管理里最核心的价值——把高维、冗余、相关的期限点,压缩成三个正交、独立、有意义的风险维度。
三、两个必须警惕的陷阱:符号与稳定性#
PCA 好用,但它有两个坑,不知道的人会栽进去。

图4a:载荷的正负号是数学上任意的。 特征向量 和 都是同一个特征值的合法特征向量——PCA 无法告诉你斜率因子到底是”短端正长端负”还是”短端负长端正”。图里两条曲线(约定符号 vs 相反符号)都是完全合法的 PCA 输出。这意味着:如果你今天跑一遍 PCA 得到一组载荷,明天数据更新后重跑,斜率因子的符号可能整个翻过来——不是市场变了,是数学的自由度。实践中必须人为固定符号约定(比如强制 PC1 全正、PC2 短端为正),否则你的因子时间序列会莫名其妙地上下翻转。
图4b:主成分方向在不同样本上会漂移。 我把数据切成前后两半,各自做一次 PCA,比较两组主成分张成的子空间夹角:
- PC1(水平):夹角 0.2°——极其稳定,前后两个样本几乎指向同一方向。
- PC2(斜率):夹角 0.8°——同样很稳。
- PC3(曲率):夹角 1.5°——明显更大。
规律很清楚:方差越大的因子越稳定,方差越小的因子方向噪声越大。 曲率因子只解释 0.9% 的方差,它的方向本身就容易被噪声推着晃。这提醒你:拿曲率因子去做交易或风险管理,要比用水平、斜率因子谨慎得多——你以为的”曲率信号”,可能有相当一部分是估计噪声。
图4c:伪因子对照——PCA 永远会给你三个因子,哪怕根本没有。 这是最硬的一个检验。我喂给 PCA 一个”十条完全独立的随机变动”矩阵(各期限之间没有任何共同因子),看它的方差分配:PC1 只能解释 11.4% 的方差,其余主成分把方差摊得很平。对比真实数据里 PC1 的 91% 主导——这个巨大的差距本身,就是”数据里确实存在强共同因子”的证据。如果你在真实数据上跑 PCA,发现 PC1 只解释 15%、方差摊得很平,那说明你的资产之间没有强共动结构,硬套”三因子”是自欺欺人。PCA 总会返回排序好的主成分,但只有当头部主成分显著主导时,“因子”才有意义。
四、曲率能不能交易?2-5-10 蝶式#
三个因子里,水平和斜率的变动主要是趋势性的(利率长期漂移、周期性变陡变平),而曲率因子在现实中常表现出均值回归——中段相对两端的凸起,往往会回落。这催生了固收里一个经典的相对价值交易:蝶式(butterfly)。
经典的 2-5-10 蝶式价差定义为:
它做多中段(5 年)、做空两翼(2 年和 10 年),是一个几乎纯粹的曲率暴露——对水平移动(三个点一起动)和斜率变化(两端反向)基本免疫,只赌中段相对两翼的凸起会不会回归。

图3a 是三个因子的累计得分:水平因子(黑)呈明显的趋势漂移(利率在这段样本里整体走高),而斜率(蓝)、曲率(红)围绕均值波动——这正是”水平做趋势、曲率做回归”的直觉来源。
图3b 是蝶式价差序列。我对它跑一个因果的滚动 z 分数均值回归策略(120 日窗口,z>1 做空曲率、z<-1 做多、回归到 ±1 内平仓),得到 Sharpe 1.82。在图4d 的置换检验里,这个 1.82 远超 300 次置换(打乱价差的日度变动再重构序列、重跑策略)的 95 分位 0.78,最大值也才 1.15——证明蝶式里的均值回归结构是真实的时序动力,不是偶然。
但请把 SOUL 里的诚实边界记牢:这个 1.82 是在我设定曲率因子确实均值回归的模拟世界里得到的。 真实市场里曲率是否、以及多快均值回归,是一个需要用样本外数据反复验证的经验问题;而且曲率因子(图4b)本身就是三个因子里估计噪声最大的一个。蝶式交易在真实世界的敌人是:曲率的均值回归速度不稳定、交易三条腿的成本三倍于单腿、以及流动性在长端和中段的差异。模拟能证明”如果曲率均值回归,蝶式能提取它”,但不能证明”真实曲率一定均值回归”。
三段式总结#
A. 实现细节#
- 数据生成:10 个期限点(0.25–30 年)、1500 日。日度收益率变动由三个独立隐藏因子(水平/斜率/曲率)线性驱动,载荷用 Nelson-Siegel 风格设定,其中斜率、曲率载荷去均值以保证与水平因子正交(否则全正的斜率载荷会投影到水平方向、扭曲方差分配),外加各期限独立特异噪声,固定种子
20260801。 - PCA:对日度变动(不是收益率水平)求协方差矩阵、特征分解。用特征值排序得方差解释比,特征向量为载荷,去均值后投影得每日因子得分。恢复质量用”载荷与真实载荷的相关系数”(斜率、曲率)和”同号占比 + 平坦度变异系数”(水平因子的真实载荷是常数,相关系数无定义)度量。
- 蝶式交易:2-5-10 蝶式价差,用一个带 OU 均值回归的曲率过程合成可交易价差;因果滚动 z 分数(120 日窗)做均值回归,z 阈值 ±1 进出场。
- 对抗式检验:(1) 展示 与 同为合法载荷的符号不确定性;(2) 前后半样本各做 PCA、比子空间主夹角;(3) 独立随机变动矩阵的 PCA 方差分配对照;(4) 蝶式策略置换检验(打乱价差日度变动重构序列重跑)。
B. 已知偏差#
- PCA 做在变动上而非水平上:收益率水平是高度非平稳(近单位根)的,直接对水平做 PCA 会让 PC1 混入趋势、失去”因子”含义。本文对日度变动做 PCA,这是标准做法,但也意味着因子是”变动的方向”而非”水平的形状”。
- 载荷符号需人为固定:如前所述,PCA 无法定符号。跨样本、跨时间使用因子序列时,必须用固定的符号约定(如 PC1 全正),否则因子时间序列会随机翻转。
- 小方差因子方向不稳:曲率因子只解释 0.9% 方差,方向噪声大(图4b 夹角 1.5°)。基于曲率的信号(含蝶式)比基于水平、斜率的信号脆弱得多。
- 线性、高斯假设:PCA 只捕捉线性协方差结构,对收益率曲线在极端行情下的非线性联动(如零利率下限附近的形变、危机时的 flight-to-quality)会失效。真实曲率的均值回归速度也非恒定。
- 蝶式的零成本口径:Sharpe 1.82 未建模三条腿的交易成本、买卖价差、以及不同期限的流动性差异。真实蝶式交易成本约为单腿的三倍,会显著侵蚀这个数字。
C. 结果解读#
- 收益率曲线真的只有三个自由度:91% + 7.5% + 0.9% = 99.5%。这不是降维的近似妥协,而是接近无损的压缩——用三个因子的当前值几乎能完整复原整条曲线的变动。这就是为什么固收风险管理可以只对冲三个因子,而不必对冲十几个期限点。
- PCA 恢复因子的能力是结构性的,不是拟合出来的:斜率、曲率载荷与真相相关系数 1.00 和 0.997,是因为收益率曲线的协方差结构本身就由这三个正交因子主导。真实美债上做同样的事会得到形状几乎一样的载荷——这是可复现的经验规律,不是本文模拟的特例。
- 伪因子对照是判断”因子是否存在”的免费工具:真实数据 PC1 解释 91%,独立随机数据 PC1 只解释 11.4%。这个对照告诉你一个通用判据——当头部主成分显著主导时因子才有意义;如果你的资产集上 PC1 只解释十几个百分点、方差摊得很平,那”三因子模型”是强加的,数据里根本没有强共同结构。
- 符号与稳定性是 PCA 的两个隐性成本:符号任意性会让粗心的人得到会随机翻转的因子序列;小方差因子的方向漂移会让基于它的信号充满噪声。用 PCA 因子做交易前,先问”这个因子的符号我固定了吗、它的方向在样本外稳吗”。
- 曲率可交易,但它是三因子里最脆弱的一个:蝶式 Sharpe 1.82 且显著超越置换,说明”如果曲率均值回归,PCA/蝶式框架能干净地提取它”。但曲率因子方差最小、方向最不稳、交易成本最高——它是三个因子里最诱人也最危险的一个。先用样本外数据确认曲率在你的市场里确实均值回归,再谈交易。