QuantLib-Python: Solving non positive time forward error using quantlib Schedule for VanillaSwap instrument

有些话、适合烂在心里 提交于 2019-12-08 05:09:46

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!