QuantLib-Python: устранение неположительной ошибки опережения времени с помощью quantlib Schedule для инструмента VanillaSwap

Я пытаюсь оценить форвардный своп, используя кривую начальной загрузки в среде QuantLib. Для моей даты оценки от 4 апреля 2019 г. начальная загрузка кривой работает, как и ожидалось. Я также могу легко оценить стартовый своп на 10–10 лет. Проблема возникает, когда я пытаюсь оценить форвардный своп на 15-5 лет. Предположим, что мое расчетное время t+2 (2019-04-08), и я нахожу дату начала форвардного свопа, используя дату расчета и объект календаря. выходной, поэтому в качестве даты начала используется следующий рабочий день. В нашем случае 08.04.2034 — это суббота, поэтому мы получаем дату начала свопа 10.04.2034. Затем возникает эта ошибка:

невозможно рассчитать форвардный курс между 11 апреля 2034 г. и 11 апреля 2034 г.: неверное время (0) с использованием счетчика "Факт/360 дней"

К этому подходили в комментариях здесь C++ Quantlib Vanilla Swap: установка будущих дат фиксации и передача плавающей ноги, но я не нашел официального вопроса, касающегося этой «проблемы».

Пытаясь понять проблему, я считаю, что генерация обратной даты может быть частью проблемы, поскольку кажется, что она создает заглушку. Дата начала обмена с использованием обратной генерации — 11 апреля 2034 года, а дата начала обмена, которую я указываю, — 10 апреля 2034 года. Это отображается как в моем расписании (фиксированное, так и плавающее).

Продолжая свое исследование, я искал «заглушку» здесь: https://leanpub.com/quantlibpythoncookbook/read и нашел то, что я думаю, является частью ответа. Конструктор Schedule позволяет указать короткие/длинные передние/задние заглушки, но даже если я укажу firstDate как 11 апреля 2034 года, будет выдана та же ошибка. Вот полный код, воспроизводящий ошибку. Как видите, оба моих расписания включают 10 апреля 2034 г. И 11 апреля 2034 г., что, как мне кажется, и является причиной моей проблемы. Я до сих пор не понимаю, почему и как это решить.


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)




person Fredaugermorin    schedule 17.05.2019    source источник
comment
спросили и ответили здесь: github.com/lballabio/QuantLib/issues/633#   -  person Fredaugermorin    schedule 21.05.2019