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