1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2013, 2016 Peter Caspers
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <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/indexes/iborindex.hpp>
28#include <ql/indexes/swapindex.hpp>
29#include <ql/instruments/nonstandardswap.hpp>
30#include <ql/termstructures/yieldtermstructure.hpp>
31#include <ql/optional.hpp>
32#include <utility>
33
34namespace QuantLib {
35
36 NonstandardSwap::NonstandardSwap(const VanillaSwap &fromVanilla)
37 : Swap(2), type_(fromVanilla.type()),
38 fixedNominal_(std::vector<Real>(fromVanilla.fixedLeg().size(),
39 fromVanilla.nominal())),
40 floatingNominal_(std::vector<Real>(fromVanilla.floatingLeg().size(),
41 fromVanilla.nominal())),
42 fixedSchedule_(fromVanilla.fixedSchedule()),
43 fixedRate_(std::vector<Real>(fromVanilla.fixedLeg().size(),
44 fromVanilla.fixedRate())),
45 fixedDayCount_(fromVanilla.fixedDayCount()),
46 floatingSchedule_(fromVanilla.floatingSchedule()),
47 iborIndex_(fromVanilla.iborIndex()),
48 spread_(std::vector<Real>(fromVanilla.floatingLeg().size(), fromVanilla.spread())),
49 gearing_(std::vector<Real>(fromVanilla.floatingLeg().size(), 1.0)),
50 singleSpreadAndGearing_(true),
51 floatingDayCount_(fromVanilla.floatingDayCount()),
52 paymentConvention_(fromVanilla.paymentConvention()),
53 intermediateCapitalExchange_(false), finalCapitalExchange_(false) {
54
55 init();
56 }
57
58 NonstandardSwap::NonstandardSwap(const Swap::Type type,
59 std::vector<Real> fixedNominal,
60 const std::vector<Real>& floatingNominal,
61 Schedule fixedSchedule,
62 std::vector<Real> fixedRate,
63 DayCounter fixedDayCount,
64 Schedule floatingSchedule,
65 ext::shared_ptr<IborIndex> iborIndex,
66 const Real gearing,
67 const Spread spread,
68 DayCounter floatingDayCount,
69 const bool intermediateCapitalExchange,
70 const bool finalCapitalExchange,
71 ext::optional<BusinessDayConvention> paymentConvention)
72 : Swap(2), type_(type), fixedNominal_(std::move(fixedNominal)),
73 floatingNominal_(floatingNominal), fixedSchedule_(std::move(fixedSchedule)),
74 fixedRate_(std::move(fixedRate)), fixedDayCount_(std::move(fixedDayCount)),
75 floatingSchedule_(std::move(floatingSchedule)), iborIndex_(std::move(iborIndex)),
76 spread_(std::vector<Real>(floatingNominal.size(), spread)),
77 gearing_(std::vector<Real>(floatingNominal.size(), gearing)), singleSpreadAndGearing_(true),
78 floatingDayCount_(std::move(floatingDayCount)),
79 intermediateCapitalExchange_(intermediateCapitalExchange),
80 finalCapitalExchange_(finalCapitalExchange) {
81
82 if (paymentConvention) // NOLINT(readability-implicit-bool-conversion)
83 paymentConvention_ = *paymentConvention;
84 else
85 paymentConvention_ = floatingSchedule_.businessDayConvention();
86 init();
87 }
88
89 NonstandardSwap::NonstandardSwap(const Swap::Type type,
90 std::vector<Real> fixedNominal,
91 std::vector<Real> floatingNominal,
92 Schedule fixedSchedule,
93 std::vector<Real> fixedRate,
94 DayCounter fixedDayCount,
95 Schedule floatingSchedule,
96 ext::shared_ptr<IborIndex> iborIndex,
97 std::vector<Real> gearing,
98 std::vector<Spread> spread,
99 DayCounter floatingDayCount,
100 const bool intermediateCapitalExchange,
101 const bool finalCapitalExchange,
102 ext::optional<BusinessDayConvention> paymentConvention)
103 : Swap(2), type_(type), fixedNominal_(std::move(fixedNominal)),
104 floatingNominal_(std::move(floatingNominal)), fixedSchedule_(std::move(fixedSchedule)),
105 fixedRate_(std::move(fixedRate)), fixedDayCount_(std::move(fixedDayCount)),
106 floatingSchedule_(std::move(floatingSchedule)), iborIndex_(std::move(iborIndex)),
107 spread_(std::move(spread)), gearing_(std::move(gearing)), singleSpreadAndGearing_(false),
108 floatingDayCount_(std::move(floatingDayCount)),
109 intermediateCapitalExchange_(intermediateCapitalExchange),
110 finalCapitalExchange_(finalCapitalExchange) {
111
112 if (paymentConvention) // NOLINT(readability-implicit-bool-conversion)
113 paymentConvention_ = *paymentConvention;
114 else
115 paymentConvention_ = floatingSchedule_.businessDayConvention();
116 init();
117 }
118
119 void NonstandardSwap::init() {
120
121 QL_REQUIRE(fixedNominal_.size() == fixedRate_.size(),
122 "Fixed nominal size ("
123 << fixedNominal_.size()
124 << ") does not match fixed rate size ("
125 << fixedRate_.size() << ")");
126
127 QL_REQUIRE(fixedNominal_.size() == fixedSchedule_.size() - 1,
128 "Fixed nominal size (" << fixedNominal_.size()
129 << ") does not match schedule size ("
130 << fixedSchedule_.size() << ") - 1");
131
132 QL_REQUIRE(floatingNominal_.size() == floatingSchedule_.size() - 1,
133 "Floating nominal size ("
134 << floatingNominal_.size()
135 << ") does not match schedule size ("
136 << floatingSchedule_.size() << ") - 1");
137
138 QL_REQUIRE(floatingNominal_.size() == spread_.size(),
139 "Floating nominal size (" << floatingNominal_.size()
140 << ") does not match spread size ("
141 << spread_.size() << ")");
142
143 QL_REQUIRE(floatingNominal_.size() == gearing_.size(),
144 "Floating nominal size ("
145 << floatingNominal_.size()
146 << ") does not match gearing size (" << gearing_.size()
147 << ")");
148
149 // if the gearing is zero then the ibor leg will be set up with fixed
150 // coupons which makes trouble here in this context. We therefore use
151 // a dirty trick and enforce the gearing to be non zero.
152 for (Real& i : gearing_) {
153 if (close(x: i, y: 0.0))
154 i = QL_EPSILON;
155 }
156
157 legs_[0] = FixedRateLeg(fixedSchedule_)
158 .withNotionals(fixedNominal_)
159 .withCouponRates(fixedRate_, paymentDayCounter: fixedDayCount_)
160 .withPaymentAdjustment(paymentConvention_);
161
162 legs_[1] = IborLeg(floatingSchedule_, iborIndex_)
163 .withNotionals(notionals: floatingNominal_)
164 .withPaymentDayCounter(floatingDayCount_)
165 .withPaymentAdjustment(paymentConvention_)
166 .withSpreads(spreads: spread_)
167 .withGearings(gearings: gearing_);
168
169 if (intermediateCapitalExchange_) {
170 for (Size i = 0; i < legs_[0].size() - 1; i++) {
171 Real cap = fixedNominal_[i] - fixedNominal_[i + 1];
172 if (!close(x: cap, y: 0.0)) {
173 auto it1 = legs_[0].begin();
174 std::advance(i&: it1, n: i + 1);
175 legs_[0].insert(
176 position: it1, x: ext::shared_ptr<CashFlow>(
177 new Redemption(cap, legs_[0][i]->date())));
178 auto it2 = fixedNominal_.begin();
179 std::advance(i&: it2, n: i + 1);
180 fixedNominal_.insert(position: it2, x: fixedNominal_[i]);
181 auto it3 = fixedRate_.begin();
182 std::advance(i&: it3, n: i + 1);
183 fixedRate_.insert(position: it3, x: 0.0);
184 i++;
185 }
186 }
187 for (Size i = 0; i < legs_[1].size() - 1; i++) {
188 Real cap = floatingNominal_[i] - floatingNominal_[i + 1];
189 if (!close(x: cap, y: 0.0)) {
190 auto it1 = legs_[1].begin();
191 std::advance(i&: it1, n: i + 1);
192 legs_[1].insert(
193 position: it1, x: ext::shared_ptr<CashFlow>(
194 new Redemption(cap, legs_[1][i]->date())));
195 auto it2 = floatingNominal_.begin();
196 std::advance(i&: it2, n: i + 1);
197 floatingNominal_.insert(position: it2, x: floatingNominal_[i]);
198 i++;
199 }
200 }
201 }
202
203 if (finalCapitalExchange_) {
204 legs_[0].push_back(x: ext::shared_ptr<CashFlow>(
205 new Redemption(fixedNominal_.back(), legs_[0].back()->date())));
206 fixedNominal_.push_back(x: fixedNominal_.back());
207 fixedRate_.push_back(x: 0.0);
208 legs_[1].push_back(x: ext::shared_ptr<CashFlow>(new Redemption(
209 floatingNominal_.back(), legs_[1].back()->date())));
210 floatingNominal_.push_back(x: floatingNominal_.back());
211 }
212
213 for (Leg::const_iterator i = legs_[1].begin(); i < legs_[1].end(); ++i)
214 registerWith(h: *i);
215
216 switch (type_) {
217 case Swap::Payer:
218 payer_[0] = -1.0;
219 payer_[1] = +1.0;
220 break;
221 case Swap::Receiver:
222 payer_[0] = +1.0;
223 payer_[1] = -1.0;
224 break;
225 default:
226 QL_FAIL("Unknown nonstandard-swap type");
227 }
228 }
229
230 void NonstandardSwap::setupArguments(PricingEngine::arguments *args) const {
231
232 Swap::setupArguments(args);
233
234 auto* arguments = dynamic_cast<NonstandardSwap::arguments*>(args);
235
236 if (arguments == nullptr)
237 return; // swap engine ...
238
239 arguments->type = type_;
240 arguments->fixedNominal = fixedNominal_;
241 arguments->floatingNominal = floatingNominal_;
242 arguments->fixedRate = fixedRate_;
243
244 const Leg &fixedCoupons = fixedLeg();
245
246 arguments->fixedResetDates = arguments->fixedPayDates =
247 std::vector<Date>(fixedCoupons.size());
248 arguments->fixedCoupons = std::vector<Real>(fixedCoupons.size());
249 arguments->fixedIsRedemptionFlow =
250 std::vector<bool>(fixedCoupons.size(), false);
251
252 for (Size i = 0; i < fixedCoupons.size(); ++i) {
253 ext::shared_ptr<FixedRateCoupon> coupon =
254 ext::dynamic_pointer_cast<FixedRateCoupon>(r: fixedCoupons[i]);
255 if (coupon != nullptr) {
256 arguments->fixedPayDates[i] = coupon->date();
257 arguments->fixedResetDates[i] = coupon->accrualStartDate();
258 arguments->fixedCoupons[i] = coupon->amount();
259 } else {
260 ext::shared_ptr<CashFlow> cashflow =
261 ext::dynamic_pointer_cast<CashFlow>(r: fixedCoupons[i]);
262 std::vector<Date>::const_iterator j =
263 std::find(first: arguments->fixedPayDates.begin(),
264 last: arguments->fixedPayDates.end(), val: cashflow->date());
265 QL_REQUIRE(j != arguments->fixedPayDates.end(),
266 "nominal redemption on "
267 << cashflow->date()
268 << "has no corresponding coupon");
269 Size jIdx = j - arguments->fixedPayDates.begin();
270 arguments->fixedIsRedemptionFlow[i] = true;
271 arguments->fixedCoupons[i] = cashflow->amount();
272 arguments->fixedResetDates[i] =
273 arguments->fixedResetDates[jIdx];
274 arguments->fixedPayDates[i] = cashflow->date();
275 }
276 }
277
278 const Leg &floatingCoupons = floatingLeg();
279
280 arguments->floatingResetDates = arguments->floatingPayDates =
281 arguments->floatingFixingDates =
282 std::vector<Date>(floatingCoupons.size());
283 arguments->floatingAccrualTimes =
284 std::vector<Time>(floatingCoupons.size());
285 arguments->floatingSpreads =
286 std::vector<Spread>(floatingCoupons.size());
287 arguments->floatingGearings = std::vector<Real>(floatingCoupons.size());
288 arguments->floatingCoupons = std::vector<Real>(floatingCoupons.size());
289 arguments->floatingIsRedemptionFlow =
290 std::vector<bool>(floatingCoupons.size(), false);
291
292 for (Size i = 0; i < floatingCoupons.size(); ++i) {
293 ext::shared_ptr<IborCoupon> coupon =
294 ext::dynamic_pointer_cast<IborCoupon>(r: floatingCoupons[i]);
295 if (coupon != nullptr) {
296 arguments->floatingResetDates[i] = coupon->accrualStartDate();
297 arguments->floatingPayDates[i] = coupon->date();
298 arguments->floatingFixingDates[i] = coupon->fixingDate();
299 arguments->floatingAccrualTimes[i] = coupon->accrualPeriod();
300 arguments->floatingSpreads[i] = coupon->spread();
301 arguments->floatingGearings[i] = coupon->gearing();
302 try {
303 arguments->floatingCoupons[i] = coupon->amount();
304 }
305 catch (Error &) {
306 arguments->floatingCoupons[i] = Null<Real>();
307 }
308 } else {
309 ext::shared_ptr<CashFlow> cashflow =
310 ext::dynamic_pointer_cast<CashFlow>(r: floatingCoupons[i]);
311 std::vector<Date>::const_iterator j = std::find(
312 first: arguments->floatingPayDates.begin(),
313 last: arguments->floatingPayDates.end(), val: cashflow->date());
314 QL_REQUIRE(j != arguments->floatingPayDates.end(),
315 "nominal redemption on "
316 << cashflow->date()
317 << "has no corresponding coupon");
318 Size jIdx = j - arguments->floatingPayDates.begin();
319 arguments->floatingIsRedemptionFlow[i] = true;
320 arguments->floatingCoupons[i] = cashflow->amount();
321 arguments->floatingResetDates[i] =
322 arguments->floatingResetDates[jIdx];
323 arguments->floatingFixingDates[i] =
324 arguments->floatingFixingDates[jIdx];
325 arguments->floatingAccrualTimes[i] = 0.0;
326 arguments->floatingSpreads[i] = 0.0;
327 arguments->floatingGearings[i] = 1.0;
328 arguments->floatingPayDates[i] = cashflow->date();
329 }
330 }
331
332 arguments->iborIndex = iborIndex();
333 }
334
335 void NonstandardSwap::setupExpired() const { Swap::setupExpired(); }
336
337 void NonstandardSwap::fetchResults(const PricingEngine::results *r) const {
338
339 Swap::fetchResults(r);
340 }
341
342 void NonstandardSwap::arguments::validate() const {
343 Swap::arguments::validate();
344 QL_REQUIRE(fixedNominal.size() == fixedPayDates.size(),
345 "number of fixed leg nominals plus redemption flows "
346 "different from number of payment dates");
347 QL_REQUIRE(fixedRate.size() == fixedPayDates.size(),
348 "number of fixed rates plus redemption flows different from "
349 "number of payment dates");
350 QL_REQUIRE(floatingNominal.size() == floatingPayDates.size(),
351 "number of float leg nominals different from number of "
352 "payment dates");
353 QL_REQUIRE(fixedResetDates.size() == fixedPayDates.size(),
354 "number of fixed start dates different from "
355 "number of fixed payment dates");
356 QL_REQUIRE(fixedPayDates.size() == fixedCoupons.size(),
357 "number of fixed payment dates different from "
358 "number of fixed coupon amounts");
359 QL_REQUIRE(floatingResetDates.size() == floatingPayDates.size(),
360 "number of floating start dates different from "
361 "number of floating payment dates");
362 QL_REQUIRE(floatingFixingDates.size() == floatingPayDates.size(),
363 "number of floating fixing dates different from "
364 "number of floating payment dates");
365 QL_REQUIRE(floatingAccrualTimes.size() == floatingPayDates.size(),
366 "number of floating accrual Times different from "
367 "number of floating payment dates");
368 QL_REQUIRE(floatingSpreads.size() == floatingPayDates.size(),
369 "number of floating spreads different from "
370 "number of floating payment dates");
371 QL_REQUIRE(floatingPayDates.size() == floatingCoupons.size(),
372 "number of floating payment dates different from "
373 "number of floating coupon amounts");
374 }
375
376 void NonstandardSwap::results::reset() { Swap::results::reset(); }
377}
378

source code of quantlib/ql/instruments/nonstandardswap.cpp

Morty Proxy This is a proxified and sanitized view of the page, visit original site.