Below is the sample code to compute the inflation swaps. I have referred the Quantlib cookbook to get the flavor of Inflation swaps. But I feel that the term structure and final NPV is not accurate and also missing something. If anyone can look into the steps and provide the final NPV value of any hypothetical swap could be very useful.
import QuantLib as ql
import datetime
import pandas as pd
valuation_date = ql.Date(14, 5, 2021)
ql.Settings.instance().setEvaluationDate(valuation_date)
# sample par rate of eonia
#eonia_par_rates = pd.read_csv('eonia.csv')
data = [['EONIA', 2022-5-14 ,2022-5-18,'1Y',-0.487185945],
['EONIA', 2022-5-14 ,2023-5-18,'2Y',-0.47487549]]
eonia_par_rates = pd.DataFrame(data, columns =
['Curve','last_update','maturity','tenor','mid_yield'])
index = ql.Eonia()
helpers = []
for idx, row in eonia_par_rates.iterrows():
rate = row["mid_yield"] / 100
tenor = row.tenor
if tenor == "1D":
print('1D')
#helpers.append(ql.DepositRateHelper(rate, index))
else:
helpers.append(
ql.OISRateHelper(
0, ql.Period(tenor), ql.QuoteHandle(ql.SimpleQuote(rate)), index
)
)
ois = ql.PiecewiseLogCubicDiscount(0, ql.TARGET(), helpers, ql.Actual365Fixed())
ois.enableExtrapolation()
observationLag = ql.Period("3M")
dc = ql.ActualActual()
frequency = ql.Monthly
cal = ql.UnitedKingdom()
bdc = ql.ModifiedFollowing
inflationIndex = ql.EUHICP(True)
# sample inflation rates of EUR-RPI
#infl_data = pd.read_csv('inflation_rates.csv')
data_2 = [[1.377, '1Y', 2022-5-14],
[1.311, '2Y', 2023-5-14]]
infl_data = pd.DataFrame(data_2, columns = ['px_last', 'tenor_two,','maturity'])
infl_data['maturity'] = pd.to_datetime(infl_data['maturity'], format="%Y-%m-%d")
inflationRateHelpers = []
for idx, row in infl_data.iterrows():
maturity = ql.Date().from_date(row.maturity)
quote = ql.QuoteHandle(ql.SimpleQuote(row.px_last / 100.0))
helper = ql.ZeroCouponInflationSwapHelper(
quote,
observationLag,
maturity,
cal,
bdc,
dc,
inflationIndex
)
inflationRateHelpers.append(helper)
baseZeroRate = infl_data.iloc[0].px_last / 100
inflationCurve =ql.PiecewiseZeroInflation(
valuation_date,
cal,
dc,
observationLag,
frequency,
inflationIndex.interpolated(),
baseZeroRate,
ql.YieldTermStructureHandle(ois),
inflationRateHelpers,
1.0e-12, #error
ql.Linear())
inflationCurve.enableExtrapolation()
discountYTS = ql.RelinkableYieldTermStructureHandle()
inflationYTS = ql.RelinkableZeroInflationTermStructureHandle()
discountYTS.linkTo(ois)
inflationYTS.linkTo(inflationCurve)
# sample historical rates of EUHICP
#rpi = pd.read_csv('historical_rates.csv')
data_3 = [[1982-1-1, 7889.25],
[1982-1-4, 7894.3]]
rpi = pd.DataFrame(data_3, columns = ['index', 'PX_LAST'])
rpi = rpi.set_index('index')
inflationIndex = ql.EUHICP(True, inflationYTS)
rpi.index = pd.to_datetime(rpi.index)
for idx, row in rpi.iterrows():
fixing_date = ql.Date().from_date(idx)
inflationIndex.addFixing(fixing_date, row.PX_LAST, True)
swap computation
notional = 1e6
startDate = ql.Date(26, 1, 2006)
endDate = ql.Date(26, 1, 2055)
fixedRate = 0.032
swapType = ql.ZeroCouponInflationSwap.Payer
swap = ql.ZeroCouponInflationSwap(
swapType,
notional,
startDate,
endDate,
cal,
ql.ModifiedFollowing,
dc,
fixedRate,
inflationIndex,
observationLag,
)
swapEngine = ql.DiscountingSwapEngine(discountYTS)
swap.setPricingEngine(swapEngine)
npv = swap.NPV()