You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python QuantLib债券定价异常(价格为0)排查及Z-spread求解方案咨询

Python QuantLib债券定价异常(价格为0)排查及Z-spread求解方案咨询

你好,我帮你梳理下代码里的问题,同时分享几个Z-spread求解的优化思路:

一、债券价格为0的核心原因排查

你遇到的定价为0的问题,核心是付息频率设置错误导致的:

  • 你代码里写的frequency = ql.Period(2),QuantLib中ql.Period(2)默认指的是2天周期,而非你想要的半年付息。这会让生成的schedule在2019-08-21到2023-02-21之间,每2天就生成一个付息日——到2023-02-18结算日时,所有现金流都已经支付完毕,没有未来现金流的债券自然定价为0。
  • 至于你提到的bond.settlementDays显示为2而非设置的0,这是因为变量命名混淆:你把ql.Thirty360(DayCounter类型)命名为paymentConvention,但FixedRateBond构造的第6个参数才是支付惯例(BusinessDayConvention,比如ql.Unadjusted),当前参数传递顺序虽没直接引发价格问题,但命名混乱容易导致后续逻辑错误。

修复后的关键代码调整

把付息频率改成正常的半年周期(两种写法任选其一):

# 写法1:用预定义的半年周期常量
frequency = ql.Semiannual
# 写法2:明确指定6个月周期
frequency = ql.Period(6, ql.Months)

同时修正变量命名,避免混淆:

# 区分DayCounter和PaymentConvention,命名更清晰
day_counter = ql.Thirty360(ql.Thirty360.ISMA)
payment_convention = ql.Unadjusted

# 修正FixedRateBond构造参数,明确传递支付惯例
bond = ql.FixedRateBond(
    settlementDays,
    faceAmount,
    schedule,
    [coupon],
    day_counter,
    payment_convention
)

调整后,债券会生成正常的半年付息现金流,结算日2023-02-18时还有3天后的到期兑付金额,价格就不会为0了。

二、Z-spread求解的替代方案

你用Scipy优化价差的思路是可行的,但QuantLib有内置工具可以简化流程,或者优化你的实现逻辑:

  1. 基于SpreadedTermStructure的优化法:给原零息曲线加上Z-spread生成带价差的曲线,再通过优化价差让债券定价匹配目标价格,示例逻辑如下:
from scipy.optimize import root_scalar

def calculate_z_spread(target_price, bond, clean_price=True):
    def spread_error(spread):
        # 给原定价曲线叠加Z-spread
        spreaded_curve = ql.ZeroSpreadedTermStructure(pricing_curve, ql.QuoteHandle(ql.SimpleQuote(spread)))
        bond.setPricingEngine(ql.DiscountingBondEngine(ql.YieldTermStructureHandle(spreaded_curve)))
        # 计算价差调整后价格与目标价格的差值
        if clean_price:
            return bond.cleanPrice() - target_price
        else:
            return bond.dirtyPrice() - target_price
    
    # 用Brentq方法求解价差,初始区间可根据市场情况调整
    result = root_scalar(spread_error, bracket=[0.0, 0.1], method='brentq')
    return result.root if result.converged else None
  1. Bootstrap构建带价差曲线:如果需要给多只债券批量计算Z-spread,可以通过Bootstrap方式构建带价差的曲线,但单只债券用上面的优化法已经足够高效。
  2. 日期校准注意事项:确保结算日、付息日的调整逻辑一致,避免因日期处理错误导致价差计算偏差。

另外,你当前的零息曲线构建中,key_term_tenor里的0对应结算日当天是合理的,但要注意线性插值方式是否符合你的定价需求。

三、额外验证建议

因为你的结算日和到期日仅差3天,修复后债券价格应该接近面值加上应计利息,你可以用bond.accruedAmount()查看应计利息,验证定价结果是否符合预期。

备注:内容来源于stack exchange,提问作者user23133258

火山引擎 最新活动