QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
Loading...
Searching...
No Matches
overnightindexedcoupon.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) 2009 Roland Lichters
5 Copyright (C) 2009 Ferdinando Ametrano
6 Copyright (C) 2014 Peter Caspers
7 Copyright (C) 2017 Joseph Jeisman
8 Copyright (C) 2017 Fabrice Lecuyer
9
10 This file is part of QuantLib, a free-software/open-source library
11 for financial quantitative analysts and developers - http://quantlib.org/
12
13 QuantLib is free software: you can redistribute it and/or modify it
14 under the terms of the QuantLib license. You should have received a
15 copy of the license along with this program; if not, please email
16 <quantlib-dev@lists.sf.net>. The license is also available online at
17 <http://quantlib.org/license.shtml>.
18
19 This program is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21 FOR A PARTICULAR PURPOSE. See the license for more details.
22*/
23
29#include <utility>
30#include <algorithm>
31
32using std::vector;
33
34namespace QuantLib {
35
36 namespace {
37 Date applyLookbackPeriod(const ext::shared_ptr<InterestRateIndex>& index,
38 const Date& valueDate,
39 Natural lookbackDays) {
40 return index->fixingCalendar().advance(valueDate, -static_cast<Integer>(lookbackDays),
41 Days);
42 }
43 }
44
46 const Date& paymentDate,
47 Real nominal,
48 const Date& startDate,
49 const Date& endDate,
50 const ext::shared_ptr<OvernightIndex>& overnightIndex,
51 Real gearing,
52 Spread spread,
53 const Date& refPeriodStart,
54 const Date& refPeriodEnd,
55 const DayCounter& dayCounter,
56 bool telescopicValueDates,
57 RateAveraging::Type averagingMethod,
58 Natural lookbackDays,
59 Natural lockoutDays,
60 bool applyObservationShift)
61 : FloatingRateCoupon(paymentDate, nominal, startDate, endDate,
62 lookbackDays,
63 overnightIndex,
64 gearing, spread,
65 refPeriodStart, refPeriodEnd,
66 dayCounter, false),
67 averagingMethod_(averagingMethod), lockoutDays_(lockoutDays),
68 applyObservationShift_(applyObservationShift) {
69
70 // value dates
71 Date tmpEndDate = endDate;
72
73 /* For the coupon's valuation only the first and last future valuation
74 dates matter, therefore we can avoid to construct the whole series
75 of valuation dates, a front and back stub will do. However notice
76 that if the global evaluation date moves forward it might run past
77 the front stub of valuation dates we build here (which incorporates
78 a grace period of 7 business after the evaluation date). This will
79 lead to false coupon projections (see the warning the class header). */
80
81 QL_REQUIRE(canApplyTelescopicFormula() || !telescopicValueDates,
82 "Telescopic formula cannot be applied for a coupon with lookback.");
83
84 if (telescopicValueDates) {
85 // build optimised value dates schedule: front stub goes
86 // from start date to max(evalDate,startDate) + 7bd
88 tmpEndDate = overnightIndex->fixingCalendar().advance(
89 std::max(startDate, evalDate), 7, Days, Following);
90 tmpEndDate = std::min(tmpEndDate, endDate);
91 }
92 Schedule sch =
94 .from(startDate)
95 // .to(endDate)
96 .to(tmpEndDate)
97 .withTenor(1 * Days)
98 .withCalendar(overnightIndex->fixingCalendar())
99 .withConvention(overnightIndex->businessDayConvention())
100 .backwards();
101 valueDates_ = sch.dates();
102
103 if (telescopicValueDates) {
104 // if lockout days are defined, we need to ensure that
105 // the lockout period is covered by the value dates
106 tmpEndDate = overnightIndex->fixingCalendar().adjust(
107 endDate, overnightIndex->businessDayConvention());
108 Date tmpLockoutDate = overnightIndex->fixingCalendar().advance(
109 endDate, -std::max<Integer>(lockoutDays_, 1), Days, Preceding);
110 while (tmpLockoutDate <= tmpEndDate)
111 {
112 if (tmpLockoutDate > valueDates_.back())
113 valueDates_.push_back(tmpLockoutDate);
114 tmpLockoutDate =
115 overnightIndex->fixingCalendar().advance(tmpLockoutDate, 1, Days, Following);
116 }
117 }
118
119 QL_ENSURE(valueDates_.size()>=2, "degenerate schedule");
120
121 n_ = valueDates_.size() - 1;
122
123 interestDates_ = vector<Date>(valueDates_.begin(), valueDates_.end());
124
125 if (fixingDays_ == overnightIndex->fixingDays() && fixingDays_ == 0) {
126 fixingDates_ = vector<Date>(valueDates_.begin(), valueDates_.end() - 1);
127 } else {
128 // Lookback (fixing days) without observation shift:
129 // The date that the fixing rate is pulled from (the observation date) is k
130 // business days before the date that interest is applied (the interest date)
131 // and is applied for the number of calendar days until the next business
132 // day following the interest date.
133 fixingDates_.resize(n_);
134 for (Size i = 0; i <= n_; ++i) {
135 Date tmp = applyLookbackPeriod(overnightIndex, valueDates_[i], fixingDays_);
136 if (i < n_)
137 fixingDates_[i] = tmp;
139 // Lookback (fixing days) with observation shift:
140 // The date that the fixing rate is pulled from (the observation date)
141 // is k business days before the date that interest is applied
142 // (the interest date) and is applied for the number of calendar
143 // days until the next business day following the observation date.
144 // This means that the fixing dates periods align with value dates.
145 interestDates_[i] = tmp;
146 if (fixingDays_ != overnightIndex->fixingDays())
147 // If fixing dates of the coupon deviate from fixing days in the index
148 // we need to correct the value dates such that they reflect dates
149 // corresponding to a deposit instrument linked to the index.
150 // This is to ensure that future projections (which are computed
151 // based on the value dates) of the index do not
152 // yield any convexity corrections.
153 valueDates_[i] = overnightIndex->valueDate(tmp);
154 }
155 }
156 // When lockout is used the fixing rate applied for the last k days of the
157 // interest period is frozen at the rate observed k days before the period ends.
158 if (lockoutDays_ != 0) {
160 "Lockout period cannot be negative or exceed the number of fixing days.");
161 Date lockoutDate = fixingDates_[n_ - 1 - lockoutDays_];
162 for (Size i = n_ - 1; i > n_ - 1 - lockoutDays_; --i)
163 fixingDates_[i] = lockoutDate;
164 }
165
166 // accrual (compounding) periods
167 dt_.resize(n_);
168 const DayCounter& dc = overnightIndex->dayCounter();
169 for (Size i=0; i<n_; ++i)
170 dt_[i] = dc.yearFraction(interestDates_[i], interestDates_[i + 1]);
171
172 switch (averagingMethod) {
175 fixingDays_ == overnightIndex->fixingDays() && !applyObservationShift_ && lockoutDays_ == 0,
176 "Cannot price an overnight coupon with simple averaging with lookback or lockout.");
177 setPricer(ext::make_shared<ArithmeticAveragedOvernightIndexedCouponPricer>(telescopicValueDates));
178 break;
180 setPricer(ext::make_shared<CompoundingOvernightIndexedCouponPricer>());
181 break;
182 default:
183 QL_FAIL("unknown compounding convention (" << Integer(averagingMethod) << ")");
184 }
185 }
186
188 if (d <= accrualStartDate_ || d > paymentDate_) {
189 // out of coupon range
190 return 0.0;
191 } else if (tradingExCoupon(d)) {
192 return nominal() * averageRate(d) * accruedPeriod(d);
193 } else {
194 // usual case
195 return nominal() * averageRate(std::min(d, accrualEndDate_)) * accruedPeriod(d);
196 }
197 }
198
200 QL_REQUIRE(pricer_, "pricer not set");
201 pricer_->initialize(*this);
202 if (const auto compoundingPricer =
203 ext::dynamic_pointer_cast<CompoundingOvernightIndexedCouponPricer>(pricer_)) {
204 return compoundingPricer->averageRate(d);
205 }
206 return pricer_->swapletRate();
207 }
208
209 const vector<Rate>& OvernightIndexedCoupon::indexFixings() const {
210 fixings_.resize(n_);
211 for (Size i=0; i<n_; ++i)
212 fixings_[i] = index_->fixing(fixingDates_[i]);
213 return fixings_;
214 }
215
217 auto* v1 = dynamic_cast<Visitor<OvernightIndexedCoupon>*>(&v);
218 if (v1 != nullptr) {
219 v1->visit(*this);
220 } else {
222 }
223 }
224
225 OvernightLeg::OvernightLeg(Schedule schedule, ext::shared_ptr<OvernightIndex> i)
226 : schedule_(std::move(schedule)), overnightIndex_(std::move(i)), paymentCalendar_(schedule_.calendar()) {
227 QL_REQUIRE(overnightIndex_, "no index provided");
228 }
229
231 notionals_ = vector<Real>(1, notional);
232 return *this;
233 }
234
235 OvernightLeg& OvernightLeg::withNotionals(const vector<Real>& notionals) {
236 notionals_ = notionals;
237 return *this;
238 }
239
242 return *this;
243 }
244
247 paymentAdjustment_ = convention;
248 return *this;
249 }
250
252 paymentCalendar_ = cal;
253 return *this;
254 }
255
257 paymentLag_ = lag;
258 return *this;
259 }
260
262 gearings_ = vector<Real>(1,gearing);
263 return *this;
264 }
265
266 OvernightLeg& OvernightLeg::withGearings(const vector<Real>& gearings) {
267 gearings_ = gearings;
268 return *this;
269 }
270
272 spreads_ = vector<Spread>(1,spread);
273 return *this;
274 }
275
276 OvernightLeg& OvernightLeg::withSpreads(const vector<Spread>& spreads) {
277 spreads_ = spreads;
278 return *this;
279 }
280
282 telescopicValueDates_ = telescopicValueDates;
283 return *this;
284 }
285
287 averagingMethod_ = averagingMethod;
288 return *this;
289 }
290
292 lookbackDays_ = lookbackDays;
293 return *this;
294 }
296 lockoutDays_ = lockoutDays;
297 return *this;
298 }
300 applyObservationShift_ = applyObservationShift;
301 return *this;
302 }
303
304 OvernightLeg::operator Leg() const {
305
306 QL_REQUIRE(!notionals_.empty(), "no notional given");
307
308 Leg cashflows;
309
310 // the following is not always correct
311 Calendar calendar = schedule_.calendar();
312
313 Date refStart, start, refEnd, end;
314 Date paymentDate;
315
316 Size n = schedule_.size()-1;
317 for (Size i=0; i<n; ++i) {
318 refStart = start = schedule_.date(i);
319 refEnd = end = schedule_.date(i+1);
320 paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_);
321
322 if (i == 0 && schedule_.hasIsRegular() && !schedule_.isRegular(i+1))
323 refStart = calendar.adjust(end - schedule_.tenor(),
324 paymentAdjustment_);
325 if (i == n-1 && schedule_.hasIsRegular() && !schedule_.isRegular(i+1))
326 refEnd = calendar.adjust(start + schedule_.tenor(),
327 paymentAdjustment_);
328
329 const auto overnightIndexedCoupon = ext::make_shared<OvernightIndexedCoupon>(
330 paymentDate, detail::get(notionals_, i, notionals_.back()), start, end,
331 overnightIndex_, detail::get(gearings_, i, 1.0), detail::get(spreads_, i, 0.0),
332 refStart, refEnd, paymentDayCounter_, telescopicValueDates_, averagingMethod_,
333 lookbackDays_, lockoutDays_, applyObservationShift_);
334
335 cashflows.push_back(overnightIndexedCoupon);
336 }
337 return cashflows;
338 }
339
340}
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
bool tradingExCoupon(const Date &refDate=Date()) const
returns true if the cashflow is trading ex-coupon on the refDate
Definition: cashflow.cpp:51
Date paymentDate_
Definition: coupon.hpp:90
virtual Real nominal() const
Definition: coupon.hpp:100
Date accrualEndDate_
Definition: coupon.hpp:92
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
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_
virtual void setPricer(const ext::shared_ptr< FloatingRateCouponPricer > &)
ext::shared_ptr< FloatingRateCouponPricer > pricer_
void accept(AcyclicVisitor &) override
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 & withCalendar(const Calendar &)
Definition: schedule.cpp:547
OvernightIndexedCoupon(const Date &paymentDate, Real nominal, const Date &startDate, const Date &endDate, const ext::shared_ptr< OvernightIndex > &overnightIndex, Real gearing=1.0, Spread spread=0.0, const Date &refPeriodStart=Date(), const Date &refPeriodEnd=Date(), const DayCounter &dayCounter=DayCounter(), bool telescopicValueDates=false, RateAveraging::Type averagingMethod=RateAveraging::Compound, Natural lookbackDays=Null< Natural >(), Natural lockoutDays=0, bool applyObservationShift=false)
const std::vector< Rate > & indexFixings() const
fixings to be compounded
void accept(AcyclicVisitor &) override
Real accruedAmount(const Date &) const override
accrued amount at the given date
RateAveraging::Type averagingMethod() const
averaging method
Rate averageRate(const Date &date) const
helper class building a sequence of overnight coupons
ext::shared_ptr< OvernightIndex > overnightIndex_
BusinessDayConvention paymentAdjustment_
OvernightLeg & withObservationShift(bool applyObservationShift=true)
OvernightLeg & withGearings(Real gearing)
OvernightLeg & withPaymentCalendar(const Calendar &)
OvernightLeg & withTelescopicValueDates(bool telescopicValueDates)
OvernightLeg & withPaymentAdjustment(BusinessDayConvention)
std::vector< Spread > spreads_
OvernightLeg & withNotionals(Real notional)
RateAveraging::Type averagingMethod_
OvernightLeg & withAveragingMethod(RateAveraging::Type averagingMethod)
OvernightLeg & withPaymentDayCounter(const DayCounter &)
OvernightLeg & withLockoutDays(Natural lockoutDays)
OvernightLeg & withSpreads(Spread spread)
OvernightLeg(Schedule schedule, ext::shared_ptr< OvernightIndex > overnightIndex)
OvernightLeg & withPaymentLag(Integer lag)
OvernightLeg & withLookbackDays(Natural lookbackDays)
Payment schedule.
Definition: schedule.hpp:40
const std::vector< Date > & dates() const
Definition: schedule.hpp:73
DateProxy & evaluationDate()
the date at which pricing is to be performed.
Definition: settings.hpp:147
static Settings & instance()
access to the unique instance
Definition: singleton.hpp:104
Visitor for a specific class
Definition: visitor.hpp:40
virtual void visit(T &)=0
Coupon pricers.
Calendar paymentCalendar_
Integer paymentLag_
#define QL_ENSURE(condition, message)
throw an error if the given post-condition is not verified
Definition: errors.hpp:130
#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
Date d
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
T get(const std::vector< T > &v, Size i, U defaultValue)
Definition: vectors.hpp:33
Definition: any.hpp:37
std::vector< ext::shared_ptr< CashFlow > > Leg
Sequence of cash-flows.
Definition: cashflow.hpp:78
STL namespace.
coupon paying the compounded daily overnight rate
contains the pricer for an OvernightIndexedCoupon
ext::shared_ptr< BlackVolTermStructure > v
Utilities for vector manipulation.
Interest-rate term structure.