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