主题切换
12.2 久期与凸度免疫
久期的三种定义
Macaulay 久期
Macaulay 久期是债券未来现金流的加权平均时间,权重为各期现金流现值占债券总现值的比例:
$$D_{\text{Mac}} = \frac{\sum_{t=1}^n t \cdot PV(CF_t)}{\sum_{t=1}^n PV(CF_t)} = \frac{\sum_{t=1}^n t \cdot \frac{CF_t}{(1+y)^t}}{P}$$
其中
此处有展示代码展开 ▼
python
def macaulay_duration(cashflows, times, ytm):
"""
计算 Macaulay 久期
cashflows: 各期现金流(含本金和利息)
times: 各期现金流的时间(年)
ytm: 到期收益率
"""
pv = []
weighted_pv = []
for cf, t in zip(cashflows, times):
pv_cf = cf / (1 + ytm) ** t
pv.append(pv_cf)
weighted_pv.append(t * pv_cf)
price = sum(pv)
duration = sum(weighted_pv) / price
return duration, price
# 示例:10年期债券,票面利率4%,YTM=4.5%
face_value = 100
coupon_rate = 0.04
ytm = 0.045
years = 10
freq = 2 # 半年付息
n = years * freq
coupon = face_value * coupon_rate / freq
cashflows = [coupon] * n
cashflows[-1] += face_value
times = [(i + 1) / freq for i in range(n)]
dur, price = macaulay_duration(cashflows, times, ytm)
print(f"Macaulay 久期: {dur:.2f} 年")
print(f"债券全价: {price:.2f}")点击展开可浏览运行结果
Macaulay 久期: 8.30 年 债券全价: 96.40
修正久期
修正久期衡量债券价格对收益率变化的百分比敏感度:
$$D_{\text{mod}} = \frac{D_{\text{Mac}}}{1 + y/f}$$
其中
$$\frac{\Delta P}{P} \approx -D_{\text{mod}} \cdot \Delta y$$
名词解释:DV01 (Dollar Value of 01)
收益率变动1个基点(0.01%)时债券价格的变化金额。DV01 = Modified Duration * Price * 0.0001。这是交易台上最常用的利率风险度量。
有效久期
对于含权债券(如可赎回债、MBS),未来现金流不确定,因此需要使用有效久期:
$$D_{\text{eff}} = \frac{P_{-\Delta y} - P_{+\Delta y}}{2 \cdot P_0 \cdot \Delta y}$$
通过扰动收益率曲线,重新计算模型价格来得到。这是实务中最灵活的方式,因为它不需要计算预期现金流。
此处有展示代码展开 ▼
python
def effective_duration(price_function, P0, y0, dy=0.0001):
"""
通过数值扰动计算有效久期
price_function(y): 给定收益率y,返回模型价格
"""
P_down = price_function(y0 - dy)
P_up = price_function(y0 + dy)
duration = (P_down - P_up) / (2 * P0 * dy)
return duration点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `effective_duration`(通过数值扰动计算有效久期)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。
凸度的数学含义
凸度(Convexity)衡量久期相对于收益率的变化率,即债券价格对收益率的二阶导数除以价格:
$$C = \frac{1}{P} \frac{\partial^2 P}{\partial y^2}$$
价格变化的二阶近似:
$$\frac{\Delta P}{P} \approx -D_{\text{mod}} \cdot \Delta y + \frac{1}{2} C \cdot (\Delta y)^2$$
此处有展示代码展开 ▼
python
def convexity(cashflows, times, ytm):
"""
计算债券的凸度
"""
pv_cf = [cf / (1 + ytm) ** t for cf, t in zip(cashflows, times)]
weighted_pv = [t * (t + 1) * pv for t, pv in zip(times, pv_cf)]
price = sum(pv_cf)
conv = sum(weighted_pv) / (price * (1 + ytm)**2)
return conv
# 凸度对价格估计的改进
conv = convexity(cashflows, times, ytm)
print(f"凸度: {conv:.2f}")
# 假设收益率上升50bp
dy = 0.0050
mod_dur = dur / (1 + ytm / freq)
pct_change_linear = -mod_dur * dy
pct_change_convexity = pct_change_linear + 0.5 * conv * dy**2
print(f"一阶近似: {pct_change_linear*100:.4f}%")
print(f"二阶近似: {pct_change_convexity*100:.4f}%")
print(f"凸度调整: {0.5 * conv * dy**2 * 100:.4f}%")点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `convexity`(计算债券的凸度)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。
凸度对债券持有者总是有利的:当收益率下降时,价格涨幅大于久期预测值;当收益率上升时,价格跌幅小于久期预测值。这就是"凸度是有价值的"这一说法的来源。
免疫策略:资产与负债久期匹配
免疫(Immunization)是固定收益组合管理的核心策略,通过让资产的久期和凸度与负债匹配,使得组合净值对利率变动不敏感。
单一负债免疫
对于一笔未来确定时点的负债
$$\begin{aligned} PV(\text{Assets}) &= PV(\text{Liabilities}) \\ D_{\text{Assets}} &= D_{\text{Liabilities}} \end{aligned}$$
此处有展示代码展开 ▼
python
def immunize_single_liability(liability, liability_time, bonds, ytm):
"""
对单一负债进行免疫
liability: 负债金额
liability_time: 负债到期时间(年)
bonds: list of dicts with 'duration', 'price', 'convexity'
"""
# 计算负债的现值和久期
pv_liability = liability / (1 + ytm) ** liability_time
print(f"负债现值: {pv_liability:,.2f}")
print(f"负债久期: {liability_time:.2f} 年")
# 目标:找到两个债券的权重使组合久期等于负债久期
# w1 * D1 + w2 * D2 = D_liability
# w1 + w2 = 1
D1, D2 = bonds[0]['duration'], bonds[1]['duration']
w1 = (liability_time - D2) / (D1 - D2)
w2 = 1 - w1
# 计算需要购买的金额
amount_bond1 = pv_liability * w1
amount_bond2 = pv_liability * w2
return {
'bond1_allocation': amount_bond1,
'bond2_allocation': amount_bond2,
'portfolio_duration': w1 * D1 + w2 * D2
}点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `immunize_single_liability`(对单一负债进行免疫)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。
多期负债免疫与再平衡
对于多期负债(如养老金支付流),免疫策略更为复杂。组合需要匹配负债的久期缺口,并且由于久期随时间漂移,需要定期再平衡:
此处有展示代码展开 ▼
python
# rebalancing_schedule 伪代码结构
# 1. 计算负债最大期限 horizon
# 2. 按 rebalance_freq 步进到 horizon
# 3. 在每个再平衡点过滤剩余负债
# 4. 计算久期缺口并调整组合匹配点击展开可浏览运行结果
(脚本执行完成,未产生可展示的模块级变量或函数定义)
关键利率久期(Key Rate Duration)
传统久期衡量的是收益率曲线平行移动的影响,但在实际市场中,不同期限的利率变动并不均匀。关键利率久期解决了这一问题。
名词解释:关键利率久期(Key Rate Duration, KRD)
组合价值对特定期限(如2年、5年、10年、30年)的即期利率变动的敏感度。KRD将收益率曲线风险分解为多个"关键点"上的暴露,提供了比单一久期数字丰富得多的风险画像。
此处有展示代码展开 ▼
python
def key_rate_duration(price_function, key_maturities, y0, dy=0.0001):
"""
计算关键利率久期
price_function(spots_dict): 输入各期限的即期利率,返回模型价格
key_maturities: 关键期限列表 [2, 5, 10, 30]
"""
P0 = price_function({m: y0 for m in key_maturities})
krds = {}
for k in key_maturities:
# 仅扰动特定期限,其他期限保持不变或插值
spots_up = {m: y0 + (dy if m == k else 0) for m in key_maturities}
spots_down = {m: y0 + (-dy if m == k else 0) for m in key_maturities}
P_up = price_function(spots_up)
P_down = price_function(spots_down)
krds[k] = -(P_up - P_down) / (2 * P0 * dy)
return krds点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `key_rate_duration`(计算关键利率久期)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。
关键利率久期的用途:
- 识别组合对不同期限的暴露集中度
- 对冲收益率曲线的非平行移动
- 做"蝶式交易"时的风险预算(例如做多5年、做空2年和10年,使总DV01和关键利率久期尽量中性)
利用关键利率久期,交易员可以精确地对冲收益率曲线上的曲线弯曲风险(bend risk)——这是传统久期/凸度框架所无法处理的。