QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
Loading...
Searching...
No Matches
multipleresetscoupon.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2008 Toyin Akin
5 Copyright (C) 2021 Marcin Rybacki
6
7 This file is part of QuantLib, a free-software/open-source library
8 for financial quantitative analysts and developers - http://quantlib.org/
9
10 QuantLib is free software: you can redistribute it and/or modify it
11 under the terms of the QuantLib license. You should have received a
12 copy of the license along with this program; if not, please email
13 <quantlib-dev@lists.sf.net>. The license is also available online at
14 <http://quantlib.org/license.shtml>.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the license for more details.
19*/
20
23#include <ql/time/schedule.hpp>
26#include <cmath>
27
28namespace QuantLib {
29
31 Real nominal,
32 const Schedule& resetSchedule,
33 Natural fixingDays,
34 const ext::shared_ptr<IborIndex>& index,
35 Real gearing,
36 Rate couponSpread,
37 Rate rateSpread,
38 const Date& refPeriodStart,
39 const Date& refPeriodEnd,
40 const DayCounter& dayCounter,
41 const Date& exCouponDate)
42 : FloatingRateCoupon(paymentDate, nominal,
43 resetSchedule.front(), resetSchedule.back(),
44 fixingDays, index, gearing, couponSpread,
45 refPeriodStart, refPeriodEnd, dayCounter,
46 false, exCouponDate),
47 rateSpread_(rateSpread) {
48 valueDates_ = resetSchedule.dates();
49
50 // fixing dates
51 n_ = valueDates_.size() - 1;
52 if (fixingDays_ == 0) {
53 fixingDates_ = std::vector<Date>(valueDates_.begin(), valueDates_.end() - 1);
54 } else {
55 fixingDates_.resize(n_);
56 for (Size i = 0; i < n_; ++i)
58 }
59
60 // accrual times of sub-periods
61 dt_.resize(n_);
62 const DayCounter& dc = index->dayCounter();
63 for (Size i = 0; i < n_; ++i)
64 dt_[i] = dc.yearFraction(valueDates_[i], valueDates_[i + 1]);
65 }
66
68 Real nominal,
69 const Date& startDate,
70 const Date& endDate,
71 Natural fixingDays,
72 const ext::shared_ptr<IborIndex>& index,
73 Real gearing,
74 Rate couponSpread,
75 Rate rateSpread,
76 const Date& refPeriodStart,
77 const Date& refPeriodEnd,
78 const DayCounter& dayCounter,
79 const Date& exCouponDate)
80 : FloatingRateCoupon(paymentDate, nominal, startDate, endDate,
81 fixingDays, index, gearing, couponSpread,
82 refPeriodStart, refPeriodEnd, dayCounter,
83 false, exCouponDate),
84 rateSpread_(rateSpread) {
86 .from(startDate)
87 .to(endDate)
88 .withTenor(index->tenor())
89 .withCalendar(index->fixingCalendar())
90 .withConvention(index->businessDayConvention())
91 .backwards()
92 .endOfMonth(index->endOfMonth());
93 valueDates_ = sch.dates();
94
95 // fixing dates
96 n_ = valueDates_.size() - 1;
97 if (fixingDays_ == 0) {
98 fixingDates_ = std::vector<Date>(valueDates_.begin(), valueDates_.end() - 1);
99 } else {
100 fixingDates_.resize(n_);
101 for (Size i = 0; i < n_; ++i)
103 }
104
105 // accrual of sub-periods
106 dt_.resize(n_);
107 const DayCounter& dc = index->dayCounter();
108 for (Size i = 0; i < n_; ++i)
109 dt_[i] = dc.yearFraction(valueDates_[i], valueDates_[i + 1]);
110 }
111
113 auto* v1 = dynamic_cast<Visitor<MultipleResetsCoupon>*>(&v);
114 if (v1 != nullptr)
115 v1->visit(*this);
116 else
118 }
119
122 index_->fixingCalendar().advance(valueDate, -static_cast<Integer>(fixingDays_), Days);
123 return fixingDate;
124 }
125
127 coupon_ = dynamic_cast<const MultipleResetsCoupon*>(&coupon);
128 QL_REQUIRE(coupon_, "sub-periods coupon required");
129
130 ext::shared_ptr<IborIndex> index = ext::dynamic_pointer_cast<IborIndex>(coupon_->index());
131 if (!index) {
132 // coupon was right, index is not
133 QL_FAIL("IborIndex required");
134 }
135
136 QL_REQUIRE(coupon_->accrualPeriod() != 0.0, "null accrual period");
137
138 const std::vector<Date>& fixingDates = coupon_->fixingDates();
139 Size n = fixingDates.size();
140 subPeriodFixings_.resize(n);
141
142 for (Size i = 0; i < n; i++) {
143 subPeriodFixings_[i] = index->fixing(fixingDates[i]) + coupon_->rateSpread();
144 }
145 }
146
148 QL_FAIL("MultipleResetsPricer::swapletPrice not implemented");
149 }
150
152 QL_FAIL("MultipleResetsPricer::capletPrice not implemented");
153 }
154
156 QL_FAIL("MultipleResetsPricer::capletRate not implemented");
157 }
158
160 QL_FAIL("MultipleResetsPricer::floorletPrice not implemented");
161 }
162
164 QL_FAIL("MultipleResetsPricer::floorletRate not implemented");
165 }
166
168 // past or future fixing is managed in InterestRateIndex::fixing()
169
170 Size nCount = subPeriodFixings_.size();
171 const std::vector<Time>& subPeriodFractions = coupon_->dt();
172 Real aggregateFactor = 0.0;
173 for (Size i = 0; i < nCount; i++) {
174 aggregateFactor += subPeriodFixings_[i] * subPeriodFractions[i];
175 }
176
177 Real rate = aggregateFactor / coupon_->accrualPeriod();
178 return coupon_->gearing() * rate + coupon_->spread();
179 }
180
182 // past or future fixing is managed in InterestRateIndex::fixing()
183
184 Real compoundFactor = 1.0;
185 const std::vector<Time>& subPeriodFractions = coupon_->dt();
186 Size nCount = subPeriodFixings_.size();
187 for (Size i = 0; i < nCount; i++) {
188 compoundFactor *= (1.0 + subPeriodFixings_[i] * subPeriodFractions[i]);
189 }
190
191 Real rate = (compoundFactor - 1.0) / coupon_->accrualPeriod();
192 return coupon_->gearing() * rate + coupon_->spread();
193 }
194
195
196
198 ext::shared_ptr<IborIndex> index,
199 Size resetsPerCoupon)
200 : schedule_(std::move(schedule)), index_(std::move(index)), resetsPerCoupon_(resetsPerCoupon),
201 paymentCalendar_(schedule_.calendar()) {
202 QL_REQUIRE(index_, "no index provided");
203 QL_REQUIRE(!schedule_.empty(), "empty schedule provided");
205 "number of resets per coupon does not divide exactly number of periods in schedule");
206 }
207
209 notionals_ = std::vector<Real>(1, notional);
210 return *this;
211 }
212
213 MultipleResetsLeg& MultipleResetsLeg::withNotionals(const std::vector<Real>& notionals) {
214 notionals_ = notionals;
215 return *this;
216 }
217
220 return *this;
221 }
222
224 paymentAdjustment_ = convention;
225 return *this;
226 }
227
229 paymentCalendar_ = cal;
230 return *this;
231 }
232
234 paymentLag_ = lag;
235 return *this;
236 }
237
239 fixingDays_ = std::vector<Natural>(1, fixingDays);
240 return *this;
241 }
242
243 MultipleResetsLeg& MultipleResetsLeg::withFixingDays(const std::vector<Natural>& fixingDays) {
244 fixingDays_ = fixingDays;
245 return *this;
246 }
247
249 gearings_ = std::vector<Real>(1, gearing);
250 return *this;
251 }
252
253 MultipleResetsLeg& MultipleResetsLeg::withGearings(const std::vector<Real>& gearings) {
254 gearings_ = gearings;
255 return *this;
256 }
257
259 couponSpreads_ = std::vector<Spread>(1, spread);
260 return *this;
261 }
262
263 MultipleResetsLeg& MultipleResetsLeg::withCouponSpreads(const std::vector<Spread>& spreads) {
264 couponSpreads_ = spreads;
265 return *this;
266 }
267
269 rateSpreads_ = std::vector<Spread>(1, spread);
270 return *this;
271 }
272
273 MultipleResetsLeg& MultipleResetsLeg::withRateSpreads(const std::vector<Spread>& spreads) {
274 rateSpreads_ = spreads;
275 return *this;
276 }
277
279 averagingMethod_ = averagingMethod;
280 return *this;
281 }
282
284 const Calendar& cal,
285 BusinessDayConvention convention,
286 bool endOfMonth) {
287 exCouponPeriod_ = period;
288 exCouponCalendar_ = cal;
289 exCouponAdjustment_ = convention;
290 exCouponEndOfMonth_ = endOfMonth;
291 return *this;
292 }
293
294 MultipleResetsLeg::operator Leg() const {
295 Leg cashflows;
296 Calendar calendar = schedule_.calendar();
297
298 Size n = (schedule_.size() - 1) / resetsPerCoupon_;
299 QL_REQUIRE(!notionals_.empty(), "no notional given");
300 QL_REQUIRE(notionals_.size() <= n,
301 "too many nominals (" << notionals_.size() << "), only " << n << " required");
302 QL_REQUIRE(gearings_.size() <= n,
303 "too many gearings (" << gearings_.size() << "), only " << n << " required");
304 QL_REQUIRE(couponSpreads_.size() <= n,
305 "too many coupon spreads (" << couponSpreads_.size() << "), only " << n << " required");
306 QL_REQUIRE(rateSpreads_.size() <= n,
307 "too many rate spreads (" << rateSpreads_.size() << "), only " << n << " required");
308 QL_REQUIRE(fixingDays_.size() <= n,
309 "too many fixing days (" << fixingDays_.size() << "), only " << n << " required");
310
311 for (Size i = 0; i < n; ++i) {
312 Date start = schedule_.date(i * resetsPerCoupon_);
313 Date end = schedule_.date((i + 1) * resetsPerCoupon_);
314 auto subSchedule = schedule_.after(start).until(end);
315 Date paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_);
316 Date exCouponDate;
317 if (exCouponPeriod_ != Period()) {
318 if (exCouponCalendar_.empty()) {
319 exCouponDate = calendar.advance(paymentDate, -exCouponPeriod_,
320 exCouponAdjustment_, exCouponEndOfMonth_);
321 } else {
322 exCouponDate = exCouponCalendar_.advance(
323 paymentDate, -exCouponPeriod_, exCouponAdjustment_, exCouponEndOfMonth_);
324 }
325 }
326
327 cashflows.push_back(ext::make_shared<MultipleResetsCoupon>(
328 paymentDate, detail::get(notionals_, i, notionals_.back()), subSchedule,
329 detail::get(fixingDays_, i, index_->fixingDays()), index_,
330 detail::get(gearings_, i, 1.0), detail::get(couponSpreads_, i, 0.0),
331 detail::get(rateSpreads_, i, 0.0), start, end, paymentDayCounter_,
332 exCouponDate));
333 }
334
335 switch (averagingMethod_) {
337 setCouponPricer(cashflows, ext::make_shared<AveragingMultipleResetsPricer>());
338 break;
340 setCouponPricer(cashflows, ext::make_shared<CompoundingMultipleResetsPricer>());
341 break;
342 default:
343 QL_FAIL("unknown compounding convention (" << Integer(averagingMethod_) << ")");
344 }
345 return cashflows;
346 }
347
348
350
351 SubPeriodsLeg::SubPeriodsLeg(Schedule schedule, ext::shared_ptr<IborIndex> i)
352 : schedule_(std::move(schedule)), index_(std::move(i)), paymentCalendar_(schedule_.calendar()) {
353 QL_REQUIRE(index_, "no index provided");
354 }
355
357 notionals_ = std::vector<Real>(1, notional);
358 return *this;
359 }
360
361 SubPeriodsLeg& SubPeriodsLeg::withNotionals(const std::vector<Real>& notionals) {
362 notionals_ = notionals;
363 return *this;
364 }
365
368 return *this;
369 }
370
372 paymentAdjustment_ = convention;
373 return *this;
374 }
375
377 paymentCalendar_ = cal;
378 return *this;
379 }
380
382 paymentLag_ = lag;
383 return *this;
384 }
385
387 fixingDays_ = std::vector<Natural>(1, fixingDays);
388 return *this;
389 }
390
391 SubPeriodsLeg& SubPeriodsLeg::withFixingDays(const std::vector<Natural>& fixingDays) {
392 fixingDays_ = fixingDays;
393 return *this;
394 }
395
397 gearings_ = std::vector<Real>(1, gearing);
398 return *this;
399 }
400
401 SubPeriodsLeg& SubPeriodsLeg::withGearings(const std::vector<Real>& gearings) {
402 gearings_ = gearings;
403 return *this;
404 }
405
407 couponSpreads_ = std::vector<Spread>(1, spread);
408 return *this;
409 }
410
411 SubPeriodsLeg& SubPeriodsLeg::withCouponSpreads(const std::vector<Spread>& spreads) {
412 couponSpreads_ = spreads;
413 return *this;
414 }
415
417 rateSpreads_ = std::vector<Spread>(1, spread);
418 return *this;
419 }
420
421 SubPeriodsLeg& SubPeriodsLeg::withRateSpreads(const std::vector<Spread>& spreads) {
422 rateSpreads_ = spreads;
423 return *this;
424 }
425
427 averagingMethod_ = averagingMethod;
428 return *this;
429 }
430
432 const Calendar& cal,
433 BusinessDayConvention convention,
434 bool endOfMonth) {
435 exCouponPeriod_ = period;
436 exCouponCalendar_ = cal;
437 exCouponAdjustment_ = convention;
438 exCouponEndOfMonth_ = endOfMonth;
439 return *this;
440 }
441
442 SubPeriodsLeg::operator Leg() const {
443 Leg cashflows;
444 Calendar calendar = schedule_.calendar();
445 Date refStart, start, refEnd, end, exCouponDate;
446 Date paymentDate;
447
448 Size n = schedule_.size() - 1;
449 QL_REQUIRE(!notionals_.empty(), "no notional given");
450 QL_REQUIRE(notionals_.size() <= n,
451 "too many nominals (" << notionals_.size() << "), only " << n << " required");
452 QL_REQUIRE(gearings_.size() <= n,
453 "too many gearings (" << gearings_.size() << "), only " << n << " required");
454 QL_REQUIRE(couponSpreads_.size() <= n,
455 "too many coupon spreads (" << couponSpreads_.size() << "), only " << n << " required");
456 QL_REQUIRE(rateSpreads_.size() <= n,
457 "too many rate spreads (" << rateSpreads_.size() << "), only " << n << " required");
458 QL_REQUIRE(fixingDays_.size() <= n,
459 "too many fixing days (" << fixingDays_.size() << "), only " << n << " required");
460
461 for (Size i = 0; i < n; ++i) {
462 refStart = start = schedule_.date(i);
463 refEnd = end = schedule_.date(i + 1);
464 paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_);
465
466 if (i == 0 && schedule_.hasIsRegular() && !schedule_.isRegular(i + 1))
467 refStart = calendar.adjust(end - schedule_.tenor(), paymentAdjustment_);
468 if (i == n - 1 && schedule_.hasIsRegular() && !schedule_.isRegular(i + 1))
469 refEnd = calendar.adjust(start + schedule_.tenor(), paymentAdjustment_);
470 if (exCouponPeriod_ != Period()) {
471 if (exCouponCalendar_.empty()) {
472 exCouponDate = calendar.advance(paymentDate, -exCouponPeriod_,
473 exCouponAdjustment_, exCouponEndOfMonth_);
474 } else {
475 exCouponDate = exCouponCalendar_.advance(
476 paymentDate, -exCouponPeriod_, exCouponAdjustment_, exCouponEndOfMonth_);
477 }
478 }
479 cashflows.push_back(ext::shared_ptr<CashFlow>(new MultipleResetsCoupon(
480 paymentDate, detail::get(notionals_, i, notionals_.back()), start, end,
481 detail::get(fixingDays_, i, index_->fixingDays()), index_,
482 detail::get(gearings_, i, 1.0), detail::get(couponSpreads_, i, 0.0),
483 detail::get(rateSpreads_, i, 0.0), refStart, refEnd, paymentDayCounter_,
484 exCouponDate)));
485 }
486
487 switch (averagingMethod_) {
489 setCouponPricer(cashflows, ext::make_shared<AveragingMultipleResetsPricer>());
490 break;
492 setCouponPricer(cashflows, ext::make_shared<CompoundingMultipleResetsPricer>());
493 break;
494 default:
495 QL_FAIL("unknown compounding convention (" << Integer(averagingMethod_) << ")");
496 }
497 return cashflows;
498 }
499
501
502}
Cash flow vector builders.
degenerate base class for the Acyclic Visitor pattern
Definition: visitor.hpp:33
calendar class
Definition: calendar.hpp:61
Date adjust(const Date &, BusinessDayConvention convention=Following) const
Definition: calendar.cpp:84
Date advance(const Date &, Integer n, TimeUnit unit, BusinessDayConvention convention=Following, bool endOfMonth=false) const
Definition: calendar.cpp:130
Time accrualPeriod() const
accrual period as fraction of year
Definition: coupon.cpp:44
Concrete date class.
Definition: date.hpp:125
static Date advance(const Date &d, Integer units, TimeUnit)
Definition: date.cpp:139
day counter class
Definition: daycounter.hpp:44
Time yearFraction(const Date &, const Date &, const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date()) const
Returns the period between two dates as a fraction of year.
Definition: daycounter.hpp:128
base floating-rate coupon class
ext::shared_ptr< InterestRateIndex > index_
void accept(AcyclicVisitor &) override
Real gearing() const
index gearing, i.e. multiplicative coefficient for the index
const ext::shared_ptr< InterestRateIndex > & index() const
floating index
Spread spread() const
spread paid over the fixing of the underlying index
MakeSchedule & withConvention(BusinessDayConvention)
Definition: schedule.cpp:552
MakeSchedule & backwards()
Definition: schedule.cpp:573
MakeSchedule & to(const Date &terminationDate)
Definition: schedule.cpp:532
MakeSchedule & withTenor(const Period &)
Definition: schedule.cpp:537
MakeSchedule & from(const Date &effectiveDate)
Definition: schedule.cpp:527
MakeSchedule & endOfMonth(bool flag=true)
Definition: schedule.cpp:578
MakeSchedule & withCalendar(const Calendar &)
Definition: schedule.cpp:547
Spread rateSpread() const
rate spread
void accept(AcyclicVisitor &) override
MultipleResetsCoupon(const Date &paymentDate, Real nominal, const Schedule &resetSchedule, Natural fixingDays, const ext::shared_ptr< IborIndex > &index, Real gearing=1.0, Rate couponSpread=0.0, Rate rateSpread=0.0, const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date(), const DayCounter &dayCounter=DayCounter(), const Date &exCouponDate=Date())
const std::vector< Time > & dt() const
accrual (compounding) periods
const std::vector< Date > & fixingDates() const
fixing dates for the rates to be compounded
Date fixingDate() const override
the date when the coupon is fully determined
helper class building a sequence of multiple-reset coupons
BusinessDayConvention paymentAdjustment_
MultipleResetsLeg & withPaymentLag(Integer lag)
BusinessDayConvention exCouponAdjustment_
std::vector< Spread > couponSpreads_
MultipleResetsLeg & withPaymentCalendar(const Calendar &)
MultipleResetsLeg & withExCouponPeriod(const Period &, const Calendar &, BusinessDayConvention, bool endOfMonth=false)
MultipleResetsLeg(Schedule fullResetSchedule, ext::shared_ptr< IborIndex > index, Size resetsPerCoupon)
MultipleResetsLeg & withNotionals(Real notional)
MultipleResetsLeg & withPaymentDayCounter(const DayCounter &)
MultipleResetsLeg & withAveragingMethod(RateAveraging::Type averagingMethod)
MultipleResetsLeg & withCouponSpreads(Spread spread)
std::vector< Natural > fixingDays_
MultipleResetsLeg & withGearings(Real gearing)
std::vector< Spread > rateSpreads_
MultipleResetsLeg & withFixingDays(Natural fixingDays)
MultipleResetsLeg & withRateSpreads(Spread spread)
MultipleResetsLeg & withPaymentAdjustment(BusinessDayConvention)
ext::shared_ptr< IborIndex > index_
Real capletPrice(Rate effectiveCap) const override
Rate floorletRate(Rate effectiveFloor) const override
void initialize(const FloatingRateCoupon &coupon) override
const MultipleResetsCoupon * coupon_
Real floorletPrice(Rate effectiveFloor) const override
Rate capletRate(Rate effectiveCap) const override
Payment schedule.
Definition: schedule.hpp:40
const std::vector< Date > & dates() const
Definition: schedule.hpp:73
bool empty() const
Definition: schedule.hpp:74
Size size() const
Definition: schedule.hpp:69
SubPeriodsLeg & withAveragingMethod(RateAveraging::Type averagingMethod)
SubPeriodsLeg & withExCouponPeriod(const Period &, const Calendar &, BusinessDayConvention, bool endOfMonth=false)
BusinessDayConvention paymentAdjustment_
BusinessDayConvention exCouponAdjustment_
std::vector< Spread > couponSpreads_
SubPeriodsLeg & withPaymentLag(Integer lag)
SubPeriodsLeg & withNotionals(Real notional)
std::vector< Real > notionals_
SubPeriodsLeg(Schedule schedule, ext::shared_ptr< IborIndex > index)
RateAveraging::Type averagingMethod_
SubPeriodsLeg & withRateSpreads(Spread spread)
std::vector< Natural > fixingDays_
std::vector< Spread > rateSpreads_
SubPeriodsLeg & withCouponSpreads(Spread spread)
SubPeriodsLeg & withGearings(Real gearing)
SubPeriodsLeg & withFixingDays(Natural fixingDays)
SubPeriodsLeg & withPaymentAdjustment(BusinessDayConvention)
SubPeriodsLeg & withPaymentDayCounter(const DayCounter &)
SubPeriodsLeg & withPaymentCalendar(const Calendar &)
ext::shared_ptr< IborIndex > index_
Visitor for a specific class
Definition: visitor.hpp:40
virtual void visit(T &)=0
Calendar paymentCalendar_
Integer paymentLag_
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Definition: errors.hpp:92
BusinessDayConvention
Business Day conventions.
QL_REAL Real
real number
Definition: types.hpp:50
unsigned QL_INTEGER Natural
positive integer
Definition: types.hpp:43
QL_INTEGER Integer
integer number
Definition: types.hpp:35
Real Spread
spreads on interest rates
Definition: types.hpp:74
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
base class for Inter-Bank-Offered-Rate indexes
Coupon compounding or averaging multiple fixings.
T get(const std::vector< T > &v, Size i, U defaultValue)
Definition: vectors.hpp:33
Definition: any.hpp:37
void setCouponPricer(const Leg &leg, const ext::shared_ptr< FloatingRateCouponPricer > &pricer)
std::vector< ext::shared_ptr< CashFlow > > Leg
Sequence of cash-flows.
Definition: cashflow.hpp:78
STL namespace.
ext::shared_ptr< BlackVolTermStructure > v
#define QL_DEPRECATED_DISABLE_WARNING
Definition: qldefines.hpp:216
#define QL_DEPRECATED_ENABLE_WARNING
Definition: qldefines.hpp:217
date schedule
Interest-rate term structure.