1

I am trying to price a forward swap using a bootstrapped curve in the QuantLib environment. For my valuationDate of 2019-04-04, the curve bootstrap runs as expected. I am also able to easily price a 10Y10Y foward start swap. The problem arise when I try pricing a 15Y5Y forward swap. Assume my settlement is t+2 (2019-04-08), and I find the forward start date of the swap using the settlement date and the calendar object, The error seems to arise mostly when my forward start date falls on a weekend, therefore using next business day as start date. In our case, 2034-04-08 is a Saturday, so we end up having a start date as of 2034-04-10 for the swap. This error is then raised:

cannot calculate forward rate between April 11th, 2034 and April 11th, 2034: non positive time (0) using Actual/360 daycounter

This was approached in the comments here C++ Quantlib Vanilla Swap: setting future fixing dates and gearing for floating leg but I did not find a formal question addressing this "issue".

Trying to understand the problem, I believe the backward date generation might be a part of the problem as it seems to create a stub. The start date of the swap using backward generation is April 11th 2034 while the swap start date I provide is April 10th 2034. This shows up in both my Schedule (fixed and float).

Going further into my research I looked for "stub" here: https://leanpub.com/quantlibpythoncookbook/read and found what I think is a part of the answer. The Schedule constructor allows to specify short/long front/back stubs but even if I specify firstDate as April 11th 2034, the same error is thrown. Here is the complete code reproducing the error. As you can see both my schedule include April 10th 2034 AND April 11th 2034, which I believe is what is causing my issue. I am still confused as to why and how to resolve this.


import QuantLib as ql

# my quotes
nodes=(
 (ql.Date( 4, 4, 2019 ), 1.0),
 (ql.Date( 8, 4, 2020 ), 0.9744804179560926),
 (ql.Date( 8, 4, 2021 ), 0.9523386108738999),
 (ql.Date( 8, 4, 2022 ), 0.9315169815568433),
 (ql.Date( 11, 4, 2023 ), 0.910405285996171),
 (ql.Date( 8, 4, 2024 ), 0.8892891964251837),
 (ql.Date( 8, 4, 2025 ), 0.8676501405451038),
 (ql.Date( 8, 4, 2026 ), 0.8457795884699698),
 (ql.Date( 8, 4, 2027 ), 0.8237398951999767),
 (ql.Date( 10, 4, 2028 ), 0.801457566049863),
 (ql.Date( 9, 4, 2029 ), 0.7795144954869505),
 (ql.Date( 8, 4, 2031 ), 0.7362944371445531),
 (ql.Date( 11, 4, 2034 ), 0.6755019523836218),
 (ql.Date( 12, 4, 2039 ), 0.5864073271433347),
 (ql.Date( 8, 4, 2044 ), 0.5120023623536163),
 (ql.Date( 8, 4, 2049 ), 0.4479312303231183),
 (ql.Date( 8, 4, 2059 ), 0.34859916237300465),
 (ql.Date( 8, 4, 2069 ), 0.2788046487083811))

node_dates, node_rates = zip(*nodes)

# Construct the discount curve
curve = ql.DiscountCurve(node_dates, node_rates, ql.Actual360(), ql.UnitedStates())
termStruct = ql.RelinkableYieldTermStructureHandle()
termStruct.linkTo(curve)


curve_date = ql.Date(4,4,2019) # the curve date
settlement = ql.Period(2,
                       ql.Days)

settle_date = ql.UnitedStates().advance(curve_date,
                                        settlement) # the settlement date, assume t+2 settlement

fwdstart = ql.UnitedStates().advance(settle_date,
                                     ql.Period(15,ql.Years)) # forward start date of swap

fwdend = ql.UnitedStates().advance(fwdstart,
                                    ql.Period(5,ql.Years)) # forwrad end date of swap

fixedSchedule = ql.Schedule( fwdstart,  # forward start
                             fwdend,  # forward end
                             ql.Period('6M'),  # period tenor
                             ql.UnitedStates(),  # calendar
                             ql.ModifiedFollowing,  # convention
                             ql.ModifiedFollowing,  # termination date convention
                             ql.DateGeneration.Backward,  # date generation
                             True  # EoM
                             )
print('\n' + 10*'*' + ' Fixed Schedule ' + 10*'*')
for d in fixedSchedule:
    print(d)
print(40*'*')

floatingSchedule = ql.Schedule( fwdstart,  # forward start
                                fwdend,  # forward end
                                ql.Period('3M'),  # period tenor
                                ql.UnitedStates(),  # calendar
                                ql.ModifiedFollowing,  # convention
                                ql.ModifiedFollowing,  # termination date convention
                                ql.DateGeneration.Backward,  # date generation
                                True  # EoM
                                )

print('\n' + 10*'*' + ' Floating Schedule ' + 10*'*')
for d in floatingSchedule:
    print(d)
print(40*'*')

forwardswap = ql.VanillaSwap( type=ql.VanillaSwap.Receiver,  # direction
                              nominal=1E8,  # notional
                              fixedSchedule=fixedSchedule,  # fixed schedule
                              fixedRate=0.023,  # fixed rate
                              fixedDayCount=ql.Actual360(),  # fixed leg basis
                              floatSchedule=floatingSchedule,  # floating schedule
                              index=ql.USDLibor(ql.Period('3M')),
                              spread=0.0,  # spread
                              floatingDayCount=ql.Thirty360() # float leg basis
                              )

swap_engine = ql.DiscountingSwapEngine(termStruct)
forwardswap.setPricingEngine(swap_engine)



0 Answers0