久期中性国债期货套利:跨期限曲线交易实战
曲线交易的第一课不是「怎么选方向」,而是「你以为你在赌利差,其实你在赌利率水平」。六年模拟曲线实测:收益率日变动的第一主成分(水平)独占 95.3% 方差、斜率只剩 2.0%——等张数 1:1 的 2s10s 组合,盈亏有 74.8% 被水平因子解释、水平 beta 高达 454 元/bp,它根本不是曲线交易,是伪装成价差的裸多头。换成 DV01 中性(2.18 张两年对一张十年)后水平 R² 降到 0.0000、与利差变动相关性 0.999,这才叫「只赌斜率」。全文最反直觉的对照:等张数版本 Sharpe 0.42 反而高于 DV01 中性的 0.24——因为它偷偷加载了 beta,用『赌错了方向』换来的收益不该记在曲线交易账上。三个必须写进风控的坑:DV01 比例自己在漂移 16.3%(CTD 切换/久期衰减)、误设 20% 就把水平 R² 从 0.00 拉回 0.25、单边成本 0.53bp 就吃光全部 alpha(毛 Sharpe 1.01 → 0.24,成本占毛利 75.8%)。真正的收益来源是 carry+roll 而不是价差波动:陡峭化组合净 carry+roll 为 -5.8bp/季度,你在逆风持仓(中阶)
做曲线交易的人最容易犯的错,不是方向判断错,而是根本没在交易曲线。
你说”我看多陡峭化,所以买两年、卖十年”,仓位一挂上去,账户每天的波动跟着 2s10s 利差走吗?我用六年模拟曲线做了实测:如果按最朴素的等张数 1:1 建仓,这个所谓的”价差组合”每日盈亏有 74.8% 被利率水平因子解释,与利差变动的相关性只有 0.46。它不是曲线交易,是一个伪装成价差的、方向不明的裸头寸。
结论先放这:曲线交易的核心工程量不在信号,在对冲比例。 把两条腿的 DV01 配平(本文实测 2.18 张两年合约对一张十年合约)之后,组合盈亏被水平因子解释的比例降到 0.0000、与利差变动的相关性升到 0.9991——这才叫”我只赌斜率”。所有数字均由下文 Python 真实计算,非占位图。

一、为什么必须做久期中性:95.3% 的方差不是你想赌的东西#
收益率曲线的日变动,几十年来的实证结论高度一致:能用三个主成分解释绝大部分——水平(level)、斜率(slope)、曲度(curvature)。我用 Nelson-Siegel 载荷合成了一条含 6 个关键期限(3M/1Y/2Y/5Y/10Y/30Y)的曲线,其中水平因子设为近乎随机游走(不可预测的那一维),斜率因子设为显著均值回复(策略要吃的那一维)。
对日变动矩阵做 PCA,结果毫不含糊:

| 主成分 | 方差解释 | 载荷形态 | 交易含义 |
|---|---|---|---|
| PC1 水平 | 95.3% | 全期限同号(0.401→0.417) | 整条曲线齐涨齐跌,方向性风险 |
| PC2 斜率 | 2.0% | 短端 -0.418 / 长端 +0.754 | 陡峭化/平坦化,曲线交易的标的 |
| PC3 曲度 | 0.9% | 两端同号、腰部反号 | 蝶式交易的标的 |
这张表就是全文的地基。你想赌的斜率只占 2.0% 的方差,而你稍不注意就会扛上 95.3% 的水平风险。 信噪比是 1:48。任何对冲上的疏忽,都不是”精度损失”,而是”标的物被换掉”。
二、DV01:把「张数」翻译成「风险」#
期货合约的张数是会计单位,不是风险单位。真正的风险单位是 DV01(收益率变动 1 个基点带来的价格变动金额)。
def bond_price(y, T, cpn, freq=2, face=100.0):
"""半年付息债券的现值"""
n = int(round(T * freq))
c = face * cpn / freq
t = np.arange(1, n + 1) / freq
df = (1 + y / freq) ** (-freq * t)
return float(c * df.sum() + face * df[-1])
def dv01(y, T, cpn, freq=2, face=100.0, bp=1e-4):
"""中心差分法:更稳,避免解析久期在高凸性时的偏差"""
return (bond_price(y - bp / 2, T, cpn, freq, face)
- bond_price(y + bp / 2, T, cpn, freq, face))python按中金所口径,2 年期国债期货(TS)合约面额 200 万元,10 年期(T)为 100 万元。换算成每张合约的 DV01:
CTR_SIZE = {"TS": 2_000_000.0, "T": 1_000_000.0}
DV2_C = dv2 / 100.0 * CTR_SIZE["TS"] # 元/bp
DV10_C = dv10 / 100.0 * CTR_SIZE["T"]
hedge_ratio = DV10_C / DV2_C # 每卖一张 T,要买几张 TSpython实测结果:
- 2 年腿修正久期 1.94,每张 DV01 = 384.8 元/bp
- 10 年腿修正久期 8.71,每张 DV01 = 838.3 元/bp
- 对冲比例 = 2.18(每一张 10 年合约对应 2.18 张 2 年合约)
注意这个数字不是 8.71/1.94 = 4.49。合约面额的差异(200 万 vs 100 万)刚好抵消掉一半久期差。混淆”久期比”和”合约 DV01 比”是这个领域最高频的低级错误,一步错就是 2 倍的敞口偏差。
三、三种对冲口径的对照实验#
固定信号不变,只换对冲比例,看组合到底在暴露什么。定义陡峭化仓位为:买 h 张 2 年 + 卖 1 张 10 年。
def leg_pnl(h):
return h * pnl2_ctr - 1.0 * pnl10_ctr
h_naive = 1.0 # 等张数
h_dv01 = DV10_C / DV2_C # DV01 中性 ≈ 2.18
h_beta = h_dv01 / b_yield # 收益率 beta 调整python第三种口径需要解释一下。DV01 中性隐含了一个假设:长短端收益率等幅移动(Δy₂ = Δy₁₀)。现实中不成立——短端受政策利率锚定,波动通常小于长端。对 Δy₂ 回归 Δy₁₀ 得到 b = 0.9244,意思是长端动 1bp,短端只跟 0.92bp。要真正把水平风险清零,2 年腿还得再放大 1/0.9244 倍。

| 对冲口径 | 水平 beta(元/bp) | 水平 R² | 与利差变动相关性 | 日盈亏标准差 |
|---|---|---|---|---|
| 等张数 1:1 | 454.0 | 0.7484 | 0.4635 | 2,274.6 元 |
| DV01 中性 (2.18) | -0.01 | 0.0000 | 0.9991 | 1,210.3 元 |
| beta 调整 (÷0.92) | -68.7 | 0.0548 | 0.9597 | 1,273.8 元 |
三个读点:
- 等张数是灾难。 74.8% 的盈亏来自水平因子,与它名义上要交易的利差只有 0.46 相关。日波动 2,275 元里,绝大部分是你没打算承担的风险。
- DV01 中性近乎完美。 R² = 0.0000,与利差变动相关 0.9991。这就是”纯斜率暴露”的样子。
- beta 调整在本样本里过度对冲了。 水平 R² 反而从 0.0000 升到 0.0548。原因是我的模拟里 NS 斜率载荷本身已经隐含了长短端的差异化响应,再叠一层 beta 就矫枉过正。这是一个真实的教训:beta 调整是经验修正,不是理论必然,必须在你自己的数据上验证它是否真的降低了残余暴露,而不是照抄论文。
四、策略回测:均值回复信号 + 三种对冲#
信号很简单,120 日回看的利差 z-score,|z|>1 入场、|z|<0.25 出场,T 日出信号、T+1 日执行:
Z = zscore(spread_2s10s, lookback=120)
for t in range(LB, N):
z, prev = Z[t], pos[t-1]
if prev == 0:
pos[t] = 1.0 if z < -1.0 else (-1.0 if z > 1.0 else 0.0)
elif prev > 0:
pos[t] = 0.0 if z > -0.25 else prev # 陡峭化仓位,等利差回归
else:
pos[t] = 0.0 if z < 0.25 else prevpython交易成本按 单边 0.4bp × 组合 DV01 计(买卖价差 + 冲击,对国债期货是偏保守的估计)。

| 组合 | 总收益 | 年化 | 年化波动 | Sharpe | 最大回撤 | 交易次数 | 在场时间 |
|---|---|---|---|---|---|---|---|
| DV01 中性 | +2.30% | 0.38% | 1.57% | 0.24 | -0.98% | 106 | 64.3% |
| 等张数 1:1 | +7.35% | 1.22% | 2.91% | 0.42 | -3.63% | 106 | 64.3% |
| beta 调整 | +1.54% | 0.26% | 1.64% | 0.16 | -1.35% | 106 | 64.3% |
| 固定对冲比例(不更新) | +2.10% | 0.35% | 1.61% | 0.22 | -1.30% | 106 | 64.3% |
| 裸多 10 年(对照) | -1.87% | -0.31% | 6.08% | -0.05 | -17.37% | — | 100% |
这里有个必须解释清楚的反直觉结果:等张数版本 Sharpe 0.42,高于 DV01 中性的 0.24。
不解释就交付,等于承认自己不懂在做什么。原因是:等张数组合有 454 元/bp 的水平 beta,而这六年的模拟水平因子恰好走出了对该敞口有利的路径。它多赚的钱来自”赌利率方向赌对了”,不是来自曲线交易。 三个证据:
- 它的日波动是 DV01 中性的 1.88 倍(2,275 vs 1,210),最大回撤是 3.7 倍(-3.63% vs -0.98%)
- 它与利差变动的相关性只有 0.46 —— 大部分盈亏跟信号想捕捉的东西无关
- 换一个随机种子,这个”优势”完全可以变成同等量级的劣势
风险调整后看起来更好的策略,如果暴露的根本不是你声称的风险,那它只是杠杆的幻觉。 这也是为什么做曲线交易必须先看归因表、再看净值表——净值表会撒谎,归因表不会。
五、对冲比例误设:容错区间有多窄#
实盘里对冲比例不可能永远精确。扫描 0.6× ~ 1.4× 的误设幅度:

| 实际比例 / 中性比例 | 水平 R² | 策略 Sharpe |
|---|---|---|
| 80% | 0.2810 | 0.39 |
| 90% | — | 0.33 |
| 100% | 0.0000 | 0.24 |
| 120% | 0.2452 | 0.04 |
关键结论:水平 R² 是一个 V 形陷阱,底部极窄。 只要偏离 20%,你就重新捡回 24%~28% 的水平暴露——四分之一的盈亏又变成了赌方向。
而 Sharpe 那一列的形状值得警惕:它在 80% 处反而更高(0.39 > 0.24)。这不是”欠对冲更好”的证据,而是第四节那个现象的延续——欠对冲重新引入了水平 beta,在这段样本里恰好有利。用 Sharpe 来调对冲比例,等于用运气来校准风控参数。正确的目标函数是残余 R²,不是收益指标。
六、真正的收益来源:carry 与 roll-down#
曲线交易的钱,很大一部分不来自价差波动,来自持有本身。分解成两块:
- Carry = 票息收益 − 融资成本
- Roll-down = 曲线形状不变时,剩余期限缩短带来的收益率下滑 × 久期

| 腿 | Carry(bp/季) | Roll-down(bp/季) | 合计 |
|---|---|---|---|
| 2 年 | -5.3 | +1.6 | -3.7 |
| 10 年 | -3.3 | +5.4 | +2.1 |
陡峭化组合(多 2 年 / 空 10 年)的净 carry+roll = -5.8bp/季度。
这是个重要的负面结论:在正斜率曲线上做陡峭化,你是在逆风持仓。 10 年腿的 roll-down 收益(+5.4bp)显著高于 2 年腿(+1.6bp),因为曲线在长端更陡、下滑空间更大——而你正在做空这条腿。每持有一个季度,就要先亏掉 5.8bp 的”时间成本”,价差回归必须跑赢这个门槛才有意义。
反过来说,平坦化仓位(空 2 年 / 多 10 年)是顺风的,每季度白拿 5.8bp。这解释了为什么真实市场里的曲线交易者对做多陡峭化格外挑剔——它需要更强的信号才划算,而做平坦化只要不亏钱就在赚 carry。
七、成本:0.53bp 就吃光全部 alpha#
前面所有讨论在成本面前都是次要的。

| 单边成本(bp × 组合 DV01) | Sharpe |
|---|---|
| 0.0(毛) | 1.01 |
| 0.2 | 0.63 |
| 0.4(基准假设) | 0.24 |
| 0.53(盈亏平衡点) | 0.00 |
| 0.8 | -0.50 |
数字很残酷:毛 Sharpe 1.01 是个像样的策略,扣掉 0.4bp 成本只剩 0.24,成本吃掉毛利的 75.8%(72,035 元成本 / 95,031 元毛利)。盈亏平衡成本仅 0.53bp。
原因不难理解:这个策略赚的是 20bp 级别的利差波动,而每次进出要付两条腿的买卖价差。分子是 bp 量级,分母也是 bp 量级,成本不是”摩擦”,是同一数量级的对手。
直接的应对是提高入场门槛,用交易频次换单笔质量:
| 入场 z 阈值 | Sharpe | 交易次数 | 在场时间 |
|---|---|---|---|
| 0.50 | -0.01 | 210 | 76.8% |
| 1.00 | 0.24 | 106 | 64.3% |
| 1.50 | 0.36 | 62 | 54.5% |
| 2.00 | 0.49 | 46 | 46.6% |
| 2.50 | 0.48 | 28 | 32.8% |
Sharpe 在 z=2.0 附近见顶(0.49)后走平。这不是”参数优化找到最优值”,而是成本结构逼出来的必然形状——低阈值区间的信号,期望收益压根覆盖不了往返成本。任何高频版本的曲线套利,在零售级成本下都是负期望。
八、被忽视的工程细节:对冲比例自己在动#
最后一个坑。上面那张图的右半边显示,DV01 对冲比例在六年里从 2.011 漂到 2.365,摆幅 16.3%。
来源有两个:
- 久期衰减:合约到期日临近,CTD 券剩余期限缩短,DV01 下降
- 收益率水平变化:DV01 本身是收益率的函数(凸性效应)
真实市场还有第三个、也是最凶的一个:CTD 券切换。收益率穿越 3% 转换因子临界点时,最便宜可交割券会跳变,DV01 可能一夜之间跳 5%~10%。本文的模拟没有建模这个机制,是明确的简化。
实测”期初算一次、之后不再更新”的固定比例版本:水平 beta -27.25、R² 0.0092、Sharpe 0.22。比逐日更新(R² 0.0000)差,但没有想象中那么灾难。原因是 16.3% 的漂移低于第五节测出的 20% 危险阈值。结论是:周频再校准足够,日频再校准的边际收益被交易成本吃掉;但”建仓时算一次然后忘记”在 CTD 切换时会翻车。
三盆冷水#
第一,模拟曲线的均值回复是我设定的,真实市场不欠你这个。 本文的斜率因子用 OU 过程生成、κ=0.011 明确均值回复,策略当然能赚钱。真实的 2s10s 在趋势性货币政策周期里可以单边走一两年——2021-2023 年美债曲线从 +130bp 一路倒挂到 -100bp,任何 z-score 均值回复策略在这段里都是持续加仓、持续亏损。曲线交易的最大风险不是对冲失效,是”均值”本身漂移了。
第二,DV01 中性只中性掉了水平因子,没管曲度。 本文的 PC3 曲度占 0.9% 方差,看着可以忽略,但 2s10s 组合对曲度的暴露并不为零——蝶式行情(腰部相对两端异动)会同时冲击两条腿,且不被斜率信号预警。要真正做到”只赌斜率”,需要三腿组合(2s5s10s 蝶式)做 PC1+PC3 双中性,代价是多一条腿的成本,在 0.53bp 的盈亏平衡线面前基本判死刑。
第三,本文完全没建模保证金与展期。 国债期货是保证金交易,两条腿各占保证金,反向波动时可能触发追保——而追保发生的时点恰恰是价差走扩、你最不该减仓的时候。此外季月合约到期需要展期,每次展期要付一次往返成本,且新旧合约的 CTD 可能不同、DV01 直接跳变。加上这两项,第七节那个 0.53bp 的盈亏平衡线只会更紧。
落地清单#
如果你要真的做这件事,按这个顺序检查:
- 先算残余 R²,再看收益。 组合日盈亏对水平因子回归,R² > 0.05 就说明对冲有问题,收益数字不用看了
- 对冲比例用合约 DV01 比,不是久期比。 记住面额差异会抵消一部分久期差
- beta 调整必须在自己的数据上验证。 它可能降低残余暴露,也可能像本文一样过度对冲
- 成本先算盈亏平衡点,再定阈值。 本文 0.53bp 的门槛意味着任何日频以上的版本都不要碰
- 算清 carry+roll 的方向。 陡峭化在正斜率曲线上是逆风持仓,需要更强信号
- 对冲比例至少周频再校准,CTD 切换窗口特别盯。
曲线交易在教科书里是”低风险套利”,在实盘里是”用极窄的容错区间,去捞一个被成本啃掉四分之三的小 alpha”。它值得做,但前提是你知道自己在跟什么较劲。