1

I am trying to price a zero-coupon USD CPI inflation swap in Quantlib and Python. My discount curve and NPV of the fixed leg looks good, but I'm a few percentage points out compared to BBG SWPM on the NPV of the inflation leg.

One thing I've noticed is that changing the values of the CPI has no effect on the price of the swap. So I think I'm setting the CPI wrong and as such the base index of the swap is wrong. Can anyone see what I'm doing wrong here?

For reference, I've backed this out from looking at the C++ unit tests. If there's a complete Python example I would be interested to see it, but couldn't find one on my own.

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())
AGPeddle
  • 65
  • 4

0 Answers0