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)
来源:https://stackoverflow.com/questions/56191445/quantlib-python-solving-non-positive-time-forward-error-using-quantlib-schedule