You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quantlib零息通胀互换未读取CPI值问题排查求助

美元CPI零息通胀互换定价问题(QuantLib Python)

问题描述

用QuantLib Python定价USD CPI零息通胀互换时,折现曲线与固定端NPV结果正常,但通胀端NPV与BBG SWPM存在数个百分点偏差。修改CPI数值对互换定价无影响,怀疑是CPI设置错误导致互换基准指数异常,求问题定位,同时希望获取完整Python示例。

代码片段

import QuantLib as quantlib
import pandas as pd

start_date = quantlib.Date.from_date(pd.Timestamp(2022, 9, 6))
calc_date = quantlib.Date.from_date(pd.Timestamp(2022, 9, 6))
end_date = quantlib.Date.from_date(pd.Timestamp(2024, 9, 6))
swap_type = quantlib.ZeroCouponInflationSwap.Receiver
calendar = quantlib.TARGET()
day_count_convention = quantlib.ActualActual()
contract_observation_lag = quantlib.Period(3, quantlib.Months)
business_day_convention = quantlib.ModifiedFollowing
nominal = 10e6
fixed_rate = 0.05

cpi_json = '{"columns":[1],"index":[1640908800000,1643587200000,1646006400000,1648684800000,1651276800000,1653955200000,1656547200000,1659225600000],"data":[[277.948],[278.802],[283.716],[287.504],[289.109],[292.296],[296.311],[296.276]]}'
cpi_prints = pd.read_json(cpi_json, orient='split')
# Pretty-printed CPI:
#                   1
# 2021-12-31  277.948
# 2022-01-31  278.802
# 2022-02-28  283.716
# 2022-03-31  287.504
# 2022-04-30  289.109
# 2022-05-31  292.296
# 2022-06-30  296.311
# 2022-07-31  296.276
zero_coupon_observations = pd.DataFrame(index=[0],
                                        data={'1Y': 2.73620,
                                              '2Y': 2.975,
                                              '3Y': 2.967,
                                              '4Y': 2.917,
                                              '5Y': 2.8484})

inflation_yield_term_structure = quantlib.RelinkableZeroInflationTermStructureHandle()
inflation_index = quantlib.USCPI(True, inflation_yield_term_structure)
for date, value in cpi_prints.itertuples():
    # Setting the CPI as fixings, but no matter what I put here the NPV comes out the same
    # Looks like the base index for the swap is not being set by me/set through the CPI prints
    # I put here.
    inflation_index.addFixing(quantlib.Date.from_date(date), value)
inflation_rate_helpers = []
nominal_term_structure = quantlib.YieldTermStructureHandle(quantlib.FlatForward(calc_date,
                                                                                0.00,  # Changing this seems to have no effect
                                                                                quantlib.ActualActual()))
for tenor in zero_coupon_observations.columns:
    maturity = calendar.advance(calc_date, quantlib.Period(tenor))
    quote = quantlib.QuoteHandle(quantlib.SimpleQuote(zero_coupon_observations.at[0, tenor] / 100.0))
    helper = quantlib.ZeroCouponInflationSwapHelper(quote,
                                                    contract_observation_lag,
                                                    maturity,
                                                    calendar,
                                                    business_day_convention,
                                                    day_count_convention,
                                                    inflation_index,
                                                    nominal_term_structure)
    inflation_rate_helpers.append(helper)

# Not sure how to choose this number, just taking the 1Y tenor on the calc date?
# I'm pricing a 2Y swap, and will want to price it off it's start date as well
base_zero_rate = zero_coupon_observations.at[0, '1Y']/100
inflation_curve = quantlib.PiecewiseZeroInflation(calc_date,
                                                  calendar,
                                                  day_count_convention,
                                                  contract_observation_lag,
                                                  quantlib.Monthly,
                                                  inflation_index.interpolated(),
                                                  base_zero_rate,
                                                  inflation_rate_helpers,
                                                  1.0e-12,
                                                  quantlib.Linear())
inflation_yield_term_structure.linkTo(inflation_curve)

swap = quantlib.ZeroCouponInflationSwap(swap_type,
                                        nominal,
                                        start_date,
                                        end_date,
                                        calendar,
                                        business_day_convention,
                                        day_count_convention,
                                        fixed_rate,
                                        inflation_index,
                                        contract_observation_lag)

# Leaving off the construction of the discount curve for brevity.
# NPV of the fixed legs checks out
discount_curve = ...
swap_engine = quantlib.DiscountingSwapEngine(discount_curve)
swap.setPricingEngine(swap_engine)
print(swap.NPV())

问题定位与修正建议

核心问题点

  1. CPI指数初始化顺序错误:先关联通胀曲线再加载fixing,导致历史CPI数据未被正确纳入指数计算。QuantLib中通胀指数的fixing需要在绑定曲线前加载,否则曲线预测值会覆盖历史数据。
  2. 通胀曲线基准值误用:base_zero_rate直接取1Y零息通胀报价是错误的,应该用最新的已发布CPI值锚定曲线基准,而非互换报价。
  3. 名义折现曲线无效:构建通胀曲线时传入的nominal_term_structure是0利率曲线,会导致helper拟合通胀曲线时折现逻辑错误,进而影响通胀端现金流计算。
  4. 观察期逻辑未验证:起息日2022-09-06搭配3个月观察期,对应的参考CPI应为2022-06-30的数值,需确认该fixing是否被指数正确识别。

修正步骤

  • 调整CPI加载顺序:先创建无曲线的USCPI实例,加载所有fixing后再绑定通胀曲线:
    # 先创建独立的通胀指数
    inflation_index = quantlib.USCPI(True)
    # 加载所有历史CPI fixings
    for date, value in cpi_prints.itertuples():
        ql_date = quantlib.Date.from_date(date)
        inflation_index.addFixing(ql_date, value)
    # 再关联通胀曲线句柄
    inflation_yield_term_structure = quantlib.RelinkableZeroInflationTermStructureHandle()
    inflation_index.setTermStructure(inflation_yield_term_structure)
    
  • 修正通胀曲线基准:用最新的CPI固定值(如2022-07-31的296.276)计算基准通胀率,或直接基于该CPI值初始化曲线,确保曲线锚定真实历史数据。
  • 传入有效名义折现曲线:构建ZeroCouponInflationSwapHelper时,传入与后续定价一致的discount_curve,而非0利率曲线。
  • 验证观察期对应关系:通过inflation_index.fixing(start_date - contract_observation_lag)确认参考CPI值是否正确,确保与BBG的计算逻辑一致。

完整示例关键要点

  • 确保CPI fixings覆盖swap起息日之前的观察期
  • 通胀曲线构建时使用与定价一致的名义折现曲线
  • 指数插值方式(True表示插值)需匹配市场惯例
  • 手动验算通胀端现金流:名义金额 * (期末CPI/期初CPI - 1),折现后与BBG结果对比验证

内容的提问来源于stack exchange,提问作者AGPeddle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 17:55:30