QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
cpicoupon.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2009 Chris Kenyon
5 Copyright (C) 2022 Quaternion Risk Management Ltd
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
21
22#include <ql/cashflows/cashflowvectors.hpp>
23#include <ql/cashflows/cpicoupon.hpp>
24#include <ql/cashflows/cpicouponpricer.hpp>
25#include <ql/cashflows/inflationcoupon.hpp>
26#include <ql/time/daycounters/thirty360.hpp>
27#include <utility>
28
29
30namespace QuantLib {
31
32 QL_DEPRECATED_DISABLE_WARNING
33
35 const Date& paymentDate,
36 Real nominal,
37 const Date& startDate,
38 const Date& endDate,
39 const ext::shared_ptr<ZeroInflationIndex>& index,
40 const Period& observationLag,
41 CPI::InterpolationType observationInterpolation,
42 const DayCounter& dayCounter,
43 Real fixedRate,
44 const Date& refPeriodStart,
45 const Date& refPeriodEnd,
46 const Date& exCouponDate)
47 : CPICoupon(baseCPI, paymentDate, nominal, startDate, endDate, index,
48 observationLag, observationInterpolation, dayCounter,
49 fixedRate, 0.0, refPeriodStart, refPeriodEnd, exCouponDate) {}
50
51 CPICoupon::CPICoupon(const Date& baseDate,
52 const Date& paymentDate,
53 Real nominal,
54 const Date& startDate,
55 const Date& endDate,
56 const ext::shared_ptr<ZeroInflationIndex>& index,
57 const Period& observationLag,
58 CPI::InterpolationType observationInterpolation,
59 const DayCounter& dayCounter,
60 Real fixedRate,
61 const Date& refPeriodStart,
62 const Date& refPeriodEnd,
63 const Date& exCouponDate)
64 : CPICoupon(baseDate, paymentDate, nominal, startDate, endDate, index,
65 observationLag, observationInterpolation, dayCounter,
66 fixedRate, 0.0, refPeriodStart, refPeriodEnd, exCouponDate) {}
67
69 const Date& baseDate,
70 const Date& paymentDate,
71 Real nominal,
72 const Date& startDate,
73 const Date& endDate,
74 const ext::shared_ptr<ZeroInflationIndex>& index,
75 const Period& observationLag,
76 CPI::InterpolationType observationInterpolation,
77 const DayCounter& dayCounter,
78 Real fixedRate,
79 const Date& refPeriodStart,
80 const Date& refPeriodEnd,
81 const Date& exCouponDate)
82 : CPICoupon(baseCPI, baseDate, paymentDate, nominal, startDate, endDate, index,
83 observationLag, observationInterpolation, dayCounter,
84 fixedRate, 0.0, refPeriodStart, refPeriodEnd, exCouponDate) {}
85
87 const Date& paymentDate,
88 Real nominal,
89 const Date& startDate,
90 const Date& endDate,
91 const ext::shared_ptr<ZeroInflationIndex>& index,
92 const Period& observationLag,
93 CPI::InterpolationType observationInterpolation,
94 const DayCounter& dayCounter,
95 Real fixedRate,
96 Spread spread,
97 const Date& refPeriodStart,
98 const Date& refPeriodEnd,
99 const Date& exCouponDate)
100 : CPICoupon(baseCPI, Null<Date>(), paymentDate, nominal, startDate, endDate, index,
101 observationLag, observationInterpolation, dayCounter,
102 fixedRate, spread, refPeriodStart, refPeriodEnd, exCouponDate) {}
103
104 CPICoupon::CPICoupon(const Date& baseDate,
105 const Date& paymentDate,
106 Real nominal,
107 const Date& startDate,
108 const Date& endDate,
109 const ext::shared_ptr<ZeroInflationIndex>& index,
110 const Period& observationLag,
111 CPI::InterpolationType observationInterpolation,
112 const DayCounter& dayCounter,
113 Real fixedRate,
114 Spread spread,
115 const Date& refPeriodStart,
116 const Date& refPeriodEnd,
117 const Date& exCouponDate)
118 : CPICoupon(Null<Real>(), baseDate, paymentDate, nominal, startDate, endDate, index,
119 observationLag, observationInterpolation, dayCounter,
120 fixedRate, spread, refPeriodStart, refPeriodEnd, exCouponDate) {}
121
123 const Date& baseDate,
124 const Date& paymentDate,
125 Real nominal,
126 const Date& startDate,
127 const Date& endDate,
128 const ext::shared_ptr<ZeroInflationIndex>& index,
129 const Period& observationLag,
130 CPI::InterpolationType observationInterpolation,
131 const DayCounter& dayCounter,
132 Real fixedRate,
133 Spread spread,
134 const Date& refPeriodStart,
135 const Date& refPeriodEnd,
136 const Date& exCouponDate)
137 : InflationCoupon(paymentDate, nominal, startDate, endDate, 0,
138 index, observationLag, dayCounter,
139 refPeriodStart, refPeriodEnd, exCouponDate),
140 baseCPI_(baseCPI), fixedRate_(fixedRate), spread_(spread),
141 observationInterpolation_(observationInterpolation), baseDate_(baseDate) {
142
143 QL_REQUIRE(index_, "no index provided");
144 QL_REQUIRE(
146 "baseCPI and baseDate can not be both null, provide a valid baseCPI or baseDate");
147 QL_REQUIRE(baseCPI_ == Null<Rate>() || std::fabs(baseCPI_) > 1e-16,
148 "|baseCPI_| < 1e-16, future divide-by-zero problem");
149 }
150
151 QL_DEPRECATED_ENABLE_WARNING
152
154 auto* v1 = dynamic_cast<Visitor<CPICoupon>*>(&v);
155 if (v1 != nullptr)
156 v1->visit(*this);
157 else
159 }
160
162 if (d <= accrualStartDate_ || d > paymentDate_) {
163 return 0.0;
164 } else {
165 auto pricer = ext::dynamic_pointer_cast<CPICouponPricer>(pricer_);
166 QL_REQUIRE(pricer, "pricer not set or of wrong type");
167 pricer->initialize(*this);
168 return nominal() * pricer->accruedRate(d) * accruedPeriod(d);
169 }
170 }
171
173
174 Rate I0 = baseCPI();
175
176 if (I0 == Null<Rate>()) {
181 }
182
184 d,
187
188 return I1 / I0;
189 }
190
192 const ext::shared_ptr<InflationCouponPricer>&pricer) const {
193 return static_cast<bool>(
194 ext::dynamic_pointer_cast<CPICouponPricer>(pricer));
195 }
196
197
198
200 const ext::shared_ptr<ZeroInflationIndex>& index,
201 const Date& baseDate,
202 Real baseFixing,
203 const Date& observationDate,
204 const Period& observationLag,
205 CPI::InterpolationType interpolation,
206 const Date& paymentDate,
207 bool growthOnly)
208 : IndexedCashFlow(notional, index, baseDate, observationDate - observationLag, paymentDate, growthOnly),
209 baseFixing_(baseFixing), observationDate_(observationDate), observationLag_(observationLag),
210 interpolation_(interpolation), frequency_(index ? index->frequency() : NoFrequency) {
211 QL_REQUIRE(index, "no index provided");
212 QL_REQUIRE(
214 "baseCPI and baseDate can not be both null, provide a valid baseCPI or baseDate");
215 QL_REQUIRE(baseFixing_ == Null<Rate>() || std::fabs(baseFixing_) > 1e-16,
216 "|baseCPI_| < 1e-16, future divide-by-zero problem");
217 }
218
221 if (base != Date()) {
222 return base;
223 } else {
224 QL_FAIL("no base date specified");
225 }
226 }
227
229 return baseFixing_;
230 }
231
233 if (observationDate_ != Date()) {
235 } else {
236 // we get to this branch when the deprecated constructor was used; it will be phased out
239 }
240 }
241
243 Rate I0 = baseFixing();
244
245 // If BaseFixing is null, use the observed index fixing
246 if (I0 == Null<Rate>()) {
248 }
249
250 Rate I1 = indexFixing();
251
252 if (growthOnly())
253 return notional() * (I1 / I0 - 1.0);
254 else
255 return notional() * (I1 / I0);
256 }
257
258 CPILeg::CPILeg(const Schedule& schedule,
259 ext::shared_ptr<ZeroInflationIndex> index,
260 const Real baseCPI,
261 const Period& observationLag)
262 : schedule_(schedule), index_(std::move(index)), baseCPI_(baseCPI),
263 observationLag_(observationLag), paymentDayCounter_(Thirty360(Thirty360::BondBasis)),
264 paymentCalendar_(schedule.calendar()),
265
266 spreads_(std::vector<Real>(1, 0)), baseDate_(Null<Date>()) {}
267
268
271 return *this;
272 }
273
274
276 fixedRates_ = std::vector<Real>(1,fixedRate);
277 return *this;
278 }
279
280 CPILeg& CPILeg::withFixedRates(const std::vector<Real>& fixedRates) {
281 fixedRates_ = fixedRates;
282 return *this;
283 }
284
286 notionals_ = std::vector<Real>(1,notional);
287 return *this;
288 }
289
290 CPILeg& CPILeg::withNotionals(const std::vector<Real>& notionals) {
291 notionals_ = notionals;
292 return *this;
293 }
294
296 subtractInflationNominal_ = growthOnly;
297 return *this;
298 }
299
301 paymentDayCounter_ = dayCounter;
302 return *this;
303 }
304
306 paymentAdjustment_ = convention;
307 return *this;
308 }
309
311 paymentCalendar_ = cal;
312 return *this;
313 }
314
316 spreads_ = std::vector<Spread>(1,spread);
317 return *this;
318 }
319
320 CPILeg& CPILeg::withSpreads(const std::vector<Spread>& spreads) {
321 spreads_ = spreads;
322 return *this;
323 }
324
326 caps_ = std::vector<Rate>(1,cap);
327 return *this;
328 }
329
330 CPILeg& CPILeg::withCaps(const std::vector<Rate>& caps) {
331 caps_ = caps;
332 return *this;
333 }
334
336 floors_ = std::vector<Rate>(1,floor);
337 return *this;
338 }
339
340 CPILeg& CPILeg::withFloors(const std::vector<Rate>& floors) {
341 floors_ = floors;
342 return *this;
343 }
344
346 const Period& period,
347 const Calendar& cal,
348 BusinessDayConvention convention,
349 bool endOfMonth) {
350 exCouponPeriod_ = period;
351 exCouponCalendar_ = cal;
352 exCouponAdjustment_ = convention;
353 exCouponEndOfMonth_ = endOfMonth;
354 return *this;
355 }
356
357 CPILeg& CPILeg::withBaseDate(const Date& baseDate) {
358 baseDate_ = baseDate;
359 return *this;
360 }
361
362
363 CPILeg::operator Leg() const {
364
365 QL_REQUIRE(!notionals_.empty(), "no notional given");
366 Size n = schedule_.size()-1;
367 Leg leg;
368 leg.reserve(n+1); // +1 for notional, we always have some sort ...
369
370 Date baseDate = baseDate_;
371 // BaseDate and baseCPI are not given, use the first date as startDate and the baseFixingg
372 // should be at startDate - observationLag
373
374 if (n>0) {
375 QL_REQUIRE(!fixedRates_.empty() || !spreads_.empty(),
376 "no fixedRates or spreads given");
377
378 if (baseDate_ == Null<Date>() && baseCPI_ == Null<Real>()) {
379 baseDate = schedule_.date(0) - observationLag_;
380 }
381
382 Date refStart, start, refEnd, end;
383
384 for (Size i=0; i<n; ++i) {
385 refStart = start = schedule_.date(i);
386 refEnd = end = schedule_.date(i+1);
387 Date paymentDate = paymentCalendar_.adjust(end, paymentAdjustment_);
388
389 Date exCouponDate;
390 if (exCouponPeriod_ != Period())
391 {
392 exCouponDate = exCouponCalendar_.advance(paymentDate,
393 -exCouponPeriod_,
394 exCouponAdjustment_,
395 exCouponEndOfMonth_);
396 }
397
398 if (i==0 && schedule_.hasIsRegular() && !schedule_.isRegular(i+1)) {
399 BusinessDayConvention bdc = schedule_.businessDayConvention();
400 refStart = schedule_.calendar().adjust(end - schedule_.tenor(), bdc);
401 }
402 if (i==n-1 && schedule_.hasIsRegular() && !schedule_.isRegular(i+1)) {
403 BusinessDayConvention bdc = schedule_.businessDayConvention();
404 refEnd = schedule_.calendar().adjust(start + schedule_.tenor(), bdc);
405 }
406 if (detail::get(fixedRates_, i, 1.0) == 0.0) { // fixed coupon
407 leg.push_back(ext::make_shared<FixedRateCoupon>
408 (paymentDate, detail::get(notionals_, i, 0.0),
409 detail::effectiveFixedRate(spreads_,caps_,floors_,i),
410 paymentDayCounter_, start, end, refStart, refEnd, exCouponDate));
411 } else { // zero inflation coupon
412 if (detail::noOption(caps_, floors_, i)) { // just swaplet
413 QL_DEPRECATED_DISABLE_WARNING
414 leg.push_back(ext::make_shared<CPICoupon>
415 (baseCPI_, // all have same base for ratio
416 baseDate,
417 paymentDate,
418 detail::get(notionals_, i, 0.0),
419 start, end,
420 index_, observationLag_,
421 observationInterpolation_,
422 paymentDayCounter_,
423 detail::get(fixedRates_, i, 0.0),
424 detail::get(spreads_, i, 0.0),
425 refStart, refEnd, exCouponDate));
426 QL_DEPRECATED_ENABLE_WARNING
427 } else { // cap/floorlet
428 QL_FAIL("caps/floors on CPI coupons not implemented.");
429 }
430 }
431 }
432 }
433
434 // in CPI legs you always have a notional flow of some sort
435 Date paymentDate = paymentCalendar_.adjust(schedule_.date(n), paymentAdjustment_);
436 leg.push_back(ext::make_shared<CPICashFlow>
437 (detail::get(notionals_, n, 0.0), index_,
438 baseDate, baseCPI_,
439 schedule_.date(n), observationLag_, observationInterpolation_,
440 paymentDate, subtractInflationNominal_));
441
442 // no caps and floors here, so this is enough
443 setCouponPricer(leg, ext::make_shared<CPICouponPricer>());
444
445 return leg;
446 }
447
448}
449
degenerate base class for the Acyclic Visitor pattern
Definition: visitor.hpp:33
CPICashFlow(Real notional, const ext::shared_ptr< ZeroInflationIndex > &index, const Date &baseDate, Real baseFixing, const Date &observationDate, const Period &observationLag, CPI::InterpolationType interpolation, const Date &paymentDate, bool growthOnly=false)
Definition: cpicoupon.cpp:199
ext::shared_ptr< ZeroInflationIndex > cpiIndex() const
Definition: cpicoupon.hpp:375
CPI::InterpolationType interpolation_
Definition: cpicoupon.hpp:266
Date baseDate() const override
you may not have a valid date
Definition: cpicoupon.cpp:219
Real amount() const override
returns the amount of the cash flow
Definition: cpicoupon.cpp:242
Real baseFixing() const override
value used on base date
Definition: cpicoupon.cpp:228
Real indexFixing() const override
Definition: cpicoupon.cpp:232
Coupon paying the performance of a CPI (zero inflation) index
Definition: cpicoupon.hpp:55
bool checkPricerImpl(const ext::shared_ptr< InflationCouponPricer > &) const override
makes sure you were given the correct type of pricer
Definition: cpicoupon.cpp:191
void accept(AcyclicVisitor &) override
Definition: cpicoupon.cpp:153
Rate baseCPI() const
base value for the CPI index
Definition: cpicoupon.hpp:358
ext::shared_ptr< ZeroInflationIndex > cpiIndex() const
index used
Definition: cpicoupon.hpp:370
CPI::InterpolationType observationInterpolation() const
how do you observe the index? as-is, flat, linear?
Definition: cpicoupon.hpp:366
CPICoupon(Real baseCPI, const Date &paymentDate, Real nominal, const Date &startDate, const Date &endDate, const ext::shared_ptr< ZeroInflationIndex > &index, const Period &observationLag, CPI::InterpolationType observationInterpolation, const DayCounter &dayCounter, Real fixedRate, const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date(), const Date &exCouponDate=Date())
Definition: cpicoupon.cpp:34
Rate indexRatio(Date d) const
the ratio between the index fixing at the passed date and the base CPI
Definition: cpicoupon.cpp:172
Date baseDate() const
base date for the base fixing of the CPI index
Definition: cpicoupon.hpp:362
Real accruedAmount(const Date &) const override
accrued amount at the given date
Definition: cpicoupon.cpp:161
Helper class building a sequence of capped/floored CPI coupons.
Definition: cpicoupon.hpp:277
CPILeg & withNotionals(Real notional)
Definition: cpicoupon.cpp:285
BusinessDayConvention paymentAdjustment_
Definition: cpicoupon.hpp:322
std::vector< Rate > caps_
Definition: cpicoupon.hpp:327
CPILeg & withPaymentAdjustment(BusinessDayConvention)
Definition: cpicoupon.cpp:305
BusinessDayConvention exCouponAdjustment_
Definition: cpicoupon.hpp:330
CPILeg & withSubtractInflationNominal(bool)
Definition: cpicoupon.cpp:295
Calendar paymentCalendar_
Definition: cpicoupon.hpp:323
CPILeg & withBaseDate(const Date &baseDate)
Definition: cpicoupon.cpp:357
CPILeg & withFixedRates(Real fixedRate)
Definition: cpicoupon.cpp:275
CPILeg & withExCouponPeriod(const Period &, const Calendar &, BusinessDayConvention, bool endOfMonth=false)
Definition: cpicoupon.cpp:345
std::vector< Real > notionals_
Definition: cpicoupon.hpp:319
std::vector< Spread > spreads_
Definition: cpicoupon.hpp:326
CPILeg & withCaps(Rate cap)
Definition: cpicoupon.cpp:325
CPILeg & withPaymentDayCounter(const DayCounter &)
Definition: cpicoupon.cpp:300
CPILeg & withPaymentCalendar(const Calendar &)
Definition: cpicoupon.cpp:310
CPILeg & withSpreads(Spread spread)
Definition: cpicoupon.cpp:315
CPILeg & withFloors(Rate floor)
Definition: cpicoupon.cpp:335
bool exCouponEndOfMonth_
Definition: cpicoupon.hpp:331
std::vector< Real > fixedRates_
Definition: cpicoupon.hpp:320
CPILeg(const Schedule &schedule, ext::shared_ptr< ZeroInflationIndex > index, Real baseCPI, const Period &observationLag)
Definition: cpicoupon.cpp:258
CPI::InterpolationType observationInterpolation_
Definition: cpicoupon.hpp:324
Period exCouponPeriod_
Definition: cpicoupon.hpp:328
Calendar exCouponCalendar_
Definition: cpicoupon.hpp:329
std::vector< Rate > floors_
Definition: cpicoupon.hpp:327
bool subtractInflationNominal_
Definition: cpicoupon.hpp:325
CPILeg & withObservationInterpolation(CPI::InterpolationType)
Definition: cpicoupon.cpp:269
DayCounter paymentDayCounter_
Definition: cpicoupon.hpp:321
calendar class
Definition: calendar.hpp:61
Date paymentDate_
Definition: coupon.hpp:90
virtual Real nominal() const
Definition: coupon.hpp:100
Time accruedPeriod(const Date &) const
accrued period as fraction of year at the given date
Definition: coupon.cpp:57
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
Cash flow dependent on an index ratio.
virtual Date fixingDate() const
virtual Real notional() const
virtual Real baseFixing() const
virtual Date baseDate() const
virtual bool growthOnly() const
virtual ext::shared_ptr< Index > index() const
Base inflation-coupon class.
ext::shared_ptr< InflationCouponPricer > pricer_
ext::shared_ptr< InflationIndex > index_
ext::shared_ptr< InflationCouponPricer > pricer() const
void accept(AcyclicVisitor &) override
Period observationLag() const
how the coupon observes the index
template class providing a null value for a given type.
Definition: null.hpp:76
Payment schedule.
Definition: schedule.hpp:40
30/360 day count convention
Definition: thirty360.hpp:76
Visitor for a specific class
Definition: visitor.hpp:40
virtual void visit(T &)=0
BusinessDayConvention
Business Day conventions.
@ NoFrequency
null frequency
Definition: frequency.hpp:37
QL_REAL Real
real number
Definition: types.hpp:50
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
T get(const std::vector< T > &v, Size i, U defaultValue)
Definition: vectors.hpp:35
Rate effectiveFixedRate(const std::vector< Spread > &spreads, const std::vector< Rate > &caps, const std::vector< Rate > &floors, Size i)
bool noOption(const std::vector< Rate > &caps, const std::vector< Rate > &floors, Size i)
Definition: any.hpp:35
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.
static Real laggedFixing(const ext::shared_ptr< ZeroInflationIndex > &index, const Date &date, const Period &observationLag, InterpolationType interpolationType)
interpolated inflation fixing
InterpolationType
when you observe an index, how do you interpolate between fixings?