Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
nonstandardcapflooredyoyinflationcoupon.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2021 Quaternion Risk Management Ltd
3
4 This file is part of ORE, a free-software/open-source library
5 for transparent pricing and risk analysis - http://opensourcerisk.org
6
7 ORE is free software: you can redistribute it and/or modify it
8 under the terms of the Modified BSD License. You should have received a
9 copy of the license along with this program.
10 The license is also available online at <http://opensourcerisk.org>
11
12 This program is distributed on the basis that it will form a useful
13 contribution to risk analytics and model standardisation, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
16*/
17
18/*
19 Copyright (C) 2009 Chris Kenyon
20
21 This file is part of QuantLib, a free-software/open-source library
22 for financial quantitative analysts and developers - http://quantlib.org/
23
24 QuantLib is free software: you can redistribute it and/or modify it
25 under the terms of the QuantLib license. You should have received a
26 copy of the license along with this program; if not, please email
27 <quantlib-dev@lists.sf.net>. The license is also available online at
28 <http://quantlib.org/license.shtml>.
29
30 This program is distributed in the hope that it will be useful, but WITHOUT
31 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
32 FOR A PARTICULAR PURPOSE. See the license for more details.
33 */
34
35#include <ql/cashflows/cashflows.hpp>
36#include <ql/cashflows/cashflowvectors.hpp>
37#include <ql/cashflows/inflationcouponpricer.hpp>
39
40namespace QuantExt {
41
43
44 isCapped_ = false;
45 isFloored_ = false;
46
47 if (gearing_ > 0) {
48 if (cap != Null<Rate>()) {
49 isCapped_ = true;
50 cap_ = cap;
51 }
52 if (floor != Null<Rate>()) {
53 floor_ = floor;
54 isFloored_ = true;
55 }
56 } else {
57 if (cap != Null<Rate>()) {
58 floor_ = cap;
59 isFloored_ = true;
60 }
61 if (floor != Null<Rate>()) {
62 isCapped_ = true;
63 cap_ = floor;
64 }
65 }
66 if (isCapped_ && isFloored_) {
67 QL_REQUIRE(cap >= floor, "cap level (" << cap << ") less than floor level (" << floor << ")");
68 }
69}
70
72 const ext::shared_ptr<NonStandardYoYInflationCoupon>& underlying, Rate cap, Rate floor)
73 : NonStandardYoYInflationCoupon(underlying->date(), underlying->nominal(), underlying->accrualStartDate(),
74 underlying->accrualEndDate(), underlying->fixingDays(), underlying->cpiIndex(),
75 underlying->observationLag(), underlying->dayCounter(), underlying->gearing(),
76 underlying->spread(), underlying->referencePeriodStart(),
77 underlying->referencePeriodEnd(), underlying->addInflationNotional(),
78 underlying->interpolationType()),
79 underlying_(underlying), isFloored_(false), isCapped_(false) {
81 registerWith(underlying);
82}
83
85 const Date& paymentDate, Real nominal, const Date& startDate, const Date& endDate, Natural fixingDays,
86 const ext::shared_ptr<ZeroInflationIndex>& index, const Period& observationLag, const DayCounter& dayCounter,
87 Real gearing, Spread spread, const Rate cap, const Rate floor, const Date& refPeriodStart, const Date& refPeriodEnd,
88 bool addInflationNotional, QuantLib::CPI::InterpolationType interpolation)
89 : NonStandardYoYInflationCoupon(paymentDate, nominal, startDate, endDate, fixingDays, index, observationLag,
90 dayCounter, gearing, spread, refPeriodStart, refPeriodEnd, addInflationNotional,
91 interpolation),
92 isFloored_(false), isCapped_(false) {
94}
95
97 const ext::shared_ptr<NonStandardYoYInflationCouponPricer>& pricer) {
98
99 NonStandardYoYInflationCoupon::setPricer(pricer);
100 if (underlying_)
101 underlying_->setPricer(pricer);
102}
103
105 Rate swapletRate = underlying_ ? underlying_->rate() : NonStandardYoYInflationCoupon::rate();
106
107 if (isFloored_ || isCapped_) {
108 if (underlying_) {
109 QL_REQUIRE(underlying_->pricer(), "pricer not set");
110 } else {
111 QL_REQUIRE(pricer_, "pricer not set");
112 }
113 }
114
115 Rate floorletRate = 0.;
116 if (isFloored_) {
117 floorletRate = underlying_ ? underlying_->pricer()->floorletRate(effectiveFloor())
118 : pricer()->floorletRate(effectiveFloor());
119 }
120 Rate capletRate = 0.;
121 if (isCapped_) {
122 capletRate =
123 underlying_ ? underlying_->pricer()->capletRate(effectiveCap()) : pricer()->capletRate(effectiveCap());
124 }
125
126 return swapletRate + floorletRate - capletRate;
127}
128
130 if ((gearing_ > 0) && isCapped_)
131 return cap_;
132 if ((gearing_ < 0) && isFloored_)
133 return floor_;
134 return Null<Rate>();
135}
136
138 if ((gearing_ > 0) && isFloored_)
139 return floor_;
140 if ((gearing_ < 0) && isCapped_)
141 return cap_;
142 return Null<Rate>();
143}
144
146 return (cap_ - (addInflationNotional_ ? 1 : 0) - spread()) / gearing();
147}
148
150 return (floor_ - (addInflationNotional_ ? 1 : 0) - spread()) / gearing();
151}
152
154
156 Visitor<NonStandardCappedFlooredYoYInflationCoupon>* v1 =
157 dynamic_cast<Visitor<NonStandardCappedFlooredYoYInflationCoupon>*>(&v);
158
159 if (v1 != 0)
160 v1->visit(*this);
161 else
163}
164
165NonStandardYoYInflationLeg::NonStandardYoYInflationLeg(const Schedule& schedule, const Calendar& paymentCalendar,
166 const ext::shared_ptr<ZeroInflationIndex>& index,
167 const Period& observationLag)
168 : schedule_(schedule), index_(index), observationLag_(observationLag), paymentAdjustment_(ModifiedFollowing),
169 paymentCalendar_(paymentCalendar), addInflationNotional_(false), interpolation_(QuantLib::CPI::Flat) {}
170
172 notionals_ = std::vector<Real>(1, notional);
173 return *this;
174}
175
177 notionals_ = notionals;
178 return *this;
179}
180
182 paymentDayCounter_ = dayCounter;
183 return *this;
184}
185
187 paymentAdjustment_ = convention;
188 return *this;
189}
190
192 fixingDays_ = std::vector<Natural>(1, fixingDays);
193 return *this;
194}
195
197 fixingDays_ = fixingDays;
198 return *this;
199}
200
202 gearings_ = std::vector<Real>(1, gearing);
203 return *this;
204}
205
207 gearings_ = gearings;
208 return *this;
209}
210
212 spreads_ = std::vector<Spread>(1, spread);
213 return *this;
214}
215
217 spreads_ = spreads;
218 return *this;
219}
220
222 caps_ = std::vector<Rate>(1, cap);
223 return *this;
224}
225
227 caps_ = caps;
228 return *this;
229}
230
232 floors_ = std::vector<Rate>(1, floor);
233 return *this;
234}
235
237 floors_ = floors;
238 return *this;
239}
240
241NonStandardYoYInflationLeg& NonStandardYoYInflationLeg::withRateCurve(const Handle<YieldTermStructure>& rateCurve) {
242 rateCurve_ = rateCurve;
243 return *this;
244}
245
247 addInflationNotional_ = addInflationNotional;
248 return *this;
249}
250
252 interpolation_ = interpolation;
253 return *this;
254}
255
256NonStandardYoYInflationLeg::operator Leg() const {
257
258 Size n = schedule_.size() - 1;
259 QL_REQUIRE(!notionals_.empty(), "no notional given");
260 QL_REQUIRE(notionals_.size() <= n, "too many nominals (" << notionals_.size() << "), only " << n << " required");
261 QL_REQUIRE(gearings_.size() <= n, "too many gearings (" << gearings_.size() << "), only " << n << " required");
262 QL_REQUIRE(spreads_.size() <= n, "too many spreads (" << spreads_.size() << "), only " << n << " required");
263 QL_REQUIRE(caps_.size() <= n, "too many caps (" << caps_.size() << "), only " << n << " required");
264 QL_REQUIRE(floors_.size() <= n, "too many floors (" << floors_.size() << "), only " << n << " required");
265
266 Leg leg;
267 leg.reserve(n);
268
269 Calendar calendar = paymentCalendar_;
270
271 Date refStart, start, refEnd, end;
272
273 for (Size i = 0; i < n; ++i) {
274 refStart = start = schedule_.date(i);
275 refEnd = end = schedule_.date(i + 1);
276 Date paymentDate = calendar.adjust(end, paymentAdjustment_);
277 if (i == 0 && schedule_.hasIsRegular() && !schedule_.isRegular(i + 1)) {
278 BusinessDayConvention bdc = schedule_.businessDayConvention();
279 refStart = schedule_.calendar().adjust(end - schedule_.tenor(), bdc);
280 }
281 if (i == n - 1 && schedule_.hasIsRegular() && !schedule_.isRegular(i + 1)) {
282 BusinessDayConvention bdc = schedule_.businessDayConvention();
283 refEnd = schedule_.calendar().adjust(start + schedule_.tenor(), bdc);
284 }
285 if (detail::get(gearings_, i, 1.0) == 0.0) { // fixed coupon
286 leg.push_back(ext::shared_ptr<CashFlow>(new FixedRateCoupon(
287 paymentDate, detail::get(notionals_, i, 1.0), detail::effectiveFixedRate(spreads_, caps_, floors_, i),
288 paymentDayCounter_, start, end, refStart, refEnd)));
289 } else { // yoy inflation coupon
290 if (detail::noOption(caps_, floors_, i)) { // just swaplet
291 ext::shared_ptr<NonStandardYoYInflationCoupon> coup(new NonStandardYoYInflationCoupon(
292 paymentDate, detail::get(notionals_, i, 1.0), start, end, detail::get(fixingDays_, i, 0), index_,
293 observationLag_, paymentDayCounter_, detail::get(gearings_, i, 1.0), detail::get(spreads_, i, 0.0),
294 refStart, refEnd, addInflationNotional_, interpolation_));
295
296 // in this case you can set a pricer
297 // straight away because it only provides computation - not data
298 ext::shared_ptr<NonStandardYoYInflationCouponPricer> pricer(
300 coup->setPricer(pricer);
301 leg.push_back(ext::dynamic_pointer_cast<CashFlow>(coup));
302
303 } else { // cap/floorlet
304 leg.push_back(ext::shared_ptr<CashFlow>(new NonStandardCappedFlooredYoYInflationCoupon(
305 paymentDate, detail::get(notionals_, i, 1.0), start, end, detail::get(fixingDays_, i, 0), index_,
306 observationLag_, paymentDayCounter_, detail::get(gearings_, i, 1.0), detail::get(spreads_, i, 0.0),
307 detail::get(caps_, i, Null<Rate>()), detail::get(floors_, i, Null<Rate>()), refStart, refEnd,
308 addInflationNotional_, interpolation_)));
309 }
310 }
311 }
312
313 return leg;
314}
315
316} // namespace QuantExt
NonStandardCappedFlooredYoYInflationCoupon(const ext::shared_ptr< NonStandardYoYInflationCoupon > &underlying, Rate cap=Null< Rate >(), Rate floor=Null< Rate >())
void setPricer(const ext::shared_ptr< NonStandardYoYInflationCouponPricer > &)
Coupon paying a YoY-inflation type index
virtual void accept(AcyclicVisitor &) override
Real gearing() const
index gearing, i.e. multiplicative coefficient for the index
Spread spread() const
spread paid over the fixing of the underlying index
base pricer for capped/floored YoY inflation coupons
NonStandardYoYInflationLeg & withPaymentAdjustment(BusinessDayConvention)
NonStandardYoYInflationLeg & withFixingDays(Natural fixingDays)
NonStandardYoYInflationLeg & withRateCurve(const Handle< YieldTermStructure > &rateCurve)
NonStandardYoYInflationLeg & withSpreads(Spread spread)
NonStandardYoYInflationLeg(const Schedule &schedule, const Calendar &cal, const ext::shared_ptr< ZeroInflationIndex > &index, const Period &observationLag)
NonStandardYoYInflationLeg & withPaymentDayCounter(const DayCounter &)
NonStandardYoYInflationLeg & withGearings(Real gearing)
NonStandardYoYInflationLeg & withNotionals(Real notional)
NonStandardYoYInflationLeg & withObservationInterpolation(QuantLib::CPI::InterpolationType interpolation)
NonStandardYoYInflationLeg & withInflationNotional(bool addInflationNotional_)
const QuantLib::ext::shared_ptr< FloatingRateCouponPricer > pricer_