Я пытаюсь оценить форвардный своп, используя кривую начальной загрузки в среде QuantLib.Для моей оценочной даты 2019-04-04, кривая начальной загрузки работает как ожидалось.Я также могу легко оценить стартовый своп на 10Y10Y.Проблема возникает, когда я пытаюсь оценить форвардный своп на 15Y5Y.Предположим, мой расчет t + 2 (2019-04-08), и я нахожу дату начала форвардного свопа, используя дату расчета и объект календаря, Кажется, что ошибка возникает в основном, когда моя форвардная дата начала падаетвыходные , поэтому в качестве даты начала используйте следующий рабочий день.В нашем случае 2034-04-08 - суббота, поэтому у нас будет своп с начальной датой 2034-04-10.Затем возникает ошибка:
не может рассчитать форвардный курс в период с 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)