利率互换(Interest Rate Swap, IRS)是整条利率衍生品食物链的底端:几乎所有利率期权、结构性票据、资产端负债端对冲,最后都还原成一组 IRS 的现金流。它交易的就是「固定利率」本身——一端付固定、一端收浮动(或反过来)。一家银行吸收浮动利率存款、放出固定利率贷款,就用一笔收固定、付浮动的 IRS 把错配的利率风险锁死;一家企业发了一笔固定利率债券、但现金流跟着短期利率走,就用相反方向的 IRS 把成本改造成浮动。IRS 每天在场内的名义本金以万亿美元计,但它的定价逻辑却异常干净:它不预测未来利率,只把当下的期限结构用现金流重新打包。这也是为什么初学利率衍生品,必须先吃透 IRS——它是后面所有复杂结构的「原子」。
结论先放这:IRS 的定价不需要「预测利率」,只需要一条自洽的折现曲线。 用市场上的存款 + 掉期报价把折现因子 逐个 pillar 地 bootstrap 出来,然后把固定端当成一只付息债券、浮动端用 FRA 链式相消直接折现,二者现值之差就是 IRS 的净现值。而市场报给你的掉期利率 ,本质上就是让这条曲线自洽的平价利率。本文从 bootstrap 讲起,附完整 Python,最后诚实拆穿四个常被忽略的真实陷阱。

一、Bootstrap:从存款到掉期,把折现因子一棵一棵种出来#
输入是两类报价:
- 存款(短期):0–6 个月,直接给年化利率,折现因子 ;
- 掉期(中长期):1y/2y/…/10y,给平价互换利率 (年付息,固定端付 )。
掉期的难点是:它的现金流横跨多个支付日,靠后的支付日折现因子还没算出来。做法是从左往右、逐 pillar 解:对于 年期平价互换,已知前 个支付日的折现因子,把未知的最远那一个 当成未知数,用「互换现值 = 0」解出来。
设年付息 、支付日 、平价固定端 ,则固定端现值(收固定方)为 ,浮动端现值为 。平价条件:
注意右侧的「1」是浮动端在重置日 的本金现值(=1)。整理出最远折现因子:
每解出一个 ,下一个更长期限的互换就能复用它。一棵一棵种,曲线就长出来了。
import numpy as np
# 存款: (期限年, 年化利率)
deposits = [(0.25, 0.0250), (0.50, 0.0265)]
# 原始掉期报价(缺失的 6/8/9 年用线性插值补齐, 使所有年付息支付日都在已知节点)
raw_swaps = {1: 0.0280, 2: 0.0305, 3: 0.0325, 4: 0.0340,
5: 0.0352, 7: 0.0365, 10: 0.0378}
ry = sorted(raw_swaps)
def interp_rate(y):
lo, hi = max([t for t in ry if t <= y]), min([t for t in ry if t >= y])
return raw_swaps[lo] if lo == hi else raw_swaps[lo]*(1-(y-lo)/(hi-lo)) + raw_swaps[hi]*((y-lo)/(hi-lo))
times, dfs, tmap = [], [], {}
for T_, r in deposits:
P = 1.0 / (1.0 + r * T_); times.append(T_); dfs.append(P); tmap[T_] = P
def get_df(t):
if t in tmap: return tmap[t]
ts, ls = np.array(times), np.log(dfs) # 零息(log-DF)线性插值
return float(np.exp(np.interp(t, ts, ls, left=ls[0], right=ls[-1])))
for y in range(1, 11): # 连续 1..10y 支柱
s, tau = interp_rate(y), 1.0
pay = np.arange(tau, y + 1e-9, tau)
sum_known = sum(tau * get_df(t) for t in pay[:-1])
Pn = (1 - s * sum_known) / (s * tau + 1.0)
times.append(y); dfs.append(Pn); tmap[y] = Pn
zc = -np.log(dfs) / np.array(times) # 连续零息利率python跑完你会发现一件漂亮的自洽事实:用这条 bootstrap 出来的曲线去给每个期限的互换重新定价,算出的互换利率精确等于市场原始报价(1y=2.80%、5y=3.52%、10y=3.78%)。因为曲线本来就是被这些报价反推出来的——这正是 bootstrap 的「自检密码」。
二、IRS 双边现值:固定端 vs 浮动端#
取一支 5y IRS(年付息),固定端现金流是一串 ,浮动端是每期重置的 FRA。用上面那条曲线:
- 固定端现值(收固定方) = ;
- 浮动端现值(收浮动方) = (链式相消:每期浮动现金流折现后首尾抵消,只剩本金两端的差)。
pay = np.arange(1, 5 + 1e-9, 1)
Pv = np.array([get_df(t) for t in pay]) # 5 个支付日 DF
annuity = Pv.sum() # Στ·P (τ=1)
pv_float = 1 - Pv[-1] # 浮动端现值 = 1 - P(T_5)
print("年金 Στ·P =", round(annuity, 5)) # 4.53723
print("浮动端现值 =", round(pv_float * 100, 4), "%") # 15.97%
# 在 K=s=3.52%: 固定端现值 = 0.0352 * 4.53723 = 15.97% == 浮动端现值python用 代入,固定端现值 = ,与浮动端现值 15.97% 完全相等——这就是「平价」互换的定义:两端现值相等,净现值为零。

三、互换利率 = 浮动端现值 / 固定端年金#
把上面的等式反过来写,就能直接由折现曲线吐出互换利率,不需要任何市场报价:
这给了你一个极有用的视角:互换利率就是折现曲线的「另类表达」。曲线上任意一段的期限结构,都能等价写成互换利率期限结构。
def swap_rate(T_, freq=1):
tau = 1.0 / freq
pay = np.arange(tau, T_ + 1e-9, tau)
Pv = np.array([get_df(t) for t in pay])
annuity = tau * Pv.sum()
pv_float = 1 - Pv[-1]
return pv_float / annuity
for T_ in [1, 2, 3, 4, 5, 7, 10]:
print(f"{T_}y 互换利率 =", round(swap_rate(T_) * 100, 3), "%")
# 2.80 / 3.05 / 3.25 / 3.40 / 3.52 / 3.65 / 3.78python
这套算出来的互换利率曲线,正是现实中交易员口中的「掉期曲线」——它是所有利率产品定价的分母(折现基准)。
四、现金流时间轴与贴现的直觉#
把 5y IRS 的现金流摊开看:固定端每年付 ,浮动端每年收一个 FRA 现金流(重置日利率 − 前期固定),全用 折现。固定端那串折现因子本身构成一条递减曲线,加权和就是年金因子 4.537。

为什么浮动端能「链式相消」成 ?因为浮动利率每期都被设定成令当期现金流现值恰好等于上一期本金剩余——数学上每期折现后只剩边界项。这是 IRS 最优雅的性质:浮动端现值只取决于两端折现因子,与中间路径无关。
五、四类真实陷阱(中阶必须知道)#
- 折现代价:单曲线 vs 双曲线:上面是「单曲线」世界(固定端、浮动端用同一条折现曲线)。2008 后业界改用OIS 折现 + Libor 投影的双曲线框架——因为危机时 Libor 与无风险利率脱钩,用错曲线会系统性偏价。如今 Libor 退场、SOFR 上位,投影曲线本身也要换成 SOFR,旧代码里写死的
Libor折现会直接作废。 - 天数计算(Day Count)与付息频率:存款用 ACT/360、债券用 30/360 或 ACT/ACT,半年付息和季付息的 不同。本文用年付息 + 是教学简化;真实 bootstrap 里 DCF 错位会让最短几个 pillar 的 DF 差几个基点,累积到长端会被放大。
- 插值方式决定曲线形状:pillar 之间怎么插值(对数线性 / 线性零息 / 样条)直接决定中间期限互换利率。本文对缺失年份用线性插值,但若你用三次样条,6y/8y/9y 的利率会和内插结果不同,进而影响以其为输入的期权(如 swaption)定价。
- Calendar / 营业日惯例与复利:支付日落在周末/节假日要顺延(Modified Following),计息区间要按实际日历数。跨年时少算一天会让年化的互换利率偏 1–2 bps——对 10y 大名义本金的 IRS,这就是真金白银的偏差。
六、IRS 怎么被「反过来用」:做市与曲线构建闭环#
IRS 最反直觉的一点是:它既是被定价的对象,又是用来给别的东西定价的工具。我们前面用掉期报价去 bootstrap 折现曲线;而这条曲线一旦建好,又反过来给每一笔新的 IRS、还有利率期权、结构性产品定价。这是一个自我喂养的闭环——市场每天用新成交的 IRS 刷新曲线,曲线又决定下一笔 IRS 的公允价值。
对做市商而言,这个闭环意味着「报价」和「对冲」是一回事:你报出一个 IRS 价格,等价于你愿意在曲线上锁定对应现金流;你的库存风险(DV01,即利率每动 1bp 时组合价值变动)可以通过再交易临近期限的 IRS 来对冲。所以做市商不是在「赌方向」,而是在管理曲线风险——他们赚的是买卖价差和库存周转,而不是利率涨跌的赌注。
这也是为什么文章开头说 IRS 交易的是「固定利率本身」:当你做一笔 IRS,你本质上是在把一条期限结构的某一段,从浮动形态重构成固定形态(或反过来)。固定端利率 、浮动端、折现曲线,三者中只有两个是自由的——给定任意两个,第三个就被无套利钉死。本文给你的是「给定曲线和固定端,求现值」;现实中更常发生的是「给定曲线,求让现值为零的 」,而那个 又成了别人曲线里的输入。利率市场的魅力,就藏在这个互相递归的系统里。
小结#
IRS 定价 = 「bootstrap 一条自洽折现曲线」 + 「固定端按年金折现、浮动端链式相消」。互换利率就是折现曲线的等价表达,市场报给你的掉期利率正是让曲线自洽的平价解。它看似在「赌利率方向」,实质是利率的期限结构被拆开又重新打包——这也是为什么 IRS 既是 hedging 工具,也是收益率曲线本身的来源。
把这篇和上篇连起来看:通胀掉期的 BEI 用名义/真实两条零息曲线之差拆出,而这里的 IRS 正是构造那条名义零息曲线最常用的报价来源。利率衍生品是一个彼此咬合的系统,不是在孤岛里定价。