|
From: Luigi B. <lui...@gm...> - 2023-10-24 15:57:37
|
Ok, I see. I was confused for a bit because adding your code above at the
end of swap.py, fixedSchedule and floatingSchedule are forward starting,
not spot; also fixedRate is not the rate used in the bootstrap.
In any case, once I use the correct schedules and fixed rate, the problem
can be seen even without compiling with indexed coupons on. As you say, we
didn't apply the timing adjustment while bootstrapping and we're applying
it now, so the values of the coupons don't match.
We should pass the coupon pricer to the SwapRateHelper constructor, but
that's not a feature we have now. I'm afraid I don't have a
workaround—except not using timing adjustments. May you open an issue on
GitHub for this?
Thanks,
Luigi
On Tue, Oct 24, 2023 at 12:12 PM Aleksis Ali Raza via QuantLib-users <
qua...@li...> wrote:
> 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
> _______________________________________________
> QuantLib-users mailing list
> Qua...@li...
> https://lists.sourceforge.net/lists/listinfo/quantlib-users
>
|