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

lballabio / QuantLib / 4127568404

pending completion
4127568404

Pull #1473

github

GitHub
Merge 115fd75c4 into 94b218ead
Pull Request #1473: Move clang-analyzer-optin.cplusplus.VirtualCall suppressions to comments

65 of 65 new or added lines in 24 files covered. (100.0%)

53766 of 74813 relevant lines covered (71.87%)

10600601.11 hits per line

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

50.54
/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/pricingengines/swap/discountingswapengine.hpp>
31
#include <ql/quote.hpp>
32
#include <ql/termstructures/yield/ratehelpers.hpp>
33
#include <ql/time/asx.hpp>
34
#include <ql/time/calendars/jointcalendar.hpp>
35
#include <ql/time/calendars/unitedstates.hpp>
36
#include <ql/time/imm.hpp>
37
#include <ql/utilities/null_deleter.hpp>
38
#include <utility>
39

40
namespace QuantLib {
41

42
    FuturesRateHelper::FuturesRateHelper(const Handle<Quote>& price,
×
43
                                         const Date& iborStartDate,
44
                                         Natural lengthInMonths,
45
                                         const Calendar& calendar,
46
                                         BusinessDayConvention convention,
47
                                         bool endOfMonth,
48
                                         const DayCounter& dayCounter,
49
                                         Handle<Quote> convAdj,
50
                                         Futures::Type type)
×
51
    : RateHelper(price), convAdj_(std::move(convAdj)) {
×
52
        switch (type) {
×
53
          case Futures::IMM:
×
54
            QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
×
55
                       iborStartDate << " is not a valid IMM date");
56
            break;
57
          case Futures::ASX:
×
58
            QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
×
59
                       iborStartDate << " is not a valid ASX date");
60
            break;
61
          default:
×
62
            QL_FAIL("unknown futures type (" << Integer(type) << ")");
×
63
        }
64
        earliestDate_ = iborStartDate;
×
65
        maturityDate_ = calendar.advance(iborStartDate, lengthInMonths*Months,
×
66
                                         convention, endOfMonth);
67
        yearFraction_ = dayCounter.yearFraction(earliestDate_, maturityDate_);
×
68
        pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
×
69

70
        registerWith(convAdj_);
×
71
    }
×
72

73
    FuturesRateHelper::FuturesRateHelper(Real price,
×
74
                                         const Date& iborStartDate,
75
                                         Natural lengthInMonths,
76
                                         const Calendar& calendar,
77
                                         BusinessDayConvention convention,
78
                                         bool endOfMonth,
79
                                         const DayCounter& dayCounter,
80
                                         Rate convAdj,
81
                                         Futures::Type type)
×
82
    : RateHelper(price),
83
      convAdj_(Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(convAdj))))
×
84
    {
85
        switch (type) {
×
86
          case Futures::IMM:
×
87
            QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
×
88
                iborStartDate << " is not a valid IMM date");
89
            break;
90
          case Futures::ASX:
×
91
            QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
×
92
                iborStartDate << " is not a valid ASX date");
93
            break;
94
          default:
×
95
            QL_FAIL("unknown futures type (" << Integer(type) << ")");
×
96
        }
97
        earliestDate_ = iborStartDate;
×
98
        maturityDate_ = calendar.advance(iborStartDate, lengthInMonths*Months,
×
99
            convention, endOfMonth);
100
        yearFraction_ = dayCounter.yearFraction(earliestDate_, maturityDate_);
×
101
        pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
×
102
    }
×
103

104
    FuturesRateHelper::FuturesRateHelper(const Handle<Quote>& price,
×
105
                                         const Date& iborStartDate,
106
                                         const Date& iborEndDate,
107
                                         const DayCounter& dayCounter,
108
                                         Handle<Quote> convAdj,
109
                                         Futures::Type type)
×
110
    : RateHelper(price), convAdj_(std::move(convAdj)) {
×
111
        switch (type) {
×
112
          case Futures::IMM:
×
113
            QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
×
114
                       iborStartDate << " is not a valid IMM date");
115
            if (iborEndDate == Date()) {
×
116
                // advance 3 months
117
                maturityDate_ = IMM::nextDate(iborStartDate, false);
×
118
                maturityDate_ = IMM::nextDate(maturityDate_, false);
×
119
                maturityDate_ = IMM::nextDate(maturityDate_, false);
×
120
            }
121
            else {
122
                QL_REQUIRE(iborEndDate>iborStartDate,
×
123
                           "end date (" << iborEndDate <<
124
                           ") must be greater than start date (" <<
125
                           iborStartDate << ")");
126
                maturityDate_ = iborEndDate;
×
127
            }
128
            break;
129
          case Futures::ASX:
×
130
            QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
×
131
                       iborStartDate << " is not a valid ASX date");
132
            if (iborEndDate == Date()) {
×
133
                // advance 3 months
134
                maturityDate_ = ASX::nextDate(iborStartDate, false);
×
135
                maturityDate_ = ASX::nextDate(maturityDate_, false);
×
136
                maturityDate_ = ASX::nextDate(maturityDate_, false);
×
137
            }
138
            else {
139
                QL_REQUIRE(iborEndDate>iborStartDate,
×
140
                           "end date (" << iborEndDate <<
141
                           ") must be greater than start date (" <<
142
                          iborStartDate << ")");
143
                maturityDate_ = iborEndDate;
×
144
            }
145
            break;
146
          default:
×
147
            QL_FAIL("unknown futures type (" << Integer(type) << ")");
×
148
        }
149
        earliestDate_ = iborStartDate;
×
150
        yearFraction_ = dayCounter.yearFraction(earliestDate_, maturityDate_);
×
151
        pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
×
152

153
        registerWith(convAdj_);
×
154
    }
×
155

156
    FuturesRateHelper::FuturesRateHelper(Real price,
×
157
                                         const Date& iborStartDate,
158
                                         const Date& iborEndDate,
159
                                         const DayCounter& dayCounter,
160
                                         Rate convAdj,
161
                                         Futures::Type type)
×
162
    : RateHelper(price),
163
      convAdj_(Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(convAdj))))
×
164
    {
165
        switch (type) {
×
166
          case Futures::IMM:
×
167
            QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
×
168
                       iborStartDate << " is not a valid IMM date");
169
            if (iborEndDate == Date()) {
×
170
                // advance 3 months
171
                maturityDate_ = IMM::nextDate(iborStartDate, false);
×
172
                maturityDate_ = IMM::nextDate(maturityDate_, false);
×
173
                maturityDate_ = IMM::nextDate(maturityDate_, false);
×
174
            }
175
            else {
176
                QL_REQUIRE(iborEndDate>iborStartDate,
×
177
                           "end date (" << iborEndDate <<
178
                           ") must be greater than start date (" <<
179
                           iborStartDate << ")");
180
                maturityDate_ = iborEndDate;
×
181
            }
182
            break;
183
          case Futures::ASX:
×
184
            QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
×
185
                iborStartDate << " is not a valid ASX date");
186
            if (iborEndDate == Date()) {
×
187
                // advance 3 months
188
                maturityDate_ = ASX::nextDate(iborStartDate, false);
×
189
                maturityDate_ = ASX::nextDate(maturityDate_, false);
×
190
                maturityDate_ = ASX::nextDate(maturityDate_, false);
×
191
            }
192
            else {
193
                QL_REQUIRE(iborEndDate>iborStartDate,
×
194
                           "end date (" << iborEndDate <<
195
                           ") must be greater than start date (" <<
196
                           iborStartDate << ")");
197
                maturityDate_ = iborEndDate;
×
198
            }
199
            break;
200
          default:
×
201
            QL_FAIL("unknown futures type (" << Integer(type) << ")");
×
202
        }
203
        earliestDate_ = iborStartDate;
×
204
        yearFraction_ = dayCounter.yearFraction(earliestDate_, maturityDate_);
×
205
        pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
×
206
    }
×
207

208
    FuturesRateHelper::FuturesRateHelper(const Handle<Quote>& price,
72✔
209
                                         const Date& iborStartDate,
210
                                         const ext::shared_ptr<IborIndex>& i,
211
                                         const Handle<Quote>& convAdj,
212
                                         Futures::Type type)
72✔
213
    : RateHelper(price), convAdj_(convAdj) {
144✔
214
        switch (type) {
72✔
215
          case Futures::IMM:
36✔
216
            QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
36✔
217
                       iborStartDate << " is not a valid IMM date");
218
            break;
219
          case Futures::ASX:
36✔
220
            QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
36✔
221
                       iborStartDate << " is not a valid ASX date");
222
            break;
223
          default:
×
224
            QL_FAIL("unknown futures type (" << Integer(type) << ")");
×
225
        }
226
        earliestDate_ = iborStartDate;
72✔
227
        const Calendar& cal = i->fixingCalendar();
72✔
228
        maturityDate_ = cal.advance(iborStartDate, i->tenor(),
72✔
229
                                    i->businessDayConvention());
230
        yearFraction_ = i->dayCounter().yearFraction(earliestDate_,
72✔
231
                                                     maturityDate_);
72✔
232
        pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
72✔
233

234
        registerWith(convAdj);
144✔
235
    }
72✔
236

237
    FuturesRateHelper::FuturesRateHelper(Real price,
×
238
                                         const Date& iborStartDate,
239
                                         const ext::shared_ptr<IborIndex>& i,
240
                                         Rate convAdj,
241
                                         Futures::Type type)
×
242
    : RateHelper(price),
243
      convAdj_(Handle<Quote>(ext::shared_ptr<Quote>(new SimpleQuote(convAdj))))
×
244
    {
245
        switch (type) {
×
246
          case Futures::IMM:
×
247
            QL_REQUIRE(IMM::isIMMdate(iborStartDate, false),
×
248
                iborStartDate << " is not a valid IMM date");
249
            break;
250
          case Futures::ASX:
×
251
            QL_REQUIRE(ASX::isASXdate(iborStartDate, false),
×
252
                iborStartDate << " is not a valid ASX date");
253
            break;
254
          default:
×
255
            QL_FAIL("unknown futures type (" << Integer(type) << ")");
×
256
        }
257
        earliestDate_ = iborStartDate;
×
258
        const Calendar& cal = i->fixingCalendar();
×
259
        maturityDate_ = cal.advance(iborStartDate, i->tenor(),
×
260
                                    i->businessDayConvention());
261
        yearFraction_ = i->dayCounter().yearFraction(earliestDate_,
×
262
                                                     maturityDate_);
×
263
        pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
×
264
    }
×
265

266
    Real FuturesRateHelper::impliedQuote() const {
567✔
267
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
567✔
268
        Rate forwardRate = (termStructure_->discount(earliestDate_) /
567✔
269
            termStructure_->discount(maturityDate_) - 1.0) / yearFraction_;
567✔
270
        Rate convAdj = convAdj_.empty() ? 0.0 : convAdj_->value();
567✔
271
        // Convexity, as FRA/futures adjustment, has been used in the
272
        // past to take into account futures margining vs FRA.
273
        // Therefore, there's no requirement for it to be non-negative.
274
        Rate futureRate = forwardRate + convAdj;
567✔
275
        return 100.0 * (1.0 - futureRate);
567✔
276
    }
277

278
    Real FuturesRateHelper::convexityAdjustment() const {
×
279
        return convAdj_.empty() ? 0.0 : convAdj_->value();
×
280
    }
281

282
    void FuturesRateHelper::accept(AcyclicVisitor& v) {
×
283
        auto* v1 = dynamic_cast<Visitor<FuturesRateHelper>*>(&v);
×
284
        if (v1 != nullptr)
×
285
            v1->visit(*this);
×
286
        else
287
            RateHelper::accept(v);
×
288
    }
×
289

290
    DepositRateHelper::DepositRateHelper(const Handle<Quote>& rate,
213✔
291
                                         const Period& tenor,
292
                                         Natural fixingDays,
293
                                         const Calendar& calendar,
294
                                         BusinessDayConvention convention,
295
                                         bool endOfMonth,
296
                                         const DayCounter& dayCounter)
213✔
297
    : RelativeDateRateHelper(rate) {
213✔
298
        iborIndex_ = ext::make_shared<IborIndex>("no-fix", // never take fixing into account
426✔
299
                      tenor, fixingDays,
300
                      Currency(), calendar, convention,
213✔
301
                      endOfMonth, dayCounter, termStructureHandle_);
213✔
302
        DepositRateHelper::initializeDates();
213✔
303
    }
213✔
304

305
    DepositRateHelper::DepositRateHelper(Rate rate,
77✔
306
                                         const Period& tenor,
307
                                         Natural fixingDays,
308
                                         const Calendar& calendar,
309
                                         BusinessDayConvention convention,
310
                                         bool endOfMonth,
311
                                         const DayCounter& dayCounter)
77✔
312
    : RelativeDateRateHelper(rate) {
77✔
313
        iborIndex_ = ext::make_shared<IborIndex>("no-fix", // never take fixing into account
154✔
314
                      tenor, fixingDays,
315
                      Currency(), calendar, convention,
77✔
316
                      endOfMonth, dayCounter, termStructureHandle_);
77✔
317
        DepositRateHelper::initializeDates();
77✔
318
    }
77✔
319

320
    DepositRateHelper::DepositRateHelper(const Handle<Quote>& rate,
72✔
321
                                         const ext::shared_ptr<IborIndex>& i)
72✔
322
    : RelativeDateRateHelper(rate) {
72✔
323
        iborIndex_ = i->clone(termStructureHandle_);
72✔
324
        DepositRateHelper::initializeDates();
72✔
325
    }
72✔
326

327
    DepositRateHelper::DepositRateHelper(Rate rate,
×
328
                                         const ext::shared_ptr<IborIndex>& i)
×
329
    : RelativeDateRateHelper(rate) {
×
330
        iborIndex_ = i->clone(termStructureHandle_);
×
331
        DepositRateHelper::initializeDates();
×
332
    }
×
333

334
    Real DepositRateHelper::impliedQuote() const {
3,630✔
335
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
3,630✔
336
        // the forecast fixing flag is set to true because
337
        // we do not want to take fixing into account
338
        return iborIndex_->fixing(fixingDate_, true);
3,630✔
339
    }
340

341
    void DepositRateHelper::setTermStructure(YieldTermStructure* t) {
527✔
342
        // do not set the relinkable handle as an observer -
343
        // force recalculation when needed---the index is not lazy
344
        bool observer = false;
345

346
        ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
347
        termStructureHandle_.linkTo(temp, observer);
527✔
348

349
        RelativeDateRateHelper::setTermStructure(t);
527✔
350
    }
527✔
351

352
    void DepositRateHelper::initializeDates() {
668✔
353
        // if the evaluation date is not a business day
354
        // then move to the next business day
355
        Date referenceDate =
356
            iborIndex_->fixingCalendar().adjust(evaluationDate_);
668✔
357
        earliestDate_ = iborIndex_->valueDate(referenceDate);
668✔
358
        fixingDate_ = iborIndex_->fixingDate(earliestDate_);
668✔
359
        maturityDate_ = iborIndex_->maturityDate(earliestDate_);
668✔
360
        pillarDate_ = latestDate_ = latestRelevantDate_ = maturityDate_;
668✔
361
    }
668✔
362

363
    void DepositRateHelper::accept(AcyclicVisitor& v) {
×
364
        auto* v1 = dynamic_cast<Visitor<DepositRateHelper>*>(&v);
×
365
        if (v1 != nullptr)
×
366
            v1->visit(*this);
×
367
        else
368
            RateHelper::accept(v);
×
369
    }
×
370

371

372
    FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
305✔
373
                                 Natural monthsToStart,
374
                                 Natural monthsToEnd,
375
                                 Natural fixingDays,
376
                                 const Calendar& calendar,
377
                                 BusinessDayConvention convention,
378
                                 bool endOfMonth,
379
                                 const DayCounter& dayCounter,
380
                                 Pillar::Choice pillarChoice,
381
                                 Date customPillarDate,
382
                                 bool useIndexedCoupon)
305✔
383
    : RelativeDateRateHelper(rate), periodToStart_(monthsToStart*Months),
384
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
305✔
385
        QL_REQUIRE(monthsToEnd>monthsToStart,
305✔
386
                   "monthsToEnd (" << monthsToEnd <<
387
                   ") must be grater than monthsToStart (" << monthsToStart <<
388
                   ")");
389
        // no way to take fixing into account,
390
        // even if we would like to for FRA over today
391
        iborIndex_ = ext::make_shared<IborIndex>("no-fix", // correct family name would be needed
305✔
392
                      (monthsToEnd-monthsToStart)*Months,
610✔
393
                      fixingDays,
394
                      Currency(), calendar, convention,
305✔
395
                      endOfMonth, dayCounter, termStructureHandle_);
305✔
396
        pillarDate_ = customPillarDate;
305✔
397
        FraRateHelper::initializeDates();
305✔
398
    }
305✔
399

400
    FraRateHelper::FraRateHelper(Rate rate,
×
401
                                 Natural monthsToStart,
402
                                 Natural monthsToEnd,
403
                                 Natural fixingDays,
404
                                 const Calendar& calendar,
405
                                 BusinessDayConvention convention,
406
                                 bool endOfMonth,
407
                                 const DayCounter& dayCounter,
408
                                 Pillar::Choice pillarChoice,
409
                                 Date customPillarDate,
410
                                 bool useIndexedCoupon)
×
411
    : RelativeDateRateHelper(rate), periodToStart_(monthsToStart*Months),
412
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
×
413
        QL_REQUIRE(monthsToEnd>monthsToStart,
×
414
                   "monthsToEnd (" << monthsToEnd <<
415
                   ") must be grater than monthsToStart (" << monthsToStart <<
416
                   ")");
417
        // no way to take fixing into account,
418
        // even if we would like to for FRA over today
419
        iborIndex_ = ext::make_shared<IborIndex>("no-fix", // correct family name would be needed
×
420
                      (monthsToEnd-monthsToStart)*Months,
×
421
                      fixingDays,
422
                      Currency(), calendar, convention,
×
423
                      endOfMonth, dayCounter, termStructureHandle_);
×
424
        pillarDate_ = customPillarDate;
×
425
        FraRateHelper::initializeDates();
×
426
    }
×
427

428
    FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
18✔
429
                                 Natural monthsToStart,
430
                                 const ext::shared_ptr<IborIndex>& i,
431
                                 Pillar::Choice pillarChoice,
432
                                 Date customPillarDate,
433
                                 bool useIndexedCoupon)
18✔
434
    : RelativeDateRateHelper(rate), periodToStart_(monthsToStart*Months),
435
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
18✔
436
        // take fixing into account
437
        iborIndex_ = i->clone(termStructureHandle_);
18✔
438
        // We want to be notified of changes of fixings, but we don't
439
        // want notifications from termStructureHandle_ (they would
440
        // interfere with bootstrapping.)
441
        iborIndex_->unregisterWith(termStructureHandle_);
18✔
442
        registerWith(iborIndex_);
18✔
443
        pillarDate_ = customPillarDate;
18✔
444
        FraRateHelper::initializeDates();
18✔
445
    }
18✔
446

447
    FraRateHelper::FraRateHelper(Rate rate,
×
448
                                 Natural monthsToStart,
449
                                 const ext::shared_ptr<IborIndex>& i,
450
                                 Pillar::Choice pillarChoice,
451
                                 Date customPillarDate,
452
                                 bool useIndexedCoupon)
×
453
    : RelativeDateRateHelper(rate), periodToStart_(monthsToStart*Months),
454
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
×
455
        // take fixing into account
456
        iborIndex_ = i->clone(termStructureHandle_);
×
457
        // see above
458
        iborIndex_->unregisterWith(termStructureHandle_);
×
459
        registerWith(iborIndex_);
×
460
        pillarDate_ = customPillarDate;
×
461
        FraRateHelper::initializeDates();
×
462
    }
×
463

464
    FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
×
465
                                 Period periodToStart,
466
                                 Natural lengthInMonths,
467
                                 Natural fixingDays,
468
                                 const Calendar& calendar,
469
                                 BusinessDayConvention convention,
470
                                 bool endOfMonth,
471
                                 const DayCounter& dayCounter,
472
                                 Pillar::Choice pillarChoice,
473
                                 Date customPillarDate,
474
                                 bool useIndexedCoupon)
×
475
    : RelativeDateRateHelper(rate), periodToStart_(periodToStart),
476
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
×
477
        // no way to take fixing into account,
478
        // even if we would like to for FRA over today
479
        iborIndex_ = ext::make_shared<IborIndex>("no-fix", // correct family name would be needed
×
480
                      lengthInMonths*Months,
×
481
                      fixingDays,
482
                      Currency(), calendar, convention,
×
483
                      endOfMonth, dayCounter, termStructureHandle_);
×
484
        pillarDate_ = customPillarDate;
×
485
        FraRateHelper::initializeDates();
×
486
    }
×
487

488
    FraRateHelper::FraRateHelper(Rate rate,
×
489
                                 Period periodToStart,
490
                                 Natural lengthInMonths,
491
                                 Natural fixingDays,
492
                                 const Calendar& calendar,
493
                                 BusinessDayConvention convention,
494
                                 bool endOfMonth,
495
                                 const DayCounter& dayCounter,
496
                                 Pillar::Choice pillarChoice,
497
                                 Date customPillarDate,
498
                                 bool useIndexedCoupon)
×
499
    : RelativeDateRateHelper(rate), periodToStart_(periodToStart),
500
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
×
501
        // no way to take fixing into account,
502
        // even if we would like to for FRA over today
503
        iborIndex_ = ext::make_shared<IborIndex>("no-fix", // correct family name would be needed
×
504
                      lengthInMonths*Months,
×
505
                      fixingDays,
506
                      Currency(), calendar, convention,
×
507
                      endOfMonth, dayCounter, termStructureHandle_);
×
508
        pillarDate_ = customPillarDate;
×
509
        FraRateHelper::initializeDates();
×
510
    }
×
511

512
    FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
3✔
513
                                 Period periodToStart,
514
                                 const ext::shared_ptr<IborIndex>& i,
515
                                 Pillar::Choice pillarChoice,
516
                                 Date customPillarDate,
517
                                 bool useIndexedCoupon)
3✔
518
    : RelativeDateRateHelper(rate), periodToStart_(periodToStart),
519
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
3✔
520
        // take fixing into account
521
        iborIndex_ = i->clone(termStructureHandle_);
3✔
522
        // see above
523
        iborIndex_->unregisterWith(termStructureHandle_);
3✔
524
        registerWith(iborIndex_);
3✔
525
        pillarDate_ = customPillarDate;
3✔
526
        FraRateHelper::initializeDates();
3✔
527
    }
3✔
528

529
    FraRateHelper::FraRateHelper(Rate rate,
19✔
530
                                 Period periodToStart,
531
                                 const ext::shared_ptr<IborIndex>& i,
532
                                 Pillar::Choice pillarChoice,
533
                                 Date customPillarDate,
534
                                 bool useIndexedCoupon)
19✔
535
    : RelativeDateRateHelper(rate), periodToStart_(periodToStart),
536
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
19✔
537
        // take fixing into account
538
        iborIndex_ = i->clone(termStructureHandle_);
19✔
539
        // see above
540
        iborIndex_->unregisterWith(termStructureHandle_);
19✔
541
        registerWith(iborIndex_);
19✔
542
        pillarDate_ = customPillarDate;
19✔
543
        FraRateHelper::initializeDates();
19✔
544
    }
19✔
545

546
    FraRateHelper::FraRateHelper(const Handle<Quote>& rate,
×
547
                                 Natural immOffsetStart,
548
                                 Natural immOffsetEnd,
549
                                 const ext::shared_ptr<IborIndex>& i,
550
                                 Pillar::Choice pillarChoice,
551
                                 Date customPillarDate,
552
                                 bool useIndexedCoupon)
×
553
    : RelativeDateRateHelper(rate), immOffsetStart_(immOffsetStart), immOffsetEnd_(immOffsetEnd),
554
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
×
555
        // take fixing into account
556
        iborIndex_ = i->clone(termStructureHandle_);
×
557
        // see above
558
        iborIndex_->unregisterWith(termStructureHandle_);
×
559
        registerWith(iborIndex_);
×
560
        pillarDate_ = customPillarDate;
×
561
        FraRateHelper::initializeDates();
×
562
    }
×
563

564
    FraRateHelper::FraRateHelper(Rate rate,
×
565
                                 Natural immOffsetStart,
566
                                 Natural immOffsetEnd,
567
                                 const ext::shared_ptr<IborIndex>& i,
568
                                 Pillar::Choice pillarChoice,
569
                                 Date customPillarDate,
570
                                 bool useIndexedCoupon)
×
571
    : RelativeDateRateHelper(rate), immOffsetStart_(immOffsetStart), immOffsetEnd_(immOffsetEnd),
572
      pillarChoice_(pillarChoice), useIndexedCoupon_(useIndexedCoupon) {
×
573
        // take fixing into account
574
        iborIndex_ = i->clone(termStructureHandle_);
×
575
        // see above
576
        iborIndex_->unregisterWith(termStructureHandle_);
×
577
        registerWith(iborIndex_);
×
578
        pillarDate_ = customPillarDate;
×
579
        FraRateHelper::initializeDates();
×
580
    }
×
581

582
    Real FraRateHelper::impliedQuote() const {
7,922✔
583
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
7,922✔
584
        if (useIndexedCoupon_)
7,922✔
585
            return iborIndex_->fixing(fixingDate_, true);
7,922✔
586
        else
587
            return (termStructure_->discount(earliestDate_) /
×
588
                        termStructure_->discount(maturityDate_) -
×
589
                    1.0) /
590
                   spanningTime_;
×
591
    }
592

593
    void FraRateHelper::setTermStructure(YieldTermStructure* t) {
318✔
594
        // do not set the relinkable handle as an observer -
595
        // force recalculation when needed---the index is not lazy
596
        bool observer = false;
597

598
        ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
599
        termStructureHandle_.linkTo(temp, observer);
318✔
600

601
        RelativeDateRateHelper::setTermStructure(t);
318✔
602
    }
318✔
603

604
    namespace {
605
        Date nthImmDate(const Date& asof, const Size n) {
×
606
            Date imm = asof;
×
607
            for (Size i = 0; i < n; ++i) {
×
608
                imm = IMM::nextDate(imm, true);
×
609
            }
610
            return imm;
×
611
        }
612
    }
613

614
    void FraRateHelper::initializeDates() {
660✔
615
        // if the evaluation date is not a business day
616
        // then move to the next business day
617
        Date referenceDate =
618
            iborIndex_->fixingCalendar().adjust(evaluationDate_);
660✔
619
        Date spotDate = iborIndex_->fixingCalendar().advance(
1,320✔
620
            referenceDate, iborIndex_->fixingDays()*Days);
660✔
621
        if (periodToStart_) { // NOLINT(readability-implicit-bool-conversion)
660✔
622
            earliestDate_ = iborIndex_->fixingCalendar().advance(
1,980✔
623
                spotDate, *periodToStart_, iborIndex_->businessDayConvention(),
660✔
624
                iborIndex_->endOfMonth());
660✔
625
            // maturity date is calculated from spot date
626
            maturityDate_ = iborIndex_->fixingCalendar().advance(
2,640✔
627
                spotDate, *periodToStart_ + iborIndex_->tenor(), iborIndex_->businessDayConvention(),
1,320✔
628
                iborIndex_->endOfMonth());
660✔
629
        } else if ((immOffsetStart_) && (immOffsetEnd_)) { // NOLINT(readability-implicit-bool-conversion)
×
630
            earliestDate_ = iborIndex_->fixingCalendar().adjust(nthImmDate(spotDate, *immOffsetStart_));
×
631
            maturityDate_ = iborIndex_->fixingCalendar().adjust(nthImmDate(spotDate, *immOffsetEnd_));
×
632
        } else {
633
            QL_FAIL("neither periodToStart nor immOffsetStart/End given");
×
634
        }
635

636
        if (useIndexedCoupon_)
660✔
637
            // latest relevant date is calculated from earliestDate_
638
            latestRelevantDate_ = iborIndex_->maturityDate(earliestDate_);
660✔
639
        else {
640
            latestRelevantDate_ = maturityDate_;
×
641
            spanningTime_ = iborIndex_->dayCounter().yearFraction(earliestDate_, maturityDate_);
×
642
        }
643

644
        switch (pillarChoice_) {
660✔
645
          case Pillar::MaturityDate:
×
646
            pillarDate_ = maturityDate_;
×
647
            break;
×
648
          case Pillar::LastRelevantDate:
660✔
649
            pillarDate_ = latestRelevantDate_;
660✔
650
            break;
660✔
651
          case Pillar::CustomDate:
×
652
            // pillarDate_ already assigned at construction time
653
            QL_REQUIRE(pillarDate_ >= earliestDate_,
×
654
                       "pillar date (" << pillarDate_ << ") must be later "
655
                       "than or equal to the instrument's earliest date (" <<
656
                       earliestDate_ << ")");
657
            QL_REQUIRE(pillarDate_ <= latestRelevantDate_,
×
658
                       "pillar date (" << pillarDate_ << ") must be before "
659
                       "or equal to the instrument's latest relevant date (" <<
660
                       latestRelevantDate_ << ")");
661
            break;
662
          default:
×
663
            QL_FAIL("unknown Pillar::Choice(" << Integer(pillarChoice_) << ")");
×
664
        }
665

666
        latestDate_ = pillarDate_; // backward compatibility
660✔
667

668
        fixingDate_ = iborIndex_->fixingDate(earliestDate_);
660✔
669
    }
660✔
670

671
    void FraRateHelper::accept(AcyclicVisitor& v) {
×
672
        auto* v1 = dynamic_cast<Visitor<FraRateHelper>*>(&v);
×
673
        if (v1 != nullptr)
×
674
            v1->visit(*this);
×
675
        else
676
            RateHelper::accept(v);
×
677
    }
×
678

679

680
    SwapRateHelper::SwapRateHelper(const Handle<Quote>& rate,
×
681
                                   const ext::shared_ptr<SwapIndex>& swapIndex,
682
                                   Handle<Quote> spread,
683
                                   const Period& fwdStart,
684
                                   Handle<YieldTermStructure> discount,
685
                                   Pillar::Choice pillarChoice,
686
                                   Date customPillarDate,
687
                                   bool endOfMonth,
688
                                   const boost::optional<bool>& useIndexedCoupons)
×
689
    : RelativeDateRateHelper(rate), settlementDays_(Null<Natural>()), tenor_(swapIndex->tenor()),
×
690
      pillarChoice_(pillarChoice), calendar_(swapIndex->fixingCalendar()),
×
691
      fixedConvention_(swapIndex->fixedLegConvention()),
×
692
      fixedFrequency_(swapIndex->fixedLegTenor().frequency()),
×
693
      fixedDayCount_(swapIndex->dayCounter()), spread_(std::move(spread)), endOfMonth_(endOfMonth),
×
694
      fwdStart_(fwdStart), discountHandle_(std::move(discount)), useIndexedCoupons_(useIndexedCoupons) {
×
695
        // take fixing into account
696
        iborIndex_ = swapIndex->iborIndex()->clone(termStructureHandle_);
×
697
        // We want to be notified of changes of fixings, but we don't
698
        // want notifications from termStructureHandle_ (they would
699
        // interfere with bootstrapping.)
700
        iborIndex_->unregisterWith(termStructureHandle_);
×
701

702
        registerWith(iborIndex_);
×
703
        registerWith(spread_);
×
704
        registerWith(discountHandle_);
×
705

706
        pillarDate_ = customPillarDate;
×
707
        SwapRateHelper::initializeDates();
×
708
    }
×
709

710
    SwapRateHelper::SwapRateHelper(const Handle<Quote>& rate,
798✔
711
                                   const Period& tenor,
712
                                   Calendar calendar,
713
                                   Frequency fixedFrequency,
714
                                   BusinessDayConvention fixedConvention,
715
                                   DayCounter fixedDayCount,
716
                                   const ext::shared_ptr<IborIndex>& iborIndex,
717
                                   Handle<Quote> spread,
718
                                   const Period& fwdStart,
719
                                   Handle<YieldTermStructure> discount,
720
                                   Natural settlementDays,
721
                                   Pillar::Choice pillarChoice,
722
                                   Date customPillarDate,
723
                                   bool endOfMonth,
724
                                   const boost::optional<bool>& useIndexedCoupons)
798✔
725
    : RelativeDateRateHelper(rate), settlementDays_(settlementDays), tenor_(tenor),
798✔
726
      pillarChoice_(pillarChoice), calendar_(std::move(calendar)),
798✔
727
      fixedConvention_(fixedConvention), fixedFrequency_(fixedFrequency),
798✔
728
      fixedDayCount_(std::move(fixedDayCount)), spread_(std::move(spread)), endOfMonth_(endOfMonth),
798✔
729
      fwdStart_(fwdStart), discountHandle_(std::move(discount)),
798✔
730
      useIndexedCoupons_(useIndexedCoupons) {
1,596✔
731

732
        // take fixing into account
733
        iborIndex_ = iborIndex->clone(termStructureHandle_);
798✔
734
        // We want to be notified of changes of fixings, but we don't
735
        // want notifications from termStructureHandle_ (they would
736
        // interfere with bootstrapping.)
737
        iborIndex_->unregisterWith(termStructureHandle_);
798✔
738

739
        registerWith(iborIndex_);
1,596✔
740
        registerWith(spread_);
1,596✔
741
        registerWith(discountHandle_);
798✔
742

743
        pillarDate_ = customPillarDate;
798✔
744
        SwapRateHelper::initializeDates();
798✔
745
    }
798✔
746

747
    SwapRateHelper::SwapRateHelper(Rate rate,
×
748
                                   const ext::shared_ptr<SwapIndex>& swapIndex,
749
                                   Handle<Quote> spread,
750
                                   const Period& fwdStart,
751
                                   Handle<YieldTermStructure> discount,
752
                                   Pillar::Choice pillarChoice,
753
                                   Date customPillarDate,
754
                                   bool endOfMonth,
755
                                   const boost::optional<bool>& useIndexedCoupons)
×
756
    : RelativeDateRateHelper(rate), settlementDays_(Null<Natural>()), tenor_(swapIndex->tenor()),
×
757
      pillarChoice_(pillarChoice), calendar_(swapIndex->fixingCalendar()),
×
758
      fixedConvention_(swapIndex->fixedLegConvention()),
×
759
      fixedFrequency_(swapIndex->fixedLegTenor().frequency()),
×
760
      fixedDayCount_(swapIndex->dayCounter()), spread_(std::move(spread)), endOfMonth_(endOfMonth),
×
761
      fwdStart_(fwdStart), discountHandle_(std::move(discount)),
×
762
      useIndexedCoupons_(useIndexedCoupons) {
×
763
        // take fixing into account
764
        iborIndex_ = swapIndex->iborIndex()->clone(termStructureHandle_);
×
765
        // We want to be notified of changes of fixings, but we don't
766
        // want notifications from termStructureHandle_ (they would
767
        // interfere with bootstrapping.)
768
        iborIndex_->unregisterWith(termStructureHandle_);
×
769

770
        registerWith(iborIndex_);
×
771
        registerWith(spread_);
×
772
        registerWith(discountHandle_);
×
773

774
        pillarDate_ = customPillarDate;
×
775
        SwapRateHelper::initializeDates();
×
776
    }
×
777

778
    SwapRateHelper::SwapRateHelper(Rate rate,
242✔
779
                                   const Period& tenor,
780
                                   Calendar calendar,
781
                                   Frequency fixedFrequency,
782
                                   BusinessDayConvention fixedConvention,
783
                                   DayCounter fixedDayCount,
784
                                   const ext::shared_ptr<IborIndex>& iborIndex,
785
                                   Handle<Quote> spread,
786
                                   const Period& fwdStart,
787
                                   Handle<YieldTermStructure> discount,
788
                                   Natural settlementDays,
789
                                   Pillar::Choice pillarChoice,
790
                                   Date customPillarDate,
791
                                   bool endOfMonth,
792
                                   const boost::optional<bool>& useIndexedCoupons)
242✔
793
    : RelativeDateRateHelper(rate), settlementDays_(settlementDays), tenor_(tenor),
242✔
794
      pillarChoice_(pillarChoice), calendar_(std::move(calendar)),
242✔
795
      fixedConvention_(fixedConvention), fixedFrequency_(fixedFrequency),
242✔
796
      fixedDayCount_(std::move(fixedDayCount)), spread_(std::move(spread)), endOfMonth_(endOfMonth),
242✔
797
      fwdStart_(fwdStart), discountHandle_(std::move(discount)),
242✔
798
      useIndexedCoupons_(useIndexedCoupons) {
484✔
799

800
        // take fixing into account
801
        iborIndex_ = iborIndex->clone(termStructureHandle_);
242✔
802
        // We want to be notified of changes of fixings, but we don't
803
        // want notifications from termStructureHandle_ (they would
804
        // interfere with bootstrapping.)
805
        iborIndex_->unregisterWith(termStructureHandle_);
242✔
806

807
        registerWith(iborIndex_);
484✔
808
        registerWith(spread_);
484✔
809
        registerWith(discountHandle_);
242✔
810

811
        pillarDate_ = customPillarDate;
242✔
812
        SwapRateHelper::initializeDates();
242✔
813
    }
242✔
814

815
    void SwapRateHelper::initializeDates() {
2,005✔
816

817
        // 1. do not pass the spread here, as it might be a Quote
818
        //    i.e. it can dinamically change
819
        // 2. input discount curve Handle might be empty now but it could
820
        //    be assigned a curve later; use a RelinkableHandle here
821
        swap_ = MakeVanillaSwap(tenor_, iborIndex_, 0.0, fwdStart_)
2,005✔
822
            .withSettlementDays(settlementDays_)
2,005✔
823
            .withDiscountingTermStructure(discountRelinkableHandle_)
2,005✔
824
            .withFixedLegDayCount(fixedDayCount_)
2,005✔
825
            .withFixedLegTenor(Period(fixedFrequency_))
2,005✔
826
            .withFixedLegConvention(fixedConvention_)
2,005✔
827
            .withFixedLegTerminationDateConvention(fixedConvention_)
2,005✔
828
            .withFixedLegCalendar(calendar_)
2,005✔
829
            .withFixedLegEndOfMonth(endOfMonth_)
2,005✔
830
            .withFloatingLegCalendar(calendar_)
2,005✔
831
            .withFloatingLegEndOfMonth(endOfMonth_)
2,005✔
832
            .withIndexedCoupons(useIndexedCoupons_);
4,010✔
833

834
        earliestDate_ = swap_->startDate();
2,005✔
835
        maturityDate_ = swap_->maturityDate();
2,005✔
836

837
        ext::shared_ptr<IborCoupon> lastCoupon =
838
            ext::dynamic_pointer_cast<IborCoupon>(swap_->floatingLeg().back());
2,005✔
839
        latestRelevantDate_ = std::max(maturityDate_, lastCoupon->fixingEndDate());
2,005✔
840

841
        switch (pillarChoice_) {
2,005✔
842
          case Pillar::MaturityDate:
×
843
            pillarDate_ = maturityDate_;
×
844
            break;
×
845
          case Pillar::LastRelevantDate:
2,005✔
846
            pillarDate_ = latestRelevantDate_;
2,005✔
847
            break;
2,005✔
848
          case Pillar::CustomDate:
×
849
            // pillarDate_ already assigned at construction time
850
            QL_REQUIRE(pillarDate_ >= earliestDate_,
×
851
                "pillar date (" << pillarDate_ << ") must be later "
852
                "than or equal to the instrument's earliest date (" <<
853
                earliestDate_ << ")");
854
            QL_REQUIRE(pillarDate_ <= latestRelevantDate_,
×
855
                "pillar date (" << pillarDate_ << ") must be before "
856
                "or equal to the instrument's latest relevant date (" <<
857
                latestRelevantDate_ << ")");
858
            break;
859
          default:
×
860
            QL_FAIL("unknown Pillar::Choice(" << Integer(pillarChoice_) << ")");
×
861
        }
862

863
        latestDate_ = pillarDate_; // backward compatibility
2,005✔
864

865
    }
2,005✔
866

867
    void SwapRateHelper::setTermStructure(YieldTermStructure* t) {
1,564✔
868
        // do not set the relinkable handle as an observer -
869
        // force recalculation when needed
870
        bool observer = false;
871

872
        ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
873
        termStructureHandle_.linkTo(temp, observer);
1,564✔
874

875
        if (discountHandle_.empty())
1,564✔
876
            discountRelinkableHandle_.linkTo(temp, observer);
1,530✔
877
        else
878
            discountRelinkableHandle_.linkTo(*discountHandle_, observer);
34✔
879

880
        RelativeDateRateHelper::setTermStructure(t);
1,564✔
881
    }
1,564✔
882

883
    Real SwapRateHelper::impliedQuote() const {
21,704✔
884
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
21,704✔
885
        // we didn't register as observers - force calculation
886
        swap_->recalculate();
21,704✔
887
        // weak implementation... to be improved
888
        static const Spread basisPoint = 1.0e-4;
889
        Real floatingLegNPV = swap_->floatingLegNPV();
21,704✔
890
        Spread spread = spread_.empty() ? 0.0 : spread_->value();
21,704✔
891
        Real spreadNPV = swap_->floatingLegBPS()/basisPoint*spread;
21,704✔
892
        Real totNPV = - (floatingLegNPV+spreadNPV);
21,704✔
893
        Real result = totNPV/(swap_->fixedLegBPS()/basisPoint);
21,704✔
894
        return result;
21,704✔
895
    }
896

897
    void SwapRateHelper::accept(AcyclicVisitor& v) {
×
898
        auto* v1 = dynamic_cast<Visitor<SwapRateHelper>*>(&v);
×
899
        if (v1 != nullptr)
×
900
            v1->visit(*this);
×
901
        else
902
            RateHelper::accept(v);
×
903
    }
×
904

905
    BMASwapRateHelper::BMASwapRateHelper(const Handle<Quote>& liborFraction,
80✔
906
                                         const Period& tenor,
907
                                         Natural settlementDays,
908
                                         Calendar calendar,
909
                                         // bma leg
910
                                         const Period& bmaPeriod,
911
                                         BusinessDayConvention bmaConvention,
912
                                         DayCounter bmaDayCount,
913
                                         ext::shared_ptr<BMAIndex> bmaIndex,
914
                                         // libor leg
915
                                         ext::shared_ptr<IborIndex> iborIndex)
80✔
916
    : RelativeDateRateHelper(liborFraction), tenor_(tenor), settlementDays_(settlementDays),
80✔
917
      calendar_(std::move(calendar)), bmaPeriod_(bmaPeriod), bmaConvention_(bmaConvention),
80✔
918
      bmaDayCount_(std::move(bmaDayCount)), bmaIndex_(std::move(bmaIndex)),
919
      iborIndex_(std::move(iborIndex)) {
80✔
920
        registerWith(iborIndex_);
160✔
921
        registerWith(bmaIndex_);
80✔
922
        BMASwapRateHelper::initializeDates();
80✔
923
    }
80✔
924

925
    void BMASwapRateHelper::initializeDates() {
160✔
926
        // if the evaluation date is not a business day
927
        // then move to the next business day
928
        JointCalendar jc(calendar_,
160✔
929
                         iborIndex_->fixingCalendar());
160✔
930
        Date referenceDate = jc.adjust(evaluationDate_);
160✔
931
        earliestDate_ =
932
            calendar_.advance(referenceDate, settlementDays_ * Days, Following);
160✔
933

934
        Date maturity = earliestDate_ + tenor_;
160✔
935

936
        // dummy BMA index with curve/swap arguments
937
        ext::shared_ptr<BMAIndex> clonedIndex(new BMAIndex(termStructureHandle_));
160✔
938

939
        Schedule bmaSchedule =
940
            MakeSchedule().from(earliestDate_).to(maturity)
160✔
941
                          .withTenor(bmaPeriod_)
160✔
942
                          .withCalendar(bmaIndex_->fixingCalendar())
320✔
943
                          .withConvention(bmaConvention_)
160✔
944
                          .backwards();
160✔
945

946
        Schedule liborSchedule =
947
            MakeSchedule().from(earliestDate_).to(maturity)
160✔
948
                          .withTenor(iborIndex_->tenor())
160✔
949
                          .withCalendar(iborIndex_->fixingCalendar())
320✔
950
                          .withConvention(iborIndex_->businessDayConvention())
160✔
951
                          .endOfMonth(iborIndex_->endOfMonth())
160✔
952
                          .backwards();
160✔
953

954
        swap_ = ext::make_shared<BMASwap>(Swap::Payer, 100.0,
320✔
955
                                          liborSchedule,
956
                                          0.75, // arbitrary
320✔
957
                                          0.0,
160✔
958
                                          iborIndex_,
959
                                          iborIndex_->dayCounter(),
160✔
960
                                          bmaSchedule,
961
                                          clonedIndex,
962
                                          bmaDayCount_);
320✔
963
        swap_->setPricingEngine(ext::shared_ptr<PricingEngine>(new
640✔
964
            DiscountingSwapEngine(iborIndex_->forwardingTermStructure())));
320✔
965

966
        Date d = calendar_.adjust(swap_->maturityDate(), Following);
160✔
967
        Weekday w = d.weekday();
968
        Date nextWednesday = (w >= 4) ?
160✔
969
            d + (11 - w) * Days :
64✔
970
            d + (4 - w) * Days;
160✔
971
        latestDate_ = clonedIndex->valueDate(
320✔
972
                         clonedIndex->fixingCalendar().adjust(nextWednesday));
320✔
973
    }
320✔
974

975
    void BMASwapRateHelper::setTermStructure(YieldTermStructure* t) {
80✔
976
        // do not set the relinkable handle as an observer -
977
        // force recalculation when needed
978
        bool observer = false;
979

980
        ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
981
        termStructureHandle_.linkTo(temp, observer);
80✔
982

983
        RelativeDateRateHelper::setTermStructure(t);
80✔
984
    }
80✔
985

986
    Real BMASwapRateHelper::impliedQuote() const {
1,213✔
987
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
1,213✔
988
        // we didn't register as observers - force calculation
989
        swap_->recalculate();
1,213✔
990
        return swap_->fairLiborFraction();
1,213✔
991
    }
992

993
    void BMASwapRateHelper::accept(AcyclicVisitor& v) {
×
994
        auto* v1 = dynamic_cast<Visitor<BMASwapRateHelper>*>(&v);
×
995
        if (v1 != nullptr)
×
996
            v1->visit(*this);
×
997
        else
998
            RateHelper::accept(v);
×
999
    }
×
1000

1001
    FxSwapRateHelper::FxSwapRateHelper(const Handle<Quote>& fwdPoint,
6✔
1002
                                       Handle<Quote> spotFx,
1003
                                       const Period& tenor,
1004
                                       Natural fixingDays,
1005
                                       Calendar calendar,
1006
                                       BusinessDayConvention convention,
1007
                                       bool endOfMonth,
1008
                                       bool isFxBaseCurrencyCollateralCurrency,
1009
                                       Handle<YieldTermStructure> coll,
1010
                                       Calendar tradingCalendar)
6✔
1011
    : RelativeDateRateHelper(fwdPoint), spot_(std::move(spotFx)), tenor_(tenor),
6✔
1012
      fixingDays_(fixingDays), cal_(std::move(calendar)), conv_(convention), eom_(endOfMonth),
6✔
1013
      isFxBaseCurrencyCollateralCurrency_(isFxBaseCurrencyCollateralCurrency),
6✔
1014
      collHandle_(std::move(coll)), tradingCalendar_(std::move(tradingCalendar)) {
18✔
1015
        registerWith(spot_);
12✔
1016
        registerWith(collHandle_);
12✔
1017

1018
        if (tradingCalendar_.empty())
6✔
1019
            jointCalendar_ = cal_;
1020
        else
1021
            jointCalendar_ = JointCalendar(tradingCalendar_, cal_,
×
1022
                                           JoinHolidays);
1023
        FxSwapRateHelper::initializeDates();
6✔
1024
    }
6✔
1025

1026
    void FxSwapRateHelper::initializeDates() {
6✔
1027
        // if the evaluation date is not a business day
1028
        // then move to the next business day
1029
        Date refDate = cal_.adjust(evaluationDate_);
6✔
1030
        earliestDate_ = cal_.advance(refDate, fixingDays_*Days);
6✔
1031

1032
        if (!tradingCalendar_.empty()) {
6✔
1033
            // check if fx trade can be settled in US, if not, adjust it
1034
            earliestDate_ = jointCalendar_.adjust(earliestDate_);
×
1035
            latestDate_ = jointCalendar_.advance(earliestDate_, tenor_,
×
1036
                                                 conv_, eom_);
×
1037
        } else {
1038
            latestDate_ = cal_.advance(earliestDate_, tenor_, conv_, eom_);
6✔
1039
        }
1040
    }
6✔
1041

1042
    Real FxSwapRateHelper::impliedQuote() const {
62✔
1043
        QL_REQUIRE(termStructure_ != nullptr, "term structure not set");
62✔
1044

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

1047
        DiscountFactor d1 = collHandle_->discount(earliestDate_);
62✔
1048
        DiscountFactor d2 = collHandle_->discount(latestDate_);
62✔
1049
        Real collRatio = d1 / d2;
62✔
1050
        d1 = termStructureHandle_->discount(earliestDate_);
62✔
1051
        d2 = termStructureHandle_->discount(latestDate_);
62✔
1052
        Real ratio = d1 / d2;
62✔
1053
        Real spot = spot_->value();
62✔
1054
        if (isFxBaseCurrencyCollateralCurrency_) {
62✔
1055
            return (ratio/collRatio-1)*spot;
62✔
1056
        } else {
1057
            return (collRatio/ratio-1)*spot;
×
1058
        }
1059
    }
1060

1061
    void FxSwapRateHelper::setTermStructure(YieldTermStructure* t) {
12✔
1062
        // do not set the relinkable handle as an observer -
1063
        // force recalculation when needed
1064
        bool observer = false;
1065

1066
        ext::shared_ptr<YieldTermStructure> temp(t, null_deleter());
1067
        termStructureHandle_.linkTo(temp, observer);
12✔
1068

1069
        collRelinkableHandle_.linkTo(*collHandle_, observer);
12✔
1070

1071
        RelativeDateRateHelper::setTermStructure(t);
12✔
1072
    }
12✔
1073

1074
    void FxSwapRateHelper::accept(AcyclicVisitor& v) {
×
1075
        auto* v1 = dynamic_cast<Visitor<FxSwapRateHelper>*>(&v);
×
1076
        if (v1 != nullptr)
×
1077
            v1->visit(*this);
×
1078
        else
1079
            RateHelper::accept(v);
×
1080
    }
×
1081

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