Coverage Report

Created: 2026-01-25 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/instruments/floatfloatswap.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2013 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/experimental/coupons/cmsspreadcoupon.hpp> // internal
28
#include <ql/indexes/iborindex.hpp>
29
#include <ql/indexes/swapindex.hpp>
30
#include <ql/instruments/floatfloatswap.hpp>
31
#include <ql/termstructures/yieldtermstructure.hpp>
32
#include <ql/optional.hpp>
33
#include <utility>
34
35
namespace QuantLib {
36
37
    FloatFloatSwap::FloatFloatSwap(const Swap::Type type,
38
                                   const Real nominal1,
39
                                   const Real nominal2,
40
                                   Schedule schedule1,
41
                                   ext::shared_ptr<InterestRateIndex> index1,
42
                                   DayCounter dayCount1,
43
                                   Schedule schedule2,
44
                                   ext::shared_ptr<InterestRateIndex> index2,
45
                                   DayCounter dayCount2,
46
                                   const bool intermediateCapitalExchange,
47
                                   const bool finalCapitalExchange,
48
                                   const Real gearing1,
49
                                   const Real spread1,
50
                                   const Real cappedRate1,
51
                                   const Real flooredRate1,
52
                                   const Real gearing2,
53
                                   const Real spread2,
54
                                   const Real cappedRate2,
55
                                   const Real flooredRate2,
56
                                   const ext::optional<BusinessDayConvention>& paymentConvention1,
57
                                   const ext::optional<BusinessDayConvention>& paymentConvention2)
58
0
    : Swap(2), type_(type), nominal1_(std::vector<Real>(schedule1.size() - 1, nominal1)),
59
0
      nominal2_(std::vector<Real>(schedule2.size() - 1, nominal2)),
60
0
      schedule1_(std::move(schedule1)), schedule2_(std::move(schedule2)),
61
0
      index1_(std::move(index1)), index2_(std::move(index2)),
62
0
      gearing1_(std::vector<Real>(schedule1_.size() - 1, gearing1)),
63
0
      gearing2_(std::vector<Real>(schedule2_.size() - 1, gearing2)),
64
0
      spread1_(std::vector<Real>(schedule1_.size() - 1, spread1)),
65
0
      spread2_(std::vector<Real>(schedule2_.size() - 1, spread2)),
66
0
      cappedRate1_(std::vector<Real>(schedule1_.size() - 1, cappedRate1)),
67
0
      flooredRate1_(std::vector<Real>(schedule1_.size() - 1, flooredRate1)),
68
0
      cappedRate2_(std::vector<Real>(schedule2_.size() - 1, cappedRate2)),
69
0
      flooredRate2_(std::vector<Real>(schedule2_.size() - 1, flooredRate2)),
70
0
      dayCount1_(std::move(dayCount1)), dayCount2_(std::move(dayCount2)),
71
0
      intermediateCapitalExchange_(intermediateCapitalExchange),
72
0
      finalCapitalExchange_(finalCapitalExchange) {
73
74
0
        init(paymentConvention1, paymentConvention2);
75
0
    }
Unexecuted instantiation: QuantLib::FloatFloatSwap::FloatFloatSwap(QuantLib::Swap::Type, double, double, QuantLib::Schedule, boost::shared_ptr<QuantLib::InterestRateIndex>, QuantLib::DayCounter, QuantLib::Schedule, boost::shared_ptr<QuantLib::InterestRateIndex>, QuantLib::DayCounter, bool, bool, double, double, double, double, double, double, double, double, std::__1::optional<QuantLib::BusinessDayConvention> const&, std::__1::optional<QuantLib::BusinessDayConvention> const&)
Unexecuted instantiation: QuantLib::FloatFloatSwap::FloatFloatSwap(QuantLib::Swap::Type, double, double, QuantLib::Schedule, boost::shared_ptr<QuantLib::InterestRateIndex>, QuantLib::DayCounter, QuantLib::Schedule, boost::shared_ptr<QuantLib::InterestRateIndex>, QuantLib::DayCounter, bool, bool, double, double, double, double, double, double, double, double, std::__1::optional<QuantLib::BusinessDayConvention> const&, std::__1::optional<QuantLib::BusinessDayConvention> const&)
76
77
    FloatFloatSwap::FloatFloatSwap(const Swap::Type type,
78
                                   std::vector<Real> nominal1,
79
                                   std::vector<Real> nominal2,
80
                                   Schedule schedule1,
81
                                   ext::shared_ptr<InterestRateIndex> index1,
82
                                   DayCounter dayCount1,
83
                                   Schedule schedule2,
84
                                   ext::shared_ptr<InterestRateIndex> index2,
85
                                   DayCounter dayCount2,
86
                                   const bool intermediateCapitalExchange,
87
                                   const bool finalCapitalExchange,
88
                                   std::vector<Real> gearing1,
89
                                   std::vector<Real> spread1,
90
                                   std::vector<Real> cappedRate1,
91
                                   std::vector<Real> flooredRate1,
92
                                   std::vector<Real> gearing2,
93
                                   std::vector<Real> spread2,
94
                                   std::vector<Real> cappedRate2,
95
                                   std::vector<Real> flooredRate2,
96
                                   const ext::optional<BusinessDayConvention>& paymentConvention1,
97
                                   const ext::optional<BusinessDayConvention>& paymentConvention2)
98
0
    : Swap(2), type_(type), nominal1_(std::move(nominal1)), nominal2_(std::move(nominal2)),
99
0
      schedule1_(std::move(schedule1)), schedule2_(std::move(schedule2)),
100
0
      index1_(std::move(index1)), index2_(std::move(index2)), gearing1_(std::move(gearing1)),
101
0
      gearing2_(std::move(gearing2)), spread1_(std::move(spread1)), spread2_(std::move(spread2)),
102
0
      cappedRate1_(std::move(cappedRate1)), flooredRate1_(std::move(flooredRate1)),
103
0
      cappedRate2_(std::move(cappedRate2)), flooredRate2_(std::move(flooredRate2)),
104
0
      dayCount1_(std::move(dayCount1)), dayCount2_(std::move(dayCount2)),
105
0
      intermediateCapitalExchange_(intermediateCapitalExchange),
106
0
      finalCapitalExchange_(finalCapitalExchange) {
107
108
0
        init(paymentConvention1, paymentConvention2);
109
0
    }
Unexecuted instantiation: QuantLib::FloatFloatSwap::FloatFloatSwap(QuantLib::Swap::Type, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, QuantLib::Schedule, boost::shared_ptr<QuantLib::InterestRateIndex>, QuantLib::DayCounter, QuantLib::Schedule, boost::shared_ptr<QuantLib::InterestRateIndex>, QuantLib::DayCounter, bool, bool, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::optional<QuantLib::BusinessDayConvention> const&, std::__1::optional<QuantLib::BusinessDayConvention> const&)
Unexecuted instantiation: QuantLib::FloatFloatSwap::FloatFloatSwap(QuantLib::Swap::Type, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, QuantLib::Schedule, boost::shared_ptr<QuantLib::InterestRateIndex>, QuantLib::DayCounter, QuantLib::Schedule, boost::shared_ptr<QuantLib::InterestRateIndex>, QuantLib::DayCounter, bool, bool, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> >, std::__1::optional<QuantLib::BusinessDayConvention> const&, std::__1::optional<QuantLib::BusinessDayConvention> const&)
110
111
    void FloatFloatSwap::init(
112
        ext::optional<BusinessDayConvention> paymentConvention1,
113
0
        ext::optional<BusinessDayConvention> paymentConvention2) {
114
115
0
        QL_REQUIRE(nominal1_.size() == schedule1_.size() - 1,
116
0
                   "nominal1 size (" << nominal1_.size()
117
0
                                     << ") does not match schedule1 size ("
118
0
                                     << schedule1_.size() << ")");
119
0
        QL_REQUIRE(nominal2_.size() == schedule2_.size() - 1,
120
0
                   "nominal2 size (" << nominal2_.size()
121
0
                                     << ") does not match schedule2 size ("
122
0
                                     << nominal2_.size() << ")");
123
0
        QL_REQUIRE(gearing1_.empty() || gearing1_.size() == nominal1_.size(),
124
0
                   "nominal1 size (" << nominal1_.size() << ") does not match gearing1 size ("
125
0
                                     << gearing1_.size() << ")");
126
0
        QL_REQUIRE(gearing2_.empty() || gearing2_.size() == nominal2_.size(),
127
0
                   "nominal2 size (" << nominal2_.size() << ") does not match gearing2 size ("
128
0
                                     << gearing2_.size() << ")");
129
0
        QL_REQUIRE(cappedRate1_.empty() || cappedRate1_.size() == nominal1_.size(),
130
0
                   "nominal1 size (" << nominal1_.size() << ") does not match cappedRate1 size ("
131
0
                                     << cappedRate1_.size() << ")");
132
0
        QL_REQUIRE(cappedRate2_.empty() || cappedRate2_.size() == nominal2_.size(),
133
0
                   "nominal2 size (" << nominal2_.size() << ") does not match cappedRate2 size ("
134
0
                                     << cappedRate2_.size() << ")");
135
0
        QL_REQUIRE(flooredRate1_.empty() || flooredRate1_.size() == nominal1_.size(),
136
0
                   "nominal1 size (" << nominal1_.size() << ") does not match flooredRate1 size ("
137
0
                                     << flooredRate1_.size() << ")");
138
0
        QL_REQUIRE(flooredRate2_.empty() || flooredRate2_.size() == nominal2_.size(),
139
0
                   "nominal2 size (" << nominal2_.size() << ") does not match flooredRate2 size ("
140
0
                                     << flooredRate2_.size() << ")");
141
142
0
        if (paymentConvention1) // NOLINT(readability-implicit-bool-conversion)
143
0
            paymentConvention1_ = *paymentConvention1;
144
0
        else
145
0
            paymentConvention1_ = schedule1_.businessDayConvention();
146
147
0
        if (paymentConvention2) // NOLINT(readability-implicit-bool-conversion)
148
0
            paymentConvention2_ = *paymentConvention2;
149
0
        else
150
0
            paymentConvention2_ = schedule2_.businessDayConvention();
151
152
0
        if (gearing1_.empty())
153
0
            gearing1_ = std::vector<Real>(nominal1_.size(), 1.0);
154
0
        if (gearing2_.empty())
155
0
            gearing2_ = std::vector<Real>(nominal2_.size(), 1.0);
156
0
        if (spread1_.empty())
157
0
            spread1_ = std::vector<Real>(nominal1_.size(), 0.0);
158
0
        if (spread2_.empty())
159
0
            spread2_ = std::vector<Real>(nominal2_.size(), 0.0);
160
0
        if (cappedRate1_.empty())
161
0
            cappedRate1_ = std::vector<Real>(nominal1_.size(), Null<Real>());
162
0
        if (cappedRate2_.empty())
163
0
            cappedRate2_ = std::vector<Real>(nominal2_.size(), Null<Real>());
164
0
        if (flooredRate1_.empty())
165
0
            flooredRate1_ = std::vector<Real>(nominal1_.size(), Null<Real>());
166
0
        if (flooredRate2_.empty())
167
0
            flooredRate2_ = std::vector<Real>(nominal2_.size(), Null<Real>());
168
169
0
        bool isNull;
170
0
        isNull = cappedRate1_[0] == Null<Real>();
171
0
        for (Size i = 0; i < cappedRate1_.size(); i++) {
172
0
            if (isNull)
173
0
                QL_REQUIRE(cappedRate1_[i] == Null<Real>(),
174
0
                           "cappedRate1 must be null for all or none entry ("
175
0
                               << (i + 1) << "th is " << cappedRate1_[i]
176
0
                               << ")");
177
0
            else
178
0
                QL_REQUIRE(cappedRate1_[i] != Null<Real>(),
179
0
                           "cappedRate 1 must be null for all or none entry ("
180
0
                               << "1st is " << cappedRate1_[0] << ")");
181
0
        }
182
0
        isNull = cappedRate2_[0] == Null<Real>();
183
0
        for (Size i = 0; i < cappedRate2_.size(); i++) {
184
0
            if (isNull)
185
0
                QL_REQUIRE(cappedRate2_[i] == Null<Real>(),
186
0
                           "cappedRate2 must be null for all or none entry ("
187
0
                               << (i + 1) << "th is " << cappedRate2_[i]
188
0
                               << ")");
189
0
            else
190
0
                QL_REQUIRE(cappedRate2_[i] != Null<Real>(),
191
0
                           "cappedRate2 must be null for all or none entry ("
192
0
                               << "1st is " << cappedRate2_[0] << ")");
193
0
        }
194
0
        isNull = flooredRate1_[0] == Null<Real>();
195
0
        for (Size i = 0; i < flooredRate1_.size(); i++) {
196
0
            if (isNull)
197
0
                QL_REQUIRE(flooredRate1_[i] == Null<Real>(),
198
0
                           "flooredRate1 must be null for all or none entry ("
199
0
                               << (i + 1) << "th is " << flooredRate1_[i]
200
0
                               << ")");
201
0
            else
202
0
                QL_REQUIRE(flooredRate1_[i] != Null<Real>(),
203
0
                           "flooredRate 1 must be null for all or none entry ("
204
0
                               << "1st is " << flooredRate1_[0] << ")");
205
0
        }
206
0
        isNull = flooredRate2_[0] == Null<Real>();
207
0
        for (Size i = 0; i < flooredRate2_.size(); i++) {
208
0
            if (isNull)
209
0
                QL_REQUIRE(flooredRate2_[i] == Null<Real>(),
210
0
                           "flooredRate2 must be null for all or none entry ("
211
0
                               << (i + 1) << "th is " << flooredRate2_[i]
212
0
                               << ")");
213
0
            else
214
0
                QL_REQUIRE(flooredRate2_[i] != Null<Real>(),
215
0
                           "flooredRate2 must be null for all or none entry ("
216
0
                               << "1st is " << flooredRate2_[0] << ")");
217
0
        }
218
219
        // if the gearing is zero then the ibor / cms leg will be set up with
220
        // fixed coupons which makes trouble here in this context. We therefore
221
        // use a dirty trick and enforce the gearing to be non zero.
222
0
        for (Real& i : gearing1_)
223
0
            if (close(i, 0.0))
224
0
                i = QL_EPSILON;
225
0
        for (Real& i : gearing2_)
226
0
            if (close(i, 0.0))
227
0
                i = QL_EPSILON;
228
229
0
        ext::shared_ptr<IborIndex> ibor1 =
230
0
            ext::dynamic_pointer_cast<IborIndex>(index1_);
231
0
        ext::shared_ptr<IborIndex> ibor2 =
232
0
            ext::dynamic_pointer_cast<IborIndex>(index2_);
233
0
        ext::shared_ptr<SwapIndex> cms1 =
234
0
            ext::dynamic_pointer_cast<SwapIndex>(index1_);
235
0
        ext::shared_ptr<SwapIndex> cms2 =
236
0
            ext::dynamic_pointer_cast<SwapIndex>(index2_);
237
0
        ext::shared_ptr<SwapSpreadIndex> cmsspread1 =
238
0
            ext::dynamic_pointer_cast<SwapSpreadIndex>(index1_);
239
0
        ext::shared_ptr<SwapSpreadIndex> cmsspread2 =
240
0
            ext::dynamic_pointer_cast<SwapSpreadIndex>(index2_);
241
242
0
        QL_REQUIRE(ibor1 != nullptr || cms1 != nullptr || cmsspread1 != nullptr,
243
0
                   "index1 must be ibor or cms or cms spread");
244
0
        QL_REQUIRE(ibor2 != nullptr || cms2 != nullptr || cmsspread2 != nullptr,
245
0
                   "index2 must be ibor or cms");
246
247
0
        if (ibor1 != nullptr) {
248
0
            IborLeg leg(schedule1_, ibor1);
249
0
            leg = leg.withNotionals(nominal1_)
250
0
                      .withPaymentDayCounter(dayCount1_)
251
0
                      .withPaymentAdjustment(paymentConvention1_)
252
0
                      .withSpreads(spread1_)
253
0
                      .withGearings(gearing1_);
254
0
            if (cappedRate1_[0] != Null<Real>())
255
0
                leg = leg.withCaps(cappedRate1_);
256
0
            if (flooredRate1_[0] != Null<Real>())
257
0
                leg = leg.withFloors(flooredRate1_);
258
0
            legs_[0] = leg;
259
0
        }
260
261
0
        if (ibor2 != nullptr) {
262
0
            IborLeg leg(schedule2_, ibor2);
263
0
            leg = leg.withNotionals(nominal2_)
264
0
                      .withPaymentDayCounter(dayCount2_)
265
0
                      .withPaymentAdjustment(paymentConvention2_)
266
0
                      .withSpreads(spread2_)
267
0
                      .withGearings(gearing2_);
268
0
            if (cappedRate2_[0] != Null<Real>())
269
0
                leg = leg.withCaps(cappedRate2_);
270
0
            if (flooredRate2_[0] != Null<Real>())
271
0
                leg = leg.withFloors(flooredRate2_);
272
0
            legs_[1] = leg;
273
0
        }
274
275
0
        if (cms1 != nullptr) {
276
0
            CmsLeg leg(schedule1_, cms1);
277
0
            leg = leg.withNotionals(nominal1_)
278
0
                      .withPaymentDayCounter(dayCount1_)
279
0
                      .withPaymentAdjustment(paymentConvention1_)
280
0
                      .withSpreads(spread1_)
281
0
                      .withGearings(gearing1_);
282
0
            if (cappedRate1_[0] != Null<Real>())
283
0
                leg = leg.withCaps(cappedRate1_);
284
0
            if (flooredRate1_[0] != Null<Real>())
285
0
                leg = leg.withFloors(flooredRate1_);
286
0
            legs_[0] = leg;
287
0
        }
288
289
0
        if (cms2 != nullptr) {
290
0
            CmsLeg leg(schedule2_, cms2);
291
0
            leg = leg.withNotionals(nominal2_)
292
0
                      .withPaymentDayCounter(dayCount2_)
293
0
                      .withPaymentAdjustment(paymentConvention2_)
294
0
                      .withSpreads(spread2_)
295
0
                      .withGearings(gearing2_);
296
0
            if (cappedRate2_[0] != Null<Real>())
297
0
                leg = leg.withCaps(cappedRate2_);
298
0
            if (flooredRate2_[0] != Null<Real>())
299
0
                leg = leg.withFloors(flooredRate2_);
300
0
            legs_[1] = leg;
301
0
        }
302
303
0
        if (cmsspread1 != nullptr) {
304
0
            CmsSpreadLeg leg(schedule1_, cmsspread1);
305
0
            leg = leg.withNotionals(nominal1_)
306
0
                      .withPaymentDayCounter(dayCount1_)
307
0
                      .withPaymentAdjustment(paymentConvention1_)
308
0
                      .withSpreads(spread1_)
309
0
                      .withGearings(gearing1_);
310
0
            if (cappedRate1_[0] != Null<Real>())
311
0
                leg = leg.withCaps(cappedRate1_);
312
0
            if (flooredRate1_[0] != Null<Real>())
313
0
                leg = leg.withFloors(flooredRate1_);
314
0
            legs_[0] = leg;
315
0
        }
316
317
0
        if (cmsspread2 != nullptr) {
318
0
            CmsSpreadLeg leg(schedule2_, cmsspread2);
319
0
            leg = leg.withNotionals(nominal2_)
320
0
                      .withPaymentDayCounter(dayCount2_)
321
0
                      .withPaymentAdjustment(paymentConvention2_)
322
0
                      .withSpreads(spread2_)
323
0
                      .withGearings(gearing2_);
324
0
            if (cappedRate2_[0] != Null<Real>())
325
0
                leg = leg.withCaps(cappedRate2_);
326
0
            if (flooredRate2_[0] != Null<Real>())
327
0
                leg = leg.withFloors(flooredRate2_);
328
0
            legs_[1] = leg;
329
0
        }
330
331
0
        if (intermediateCapitalExchange_) {
332
0
            for (Size i = 0; i < legs_[0].size() - 1; i++) {
333
0
                Real cap = nominal1_[i] - nominal1_[i + 1];
334
0
                if (!close(cap, 0.0)) {
335
0
                    auto it1 = legs_[0].begin();
336
0
                    std::advance(it1, i + 1);
337
0
                    legs_[0].insert(
338
0
                        it1, ext::shared_ptr<CashFlow>(
339
0
                                 new Redemption(cap, legs_[0][i]->date())));
340
0
                    auto it2 = nominal1_.begin();
341
0
                    std::advance(it2, i + 1);
342
0
                    nominal1_.insert(it2, nominal1_[i]);
343
0
                    i++;
344
0
                }
345
0
            }
346
0
            for (Size i = 0; i < legs_[1].size() - 1; i++) {
347
0
                Real cap = nominal2_[i] - nominal2_[i + 1];
348
0
                if (!close(cap, 0.0)) {
349
0
                    auto it1 = legs_[1].begin();
350
0
                    std::advance(it1, i + 1);
351
0
                    legs_[1].insert(
352
0
                        it1, ext::shared_ptr<CashFlow>(
353
0
                                 new Redemption(cap, legs_[1][i]->date())));
354
0
                    auto it2 = nominal2_.begin();
355
0
                    std::advance(it2, i + 1);
356
0
                    nominal2_.insert(it2, nominal2_[i]);
357
0
                    i++;
358
0
                }
359
0
            }
360
0
        }
361
362
0
        if (finalCapitalExchange_) {
363
0
            legs_[0].push_back(ext::shared_ptr<CashFlow>(
364
0
                new Redemption(nominal1_.back(), legs_[0].back()->date())));
365
0
            nominal1_.push_back(nominal1_.back());
366
0
            legs_[1].push_back(ext::shared_ptr<CashFlow>(
367
0
                new Redemption(nominal2_.back(), legs_[1].back()->date())));
368
0
            nominal2_.push_back(nominal2_.back());
369
0
        }
370
371
0
        for (auto i = legs_[0].begin(); i < legs_[0].end(); ++i)
372
0
            registerWith(*i);
373
374
0
        for (auto i = legs_[1].begin(); i < legs_[1].end(); ++i)
375
0
            registerWith(*i);
376
377
0
        switch (type_) {
378
0
        case Swap::Payer:
379
0
            payer_[0] = -1.0;
380
0
            payer_[1] = +1.0;
381
0
            break;
382
0
        case Swap::Receiver:
383
0
            payer_[0] = +1.0;
384
0
            payer_[1] = -1.0;
385
0
            break;
386
0
        default:
387
0
            QL_FAIL("Unknown float float - swap type");
388
0
        }
389
0
    }
390
391
0
    void FloatFloatSwap::setupArguments(PricingEngine::arguments *args) const {
392
393
0
        Swap::setupArguments(args);
394
395
0
        auto* arguments = dynamic_cast<FloatFloatSwap::arguments*>(args);
396
397
0
        if (arguments == nullptr)
398
0
            return; // swap engine ... // QL_REQUIRE(arguments != 0, "argument type does not match");
399
400
0
        arguments->type = type_;
401
0
        arguments->nominal1 = nominal1_;
402
0
        arguments->nominal2 = nominal2_;
403
0
        arguments->index1 = index1_;
404
0
        arguments->index2 = index2_;
405
406
0
        const Leg &leg1Coupons = leg1();
407
0
        const Leg &leg2Coupons = leg2();
408
409
0
        arguments->leg1ResetDates = arguments->leg1PayDates =
410
0
            arguments->leg1FixingDates = std::vector<Date>(leg1Coupons.size());
411
0
        arguments->leg2ResetDates = arguments->leg2PayDates =
412
0
            arguments->leg2FixingDates = std::vector<Date>(leg2Coupons.size());
413
414
0
        arguments->leg1Spreads = arguments->leg1AccrualTimes =
415
0
            arguments->leg1Gearings = std::vector<Real>(leg1Coupons.size());
416
0
        arguments->leg2Spreads = arguments->leg2AccrualTimes =
417
0
            arguments->leg2Gearings = std::vector<Real>(leg2Coupons.size());
418
419
0
        arguments->leg1Coupons =
420
0
            std::vector<Real>(leg1Coupons.size(), Null<Real>());
421
0
        arguments->leg2Coupons =
422
0
            std::vector<Real>(leg2Coupons.size(), Null<Real>());
423
424
0
        arguments->leg1IsRedemptionFlow =
425
0
            std::vector<bool>(leg1Coupons.size(), false);
426
0
        arguments->leg2IsRedemptionFlow =
427
0
            std::vector<bool>(leg2Coupons.size(), false);
428
429
0
        arguments->leg1CappedRates = arguments->leg1FlooredRates =
430
0
            std::vector<Real>(leg1Coupons.size(), Null<Real>());
431
0
        arguments->leg2CappedRates = arguments->leg2FlooredRates =
432
0
            std::vector<Real>(leg2Coupons.size(), Null<Real>());
433
434
0
        for (Size i = 0; i < leg1Coupons.size(); ++i) {
435
0
            ext::shared_ptr<FloatingRateCoupon> coupon =
436
0
                ext::dynamic_pointer_cast<FloatingRateCoupon>(leg1Coupons[i]);
437
0
            if (coupon != nullptr) {
438
0
                arguments->leg1AccrualTimes[i] = coupon->accrualPeriod();
439
0
                arguments->leg1PayDates[i] = coupon->date();
440
0
                arguments->leg1ResetDates[i] = coupon->accrualStartDate();
441
0
                arguments->leg1FixingDates[i] = coupon->fixingDate();
442
0
                arguments->leg1Spreads[i] = coupon->spread();
443
0
                arguments->leg1Gearings[i] = coupon->gearing();
444
0
                try {
445
0
                    arguments->leg1Coupons[i] = coupon->amount();
446
0
                }
447
0
                catch (Error &) {
448
0
                    arguments->leg1Coupons[i] = Null<Real>();
449
0
                }
450
0
                ext::shared_ptr<CappedFlooredCoupon> cfcoupon =
451
0
                    ext::dynamic_pointer_cast<CappedFlooredCoupon>(
452
0
                        leg1Coupons[i]);
453
0
                if (cfcoupon != nullptr) {
454
0
                    arguments->leg1CappedRates[i] = cfcoupon->cap();
455
0
                    arguments->leg1FlooredRates[i] = cfcoupon->floor();
456
0
                }
457
0
            } else {
458
0
                ext::shared_ptr<CashFlow> cashflow =
459
0
                    ext::dynamic_pointer_cast<CashFlow>(leg1Coupons[i]);
460
0
                auto j =
461
0
                    std::find(arguments->leg1PayDates.begin(),
462
0
                              arguments->leg1PayDates.end(), cashflow->date());
463
0
                QL_REQUIRE(j != arguments->leg1PayDates.end(),
464
0
                           "nominal redemption on "
465
0
                               << cashflow->date()
466
0
                               << "has no corresponding coupon");
467
0
                Size jIdx = j - arguments->leg1PayDates.begin();
468
0
                arguments->leg1IsRedemptionFlow[i] = true;
469
0
                arguments->leg1Coupons[i] = cashflow->amount();
470
0
                arguments->leg1ResetDates[i] = arguments->leg1ResetDates[jIdx];
471
0
                arguments->leg1FixingDates[i] =
472
0
                    arguments->leg1FixingDates[jIdx];
473
0
                arguments->leg1AccrualTimes[i] = 0.0;
474
0
                arguments->leg1Spreads[i] = 0.0;
475
0
                arguments->leg1Gearings[i] = 1.0;
476
0
                arguments->leg1PayDates[i] = cashflow->date();
477
0
            }
478
0
        }
479
480
0
        for (Size i = 0; i < leg2Coupons.size(); ++i) {
481
0
            ext::shared_ptr<FloatingRateCoupon> coupon =
482
0
                ext::dynamic_pointer_cast<FloatingRateCoupon>(leg2Coupons[i]);
483
0
            if (coupon != nullptr) {
484
0
                arguments->leg2AccrualTimes[i] = coupon->accrualPeriod();
485
0
                arguments->leg2PayDates[i] = coupon->date();
486
0
                arguments->leg2ResetDates[i] = coupon->accrualStartDate();
487
0
                arguments->leg2FixingDates[i] = coupon->fixingDate();
488
0
                arguments->leg2Spreads[i] = coupon->spread();
489
0
                arguments->leg2Gearings[i] = coupon->gearing();
490
0
                try {
491
0
                    arguments->leg2Coupons[i] = coupon->amount();
492
0
                }
493
0
                catch (Error &) {
494
0
                    arguments->leg2Coupons[i] = Null<Real>();
495
0
                }
496
0
                ext::shared_ptr<CappedFlooredCoupon> cfcoupon =
497
0
                    ext::dynamic_pointer_cast<CappedFlooredCoupon>(
498
0
                        leg2Coupons[i]);
499
0
                if (cfcoupon != nullptr) {
500
0
                    arguments->leg2CappedRates[i] = cfcoupon->cap();
501
0
                    arguments->leg2FlooredRates[i] = cfcoupon->floor();
502
0
                }
503
0
            } else {
504
0
                ext::shared_ptr<CashFlow> cashflow =
505
0
                    ext::dynamic_pointer_cast<CashFlow>(leg2Coupons[i]);
506
0
                auto j =
507
0
                    std::find(arguments->leg2PayDates.begin(),
508
0
                              arguments->leg2PayDates.end(), cashflow->date());
509
0
                QL_REQUIRE(j != arguments->leg2PayDates.end(),
510
0
                           "nominal redemption on "
511
0
                               << cashflow->date()
512
0
                               << "has no corresponding coupon");
513
0
                Size jIdx = j - arguments->leg2PayDates.begin();
514
0
                arguments->leg2IsRedemptionFlow[i] = true;
515
0
                arguments->leg2Coupons[i] = cashflow->amount();
516
0
                arguments->leg2ResetDates[i] = arguments->leg2ResetDates[jIdx];
517
0
                arguments->leg2FixingDates[i] =
518
0
                    arguments->leg2FixingDates[jIdx];
519
0
                arguments->leg2AccrualTimes[i] = 0.0;
520
0
                arguments->leg2Spreads[i] = 0.0;
521
0
                arguments->leg2Gearings[i] = 1.0;
522
0
                arguments->leg2PayDates[i] = cashflow->date();
523
0
            }
524
0
        }
525
0
    }
526
527
0
    void FloatFloatSwap::setupExpired() const { Swap::setupExpired(); }
528
529
0
    void FloatFloatSwap::fetchResults(const PricingEngine::results *r) const {
530
0
        Swap::fetchResults(r);
531
0
    }
532
533
0
    void FloatFloatSwap::arguments::validate() const {
534
535
0
        Swap::arguments::validate();
536
537
0
        QL_REQUIRE(nominal1.size() == leg1ResetDates.size(),
538
0
                   "nominal1 size is different from resetDates1 size");
539
0
        QL_REQUIRE(nominal1.size() == leg1FixingDates.size(),
540
0
                   "nominal1 size is different from fixingDates1 size");
541
0
        QL_REQUIRE(nominal1.size() == leg1PayDates.size(),
542
0
                   "nominal1 size is different from payDates1 size");
543
0
        QL_REQUIRE(nominal1.size() == leg1Spreads.size(),
544
0
                   "nominal1 size is different from spreads1 size");
545
0
        QL_REQUIRE(nominal1.size() == leg1Gearings.size(),
546
0
                   "nominal1 size is different from gearings1 size");
547
0
        QL_REQUIRE(nominal1.size() == leg1CappedRates.size(),
548
0
                   "nominal1 size is different from cappedRates1 size");
549
0
        QL_REQUIRE(nominal1.size() == leg1FlooredRates.size(),
550
0
                   "nominal1 size is different from flooredRates1 size");
551
0
        QL_REQUIRE(nominal1.size() == leg1Coupons.size(),
552
0
                   "nominal1 size is different from coupons1 size");
553
0
        QL_REQUIRE(nominal1.size() == leg1AccrualTimes.size(),
554
0
                   "nominal1 size is different from accrualTimes1 size");
555
0
        QL_REQUIRE(nominal1.size() == leg1IsRedemptionFlow.size(),
556
0
                   "nominal1 size is different from redemption1 size");
557
558
0
        QL_REQUIRE(nominal2.size() == leg2ResetDates.size(),
559
0
                   "nominal2 size is different from resetDates2 size");
560
0
        QL_REQUIRE(nominal2.size() == leg2FixingDates.size(),
561
0
                   "nominal2 size is different from fixingDates2 size");
562
0
        QL_REQUIRE(nominal2.size() == leg2PayDates.size(),
563
0
                   "nominal2 size is different from payDates2 size");
564
0
        QL_REQUIRE(nominal2.size() == leg2Spreads.size(),
565
0
                   "nominal2 size is different from spreads2 size");
566
0
        QL_REQUIRE(nominal2.size() == leg2Gearings.size(),
567
0
                   "nominal2 size is different from gearings2 size");
568
0
        QL_REQUIRE(nominal2.size() == leg2CappedRates.size(),
569
0
                   "nominal2 size is different from cappedRates2 size");
570
0
        QL_REQUIRE(nominal2.size() == leg2FlooredRates.size(),
571
0
                   "nominal2 size is different from flooredRates2 size");
572
0
        QL_REQUIRE(nominal2.size() == leg2Coupons.size(),
573
0
                   "nominal2 size is different from coupons2 size");
574
0
        QL_REQUIRE(nominal2.size() == leg2AccrualTimes.size(),
575
0
                   "nominal2 size is different from accrualTimes2 size");
576
0
        QL_REQUIRE(nominal2.size() == leg2IsRedemptionFlow.size(),
577
0
                   "nominal2 size is different from redemption2 size");
578
579
0
        QL_REQUIRE(index1 != nullptr, "index1 is null");
580
0
        QL_REQUIRE(index2 != nullptr, "index2 is null");
581
0
    }
582
583
0
    void FloatFloatSwap::results::reset() { Swap::results::reset(); }
584
}