第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),这样曲线在两端不会乱翘。如果你发现曲线在短端或长端出现异常波动,先检查边界条件设置。

知识体系总览

下面这张图,是我自己画的本章知识结构。你可以把它当成一张地图,随时回来看看:

利率基础与期限结构知识体系 核心概念 构建方法 插值技术 即期利率 vs 远期利率 贴现因子 零息曲线 Bootstrapping原理 从附息债券提取零息利率 Python实现示例 线性插值 三次样条插值 边界条件选择 核心逻辑:无套利定价 → 曲线构建 → 插值平滑 所有利率衍生品定价的起点

好了,这一章的内容就到这里。利率和期限结构是后面所有定价模型的基础,建议你亲手跑一遍代码,把Bootstrapping和插值的逻辑吃透。下一章我们会进入更实战的内容——用这些工具给利率互换定价。

专注资料整理