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

lballabio / QuantLib / 29513377275

16 Jul 2026 03:55PM UTC coverage: 74.954%. Remained the same
29513377275

push

github

web-flow
Deprecate `ext::any`, `ext::optional` and friends (#2660)

27 of 38 new or added lines in 27 files covered. (71.05%)

59555 of 79455 relevant lines covered (74.95%)

8618938.55 hits per line

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

74.86
/ql/instruments/nonstandardswap.cpp
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2

3
/*
4
 Copyright (C) 2013, 2016 Peter Caspers
5

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

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

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

20
#include <ql/cashflows/capflooredcoupon.hpp>
21
#include <ql/cashflows/cashflows.hpp>
22
#include <ql/cashflows/cashflowvectors.hpp>
23
#include <ql/cashflows/cmscoupon.hpp>
24
#include <ql/cashflows/couponpricer.hpp>
25
#include <ql/cashflows/iborcoupon.hpp>
26
#include <ql/cashflows/simplecashflow.hpp>
27
#include <ql/indexes/iborindex.hpp>
28
#include <ql/indexes/swapindex.hpp>
29
#include <ql/instruments/nonstandardswap.hpp>
30
#include <ql/termstructures/yieldtermstructure.hpp>
31
#include <ql/optional.hpp>
32
#include <utility>
33

34
namespace QuantLib {
35

36
    NonstandardSwap::NonstandardSwap(const FixedVsFloatingSwap &fromVanilla)
2✔
37
        : Swap(2), type_(fromVanilla.type()),
2✔
38
          fixedNominal_(std::vector<Real>(fromVanilla.fixedLeg().size(),
2✔
39
                                          fromVanilla.nominal())),
2✔
40
          floatingNominal_(std::vector<Real>(fromVanilla.floatingLeg().size(),
2✔
41
                                             fromVanilla.nominal())),
2✔
42
          fixedSchedule_(fromVanilla.fixedSchedule()),
2✔
43
          fixedRate_(std::vector<Real>(fromVanilla.fixedLeg().size(),
2✔
44
                                       fromVanilla.fixedRate())),
2✔
45
          fixedDayCount_(fromVanilla.fixedDayCount()),
46
          floatingSchedule_(fromVanilla.floatingSchedule()),
2✔
47
          iborIndex_(fromVanilla.iborIndex()),
48
          spread_(std::vector<Real>(fromVanilla.floatingLeg().size(), fromVanilla.spread())),
2✔
49
          gearing_(std::vector<Real>(fromVanilla.floatingLeg().size(), 1.0)),
2✔
50
          singleSpreadAndGearing_(true),
2✔
51
          floatingDayCount_(fromVanilla.floatingDayCount()),
52
          paymentConvention_(fromVanilla.paymentConvention()),
2✔
53
          intermediateCapitalExchange_(false), finalCapitalExchange_(false) {
2✔
54

55
        init();
2✔
56
    }
2✔
57

58
    NonstandardSwap::NonstandardSwap(const Swap::Type type,
2✔
59
                                     std::vector<Real> fixedNominal,
60
                                     const std::vector<Real>& floatingNominal,
61
                                     Schedule fixedSchedule,
62
                                     std::vector<Real> fixedRate,
63
                                     DayCounter fixedDayCount,
64
                                     Schedule floatingSchedule,
65
                                     ext::shared_ptr<IborIndex> iborIndex,
66
                                     const Real gearing,
67
                                     const Spread spread,
68
                                     DayCounter floatingDayCount,
69
                                     const bool intermediateCapitalExchange,
70
                                     const bool finalCapitalExchange,
71
                                     std::optional<BusinessDayConvention> paymentConvention)
2✔
72
    : Swap(2), type_(type), fixedNominal_(std::move(fixedNominal)),
2✔
73
      floatingNominal_(floatingNominal), fixedSchedule_(std::move(fixedSchedule)),
2✔
74
      fixedRate_(std::move(fixedRate)), fixedDayCount_(std::move(fixedDayCount)),
75
      floatingSchedule_(std::move(floatingSchedule)), iborIndex_(std::move(iborIndex)),
2✔
76
      spread_(std::vector<Real>(floatingNominal.size(), spread)),
2✔
77
      gearing_(std::vector<Real>(floatingNominal.size(), gearing)), singleSpreadAndGearing_(true),
2✔
78
      floatingDayCount_(std::move(floatingDayCount)),
79
      intermediateCapitalExchange_(intermediateCapitalExchange),
2✔
80
      finalCapitalExchange_(finalCapitalExchange) {
4✔
81

82
        if (paymentConvention) // NOLINT(readability-implicit-bool-conversion)
2✔
83
            paymentConvention_ = *paymentConvention;
×
84
        else
85
            paymentConvention_ = floatingSchedule_.businessDayConvention();
2✔
86
        init();
2✔
87
    }
2✔
88

89
    NonstandardSwap::NonstandardSwap(const Swap::Type type,
×
90
                                     std::vector<Real> fixedNominal,
91
                                     std::vector<Real> floatingNominal,
92
                                     Schedule fixedSchedule,
93
                                     std::vector<Real> fixedRate,
94
                                     DayCounter fixedDayCount,
95
                                     Schedule floatingSchedule,
96
                                     ext::shared_ptr<IborIndex> iborIndex,
97
                                     std::vector<Real> gearing,
98
                                     std::vector<Spread> spread,
99
                                     DayCounter floatingDayCount,
100
                                     const bool intermediateCapitalExchange,
101
                                     const bool finalCapitalExchange,
NEW
102
                                     std::optional<BusinessDayConvention> paymentConvention)
×
103
    : Swap(2), type_(type), fixedNominal_(std::move(fixedNominal)),
×
104
      floatingNominal_(std::move(floatingNominal)), fixedSchedule_(std::move(fixedSchedule)),
×
105
      fixedRate_(std::move(fixedRate)), fixedDayCount_(std::move(fixedDayCount)),
106
      floatingSchedule_(std::move(floatingSchedule)), iborIndex_(std::move(iborIndex)),
×
107
      spread_(std::move(spread)), gearing_(std::move(gearing)), singleSpreadAndGearing_(false),
×
108
      floatingDayCount_(std::move(floatingDayCount)),
109
      intermediateCapitalExchange_(intermediateCapitalExchange),
×
110
      finalCapitalExchange_(finalCapitalExchange) {
×
111

112
        if (paymentConvention) // NOLINT(readability-implicit-bool-conversion)
×
113
            paymentConvention_ = *paymentConvention;
×
114
        else
115
            paymentConvention_ = floatingSchedule_.businessDayConvention();
×
116
        init();
×
117
    }
×
118

119
    void NonstandardSwap::init() {
4✔
120

121
        QL_REQUIRE(fixedNominal_.size() == fixedRate_.size(),
4✔
122
                   "Fixed nominal size ("
123
                       << fixedNominal_.size()
124
                       << ") does not match fixed rate size ("
125
                       << fixedRate_.size() << ")");
126

127
        QL_REQUIRE(fixedNominal_.size() == fixedSchedule_.size() - 1,
4✔
128
                   "Fixed nominal size (" << fixedNominal_.size()
129
                                          << ") does not match schedule size ("
130
                                          << fixedSchedule_.size() << ") - 1");
131

132
        QL_REQUIRE(floatingNominal_.size() == floatingSchedule_.size() - 1,
4✔
133
                   "Floating nominal size ("
134
                       << floatingNominal_.size()
135
                       << ") does not match schedule size ("
136
                       << floatingSchedule_.size() << ") - 1");
137

138
        QL_REQUIRE(floatingNominal_.size() == spread_.size(),
4✔
139
                   "Floating nominal size (" << floatingNominal_.size()
140
                                             << ") does not match spread size ("
141
                                             << spread_.size() << ")");
142

143
        QL_REQUIRE(floatingNominal_.size() == gearing_.size(),
4✔
144
                   "Floating nominal size ("
145
                       << floatingNominal_.size()
146
                       << ") does not match gearing size (" << gearing_.size()
147
                       << ")");
148

149
        // if the gearing is zero then the ibor leg will be set up with fixed
150
        // coupons which makes trouble here in this context. We therefore use
151
        // a dirty trick and enforce the gearing to be non zero.
152
        for (Real& i : gearing_) {
84✔
153
            if (close(i, 0.0))
80✔
154
                i = QL_EPSILON;
×
155
        }
156

157
        legs_[0] = FixedRateLeg(fixedSchedule_)
8✔
158
                       .withNotionals(fixedNominal_)
4✔
159
                       .withCouponRates(fixedRate_, fixedDayCount_)
4✔
160
                       .withPaymentAdjustment(paymentConvention_);
8✔
161

162
        legs_[1] = IborLeg(floatingSchedule_, iborIndex_)
8✔
163
                       .withNotionals(floatingNominal_)
4✔
164
                       .withPaymentDayCounter(floatingDayCount_)
4✔
165
                       .withPaymentAdjustment(paymentConvention_)
4✔
166
                       .withSpreads(spread_)
4✔
167
                       .withGearings(gearing_);
8✔
168

169
        if (intermediateCapitalExchange_) {
4✔
170
            for (Size i = 0; i < legs_[0].size() - 1; i++) {
×
171
                Real cap = fixedNominal_[i] - fixedNominal_[i + 1];
×
172
                if (!close(cap, 0.0)) {
×
173
                    auto it1 = legs_[0].begin();
×
174
                    std::advance(it1, i + 1);
175
                    legs_[0].insert(
×
176
                        it1, ext::shared_ptr<CashFlow>(
×
177
                                 new Redemption(cap, legs_[0][i]->date())));
×
178
                    auto it2 = fixedNominal_.begin();
×
179
                    std::advance(it2, i + 1);
180
                    fixedNominal_.insert(it2, fixedNominal_[i]);
×
181
                    auto it3 = fixedRate_.begin();
×
182
                    std::advance(it3, i + 1);
183
                    fixedRate_.insert(it3, 0.0);
×
184
                    i++;
185
                }
186
            }
187
            for (Size i = 0; i < legs_[1].size() - 1; i++) {
×
188
                Real cap = floatingNominal_[i] - floatingNominal_[i + 1];
×
189
                if (!close(cap, 0.0)) {
×
190
                    auto it1 = legs_[1].begin();
×
191
                    std::advance(it1, i + 1);
192
                    legs_[1].insert(
×
193
                        it1, ext::shared_ptr<CashFlow>(
×
194
                                 new Redemption(cap, legs_[1][i]->date())));
×
195
                    auto it2 = floatingNominal_.begin();
×
196
                    std::advance(it2, i + 1);
197
                    floatingNominal_.insert(it2, floatingNominal_[i]);
×
198
                    i++;
199
                }
200
            }
201
        }
202

203
        if (finalCapitalExchange_) {
4✔
204
            legs_[0].push_back(ext::shared_ptr<CashFlow>(
1✔
205
                new Redemption(fixedNominal_.back(), legs_[0].back()->date())));
2✔
206
            fixedNominal_.push_back(fixedNominal_.back());
1✔
207
            fixedRate_.push_back(0.0);
1✔
208
            legs_[1].push_back(ext::shared_ptr<CashFlow>(new Redemption(
1✔
209
                floatingNominal_.back(), legs_[1].back()->date())));
2✔
210
            floatingNominal_.push_back(floatingNominal_.back());
1✔
211
        }
212

213
        for (auto i = legs_[1].begin(); i < legs_[1].end(); ++i)
85✔
214
            registerWith(*i);
162✔
215

216
        switch (type_) {
4✔
217
        case Swap::Payer:
3✔
218
            payer_[0] = -1.0;
3✔
219
            payer_[1] = +1.0;
3✔
220
            break;
3✔
221
        case Swap::Receiver:
1✔
222
            payer_[0] = +1.0;
1✔
223
            payer_[1] = -1.0;
1✔
224
            break;
1✔
225
        default:
×
226
            QL_FAIL("Unknown nonstandard-swap type");
×
227
        }
228
    }
4✔
229

230
    void NonstandardSwap::setupArguments(PricingEngine::arguments *args) const {
10✔
231

232
        Swap::setupArguments(args);
10✔
233

234
        auto* arguments = dynamic_cast<NonstandardSwap::arguments*>(args);
10✔
235

236
        if (arguments == nullptr)
10✔
237
            return; // swap engine ...
238

239
        arguments->type = type_;
10✔
240
        arguments->fixedNominal = fixedNominal_;
10✔
241
        arguments->floatingNominal = floatingNominal_;
10✔
242
        arguments->fixedRate = fixedRate_;
10✔
243

244
        const Leg &fixedCoupons = fixedLeg();
245

246
        arguments->fixedResetDates = arguments->fixedPayDates =
247
            std::vector<Date>(fixedCoupons.size());
20✔
248
        arguments->fixedCoupons = std::vector<Real>(fixedCoupons.size());
10✔
249
        arguments->fixedIsRedemptionFlow =
250
            std::vector<bool>(fixedCoupons.size(), false);
10✔
251

252
        for (Size i = 0; i < fixedCoupons.size(); ++i) {
114✔
253
            ext::shared_ptr<FixedRateCoupon> coupon =
254
                ext::dynamic_pointer_cast<FixedRateCoupon>(fixedCoupons[i]);
104✔
255
            if (coupon != nullptr) {
104✔
256
                arguments->fixedPayDates[i] = coupon->date();
100✔
257
                arguments->fixedResetDates[i] = coupon->accrualStartDate();
100✔
258
                arguments->fixedCoupons[i] = coupon->amount();
100✔
259
            } else {
260
                ext::shared_ptr<CashFlow> cashflow =
261
                    ext::dynamic_pointer_cast<CashFlow>(fixedCoupons[i]);
4✔
262
                auto j =
263
                    std::find(arguments->fixedPayDates.begin(),
4✔
264
                              arguments->fixedPayDates.end(), cashflow->date());
4✔
265
                QL_REQUIRE(j != arguments->fixedPayDates.end(),
4✔
266
                           "nominal redemption on "
267
                               << cashflow->date()
268
                               << "has no corresponding coupon");
269
                Size jIdx = j - arguments->fixedPayDates.begin();
270
                arguments->fixedIsRedemptionFlow[i] = true;
271
                arguments->fixedCoupons[i] = cashflow->amount();
4✔
272
                arguments->fixedResetDates[i] =
4✔
273
                    arguments->fixedResetDates[jIdx];
274
                arguments->fixedPayDates[i] = cashflow->date();
4✔
275
            }
276
        }
277

278
        const Leg &floatingCoupons = floatingLeg();
279

280
        arguments->floatingResetDates = arguments->floatingPayDates =
281
            arguments->floatingFixingDates =
282
                std::vector<Date>(floatingCoupons.size());
20✔
283
        arguments->floatingAccrualTimes =
284
            std::vector<Time>(floatingCoupons.size());
20✔
285
        arguments->floatingSpreads =
286
            std::vector<Spread>(floatingCoupons.size());
20✔
287
        arguments->floatingGearings = std::vector<Real>(floatingCoupons.size());
20✔
288
        arguments->floatingCoupons = std::vector<Real>(floatingCoupons.size());
10✔
289
        arguments->floatingIsRedemptionFlow =
290
            std::vector<bool>(floatingCoupons.size(), false);
10✔
291

292
        for (Size i = 0; i < floatingCoupons.size(); ++i) {
214✔
293
            ext::shared_ptr<IborCoupon> coupon =
294
                ext::dynamic_pointer_cast<IborCoupon>(floatingCoupons[i]);
204✔
295
            if (coupon != nullptr) {
204✔
296
                arguments->floatingResetDates[i] = coupon->accrualStartDate();
200✔
297
                arguments->floatingPayDates[i] = coupon->date();
200✔
298
                arguments->floatingFixingDates[i] = coupon->fixingDate();
200✔
299
                arguments->floatingAccrualTimes[i] = coupon->accrualPeriod();
200✔
300
                arguments->floatingSpreads[i] = coupon->spread();
200✔
301
                arguments->floatingGearings[i] = coupon->gearing();
200✔
302
                try {
303
                    arguments->floatingCoupons[i] = coupon->amount();
200✔
304
                }
305
                catch (Error &) {
×
306
                    arguments->floatingCoupons[i] = Null<Real>();
×
307
                }
×
308
            } else {
309
                ext::shared_ptr<CashFlow> cashflow =
310
                    ext::dynamic_pointer_cast<CashFlow>(floatingCoupons[i]);
4✔
311
                auto j = std::find(
4✔
312
                    arguments->floatingPayDates.begin(),
313
                    arguments->floatingPayDates.end(), cashflow->date());
4✔
314
                QL_REQUIRE(j != arguments->floatingPayDates.end(),
4✔
315
                           "nominal redemption on "
316
                               << cashflow->date()
317
                               << "has no corresponding coupon");
318
                Size jIdx = j - arguments->floatingPayDates.begin();
319
                arguments->floatingIsRedemptionFlow[i] = true;
320
                arguments->floatingCoupons[i] = cashflow->amount();
4✔
321
                arguments->floatingResetDates[i] =
4✔
322
                    arguments->floatingResetDates[jIdx];
323
                arguments->floatingFixingDates[i] =
4✔
324
                    arguments->floatingFixingDates[jIdx];
325
                arguments->floatingAccrualTimes[i] = 0.0;
4✔
326
                arguments->floatingSpreads[i] = 0.0;
4✔
327
                arguments->floatingGearings[i] = 1.0;
4✔
328
                arguments->floatingPayDates[i] = cashflow->date();
4✔
329
            }
330
        }
331

332
        arguments->iborIndex = iborIndex();
10✔
333
    }
334

335
    void NonstandardSwap::setupExpired() const { Swap::setupExpired(); }
×
336

337
    void NonstandardSwap::fetchResults(const PricingEngine::results *r) const {
×
338

339
        Swap::fetchResults(r);
×
340
    }
×
341

342
    void NonstandardSwap::arguments::validate() const {
10✔
343
        Swap::arguments::validate();
10✔
344
        QL_REQUIRE(fixedNominal.size() == fixedPayDates.size(),
10✔
345
                   "number of fixed leg nominals plus redemption flows "
346
                   "different from number of payment dates");
347
        QL_REQUIRE(fixedRate.size() == fixedPayDates.size(),
10✔
348
                   "number of fixed rates plus redemption flows different from "
349
                   "number of payment dates");
350
        QL_REQUIRE(floatingNominal.size() == floatingPayDates.size(),
10✔
351
                   "number of float leg nominals different from number of "
352
                   "payment dates");
353
        QL_REQUIRE(fixedResetDates.size() == fixedPayDates.size(),
10✔
354
                   "number of fixed start dates different from "
355
                   "number of fixed payment dates");
356
        QL_REQUIRE(fixedPayDates.size() == fixedCoupons.size(),
10✔
357
                   "number of fixed payment dates different from "
358
                   "number of fixed coupon amounts");
359
        QL_REQUIRE(floatingResetDates.size() == floatingPayDates.size(),
10✔
360
                   "number of floating start dates different from "
361
                   "number of floating payment dates");
362
        QL_REQUIRE(floatingFixingDates.size() == floatingPayDates.size(),
10✔
363
                   "number of floating fixing dates different from "
364
                   "number of floating payment dates");
365
        QL_REQUIRE(floatingAccrualTimes.size() == floatingPayDates.size(),
10✔
366
                   "number of floating accrual Times different from "
367
                   "number of floating payment dates");
368
        QL_REQUIRE(floatingSpreads.size() == floatingPayDates.size(),
10✔
369
                   "number of floating spreads different from "
370
                   "number of floating payment dates");
371
        QL_REQUIRE(floatingPayDates.size() == floatingCoupons.size(),
10✔
372
                   "number of floating payment dates different from "
373
                   "number of floating coupon amounts");
374
    }
10✔
375

376
    void NonstandardSwap::results::reset() { Swap::results::reset(); }
×
377
}
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