|
From: Aleksis A. R. <ale...@go...> - 2023-10-24 16:27:21
|
Thanks Luigi.
Done.
> On Oct 24, 2023, at 4:57 PM, Luigi Ballabio <lui...@gm...> wrote:
>
> 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... <mailto: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... <mailto:Qua...@li...>
>> https://lists.sourceforge.net/lists/listinfo/quantlib-users
|