第1章:利率基础与期限结构
大家好,欢迎来到《利率衍生品定价与对冲策略实战》。我是你们的老朋友,一个在固收市场摸爬滚打了十几年的量化工程师。今天咱们聊聊最基础、也最核心的东西——利率与期限结构。
说实话,很多人一上来就搞复杂的定价模型,结果连即期利率和远期利率都分不清。我当年刚入行时也犯过这毛病,被老交易员骂了一顿才老实。嗯,咱们今天就踏踏实实把地基打牢。
1.1 即期利率与远期利率
即期利率,说白了就是你今天借钱,到期一次性还本付息的年化收益率。比如你买一张1年期零息国债,花了97块钱,到期拿回100块,那即期利率就是(100/97)^(1/1) - 1 ≈ 3.09%。
远期利率呢?它代表的是未来某个时间点开始的借款利率。比如你想知道1年后开始的1年期利率是多少,这就是1×2远期利率。它不是市场直接报给你的,而是从即期利率里推导出来的。
我习惯用一个简单的例子来理解:
- 1年期即期利率 r1 = 3%
- 2年期即期利率 r2 = 4%
那1年后的1年期远期利率 f(1,2) 是多少?逻辑很简单:
投资2年拿到的收益,应该等于先投资1年,再按远期利率续投1年的收益。否则就有套利空间。公式就是:
(1 + r2)^2 = (1 + r1) × (1 + f(1,2))
算出来 f(1,2) ≈ 5.01%。你看,远期利率比即期利率高,说明市场预期未来利率会上升。
核心要点:远期利率不是预测,而是市场对未来的无套利定价。我曾经在项目中见过有人把远期利率当成预测值来用,结果对冲策略一塌糊涂。记住,它只是数学推导的结果。
1.2 贴现因子与零息曲线
贴现因子,就是未来1块钱现在值多少钱。比如贴现因子 d(T) = 0.95,意味着T时刻的1块钱,现在只值0.95元。它和即期利率的关系很简单:
d(T) = 1 / (1 + r(T))^T
贴现因子有几个特点:
- d(0) = 1,今天的钱就是今天的钱
- 随着期限增加,贴现因子单调递减
- 它永远为正,且小于等于1
零息曲线,就是把不同期限的零息利率连起来形成的曲线。它是整个利率衍生品定价的基石。你想想看,任何固定收益产品,本质上都是一堆未来现金流的组合。只要有了零息曲线,你就能把这些现金流贴现到今天,算出它的合理价格。
我在做利率互换定价时,第一步永远是构建零息曲线。没有它,后面全是空中楼阁。
1.3 收益率曲线构建(Bootstrapping)
Bootstrapping,中文叫「自举法」或「拔靴法」。名字挺唬人,其实逻辑很简单:
市场上我们能直接看到的,大多是附息债券的价格。比如一个2年期国债,每年付息5块,现在价格是98块。我们怎么从它身上提取出2年期的零息利率?
答案是:先利用1年期零息利率,把第一年的利息贴现掉,剩下的部分就是2年后本金和最后一期利息的现值。然后反解出2年期零息利率。
这个过程就像剥洋葱,一层一层往里剥。从最短期限开始,逐步推导出所有期限的零息利率。
我给大家写个简单的Python代码,演示一下Bootstrapping的核心逻辑:
import numpy as np
def bootstrap_zeros(coupon_bonds):
"""
从附息债券价格中提取零息利率
coupon_bonds: list of dict, 每个dict包含期限、票面利率、价格
"""
zeros = {} # 存储零息利率
for bond in coupon_bonds:
T = bond['maturity']
c = bond['coupon'] / 100 # 票面利率
p = bond['price']
# 计算已贴现的现金流之和(除最后一期)
pv_coupons = 0
for t in range(1, int(T)):
if t in zeros:
pv_coupons += c * np.exp(-zeros[t] * t)
# 反解最后一期的零息利率
# p = pv_coupons + (100 + c) * exp(-r * T)
r = -np.log((p - pv_coupons) / (100 + c)) / T
zeros[T] = r
return zeros
# 示例数据
bonds = [
{'maturity': 1, 'coupon': 0, 'price': 97.0},
{'maturity': 2, 'coupon': 5, 'price': 98.5},
{'maturity': 3, 'coupon': 4, 'price': 96.0}
]
rates = bootstrap_zeros(bonds)
for T, r in rates.items():
print(f"{T}年期零息利率: {r*100:.2f}%")
注意:实际市场中,债券的付息频率、计息基准、节假日调整都会影响结果。我曾经在项目中因为忽略了「实际/365」和「30/360」的差异,导致曲线出现微小扭曲,最后被审计追着问了一周。细节决定成败。
1.4 插值方法(线性、三次样条)
Bootstrapping只能给出有限几个期限的零息利率。比如你只有1年、2年、3年、5年、10年的数据,那1.5年、2.3年的利率怎么来?这就需要插值。
线性插值是最简单粗暴的方法。两个点之间画条直线,中间的值按比例算。优点是简单、稳定,缺点是曲线不够平滑,一阶导数不连续。对于交易员来说,不平滑意味着对冲参数可能跳变,挺烦人的。
三次样条插值就好多了。它用分段三次多项式来拟合,保证曲线本身和一阶、二阶导数都连续。这样曲线看起来非常平滑,适合用于定价和对冲。
我个人习惯在构建收益率曲线时,先用线性插值做快速原型,验证逻辑没问题后,再换成三次样条做精细处理。你想想看,如果一开始就用复杂的插值方法,出了问题你都不知道是插值的问题还是数据的问题。
下面是一个简单的三次样条插值示例:
from scipy.interpolate import CubicSpline
import numpy as np
# 已知的期限和零息利率
maturities = np.array([1, 2, 3, 5, 10])
rates = np.array([0.03, 0.035, 0.04, 0.045, 0.05])
# 构建三次样条插值函数
cs = CubicSpline(maturities, rates, bc_type='natural')
# 插值得到1.5年和2.3年的利率
print(f"1.5年利率: {cs(1.5)*100:.2f}%")
print(f"2.3年利率: {cs(2.3)*100:.2f}%")
小技巧:三次样条的边界条件很关键。我一般用「自然边界条件」(二阶导数为0),这样曲线在两端不会乱翘。如果你发现曲线在短端或长端出现异常波动,先检查边界条件设置。
知识体系总览
下面这张图,是我自己画的本章知识结构。你可以把它当成一张地图,随时回来看看:
好了,这一章的内容就到这里。利率和期限结构是后面所有定价模型的基础,建议你亲手跑一遍代码,把Bootstrapping和插值的逻辑吃透。下一章我们会进入更实战的内容——用这些工具给利率互换定价。