|
From: Aleksis A. R. <ale...@go...> - 2023-10-24 10:09:49
|
Hi.
Quantlib allows for timing adjustments using the BlackIborCouponPricer class. My understanding is that Quantlib must be built with the indexed-coupon flag enabled to see effects from convexity/timing adjustments.
However doing so appears to create non-zero NPVs even for vanilla swaps priced at fair rate.
Adding the following code to the existing swap.py example that comes with the Quantlib SWIG package demonstrates this:
myforecastTermStructure = ql.YieldTermStructureHandle(ql.PiecewiseLinearZero(0, calendar, helpers, dayCounter))
flatcfvol = ql.SimpleQuote(.01)
flatcfvols = ql.ConstantOptionletVolatility(2, calendar, ql.ModifiedFollowing, ql.QuoteHandle(flatcfvol),floatingLegDayCounter, ql.Normal, 0.0)
flatcfvolsurface = ql.OptionletVolatilityStructureHandle(flatcfvols)
flatcfvolsurface.enableExtrapolation()
myindex = ql.IborIndex('', ql.Period('3m'), 2, ql.EURCurrency(), calendar, ql.ModifiedFollowing, False, dayCounter,myforecastTermStructure)
fixedleg=ql.FixedRateLeg(fixedSchedule,fixedLegDayCounter,[nominal],[fixedRate])
floatingleg=ql.IborLeg([nominal],floatingSchedule,myindex,floatingLegDayCounter,floatingLegAdjustment,[fixingDays],[1],[0],caps=[],floors=[],isInArrears=False)
couponpricer = ql.BlackIborCouponPricer(flatcfvolsurface, 1, ql.QuoteHandle(ql.SimpleQuote(.2)))
ql.setCouponPricer(floatingleg, couponpricer)
myswap=ql.Swap(fixedleg,floatingleg)
myswap.setPricingEngine(swapEngine)
print(myswap.NPV())
I think the reason for the non-zero PV is that accrual periods mismatch index periods for coupons which have start/end dates that are non-business days.
Is there a work-around for this issue? A vanilla swap at fair rate should PV to zero in all cases. Perhaps the swap helpers in the curve construction need to incorporate this information somehow?
Thanks, Aleksis |