4、静态利差法:假设条件、计算步骤、Python实现与案例

静态利差法,说白了就是算一个「固定价差」。

什么意思呢?你想想看,国债收益率曲线是基准,企业债收益率比国债高,高出来的这部分就是利差。静态利差法假设这个利差在整个存续期内是恒定不变的。嗯,这个假设很理想化,但实际工作中,它确实是最常用的起步方法。

我个人习惯把静态利差叫做「Z-Spread」,全称是Zero-Volatility Spread。为什么叫零波动?因为它不考虑未来利率路径的变化,只假设一个固定的利差加在整条即期曲线上。

4.1 假设条件

做任何模型都要先搞清楚假设,否则算出来的数字就是垃圾。

  • 假设一:利差恒定——债券存续期内,信用利差不随时间变化。说白了就是今天算出来是150bp,三年后还是150bp。当然现实不可能,但作为定价基准,这个假设够用了。
  • 假设二:即期利率曲线已知——我们需要一条完整的国债即期收益率曲线,通常用Nelson-Siegel或样条法拟合出来。我在项目中遇到过,如果曲线拟合得不好,静态利差算出来会非常离谱。
  • 假设三:现金流确定——债券不违约,按约定付息还本。静态利差法不包含违约概率,它只是衡量相对于国债的额外补偿。
  • 假设四:无套利——市场定价是有效的,计算出的利差反映了信用风险、流动性风险等综合溢价。

核心要点:静态利差法本质上是「折现因子差值法」。把债券所有现金流用「国债即期利率+固定利差」折现,让现值等于市场价格,这个固定利差就是Z-Spread。

4.2 计算步骤

步骤其实不复杂,但细节容易出错。我踩过坑,所以给你拆细一点。

  1. 获取国债即期利率曲线——从市场数据中提取关键期限的国债即期利率,插值得到任意期限的即期利率 \( r(t) \)。
  2. 确定债券现金流——包括每期票息和到期本金。注意付息频率,半年付息和年付息的处理方式不同。
  3. 设定目标函数——债券理论价格公式:
P_theoretical = Σ [CF_i / (1 + r(t_i) + s)^(t_i)]

其中 \( s \) 就是我们要找的静态利差。

  1. 求解方程——让理论价格等于市场价格(全价),解出 \( s \)。这是个一元非线性方程,用牛顿法或二分法都能解。
  2. 输出结果——通常以基点(bp)为单位,1bp = 0.01%。

我的经验:求解时初始值设多少很关键。我一般先用简单利差(到期收益率差)作为初始值,这样牛顿法收敛很快。如果直接设0,有时候会跑到负利差去,虽然负利差也可能存在,但大部分信用债还是正的。

4.3 Python实现

直接上代码。我习惯用numpy和scipy,scipy的优化器比手写二分法稳定得多。

import numpy as np
from scipy.optimize import fsolve

def calculate_z_spread(price, coupon_rate, maturity, freq, spot_rates, spot_tenors):
    """
    计算静态利差(Z-Spread)
    
    参数:
        price: 债券全价(面值100)
        coupon_rate: 票面利率(小数形式,如0.05表示5%)
        maturity: 剩余期限(年)
        freq: 年付息次数(1或2)
        spot_rates: 即期利率数组(小数形式)
        spot_tenors: 即期利率对应的期限数组(年)
    
    返回:
        z_spread: 静态利差(基点)
    """
    # 生成现金流时间点
    n_periods = int(maturity * freq)
    periods = np.arange(1, n_periods + 1) / freq
    
    # 每期现金流
    coupon = coupon_rate / freq * 100
    cashflows = np.full(n_periods, coupon)
    cashflows[-1] += 100  # 最后一期加本金
    
    # 插值得到每个时间点的即期利率
    spot_interp = np.interp(periods, spot_tenors, spot_rates)
    
    def price_diff(spread):
        # 用即期利率+利差折现
        discount_factors = 1 / (1 + spot_interp + spread) ** periods
        pv = np.sum(cashflows * discount_factors)
        return pv - price
    
    # 用fsolve求解,初始值设为0.01(100bp)
    z_spread_decimal = fsolve(price_diff, 0.01)[0]
    z_spread_bp = z_spread_decimal * 10000
    
    return z_spread_bp

# 示例:一个5年期,票面4%,半年付息的公司债
price = 98.5  # 全价98.5
coupon = 0.04
maturity = 5.0
freq = 2

# 假设的国债即期曲线
tenors = np.array([0.5, 1, 2, 3, 5, 7, 10])
rates = np.array([0.025, 0.028, 0.030, 0.032, 0.035, 0.036, 0.037])

z_spread = calculate_z_spread(price, coupon, maturity, freq, rates, tenors)
print(f"静态利差: {z_spread:.2f} bp")

注意:这里的price必须是全价,不是净价。全价=净价+应计利息。我曾经在这个地方吃过亏,算出来的利差总是对不上Bloomberg,后来发现是价格类型搞错了。应计利息的计算公式:应计利息 = 票面利率 × 面值 × (上次付息到结算日的天数 / 付息周期天数)。

4.4 案例:某城投债的静态利差计算

拿一个真实案例来说。2023年我处理过一只AA+城投债,剩余期限3.2年,票面利率5.8%,每年付息一次,当前全价102.3。

国债即期曲线数据如下(简化版):

期限(年) 0.5 1 2 3 5
即期利率(%) 2.10 2.35 2.60 2.80 3.00

运行上面的代码,得到静态利差为187.3bp。这意味着什么?市场认为这只城投债比国债多补偿187.3bp的信用风险。

我对比了一下同期限同评级的其他城投债,利差大概在160-200bp之间,187bp处于合理区间。但如果某只债的利差突然跳到300bp以上,那就要警惕了——可能是市场在提前定价违约风险。

4.5 静态利差法的局限性

说实话,静态利差法虽然好用,但缺陷也很明显。

  • 利差恒定假设太强——现实中信用利差是时变的,经济下行期利差会走阔,上行期会收窄。静态利差法完全忽略了这个动态特征。
  • 对曲线敏感——如果国债即期曲线拟合得不好,或者插值方法选错了,结果差异很大。我试过用线性插值和三次样条插值,利差能差20bp以上。
  • 不包含期权调整——如果债券含权(如可赎回、可回售),静态利差法就不适用了,得用期权调整利差(OAS)。

一句话总结:静态利差法是信用利差分析的「入门功夫」,简单、直观、可复现。但别把它当真理,它只是一个参考基准。真正做投资决策时,还得结合动态利差、行业轮动、个券基本面等因素综合判断。

嗯,这一章就到这里。代码你拿去跑跑看,有问题随时调。记住,模型是工具,市场才是老师。


公众号:蓝海资料掘金营,微信deep3321