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

lballabio / QuantLib / 8467932009

28 Mar 2024 01:18PM UTC coverage: 72.497% (+0.07%) from 72.426%
8467932009

Pull #1593

github

web-flow
Merge 9b4efa33c into d6f6c13a5
Pull Request #1593: allow swaptions to take OvernightIndexedSwap

103 of 127 new or added lines in 13 files covered. (81.1%)

373 existing lines in 21 files now uncovered.

54966 of 75818 relevant lines covered (72.5%)

8708317.57 hits per line

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

63.51
/ql/termstructures/yield/ratehelpers.cpp
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2

3
/*
4
 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
5
 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 StatPro Italia srl
6
 Copyright (C) 2007, 2008, 2009, 2015 Ferdinando Ametrano
7
 Copyright (C) 2007, 2009 Roland Lichters
8
 Copyright (C) 2015 Maddalena Zanzi
9
 Copyright (C) 2015 Paolo Mazzocchi
10
 Copyright (C) 2018 Matthias Lungwitz
11

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

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

21
 This program is distributed in the hope that it will be useful, but WITHOUT
22
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23
 FOR A PARTICULAR PURPOSE.  See the license for more details.
24
*/
25

26
#include <ql/cashflows/iborcoupon.hpp>
27
#include <ql/currency.hpp>
28
#include <ql/indexes/swapindex.hpp>
29
#include <ql/instruments/makevanillaswap.hpp>
30
#include <ql/instruments/simplifynotificationgraph.hpp>
31
#include <ql/optional.hpp>
32
#include <ql/pricingengines/swap/discountingswapengine.hpp>
33
#include <ql/quote.hpp>
34
#include <ql/termstructures/yield/ratehelpers.hpp>
35
#include <ql/time/asx.hpp>
36
#include <ql/time/calendars/jointcalendar.hpp>
37
#include <ql/time/imm.hpp>
38
#include <ql/utilities/null_deleter.hpp>
39
#include <utility>
40

41
namespace QuantLib {
42

43
    namespace {
44

45
        void CheckDate(const Date& date, const Futures::Type type) {
93✔
46
            switch (type) {
93✔
47
              case Futures::IMM:
48✔
48
                QL_REQUIRE(IMM::isIMMdate(date, false), date << " is not a valid IMM date");
48✔
49
                break;
50
              case Futures::ASX:
45✔
51
                QL_REQUIRE(ASX::isASXdate(date, false), date << " is not a valid ASX date");
45✔
52
                break;
53
              case Futures::Custom:
54
                break;
UNCOV
55
              default:
×
UNCOV
56
                QL_FAIL("unknown futures type (" << type << ')');
×
57
            }
58
        }
93✔
59

60
        Time DetermineYearFraction(const Date& earliestDate,
93✔
61
                                   const Date& maturityDate,
62
                                   const DayCounter& dayCounter) {
63
            return dayCounter.yearFraction(earliestDate, maturityDate,
93✔
64
                                           earliestDate, maturityDate);
93✔
65
        }
66

67
    } // namespace
68

UNCOV
69
    FuturesRateHelper::FuturesRateHelper(const Handle<Quote>& price,
×
70
                                         const Date& iborStartDate,
71
                                         Natural lengthInMonths,
72
                                         const Calendar& calendar,
73
                                         BusinessDayConvention convention,
74
                                         bool endOfMonth,
75
                                         const DayCounter& dayCounter,
76
                                         Handle<Quote> convAdj,
77
                                         Futures::Type type)
×
UNCOV
78
    : RateHelper(price), convAdj_(std::move(convAdj)) {
×
79
        CheckDate(iborStartDate, type);
×
80

81
        earliestDate_ = iborStartDate;
×
82
        maturityDate_ =
83
            calendar.advance(iborStartDate, lengthInMonths * Months, convention, endOfMonth);
×
UNCOV
84
        yearFraction_ = DetermineYearFraction(earliestDate_, maturityDate_, dayCounter);
×
85
        pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
×
86

UNCOV
87
        registerWith(convAdj_);
×
88
    }
×
89

UNCOV
90
    FuturesRateHelper::FuturesRateHelper(Real price,
×
91
                                         const Date& iborStartDate,
92
                                         Natural lengthInMonths,
93
                                         const Calendar& calendar,
94
                                         BusinessDayConvention convention,
95
                                         bool endOfMonth,
96
                                         const DayCounter& dayCounter,
97
                                         Rate convAdj,
UNCOV
98
                                         Futures::Type type)
×
UNCOV
99
    : FuturesRateHelper(makeQuoteHandle(price), iborStartDate, lengthInMonths, calendar,
×
100
                        convention, endOfMonth, dayCounter, makeQuoteHandle(convAdj), type) {}
×
101

102
    FuturesRateHelper::FuturesRateHelper(const Handle<Quote>& price,
×
103
                                         const Date& iborStartDate,
104
                                         const Date& iborEndDate,
105
                                         const DayCounter& dayCounter,
106
                                         Handle<Quote> convAdj,
107
                                         Futures::Type type)
×
108
    : RateHelper(price), convAdj_(std::move(convAdj)) {
×
109
        CheckDate(iborStartDate, type);
×
110

111
        const auto determineMaturityDate =
112
            [&iborStartDate, &iborEndDate](const auto nextDateCalculator) -> Date {
×
113
                Date maturityDate;
×
114
                if (iborEndDate == Date()) {
×
115
                    // advance 3 months
116
                    maturityDate = nextDateCalculator(iborStartDate);
×
117
                    maturityDate = nextDateCalculator(maturityDate);
×
118
                    maturityDate = nextDateCalculator(maturityDate);
×
119
                } else {
120
                    QL_REQUIRE(iborEndDate > iborStartDate,
×
121
                               "end date (" << iborEndDate << ") must be greater than start date ("
122
                                            << iborStartDate << ')');
123
                    maturityDate = iborEndDate;
×
124
                }
125
                return maturityDate;
×
126
            };
×
127

128
        switch (type) {
×
129
          case Futures::IMM:
×
130
            maturityDate_ = determineMaturityDate(
×
131
                [](const Date date) -> Date { return IMM::nextDate(date, false); });
×
132
            break;
133
          case Futures::ASX:
×
134
            maturityDate_ = determineMaturityDate(
×
135
                [](const Date date) -> Date { return ASX::nextDate(date, false); });
×
136
            break;
137
          default:
×
138
            QL_FAIL("unsupported futures type (" << type << ')');
×
139
        }
140
        earliestDate_ = iborStartDate;
×
141
        yearFraction_ = DetermineYearFraction(earliestDate_, maturityDate_, dayCounter);
×
142
        pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
×
143

144
        registerWith(convAdj_);
×
145
    }
×
146

147
    FuturesRateHelper::FuturesRateHelper(Real price,
×
148
                                         const Date& iborStartDate,
149
                                         const Date& iborEndDate,
150
                                         const DayCounter& dayCounter,
151
                                         Rate convAdj,
152
                                         Futures::Type type)
×
153
    : FuturesRateHelper(makeQuoteHandle(price), iborStartDate, iborEndDate, dayCounter,
×
UNCOV
154
                        makeQuoteHandle(convAdj), type) {}
×
155

156
    FuturesRateHelper::FuturesRateHelper(const Handle<Quote>& price,
93✔
157
                                         const Date& iborStartDate,
158
                                         const ext::shared_ptr<IborIndex>& index,
159
                                         const Handle<Quote>& convAdj,
160
                                         Futures::Type type)
93✔
161
    : RateHelper(price), convAdj_(convAdj) {
186✔
162
        CheckDate(iborStartDate, type);
93✔
163

164
        earliestDate_ = iborStartDate;
93✔
165
        const Calendar& cal = index->fixingCalendar();
93✔
166
        maturityDate_ =
167
            cal.advance(iborStartDate, index->tenor(), index->businessDayConvention());
93✔
168
        yearFraction_ = DetermineYearFraction(earliestDate_, maturityDate_, index->dayCounter());
93✔
169
        pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
93✔
170

171
        registerWith(convAdj);
186✔
172
    }
93✔
173

UNCOV
174
    FuturesRateHelper::FuturesRateHelper(Real price,
×
175
                                         const Date& iborStartDate,
176
                                         const ext::shared_ptr<IborIndex>& index,
177
                                         Rate convAdj,
UNCOV
178
                                         Futures::Type type)
×
179
    : FuturesRateHelper(makeQuoteHandle(price), iborStartDate, index, makeQuoteHandle(convAdj), type) {}
×
180

181
    Real FuturesRateHelper::impliedQuote() const {
808✔
182
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
808✔
183
        Rate forwardRate = (termStructure_->discount(earliestDate_) /
808✔
184
            termStructure_->discount(maturityDate_) - 1.0) / yearFraction_;
808✔
185
        // Convexity, as FRA/futures adjustment, has been used in the
186
        // past to take into account futures margining vs FRA.
187
        // Therefore, there's no requirement for it to be non-negative.
188
        Rate futureRate = forwardRate + convexityAdjustment();
808✔
189
        return 100.0 * (1.0 - futureRate);
808✔
190
    }
191

192
    Real FuturesRateHelper::convexityAdjustment() const {
808✔
193
        return convAdj_.empty() ? 0.0 : convAdj_->value();
808✔
194
    }
195

196
    void FuturesRateHelper::accept(AcyclicVisitor& v) {
×
197
        auto* v1 = dynamic_cast<Visitor<FuturesRateHelper>*>(&v);
×
UNCOV
198
        if (v1 != nullptr)
×
UNCOV
199
            v1->visit(*this);
×
200
        else
201
            RateHelper::accept(v);
×
202
    }
×
203

204
    DepositRateHelper::DepositRateHelper(const Handle<Quote>& rate,
290✔
205
                                         const Period& tenor,
206
                                         Natural fixingDays,
207
                                         const Calendar& calendar,
208
                                         BusinessDayConvention convention,
209
                                         bool endOfMonth,
210
                                         const DayCounter& dayCounter)
290✔
211
    : RelativeDateRateHelper(rate) {
290✔
212
        iborIndex_ = ext::make_shared<IborIndex>("no-fix", // never take fixing into account
580✔
213
                      tenor, fixingDays,
214
                      Currency(), calendar, convention,
290✔
215
                      endOfMonth, dayCounter, termStructureHandle_);
290✔
216
        DepositRateHelper::initializeDates();
290✔
217
    }
290✔
218

219
    DepositRateHelper::DepositRateHelper(Rate rate,
77✔
220
                                         const Period& tenor,
221
                                         Natural fixingDays,
222
                                         const Calendar& calendar,
223
                                         BusinessDayConvention convention,
224
                                         bool endOfMonth,
225
                                         const DayCounter& dayCounter)
77✔
226
    : DepositRateHelper(makeQuoteHandle(rate), tenor, fixingDays, calendar, convention,
154✔
227
                        endOfMonth, dayCounter) {}
154✔
228

229
    DepositRateHelper::DepositRateHelper(const Handle<Quote>& rate,
90✔
230
                                         const ext::shared_ptr<IborIndex>& i)
90✔
231
    : RelativeDateRateHelper(rate) {
90✔
232
        iborIndex_ = i->clone(termStructureHandle_);
90✔
233
        DepositRateHelper::initializeDates();
90✔
234
    }
90✔
235

UNCOV
236
    DepositRateHelper::DepositRateHelper(Rate rate,
×
UNCOV
237
                                         const ext::shared_ptr<IborIndex>& i)
×
UNCOV
238
    : DepositRateHelper(makeQuoteHandle(rate), i) {}
×
239

240
    Real DepositRateHelper::impliedQuote() const {
3,624✔
241
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
3,624✔
242
        // the forecast fixing flag is set to true because
243
        // we do not want to take fixing into account
244
        return iborIndex_->fixing(fixingDate_, true);
3,624✔
245
    }
246

247
    void DepositRateHelper::setTermStructure(YieldTermStructure* t) {
527✔
248
        // do not set the relinkable handle as an observer -
249
        // force recalculation when needed---the index is not lazy
250
        bool observer = false;
251

252
        ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
253
        termStructureHandle_.linkTo(temp, observer);
527✔
254

255
        RelativeDateRateHelper::setTermStructure(t);
527✔
256
    }
527✔
257

258
    void DepositRateHelper::initializeDates() {
567✔
259
        // if the evaluation date is not a business day
260
        // then move to the next business day
261
        Date referenceDate =
262
            iborIndex_->fixingCalendar().adjust(evaluationDate_);
567✔
263
        earliestDate_ = iborIndex_->valueDate(referenceDate);
567✔
264
        fixingDate_ = iborIndex_->fixingDate(earliestDate_);
567✔
265
        maturityDate_ = iborIndex_->maturityDate(earliestDate_);
567✔
266
        pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
567✔
267
    }
567✔
268

UNCOV
269
    void DepositRateHelper::accept(AcyclicVisitor& v) {
×
UNCOV
270
        auto* v1 = dynamic_cast<Visitor<DepositRateHelper>*>(&v);
×
UNCOV
271
        if (v1 != nullptr)
×
UNCOV
272
            v1->visit(*this);
×
273
        else
UNCOV
274
            RateHelper::accept(v);
×
UNCOV
275
    }
×
276

277

278
    FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
330✔
279
                                 Natural monthsToStart,
280
                                 Natural monthsToEnd,
281
                                 Natural fixingDays,
282
                                 const Calendar& calendar,
283
                                 BusinessDayConvention convention,
284
                                 bool endOfMonth,
285
                                 const DayCounter& dayCounter,
286
                                 Pillar::Choice pillarChoice,
287
                                 Date customPillarDate,
288
                                 bool useIndexedCoupon)
330✔
289
    : FraRateHelper(rate, monthsToStart*Months, monthsToEnd-monthsToStart, fixingDays, calendar,
290
        convention, endOfMonth, dayCounter, pillarChoice, customPillarDate, useIndexedCoupon) {
330✔
291
        QL_REQUIRE(monthsToEnd>monthsToStart,
330✔
292
                   "monthsToEnd (" << monthsToEnd <<
293
                   ") must be grater than monthsToStart (" << monthsToStart <<
294
                   ")");
295
    }
330✔
296

UNCOV
297
    FraRateHelper::FraRateHelper(Rate rate,
×
298
                                 Natural monthsToStart,
299
                                 Natural monthsToEnd,
300
                                 Natural fixingDays,
301
                                 const Calendar& calendar,
302
                                 BusinessDayConvention convention,
303
                                 bool endOfMonth,
304
                                 const DayCounter& dayCounter,
305
                                 Pillar::Choice pillarChoice,
306
                                 Date customPillarDate,
UNCOV
307
                                 bool useIndexedCoupon)
×
UNCOV
308
    : FraRateHelper(makeQuoteHandle(rate), monthsToStart, monthsToEnd, fixingDays, calendar,
×
UNCOV
309
                    convention, endOfMonth, dayCounter, pillarChoice, customPillarDate, useIndexedCoupon) {}
×
310

311
    FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
18✔
312
                                 Natural monthsToStart,
313
                                 const ext::shared_ptr<IborIndex>& i,
314
                                 Pillar::Choice pillarChoice,
315
                                 Date customPillarDate,
316
                                 bool useIndexedCoupon)
18✔
317
    : FraRateHelper(rate, monthsToStart*Months, i, pillarChoice, customPillarDate, useIndexedCoupon)
18✔
318
    {}
18✔
319

UNCOV
320
    FraRateHelper::FraRateHelper(Rate rate,
×
321
                                 Natural monthsToStart,
322
                                 const ext::shared_ptr<IborIndex>& i,
323
                                 Pillar::Choice pillarChoice,
324
                                 Date customPillarDate,
UNCOV
325
                                 bool useIndexedCoupon)
×
UNCOV
326
    : FraRateHelper(makeQuoteHandle(rate), monthsToStart, i, pillarChoice, customPillarDate, useIndexedCoupon) {}
×
327

328
    FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
330✔
329
                                 Period periodToStart,
330
                                 Natural lengthInMonths,
331
                                 Natural fixingDays,
332
                                 const Calendar& calendar,
333
                                 BusinessDayConvention convention,
334
                                 bool endOfMonth,
335
                                 const DayCounter& dayCounter,
336
                                 Pillar::Choice pillarChoice,
337
                                 Date customPillarDate,
338
                                 bool useIndexedCoupon)
330✔
339
    : RelativeDateRateHelper(rate), periodToStart_(periodToStart),
340
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
330✔
341
        // no way to take fixing into account,
342
        // even if we would like to for FRA over today
343
        iborIndex_ = ext::make_shared<IborIndex>("no-fix", // correct family name would be needed
660✔
344
                      lengthInMonths*Months,
660✔
345
                      fixingDays,
346
                      Currency(), calendar, convention,
330✔
347
                      endOfMonth, dayCounter, termStructureHandle_);
330✔
348
        pillarDate_ = customPillarDate;
330✔
349
        FraRateHelper::initializeDates();
330✔
350
    }
330✔
351

UNCOV
352
    FraRateHelper::FraRateHelper(Rate rate,
×
353
                                 Period periodToStart,
354
                                 Natural lengthInMonths,
355
                                 Natural fixingDays,
356
                                 const Calendar& calendar,
357
                                 BusinessDayConvention convention,
358
                                 bool endOfMonth,
359
                                 const DayCounter& dayCounter,
360
                                 Pillar::Choice pillarChoice,
361
                                 Date customPillarDate,
UNCOV
362
                                 bool useIndexedCoupon)
×
UNCOV
363
    : FraRateHelper(makeQuoteHandle(rate), periodToStart, lengthInMonths, fixingDays, calendar,
×
UNCOV
364
                    convention, endOfMonth, dayCounter, pillarChoice, customPillarDate, useIndexedCoupon) {}
×
365

366
    FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
40✔
367
                                 Period periodToStart,
368
                                 const ext::shared_ptr<IborIndex>& i,
369
                                 Pillar::Choice pillarChoice,
370
                                 Date customPillarDate,
371
                                 bool useIndexedCoupon)
40✔
372
    : RelativeDateRateHelper(rate), periodToStart_(periodToStart),
373
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
40✔
374
        // take fixing into account
375
        iborIndex_ = i->clone(termStructureHandle_);
40✔
376
        // We want to be notified of changes of fixings, but we don't
377
        // want notifications from termStructureHandle_ (they would
378
        // interfere with bootstrapping.)
379
        iborIndex_->unregisterWith(termStructureHandle_);
40✔
380
        registerWith(iborIndex_);
40✔
381
        pillarDate_ = customPillarDate;
40✔
382
        FraRateHelper::initializeDates();
40✔
383
    }
40✔
384

385
    FraRateHelper::FraRateHelper(Rate rate,
19✔
386
                                 Period periodToStart,
387
                                 const ext::shared_ptr<IborIndex>& i,
388
                                 Pillar::Choice pillarChoice,
389
                                 Date customPillarDate,
390
                                 bool useIndexedCoupon)
19✔
391
    : FraRateHelper(makeQuoteHandle(rate), periodToStart, i, pillarChoice, customPillarDate, useIndexedCoupon) {}
38✔
392

UNCOV
393
    FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
×
394
                                 Natural immOffsetStart,
395
                                 Natural immOffsetEnd,
396
                                 const ext::shared_ptr<IborIndex>& i,
397
                                 Pillar::Choice pillarChoice,
398
                                 Date customPillarDate,
UNCOV
399
                                 bool useIndexedCoupon)
×
400
    : RelativeDateRateHelper(rate), immOffsetStart_(immOffsetStart), immOffsetEnd_(immOffsetEnd),
401
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
×
402
        // take fixing into account
403
        iborIndex_ = i->clone(termStructureHandle_);
×
404
        // see above
UNCOV
405
        iborIndex_->unregisterWith(termStructureHandle_);
×
406
        registerWith(iborIndex_);
×
UNCOV
407
        pillarDate_ = customPillarDate;
×
UNCOV
408
        FraRateHelper::initializeDates();
×
UNCOV
409
    }
×
410

UNCOV
411
    FraRateHelper::FraRateHelper(Rate rate,
×
412
                                 Natural immOffsetStart,
413
                                 Natural immOffsetEnd,
414
                                 const ext::shared_ptr<IborIndex>& i,
415
                                 Pillar::Choice pillarChoice,
416
                                 Date customPillarDate,
UNCOV
417
                                 bool useIndexedCoupon)
×
418
    : FraRateHelper(makeQuoteHandle(rate), immOffsetStart, immOffsetEnd, i, pillarChoice,
×
UNCOV
419
                    customPillarDate, useIndexedCoupon) {}
×
420

421
    Real FraRateHelper::impliedQuote() const {
8,719✔
422
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
8,719✔
423
        if (useIndexedCoupon_)
8,719✔
424
            return iborIndex_->fixing(fixingDate_, true);
7,958✔
425
        else
426
            return (termStructure_->discount(earliestDate_) /
761✔
427
                        termStructure_->discount(maturityDate_) -
761✔
428
                    1.0) /
429
                   spanningTime_;
761✔
430
    }
431

432
    void FraRateHelper::setTermStructure(YieldTermStructure* t) {
363✔
433
        // do not set the relinkable handle as an observer -
434
        // force recalculation when needed---the index is not lazy
435
        bool observer = false;
436

437
        ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
438
        termStructureHandle_.linkTo(temp, observer);
363✔
439

440
        RelativeDateRateHelper::setTermStructure(t);
363✔
441
    }
363✔
442

443
    namespace {
UNCOV
444
        Date nthImmDate(const Date& asof, const Size n) {
×
UNCOV
445
            Date imm = asof;
×
UNCOV
446
            for (Size i = 0; i < n; ++i) {
×
UNCOV
447
                imm = IMM::nextDate(imm, true);
×
448
            }
UNCOV
449
            return imm;
×
450
        }
451
    }
452

453
    void FraRateHelper::initializeDates() {
610✔
454
        // if the evaluation date is not a business day
455
        // then move to the next business day
456
        Date referenceDate =
457
            iborIndex_->fixingCalendar().adjust(evaluationDate_);
610✔
458
        Date spotDate = iborIndex_->fixingCalendar().advance(
1,220✔
459
            referenceDate, iborIndex_->fixingDays()*Days);
610✔
460
        if (periodToStart_) { // NOLINT(readability-implicit-bool-conversion)
610✔
461
            earliestDate_ = iborIndex_->fixingCalendar().advance(
1,830✔
462
                spotDate, *periodToStart_, iborIndex_->businessDayConvention(),
610✔
463
                iborIndex_->endOfMonth());
610✔
464
            // maturity date is calculated from spot date
465
            maturityDate_ = iborIndex_->fixingCalendar().advance(
2,440✔
466
                spotDate, *periodToStart_ + iborIndex_->tenor(), iborIndex_->businessDayConvention(),
1,220✔
467
                iborIndex_->endOfMonth());
610✔
468

UNCOV
469
        } else if ((immOffsetStart_) && (immOffsetEnd_)) { // NOLINT(readability-implicit-bool-conversion)
×
470
            earliestDate_ = iborIndex_->fixingCalendar().adjust(nthImmDate(spotDate, *immOffsetStart_));
×
UNCOV
471
            maturityDate_ = iborIndex_->fixingCalendar().adjust(nthImmDate(spotDate, *immOffsetEnd_));
×
472
        } else {
UNCOV
473
            QL_FAIL("neither periodToStart nor immOffsetStart/End given");
×
474
        }
475

476
        if (useIndexedCoupon_)
610✔
477
            // latest relevant date is calculated from earliestDate_
478
            latestRelevantDate_ = iborIndex_->maturityDate(earliestDate_);
565✔
479
        else {
480
            latestRelevantDate_ = maturityDate_;
45✔
481
            spanningTime_ = iborIndex_->dayCounter().yearFraction(earliestDate_, maturityDate_);
45✔
482
        }
483

484
        switch (pillarChoice_) {
610✔
UNCOV
485
          case Pillar::MaturityDate:
×
UNCOV
486
            pillarDate_ = maturityDate_;
×
UNCOV
487
            break;
×
488
          case Pillar::LastRelevantDate:
610✔
489
            pillarDate_ = latestRelevantDate_;
610✔
490
            break;
610✔
UNCOV
491
          case Pillar::CustomDate:
×
492
            // pillarDate_ already assigned at construction time
UNCOV
493
            QL_REQUIRE(pillarDate_ >= earliestDate_,
×
494
                       "pillar date (" << pillarDate_ << ") must be later "
495
                       "than or equal to the instrument's earliest date (" <<
496
                       earliestDate_ << ")");
497
            QL_REQUIRE(pillarDate_ <= latestRelevantDate_,
×
498
                       "pillar date (" << pillarDate_ << ") must be before "
499
                       "or equal to the instrument's latest relevant date (" <<
500
                       latestRelevantDate_ << ")");
501
            break;
UNCOV
502
          default:
×
UNCOV
503
            QL_FAIL("unknown Pillar::Choice(" << Integer(pillarChoice_) << ")");
×
504
        }
505

506
        latestDate_ = pillarDate_; // backward compatibility
610✔
507

508
        fixingDate_ = iborIndex_->fixingDate(earliestDate_);
610✔
509
    }
610✔
510

UNCOV
511
    void FraRateHelper::accept(AcyclicVisitor& v) {
×
UNCOV
512
        auto* v1 = dynamic_cast<Visitor<FraRateHelper>*>(&v);
×
UNCOV
513
        if (v1 != nullptr)
×
UNCOV
514
            v1->visit(*this);
×
515
        else
UNCOV
516
            RateHelper::accept(v);
×
UNCOV
517
    }
×
518

519

UNCOV
520
    SwapRateHelper::SwapRateHelper(const Handle<Quote>& rate,
×
521
                                   const ext::shared_ptr<SwapIndex>& swapIndex,
522
                                   Handle<Quote> spread,
523
                                   const Period& fwdStart,
524
                                   Handle<YieldTermStructure> discount,
525
                                   Pillar::Choice pillarChoice,
526
                                   Date customPillarDate,
527
                                   bool endOfMonth,
528
                                   const ext::optional<bool>& useIndexedCoupons)
×
UNCOV
529
    : SwapRateHelper(rate, swapIndex->tenor(), swapIndex->fixingCalendar(),
×
UNCOV
530
        swapIndex->fixedLegTenor().frequency(), swapIndex->fixedLegConvention(),
×
UNCOV
531
        swapIndex->dayCounter(), swapIndex->iborIndex(), std::move(spread), fwdStart,
×
532
        std::move(discount), Null<Natural>(), pillarChoice, customPillarDate, endOfMonth,
UNCOV
533
        useIndexedCoupons) {}
×
534

535
    SwapRateHelper::SwapRateHelper(const Handle<Quote>& rate,
1,085✔
536
                                   const Period& tenor,
537
                                   Calendar calendar,
538
                                   Frequency fixedFrequency,
539
                                   BusinessDayConvention fixedConvention,
540
                                   DayCounter fixedDayCount,
541
                                   const ext::shared_ptr<IborIndex>& iborIndex,
542
                                   Handle<Quote> spread,
543
                                   const Period& fwdStart,
544
                                   Handle<YieldTermStructure> discount,
545
                                   Natural settlementDays,
546
                                   Pillar::Choice pillarChoice,
547
                                   Date customPillarDate,
548
                                   bool endOfMonth,
549
                                   const ext::optional<bool>& useIndexedCoupons)
1,085✔
550
    : RelativeDateRateHelper(rate), settlementDays_(settlementDays), tenor_(tenor),
1,085✔
551
      pillarChoice_(pillarChoice), calendar_(std::move(calendar)),
1,085✔
552
      fixedConvention_(fixedConvention), fixedFrequency_(fixedFrequency),
1,085✔
553
      fixedDayCount_(std::move(fixedDayCount)), spread_(std::move(spread)), endOfMonth_(endOfMonth),
1,085✔
554
      fwdStart_(fwdStart), discountHandle_(std::move(discount)),
1,085✔
555
      useIndexedCoupons_(useIndexedCoupons) {
2,170✔
556

557
        // take fixing into account
558
        iborIndex_ = iborIndex->clone(termStructureHandle_);
1,085✔
559
        // We want to be notified of changes of fixings, but we don't
560
        // want notifications from termStructureHandle_ (they would
561
        // interfere with bootstrapping.)
562
        iborIndex_->unregisterWith(termStructureHandle_);
1,085✔
563

564
        registerWith(iborIndex_);
2,170✔
565
        registerWith(spread_);
2,170✔
566
        registerWith(discountHandle_);
1,085✔
567

568
        pillarDate_ = customPillarDate;
1,085✔
569
        SwapRateHelper::initializeDates();
1,085✔
570
    }
1,085✔
571

572
    SwapRateHelper::SwapRateHelper(Rate rate,
×
573
                                   const ext::shared_ptr<SwapIndex>& swapIndex,
574
                                   Handle<Quote> spread,
575
                                   const Period& fwdStart,
576
                                   Handle<YieldTermStructure> discount,
577
                                   Pillar::Choice pillarChoice,
578
                                   Date customPillarDate,
579
                                   bool endOfMonth,
UNCOV
580
                                   const ext::optional<bool>& useIndexedCoupons)
×
581
    : SwapRateHelper(makeQuoteHandle(rate), swapIndex, std::move(spread), fwdStart,
×
582
                     std::move(discount), pillarChoice, customPillarDate, endOfMonth, useIndexedCoupons) {}
×
583

584
    SwapRateHelper::SwapRateHelper(Rate rate,
242✔
585
                                   const Period& tenor,
586
                                   Calendar calendar,
587
                                   Frequency fixedFrequency,
588
                                   BusinessDayConvention fixedConvention,
589
                                   DayCounter fixedDayCount,
590
                                   const ext::shared_ptr<IborIndex>& iborIndex,
591
                                   Handle<Quote> spread,
592
                                   const Period& fwdStart,
593
                                   Handle<YieldTermStructure> discount,
594
                                   Natural settlementDays,
595
                                   Pillar::Choice pillarChoice,
596
                                   Date customPillarDate,
597
                                   bool endOfMonth,
598
                                   const ext::optional<bool>& useIndexedCoupons)
242✔
599
    : SwapRateHelper(makeQuoteHandle(rate), tenor, std::move(calendar), fixedFrequency, fixedConvention,
484✔
600
                     std::move(fixedDayCount), iborIndex, std::move(spread), fwdStart, std::move(discount), settlementDays,
601
                     pillarChoice, customPillarDate, endOfMonth, useIndexedCoupons) {}
484✔
602

603
    void SwapRateHelper::initializeDates() {
1,708✔
604

605
        // 1. do not pass the spread here, as it might be a Quote
606
        //    i.e. it can dynamically change
607
        // 2. input discount curve Handle might be empty now but it could
608
        //    be assigned a curve later; use a RelinkableHandle here
609
        swap_ = MakeVanillaSwap(tenor_, iborIndex_, 0.0, fwdStart_)
1,708✔
610
            .withSettlementDays(settlementDays_)
1,708✔
611
            .withDiscountingTermStructure(discountRelinkableHandle_)
1,708✔
612
            .withFixedLegDayCount(fixedDayCount_)
1,708✔
613
            .withFixedLegTenor(Period(fixedFrequency_))
1,708✔
614
            .withFixedLegConvention(fixedConvention_)
1,708✔
615
            .withFixedLegTerminationDateConvention(fixedConvention_)
1,708✔
616
            .withFixedLegCalendar(calendar_)
1,708✔
617
            .withFixedLegEndOfMonth(endOfMonth_)
1,708✔
618
            .withFloatingLegCalendar(calendar_)
1,708✔
619
            .withFloatingLegEndOfMonth(endOfMonth_)
1,708✔
620
            .withIndexedCoupons(useIndexedCoupons_);
3,416✔
621

622
        simplifyNotificationGraph(*swap_, true);
1,708✔
623

624
        earliestDate_ = swap_->startDate();
1,708✔
625
        maturityDate_ = swap_->maturityDate();
1,708✔
626

627
        ext::shared_ptr<IborCoupon> lastCoupon =
628
            ext::dynamic_pointer_cast<IborCoupon>(swap_->floatingLeg().back());
1,708✔
629
        latestRelevantDate_ = std::max(maturityDate_, lastCoupon->fixingEndDate());
1,708✔
630

631
        switch (pillarChoice_) {
1,708✔
UNCOV
632
          case Pillar::MaturityDate:
×
UNCOV
633
            pillarDate_ = maturityDate_;
×
UNCOV
634
            break;
×
635
          case Pillar::LastRelevantDate:
1,708✔
636
            pillarDate_ = latestRelevantDate_;
1,708✔
637
            break;
1,708✔
UNCOV
638
          case Pillar::CustomDate:
×
639
            // pillarDate_ already assigned at construction time
UNCOV
640
            QL_REQUIRE(pillarDate_ >= earliestDate_,
×
641
                "pillar date (" << pillarDate_ << ") must be later "
642
                "than or equal to the instrument's earliest date (" <<
643
                earliestDate_ << ")");
UNCOV
644
            QL_REQUIRE(pillarDate_ <= latestRelevantDate_,
×
645
                "pillar date (" << pillarDate_ << ") must be before "
646
                "or equal to the instrument's latest relevant date (" <<
647
                latestRelevantDate_ << ")");
648
            break;
UNCOV
649
          default:
×
UNCOV
650
            QL_FAIL("unknown Pillar::Choice(" << Integer(pillarChoice_) << ")");
×
651
        }
652

653
        latestDate_ = pillarDate_; // backward compatibility
1,708✔
654

655
    }
1,708✔
656

657
    void SwapRateHelper::setTermStructure(YieldTermStructure* t) {
1,564✔
658
        // do not set the relinkable handle as an observer -
659
        // force recalculation when needed
660
        bool observer = false;
661

662
        ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
663
        termStructureHandle_.linkTo(temp, observer);
1,564✔
664

665
        if (discountHandle_.empty())
1,564✔
666
            discountRelinkableHandle_.linkTo(temp, observer);
1,530✔
667
        else
668
            discountRelinkableHandle_.linkTo(*discountHandle_, observer);
34✔
669

670
        RelativeDateRateHelper::setTermStructure(t);
1,564✔
671
    }
1,564✔
672

673
    Real SwapRateHelper::impliedQuote() const {
21,733✔
674
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
21,733✔
675
        // we didn't register as observers - force calculation
676
        swap_->deepUpdate();
21,733✔
677
        // weak implementation... to be improved
678
        static const Spread basisPoint = 1.0e-4;
679
        Real floatingLegNPV = swap_->floatingLegNPV();
21,733✔
680
        Spread spread = spread_.empty() ? 0.0 : spread_->value();
21,733✔
681
        Real spreadNPV = swap_->floatingLegBPS()/basisPoint*spread;
21,733✔
682
        Real totNPV = - (floatingLegNPV+spreadNPV);
21,733✔
683
        Real result = totNPV/(swap_->fixedLegBPS()/basisPoint);
21,733✔
684
        return result;
21,733✔
685
    }
686

687
    void SwapRateHelper::accept(AcyclicVisitor& v) {
×
UNCOV
688
        auto* v1 = dynamic_cast<Visitor<SwapRateHelper>*>(&v);
×
689
        if (v1 != nullptr)
×
690
            v1->visit(*this);
×
691
        else
UNCOV
692
            RateHelper::accept(v);
×
693
    }
×
694

695
    BMASwapRateHelper::BMASwapRateHelper(const Handle<Quote>& liborFraction,
80✔
696
                                         const Period& tenor,
697
                                         Natural settlementDays,
698
                                         Calendar calendar,
699
                                         // bma leg
700
                                         const Period& bmaPeriod,
701
                                         BusinessDayConvention bmaConvention,
702
                                         DayCounter bmaDayCount,
703
                                         ext::shared_ptr<BMAIndex> bmaIndex,
704
                                         // libor leg
705
                                         ext::shared_ptr<IborIndex> iborIndex)
80✔
706
    : RelativeDateRateHelper(liborFraction), tenor_(tenor), settlementDays_(settlementDays),
80✔
707
      calendar_(std::move(calendar)), bmaPeriod_(bmaPeriod), bmaConvention_(bmaConvention),
80✔
708
      bmaDayCount_(std::move(bmaDayCount)), bmaIndex_(std::move(bmaIndex)),
709
      iborIndex_(std::move(iborIndex)) {
80✔
710
        registerWith(iborIndex_);
160✔
711
        registerWith(bmaIndex_);
80✔
712
        BMASwapRateHelper::initializeDates();
80✔
713
    }
80✔
714

715
    void BMASwapRateHelper::initializeDates() {
80✔
716
        // if the evaluation date is not a business day
717
        // then move to the next business day
718
        JointCalendar jc(calendar_,
80✔
719
                         iborIndex_->fixingCalendar());
80✔
720
        Date referenceDate = jc.adjust(evaluationDate_);
80✔
721
        earliestDate_ =
722
            calendar_.advance(referenceDate, settlementDays_ * Days, Following);
80✔
723

724
        Date maturity = earliestDate_ + tenor_;
80✔
725

726
        // dummy BMA index with curve/swap arguments
727
        ext::shared_ptr<BMAIndex> clonedIndex(new BMAIndex(termStructureHandle_));
80✔
728

729
        Schedule bmaSchedule =
730
            MakeSchedule().from(earliestDate_).to(maturity)
80✔
731
                          .withTenor(bmaPeriod_)
80✔
732
                          .withCalendar(bmaIndex_->fixingCalendar())
160✔
733
                          .withConvention(bmaConvention_)
80✔
734
                          .backwards();
80✔
735

736
        Schedule liborSchedule =
737
            MakeSchedule().from(earliestDate_).to(maturity)
80✔
738
                          .withTenor(iborIndex_->tenor())
80✔
739
                          .withCalendar(iborIndex_->fixingCalendar())
160✔
740
                          .withConvention(iborIndex_->businessDayConvention())
80✔
741
                          .endOfMonth(iborIndex_->endOfMonth())
80✔
742
                          .backwards();
80✔
743

744
        swap_ = ext::make_shared<BMASwap>(Swap::Payer, 100.0,
160✔
745
                                          liborSchedule,
746
                                          0.75, // arbitrary
160✔
747
                                          0.0,
80✔
748
                                          iborIndex_,
749
                                          iborIndex_->dayCounter(),
80✔
750
                                          bmaSchedule,
751
                                          clonedIndex,
752
                                          bmaDayCount_);
160✔
753
        swap_->setPricingEngine(ext::shared_ptr<PricingEngine>(new
320✔
754
            DiscountingSwapEngine(iborIndex_->forwardingTermStructure())));
160✔
755

756
        Date d = calendar_.adjust(swap_->maturityDate(), Following);
80✔
757
        Weekday w = d.weekday();
758
        Date nextWednesday = (w >= 4) ?
80✔
759
            d + (11 - w) * Days :
24✔
760
            d + (4 - w) * Days;
80✔
761
        latestDate_ = clonedIndex->valueDate(
160✔
762
                         clonedIndex->fixingCalendar().adjust(nextWednesday));
160✔
763
    }
160✔
764

765
    void BMASwapRateHelper::setTermStructure(YieldTermStructure* t) {
80✔
766
        // do not set the relinkable handle as an observer -
767
        // force recalculation when needed
768
        bool observer = false;
769

770
        ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
771
        termStructureHandle_.linkTo(temp, observer);
80✔
772

773
        RelativeDateRateHelper::setTermStructure(t);
80✔
774
    }
80✔
775

776
    Real BMASwapRateHelper::impliedQuote() const {
1,198✔
777
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
1,198✔
778
        // we didn't register as observers - force calculation
779
        swap_->deepUpdate();
1,198✔
780
        return swap_->fairLiborFraction();
1,198✔
781
    }
782

UNCOV
783
    void BMASwapRateHelper::accept(AcyclicVisitor& v) {
×
UNCOV
784
        auto* v1 = dynamic_cast<Visitor<BMASwapRateHelper>*>(&v);
×
UNCOV
785
        if (v1 != nullptr)
×
UNCOV
786
            v1->visit(*this);
×
787
        else
UNCOV
788
            RateHelper::accept(v);
×
UNCOV
789
    }
×
790

791
    FxSwapRateHelper::FxSwapRateHelper(const Handle<Quote>& fwdPoint,
6✔
792
                                       Handle<Quote> spotFx,
793
                                       const Period& tenor,
794
                                       Natural fixingDays,
795
                                       Calendar calendar,
796
                                       BusinessDayConvention convention,
797
                                       bool endOfMonth,
798
                                       bool isFxBaseCurrencyCollateralCurrency,
799
                                       Handle<YieldTermStructure> coll,
800
                                       Calendar tradingCalendar)
6✔
801
    : RelativeDateRateHelper(fwdPoint), spot_(std::move(spotFx)), tenor_(tenor),
6✔
802
      fixingDays_(fixingDays), cal_(std::move(calendar)), conv_(convention), eom_(endOfMonth),
6✔
803
      isFxBaseCurrencyCollateralCurrency_(isFxBaseCurrencyCollateralCurrency),
6✔
804
      collHandle_(std::move(coll)), tradingCalendar_(std::move(tradingCalendar)) {
18✔
805
        registerWith(spot_);
12✔
806
        registerWith(collHandle_);
12✔
807

808
        if (tradingCalendar_.empty())
6✔
809
            jointCalendar_ = cal_;
810
        else
UNCOV
811
            jointCalendar_ = JointCalendar(tradingCalendar_, cal_,
×
812
                                           JoinHolidays);
813
        FxSwapRateHelper::initializeDates();
6✔
814
    }
6✔
815

816
    void FxSwapRateHelper::initializeDates() {
6✔
817
        // if the evaluation date is not a business day
818
        // then move to the next business day
819
        Date refDate = cal_.adjust(evaluationDate_);
6✔
820
        earliestDate_ = cal_.advance(refDate, fixingDays_*Days);
6✔
821

822
        if (!tradingCalendar_.empty()) {
6✔
823
            // check if fx trade can be settled in US, if not, adjust it
824
            earliestDate_ = jointCalendar_.adjust(earliestDate_);
×
UNCOV
825
            latestDate_ = jointCalendar_.advance(earliestDate_, tenor_,
×
UNCOV
826
                                                 conv_, eom_);
×
827
        } else {
828
            latestDate_ = cal_.advance(earliestDate_, tenor_, conv_, eom_);
6✔
829
        }
830
    }
6✔
831

832
    Real FxSwapRateHelper::impliedQuote() const {
62✔
833
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
62✔
834

835
        QL_REQUIRE(!collHandle_.empty(), "collateral term structure not set");
62✔
836

837
        DiscountFactor d1 = collHandle_->discount(earliestDate_);
62✔
838
        DiscountFactor d2 = collHandle_->discount(latestDate_);
62✔
839
        Real collRatio = d1 / d2;
62✔
840
        d1 = termStructureHandle_->discount(earliestDate_);
62✔
841
        d2 = termStructureHandle_->discount(latestDate_);
62✔
842
        Real ratio = d1 / d2;
62✔
843
        Real spot = spot_->value();
62✔
844
        if (isFxBaseCurrencyCollateralCurrency_) {
62✔
845
            return (ratio/collRatio-1)*spot;
62✔
846
        } else {
UNCOV
847
            return (collRatio/ratio-1)*spot;
×
848
        }
849
    }
850

851
    void FxSwapRateHelper::setTermStructure(YieldTermStructure* t) {
12✔
852
        // do not set the relinkable handle as an observer -
853
        // force recalculation when needed
854
        bool observer = false;
855

856
        ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
857
        termStructureHandle_.linkTo(temp, observer);
12✔
858

859
        collRelinkableHandle_.linkTo(*collHandle_, observer);
12✔
860

861
        RelativeDateRateHelper::setTermStructure(t);
12✔
862
    }
12✔
863

UNCOV
864
    void FxSwapRateHelper::accept(AcyclicVisitor& v) {
×
UNCOV
865
        auto* v1 = dynamic_cast<Visitor<FxSwapRateHelper>*>(&v);
×
UNCOV
866
        if (v1 != nullptr)
×
UNCOV
867
            v1->visit(*this);
×
868
        else
UNCOV
869
            RateHelper::accept(v);
×
UNCOV
870
    }
×
871

872
}
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

© 2026 Coveralls, Inc