• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lballabio / QuantLib / 18902330216

29 Oct 2025 08:56AM UTC coverage: 74.321% (+0.4%) from 73.914%
18902330216

Pull #2344

github

web-flow
Merge a8095fd90 into d823f4ecb
Pull Request #2344: add multicurve bootstrap

100 of 104 new or added lines in 8 files covered. (96.15%)

216 existing lines in 13 files now uncovered.

57073 of 76793 relevant lines covered (74.32%)

8779123.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.92
/ql/termstructures/inflation/inflationhelpers.cpp
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2

3
/*
4
 Copyright (C) 2007, 2009 Chris Kenyon
5
 Copyright (C) 2007 StatPro Italia srl
6

7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9

10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <https://www.quantlib.org/license.shtml>.
15

16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
 */
20

21
#include <ql/cashflows/inflationcouponpricer.hpp>
22
#include <ql/indexes/inflationindex.hpp>
23
#include <ql/pricingengines/swap/discountingswapengine.hpp>
24
#include <ql/shared_ptr.hpp>
25
#include <ql/termstructures/inflation/inflationhelpers.hpp>
26
#include <ql/termstructures/yield/flatforward.hpp>
27
#include <ql/utilities/null_deleter.hpp>
28
#include <utility>
29

30
namespace QuantLib {
31

32
    QL_DEPRECATED_DISABLE_WARNING
33

34
    ZeroCouponInflationSwapHelper::ZeroCouponInflationSwapHelper(
161✔
35
        const Handle<Quote>& quote,
36
        const Period& swapObsLag,
37
        const Date& maturity,
38
        Calendar calendar,
39
        BusinessDayConvention paymentConvention,
40
        DayCounter dayCounter,
41
        const ext::shared_ptr<ZeroInflationIndex>& zii,
42
        CPI::InterpolationType observationInterpolation)
161✔
43
    : ZeroCouponInflationSwapHelper(
44
        quote, swapObsLag, Date(), maturity, std::move(calendar), paymentConvention,
322✔
45
        std::move(dayCounter), zii, observationInterpolation) {}
322✔
46

47
    ZeroCouponInflationSwapHelper::ZeroCouponInflationSwapHelper(
161✔
48
        const Handle<Quote>& quote,
49
        const Period& swapObsLag,
50
        const Date& startDate,
51
        const Date& endDate,
52
        Calendar calendar,
53
        BusinessDayConvention paymentConvention,
54
        DayCounter dayCounter,
55
        const ext::shared_ptr<ZeroInflationIndex>& zii,
56
        CPI::InterpolationType observationInterpolation)
161✔
57
    : ZeroCouponInflationSwapHelper(
58
        quote, swapObsLag, startDate, endDate, std::move(calendar), paymentConvention,
59
        std::move(dayCounter), zii, observationInterpolation,
60
        // any nominal term structure will give the same result;
61
        // when calculating the fair rate, the equal discount factors
62
        // for the payments on the two legs will cancel out.
63
        Handle<YieldTermStructure>(ext::make_shared<FlatForward>(0, NullCalendar(), 0.0, dayCounter))) {}
483✔
64

65
    ZeroCouponInflationSwapHelper::ZeroCouponInflationSwapHelper(
14✔
66
        const Handle<Quote>& quote,
67
        const Period& swapObsLag,
68
        const Date& maturity,
69
        Calendar calendar,
70
        BusinessDayConvention paymentConvention,
71
        DayCounter dayCounter,
72
        const ext::shared_ptr<ZeroInflationIndex>& zii,
73
        CPI::InterpolationType observationInterpolation,
74
        Handle<YieldTermStructure> nominalTermStructure)
14✔
75
    : ZeroCouponInflationSwapHelper(
76
        quote, swapObsLag, Date(), maturity, std::move(calendar), paymentConvention,
28✔
77
        std::move(dayCounter), zii, observationInterpolation, std::move(nominalTermStructure)) {}
28✔
78

79
    ZeroCouponInflationSwapHelper::ZeroCouponInflationSwapHelper(
175✔
80
        const Handle<Quote>& quote,
81
        const Period& swapObsLag,
82
        const Date& startDate,
83
        const Date& endDate,
84
        Calendar calendar,
85
        BusinessDayConvention paymentConvention,
86
        DayCounter dayCounter,
87
        const ext::shared_ptr<ZeroInflationIndex>& zii,
88
        CPI::InterpolationType observationInterpolation,
89
        Handle<YieldTermStructure> nominalTermStructure)
175✔
90
    : RelativeDateBootstrapHelper<ZeroInflationTermStructure>(quote, startDate == Date()),
350✔
91
      swapObsLag_(swapObsLag), startDate_(startDate), maturity_(endDate),
175✔
92
      calendar_(std::move(calendar)), paymentConvention_(paymentConvention),
175✔
93
      dayCounter_(std::move(dayCounter)), observationInterpolation_(observationInterpolation),
175✔
94
      nominalTermStructure_(std::move(nominalTermStructure)) {
350✔
95
        zii_ = zii->clone(termStructureHandle_);
175✔
96
        // We want to be notified of changes of fixings, but we don't
97
        // want notifications from termStructureHandle_ (they would
98
        // interfere with bootstrapping.)
99
        zii_->unregisterWith(termStructureHandle_);
175✔
100

101
        auto fixingPeriod = inflationPeriod(maturity_ - swapObsLag_, zii_->frequency());
175✔
102
        auto interpolationPeriod = inflationPeriod(maturity_, zii_->frequency());
175✔
103

104
        if (detail::CPI::isInterpolated(observationInterpolation_) && maturity_ > interpolationPeriod.first) {
175✔
105
            // if interpolated, we need to cover the end of the interpolation period
UNCOV
106
            earliestDate_ = fixingPeriod.first;
×
UNCOV
107
            latestDate_ = fixingPeriod.second + 1;
×
108
        } else {
109
            // if not interpolated, the date of the initial fixing is enough
110
            earliestDate_ = fixingPeriod.first;
175✔
111
            latestDate_ = fixingPeriod.first;
175✔
112
        }
113

114
        // check that the observation lag of the swap
115
        // is compatible with the availability lag of the index AND
116
        // it's interpolation (assuming the start day is spot)
117
        if (detail::CPI::isInterpolated(observationInterpolation_)) {
175✔
UNCOV
118
            Period pShift(zii_->frequency());
×
UNCOV
119
            QL_REQUIRE(swapObsLag_ - pShift >= zii_->availabilityLag(),
×
120
                       "inconsistency between swap observation lag "
121
                           << swapObsLag_ << ", index period " << pShift << " and index availability "
122
                           << zii_->availabilityLag() << ": need (obsLag-index period) >= availLag");
123
        }
124

125
        registerWith(zii_);
350✔
126
        registerWith(nominalTermStructure_);
175✔
127
        ZeroCouponInflationSwapHelper::initializeDates();
175✔
128
    }
175✔
129

130
    QL_DEPRECATED_ENABLE_WARNING
131

132

133
    Real ZeroCouponInflationSwapHelper::impliedQuote() const {
1,533✔
134
        zciis_->deepUpdate();
1,533✔
135
        return zciis_->fairRate();
1,533✔
136
    }
137

138
    void ZeroCouponInflationSwapHelper::initializeDates() {
175✔
139
        zciis_ = ext::make_shared<ZeroCouponInflationSwap>(
175✔
140
            Swap::Payer, 1.0, updateDates_ ? evaluationDate_ : startDate_, maturity_, calendar_,
175✔
141
            paymentConvention_, dayCounter_, 0.0, zii_, swapObsLag_,
350✔
142
            observationInterpolation_);
350✔
143
        // The instrument takes a standard discounting swap engine.
144
        // The inflation-related work is done by the coupons.
145
        zciis_->setPricingEngine(
525✔
146
            ext::make_shared<DiscountingSwapEngine>(nominalTermStructure_));
175✔
147
    }
175✔
148

149
    void ZeroCouponInflationSwapHelper::setTermStructure(ZeroInflationTermStructure* z) {
251✔
150
        // do not set the relinkable handle as an observer -
151
        // force recalculation when needed
152
        bool observer = false;
153

154
        ext::shared_ptr<ZeroInflationTermStructure> temp(z, null_deleter());
155
        termStructureHandle_.linkTo(std::move(temp), observer);
251✔
156

157
        RelativeDateBootstrapHelper<ZeroInflationTermStructure>::setTermStructure(z);
251✔
158
    }
251✔
159

160

161
    YearOnYearInflationSwapHelper::YearOnYearInflationSwapHelper(
165✔
162
        const Handle<Quote>& quote,
163
        const Period& swapObsLag,
164
        const Date& maturity,
165
        Calendar calendar,
166
        BusinessDayConvention paymentConvention,
167
        DayCounter dayCounter,
168
        const ext::shared_ptr<YoYInflationIndex>& yii,
169
        CPI::InterpolationType interpolation,
170
        Handle<YieldTermStructure> nominalTermStructure)
165✔
171
    : YearOnYearInflationSwapHelper(
172
        quote, swapObsLag, Date(), maturity, std::move(calendar), paymentConvention,
330✔
173
        std::move(dayCounter), yii, interpolation, std::move(nominalTermStructure)) {}
330✔
174

175
    YearOnYearInflationSwapHelper::YearOnYearInflationSwapHelper(
165✔
176
        const Handle<Quote>& quote,
177
        const Period& swapObsLag,
178
        const Date& startDate,
179
        const Date& endDate,
180
        Calendar calendar,
181
        BusinessDayConvention paymentConvention,
182
        DayCounter dayCounter,
183
        const ext::shared_ptr<YoYInflationIndex>& yii,
184
        CPI::InterpolationType interpolation,
185
        Handle<YieldTermStructure> nominalTermStructure)
165✔
186
    : RelativeDateBootstrapHelper<YoYInflationTermStructure>(quote, startDate == Date()),
330✔
187
      swapObsLag_(swapObsLag), startDate_(startDate), maturity_(endDate),
165✔
188
      calendar_(std::move(calendar)), paymentConvention_(paymentConvention),
165✔
189
      dayCounter_(std::move(dayCounter)), interpolation_(interpolation),
165✔
190
      nominalTermStructure_(std::move(nominalTermStructure)) {
330✔
191
        yii_ = yii->clone(termStructureHandle_);
165✔
192
        // We want to be notified of changes of fixings, but we don't
193
        // want notifications from termStructureHandle_ (they would
194
        // interfere with bootstrapping.)
195
        yii_->unregisterWith(termStructureHandle_);
165✔
196

197
        auto fixingPeriod = inflationPeriod(maturity_ - swapObsLag_, yii_->frequency());
165✔
198
        auto interpolationPeriod = inflationPeriod(maturity_, yii_->frequency());
165✔
199

200
        if (detail::CPI::isInterpolated(interpolation_, yii_) && maturity_ > interpolationPeriod.first) {
165✔
201
            // if interpolated, we need to cover the end of the interpolation period
202
            earliestDate_ = fixingPeriod.first;
60✔
203
            latestDate_ = fixingPeriod.second + 1;
60✔
204
        } else {
205
            // if not interpolated, the date of the initial fixing is enough
206
            earliestDate_ = fixingPeriod.first;
105✔
207
            latestDate_ = fixingPeriod.first;
105✔
208
        }
209

210
        // check that the observation lag of the swap
211
        // is compatible with the availability lag of the index AND
212
        // its interpolation (assuming the start day is spot)
213
        if (detail::CPI::isInterpolated(interpolation_, yii_)) {
165✔
214
            Period pShift(yii_->frequency());
60✔
215
            QL_REQUIRE(swapObsLag_ - pShift >= yii_->availabilityLag(),
120✔
216
                       "inconsistency between swap observation lag "
217
                       << swapObsLag_ << ", index period " << pShift << " and index availability "
218
                       << yii_->availabilityLag() << ": need (obsLag-index period) >= availLag");
219
        }
220

221
        registerWith(yii_);
330✔
222
        registerWith(nominalTermStructure_);
165✔
223
        YearOnYearInflationSwapHelper::initializeDates();
165✔
224
    }
165✔
225

226
    Real YearOnYearInflationSwapHelper::impliedQuote() const {
970✔
227
        yyiis_->deepUpdate();
970✔
228
        return yyiis_->fairRate();
970✔
229
    }
230

231
    void YearOnYearInflationSwapHelper::initializeDates() {
165✔
232
        // always works because tenor is always 1 year so
233
        // no problem with different days-in-month
234
        Schedule fixedSchedule = MakeSchedule()
165✔
235
                                     .from(updateDates_ ? evaluationDate_ : startDate_)
165✔
236
                                     .to(maturity_)
165✔
237
                                     .withTenor(1 * Years)
330✔
238
                                     .withConvention(Unadjusted)
165✔
239
                                     .withCalendar(calendar_) // fixed leg gets cal from sched
165✔
240
                                     .backwards();
165✔
241
        const Schedule& yoySchedule = fixedSchedule;
242

243
        yyiis_ = ext::make_shared<YearOnYearInflationSwap>(
330✔
244
            Swap::Payer, 1.0, fixedSchedule, 0.0, dayCounter_,
330✔
245
            yoySchedule, yii_, swapObsLag_, interpolation_,
165✔
246
            0.0, dayCounter_, calendar_, paymentConvention_);
165✔
247

248
        // The instrument takes a standard discounting swap engine.
249
        // The inflation-related work is done by the coupons.
250
        yyiis_->setPricingEngine(
495✔
251
            ext::make_shared<DiscountingSwapEngine>(nominalTermStructure_));
165✔
252
    }
165✔
253

254
    void YearOnYearInflationSwapHelper::setTermStructure(YoYInflationTermStructure* y) {
165✔
255
        // do not set the relinkable handle as an observer -
256
        // force recalculation when needed
257
        bool observer = false;
258

259
        ext::shared_ptr<YoYInflationTermStructure> temp(y, null_deleter());
260
        termStructureHandle_.linkTo(std::move(temp), observer);
165✔
261

262
        RelativeDateBootstrapHelper<YoYInflationTermStructure>::setTermStructure(y);
165✔
263
    }
165✔
264

265
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc