QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.38
Loading...
Searching...
No Matches
overnightindexedcouponpricer.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) 2016 Stefano Fondi
8 Copyright (C) 2017 Joseph Jeisman
9 Copyright (C) 2017 Fabrice Lecuyer
10
11 This file is part of QuantLib, a free-software/open-source library
12 for financial quantitative analysts and developers - http://quantlib.org/
13
14 QuantLib is free software: you can redistribute it and/or modify it
15 under the terms of the QuantLib license. You should have received a
16 copy of the license along with this program; if not, please email
17 <quantlib-dev@lists.sf.net>. The license is also available online at
18 <http://quantlib.org/license.shtml>.
19
20 This program is distributed in the hope that it will be useful, but WITHOUT
21 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22 FOR A PARTICULAR PURPOSE. See the license for more details.
23*/
24
26
27namespace QuantLib {
28
29 namespace {
30
31 Size determineNumberOfFixings(const std::vector<Date>& interestDates,
32 const Date& date,
33 bool applyObservationShift) {
34 Size n = std::lower_bound(interestDates.begin(), interestDates.end(), date) -
35 interestDates.begin();
36 // When using the observation shift, it may happen that
37 // that the end of accrual period will fall later than the last
38 // interest date. In which case, n will be equal to the number of
39 // interest dates, while we know that the number of fixing dates is
40 // always one less than the number of interest dates.
41 return n == interestDates.size() && applyObservationShift ? n - 1 : n;
42 }
43 }
44
46 coupon_ = dynamic_cast<const OvernightIndexedCoupon*>(&coupon);
47 QL_ENSURE(coupon_, "wrong coupon type");
48 }
49
52 }
53
55 const Date today = Settings::instance().evaluationDate();
56
57 const ext::shared_ptr<OvernightIndex> index =
58 ext::dynamic_pointer_cast<OvernightIndex>(coupon_->index());
59 const auto& pastFixings = index->timeSeries();
60
61 const auto& fixingDates = coupon_->fixingDates();
62 const auto& valueDates = coupon_->valueDates();
63 const auto& interestDates = coupon_->interestDates();
64 const auto& dt = coupon_->dt();
65 const bool applyObservationShift = coupon_->applyObservationShift();
66
67 Size i = 0;
68 const Size n = determineNumberOfFixings(interestDates, date, applyObservationShift);
69
70 Real compoundFactor = 1.0;
71
72 // already fixed part
73 while (i < n && fixingDates[i] < today) {
74 // rate must have been fixed
75 const Rate fixing = pastFixings[fixingDates[i]];
76 QL_REQUIRE(fixing != Null<Real>(),
77 "Missing " << index->name() << " fixing for " << fixingDates[i]);
78 Time span = (date >= interestDates[i + 1] ?
79 dt[i] :
80 index->dayCounter().yearFraction(interestDates[i], date));
81 compoundFactor *= (1.0 + fixing * span);
82 ++i;
83 }
84
85 // today is a border case
86 if (i < n && fixingDates[i] == today) {
87 // might have been fixed
88 try {
89 Rate fixing = pastFixings[fixingDates[i]];
90 if (fixing != Null<Real>()) {
91 Time span = (date >= interestDates[i + 1] ?
92 dt[i] :
93 index->dayCounter().yearFraction(interestDates[i], date));
94 compoundFactor *= (1.0 + fixing * span);
95 ++i;
96 } else {
97 ; // fall through and forecast
98 }
99 } catch (Error&) {
100 ; // fall through and forecast
101 }
102 }
103
104 // forward part using telescopic property in order
105 // to avoid the evaluation of multiple forward fixings
106 // where possible.
107 if (i < n) {
108 const Handle<YieldTermStructure> curve = index->forwardingTermStructure();
109 QL_REQUIRE(!curve.empty(),
110 "null term structure set to this instance of " << index->name());
111
112 const auto effectiveRate = [&index, &fixingDates, &date, &interestDates,
113 &dt](Size position) {
114 Rate fixing = index->fixing(fixingDates[position]);
115 Time span = (date >= interestDates[position + 1] ?
116 dt[position] :
117 index->dayCounter().yearFraction(interestDates[position], date));
118 return span * fixing;
119 };
120
122 // With lookback applied, the telescopic formula cannot be used,
123 // we need to project each fixing in the coupon.
124 // Only in one particular case when observation shift is used and
125 // no intrinsic index fixing delay is applied, the telescopic formula
126 // holds, because regardless of the fixing delay in the coupon,
127 // in such configuration value dates will be equal to interest dates.
128 // A potential lockout, which may occur in tandem with a lookback
129 // setting, will be handled automatically based on fixing dates.
130 // Same applies to a case when accrual calculation date does or
131 // does not occur on an interest date.
132 while (i < n) {
133 compoundFactor *= (1.0 + effectiveRate(i));
134 ++i;
135 }
136 } else {
137 // No lookback, we can partially apply the telescopic formula.
138 // But we need to make a correction for a potential lockout.
139 const Size nLockout = n - coupon_->lockoutDays();
140 const bool isLockoutApplied = coupon_->lockoutDays() > 0;
141
142 // Lockout could already start at or before i.
143 // In such case the ratio of discount factors will be equal to 1.
144 const DiscountFactor startDiscount =
145 curve->discount(valueDates[std::min<Size>(nLockout, i)]);
146 if (interestDates[n] == date || isLockoutApplied) {
147 // telescopic formula up to potential lockout dates.
148 const DiscountFactor endDiscount =
149 curve->discount(valueDates[std::min<Size>(nLockout, n)]);
150 compoundFactor *= startDiscount / endDiscount;
151 // For the lockout periods the telescopic formula does not apply.
152 // The value dates (at which the projection is calculated) correspond
153 // to the locked-out fixing, while the interest dates (at which the
154 // interest over that fixing is accrued) are not fixed at lockout,
155 // hence they do not cancel out.
156 i = std::max(nLockout, i);
157
158 // With no lockout, the loop is skipped because i = n.
159 while (i < n) {
160 compoundFactor *= (1.0 + effectiveRate(i));
161 ++i;
162 }
163 } else {
164 // No lockout and date is different than last interest date.
165 // The last fixing is not used for its full period (the date is between
166 // its start and end date). We can use the telescopic formula until the
167 // previous date, then we'll add the missing bit.
168 const DiscountFactor endDiscount = curve->discount(valueDates[n - 1]);
169 compoundFactor *= startDiscount / endDiscount;
170 compoundFactor *= (1.0 + effectiveRate(n - 1));
171 }
172 }
173 }
174
175 const Rate rate = (compoundFactor - 1.0) / coupon_->accruedPeriod(date);
176 return coupon_->gearing() * rate + coupon_->spread();
177 }
178
179 void
181 coupon_ = dynamic_cast<const OvernightIndexedCoupon*>(&coupon);
182 QL_ENSURE(coupon_, "wrong coupon type");
183 }
184
186
187 ext::shared_ptr<OvernightIndex> index =
188 ext::dynamic_pointer_cast<OvernightIndex>(coupon_->index());
189
190 const auto& fixingDates = coupon_->fixingDates();
191 const auto& dt = coupon_->dt();
192
193 Size n = dt.size(), i = 0;
194
195 Real accumulatedRate = 0.0;
196
197 const auto& pastFixings = index->timeSeries();
198
199 // already fixed part
201 while (i < n && fixingDates[i] < today) {
202 // rate must have been fixed
203 Rate pastFixing = pastFixings[fixingDates[i]];
204 QL_REQUIRE(pastFixing != Null<Real>(),
205 "Missing " << index->name() << " fixing for " << fixingDates[i]);
206 accumulatedRate += pastFixing * dt[i];
207 ++i;
208 }
209
210 // today is a border case
211 if (i < n && fixingDates[i] == today) {
212 // might have been fixed
213 try {
214 Rate pastFixing = pastFixings[fixingDates[i]];
215 if (pastFixing != Null<Real>()) {
216 accumulatedRate += pastFixing * dt[i];
217 ++i;
218 } else {
219 ; // fall through and forecast
220 }
221 } catch (Error&) {
222 ; // fall through and forecast
223 }
224 }
225
226 /* forward part using telescopic property in order
227 to avoid the evaluation of multiple forward fixings
228 (approximation proposed by Katsumi Takada)*/
229 if (byApprox_ && i < n) {
230 Handle<YieldTermStructure> curve = index->forwardingTermStructure();
231 QL_REQUIRE(!curve.empty(),
232 "null term structure set to this instance of " << index->name());
233
234 const auto& dates = coupon_->valueDates();
235 DiscountFactor startDiscount = curve->discount(dates[i]);
236 DiscountFactor endDiscount = curve->discount(dates[n]);
237
238 accumulatedRate +=
239 log(startDiscount / endDiscount) -
240 convAdj1(curve->timeFromReference(dates[i]), curve->timeFromReference(dates[n])) -
241 convAdj2(curve->timeFromReference(dates[i]), curve->timeFromReference(dates[n]));
242 }
243 // otherwise
244 else if (i < n) {
245 Handle<YieldTermStructure> curve = index->forwardingTermStructure();
246 QL_REQUIRE(!curve.empty(),
247 "null term structure set to this instance of " << index->name());
248
249 const auto& dates = coupon_->valueDates();
250 Time te = curve->timeFromReference(dates[n]);
251 while (i < n) {
252 // forcast fixing
253 Rate forecastFixing = index->fixing(fixingDates[i]);
254 Time ti1 = curve->timeFromReference(dates[i]);
255 Time ti2 = curve->timeFromReference(dates[i + 1]);
256 /*convexity adjustment due to payment dalay of each
257 overnight fixing, supposing an Hull-White short rate model*/
258 Real convAdj = exp(
259 0.5 * pow(vol_, 2.0) / pow(mrs_, 3.0) * (exp(2 * mrs_ * ti1) - 1) *
260 (exp(-mrs_ * ti2) - exp(-mrs_ * te)) * (exp(-mrs_ * ti2) - exp(-mrs_ * ti1)));
261 accumulatedRate += convAdj * (1 + forecastFixing * dt[i]) - 1;
262 ++i;
263 }
264 }
265
266 Rate rate = accumulatedRate / coupon_->accrualPeriod();
267 return coupon_->gearing() * rate + coupon_->spread();
268 }
269
271 return vol_ * vol_ / (4.0 * pow(mrs_, 3.0)) * (1.0 - exp(-2.0 * mrs_ * ts)) *
272 pow((1.0 - exp(-mrs_ * (te - ts))), 2.0);
273 }
274
276 return vol_ * vol_ / (2.0 * pow(mrs_, 2.0)) *
277 ((te - ts) - pow(1.0 - exp(-mrs_ * (te - ts)), 2.0) / mrs_ -
278 (1.0 - exp(-2.0 * mrs_ * (te - ts))) / (2.0 * mrs_));
279 }
280}
void initialize(const FloatingRateCoupon &coupon) override
void initialize(const FloatingRateCoupon &coupon) override
const Date & accrualEndDate() const
end of the accrual period
Definition: coupon.hpp:108
Time accruedPeriod(const Date &) const
accrued period as fraction of year at the given date
Definition: coupon.cpp:57
Time accrualPeriod() const
accrual period as fraction of year
Definition: coupon.cpp:44
Concrete date class.
Definition: date.hpp:125
Base error class.
Definition: errors.hpp:39
base floating-rate coupon class
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
Shared handle to an observable.
Definition: handle.hpp:41
bool empty() const
checks if the contained shared pointer points to anything
Definition: handle.hpp:188
template class providing a null value for a given type.
Definition: null.hpp:59
const std::vector< Date > & valueDates() const
value dates for the rates to be compounded
const std::vector< Date > & interestDates() const
interest dates for the rates to be compounded
Natural lockoutDays() const
lockout days
bool applyObservationShift() const
apply observation shift
const std::vector< Time > & dt() const
accrual (compounding) periods
const std::vector< Date > & fixingDates() const
fixing dates for the rates to be compounded
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
#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
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
Real DiscountFactor
discount factor between dates
Definition: types.hpp:66
Real Rate
interest rates
Definition: types.hpp:70
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:37
contains the pricer for an OvernightIndexedCoupon