QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
nonstandardswap.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2013, 2016 Peter Caspers
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <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
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
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)
84 else
86 init();
87 }
88
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)
114 else
116 init();
117 }
118
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(i, 0.0))
154 i = QL_EPSILON;
155 }
156
161
168
170 for (Size i = 0; i < legs_[0].size() - 1; i++) {
171 Real cap = fixedNominal_[i] - fixedNominal_[i + 1];
172 if (!close(cap, 0.0)) {
173 auto it1 = legs_[0].begin();
174 std::advance(it1, i + 1);
175 legs_[0].insert(
176 it1, ext::shared_ptr<CashFlow>(
177 new Redemption(cap, legs_[0][i]->date())));
178 auto it2 = fixedNominal_.begin();
179 std::advance(it2, i + 1);
180 fixedNominal_.insert(it2, fixedNominal_[i]);
181 auto it3 = fixedRate_.begin();
182 std::advance(it3, i + 1);
183 fixedRate_.insert(it3, 0.0);
184 i++;
185 }
186 }
187 for (Size i = 0; i < legs_[1].size() - 1; i++) {
188 Real cap = floatingNominal_[i] - floatingNominal_[i + 1];
189 if (!close(cap, 0.0)) {
190 auto it1 = legs_[1].begin();
191 std::advance(it1, i + 1);
192 legs_[1].insert(
193 it1, ext::shared_ptr<CashFlow>(
194 new Redemption(cap, legs_[1][i]->date())));
195 auto it2 = floatingNominal_.begin();
196 std::advance(it2, i + 1);
197 floatingNominal_.insert(it2, floatingNominal_[i]);
198 i++;
199 }
200 }
201 }
202
204 legs_[0].push_back(ext::shared_ptr<CashFlow>(
205 new Redemption(fixedNominal_.back(), legs_[0].back()->date())));
206 fixedNominal_.push_back(fixedNominal_.back());
207 fixedRate_.push_back(0.0);
208 legs_[1].push_back(ext::shared_ptr<CashFlow>(new Redemption(
209 floatingNominal_.back(), legs_[1].back()->date())));
210 floatingNominal_.push_back(floatingNominal_.back());
211 }
212
213 for (Leg::const_iterator i = legs_[1].begin(); i < legs_[1].end(); ++i)
214 registerWith(*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
231
233
234 auto* arguments = dynamic_cast<NonstandardSwap::arguments*>(args);
235
236 if (arguments == nullptr)
237 return; // swap engine ...
238
243
244 const Leg &fixedCoupons = fixedLeg();
245
247 std::vector<Date>(fixedCoupons.size());
248 arguments->fixedCoupons = std::vector<Real>(fixedCoupons.size());
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>(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>(fixedCoupons[i]);
262 std::vector<Date>::const_iterator j =
263 std::find(arguments->fixedPayDates.begin(),
264 arguments->fixedPayDates.end(), 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();
271 arguments->fixedCoupons[i] = cashflow->amount();
274 arguments->fixedPayDates[i] = cashflow->date();
275 }
276 }
277
278 const Leg &floatingCoupons = floatingLeg();
279
282 std::vector<Date>(floatingCoupons.size());
284 std::vector<Time>(floatingCoupons.size());
286 std::vector<Spread>(floatingCoupons.size());
287 arguments->floatingGearings = std::vector<Real>(floatingCoupons.size());
288 arguments->floatingCoupons = std::vector<Real>(floatingCoupons.size());
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>(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 &) {
307 }
308 } else {
309 ext::shared_ptr<CashFlow> cashflow =
310 ext::dynamic_pointer_cast<CashFlow>(floatingCoupons[i]);
311 std::vector<Date>::const_iterator j = std::find(
313 arguments->floatingPayDates.end(), 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();
320 arguments->floatingCoupons[i] = cashflow->amount();
326 arguments->floatingSpreads[i] = 0.0;
327 arguments->floatingGearings[i] = 1.0;
328 arguments->floatingPayDates[i] = cashflow->date();
329 }
330 }
331
333 }
334
336
338
340 }
341
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
377}
day counter class
Definition: daycounter.hpp:44
Base error class.
Definition: errors.hpp:39
helper class building a sequence of fixed rate coupons
FixedRateLeg & withNotionals(Real)
FixedRateLeg & withPaymentAdjustment(BusinessDayConvention)
FixedRateLeg & withCouponRates(Rate, const DayCounter &paymentDayCounter, Compounding comp=Simple, Frequency freq=Annual)
helper class building a sequence of capped/floored ibor-rate coupons
Definition: iborcoupon.hpp:133
IborLeg & withSpreads(Spread spread)
Definition: iborcoupon.cpp:208
IborLeg & withPaymentAdjustment(BusinessDayConvention)
Definition: iborcoupon.cpp:173
IborLeg & withPaymentDayCounter(const DayCounter &)
Definition: iborcoupon.cpp:168
IborLeg & withNotionals(Real notional)
Definition: iborcoupon.cpp:158
IborLeg & withGearings(Real gearing)
Definition: iborcoupon.cpp:198
Arguments for nonstandard swap calculation
ext::shared_ptr< IborIndex > iborIndex
std::vector< Real > gearing_
std::vector< Real > fixedRate_
BusinessDayConvention paymentConvention() const
std::vector< Real > fixedNominal_
const Leg & floatingLeg() const
std::vector< Real > floatingNominal_
ext::shared_ptr< IborIndex > iborIndex_
std::vector< Spread > spread_
const ext::shared_ptr< IborIndex > & iborIndex() const
NonstandardSwap(const VanillaSwap &fromVanilla)
void setupArguments(PricingEngine::arguments *args) const override
BusinessDayConvention paymentConvention_
const Leg & fixedLeg() const
void setupExpired() const override
void fetchResults(const PricingEngine::results *) const override
template class providing a null value for a given type.
Definition: null.hpp:76
std::pair< iterator, bool > registerWith(const ext::shared_ptr< Observable > &)
Definition: observable.hpp:228
Bond redemption.
Payment schedule.
Definition: schedule.hpp:40
Size size() const
Definition: schedule.hpp:69
BusinessDayConvention businessDayConvention() const
Definition: schedule.hpp:196
void validate() const override
Definition: swap.cpp:171
void reset() override
Definition: swap.cpp:176
Interest rate swap.
Definition: swap.hpp:41
void setupArguments(PricingEngine::arguments *) const override
Definition: swap.cpp:87
std::vector< Leg > legs_
Definition: swap.hpp:133
void setupExpired() const override
Definition: swap.cpp:78
void fetchResults(const PricingEngine::results *) const override
Definition: swap.cpp:95
std::vector< Real > payer_
Definition: swap.hpp:134
Plain-vanilla swap: fix vs ibor leg.
Definition: vanillaswap.hpp:65
#define QL_EPSILON
Definition: qldefines.hpp:178
QL_REAL Real
real number
Definition: types.hpp:50
Real Spread
spreads on interest rates
Definition: types.hpp:74
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
bool close(const Quantity &m1, const Quantity &m2, Size n)
Definition: quantity.cpp:163
std::vector< ext::shared_ptr< CashFlow > > Leg
Sequence of cash-flows.
Definition: cashflow.hpp:78
STL namespace.