QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
overnightindexedcoupon.cpp
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
24#include <ql/cashflows/couponpricer.hpp>
25#include <ql/experimental/averageois/averageoiscouponpricer.hpp>
26#include <ql/cashflows/overnightindexedcoupon.hpp>
27#include <ql/termstructures/yieldtermstructure.hpp>
28#include <ql/utilities/vectors.hpp>
29#include <utility>
30#include <algorithm>
31
32using std::vector;
33
34namespace QuantLib {
35
36 namespace {
37
38 class OvernightIndexedCouponPricer : public FloatingRateCouponPricer {
39 public:
40 void initialize(const FloatingRateCoupon& coupon) override {
41 coupon_ = dynamic_cast<const OvernightIndexedCoupon*>(&coupon);
42 QL_ENSURE(coupon_, "wrong coupon type");
43 }
44
45 Rate averageRate(const Date& date) const {
46
47 const Date today = Settings::instance().evaluationDate();
48
49 const ext::shared_ptr<OvernightIndex> index =
50 ext::dynamic_pointer_cast<OvernightIndex>(coupon_->index());
51 const auto& pastFixings = IndexManager::instance().getHistory(index->name());
52
53 const vector<Date>& fixingDates = coupon_->fixingDates();
54 const vector<Date>& valueDates = coupon_->valueDates();
55 const vector<Time>& dt = coupon_->dt();
56
57 Size i = 0;
58 const size_t n = std::lower_bound(valueDates.begin(), valueDates.end(), date) - valueDates.begin();
59 Real compoundFactor = 1.0;
60
61 // already fixed part
62 while (i < n && fixingDates[i] < today) {
63 // rate must have been fixed
64 const Rate fixing = pastFixings[fixingDates[i]];
65 QL_REQUIRE(fixing != Null<Real>(),
66 "Missing " << index->name() <<
67 " fixing for " << fixingDates[i]);
68 Time span = (date >= valueDates[i+1] ?
69 dt[i] :
70 index->dayCounter().yearFraction(valueDates[i], date));
71 compoundFactor *= (1.0 + fixing * span);
72 ++i;
73 }
74
75 // today is a border case
76 if (i < n && fixingDates[i] == today) {
77 // might have been fixed
78 try {
79 Rate fixing = pastFixings[fixingDates[i]];
80 if (fixing != Null<Real>()) {
81 Time span = (date >= valueDates[i+1] ?
82 dt[i] :
83 index->dayCounter().yearFraction(valueDates[i], date));
84 compoundFactor *= (1.0 + fixing * span);
85 ++i;
86 } else {
87 ; // fall through and forecast
88 }
89 } catch (Error&) {
90 ; // fall through and forecast
91 }
92 }
93
94 // forward part using telescopic property in order
95 // to avoid the evaluation of multiple forward fixings
96 if (i<n) {
97 const Handle<YieldTermStructure> curve = index->forwardingTermStructure();
98 QL_REQUIRE(!curve.empty(),
99 "null term structure set to this instance of " << index->name());
100
101 const DiscountFactor startDiscount = curve->discount(valueDates[i]);
102 if (valueDates[n] == date) {
103 // full telescopic formula
104 const DiscountFactor endDiscount = curve->discount(valueDates[n]);
105 compoundFactor *= startDiscount / endDiscount;
106 } else {
107 // The last fixing is not used for its full period (the date is between its
108 // start and end date). We can use the telescopic formula until the previous
109 // date, then we'll add the missing bit.
110 const DiscountFactor endDiscount = curve->discount(valueDates[n-1]);
111 compoundFactor *= startDiscount / endDiscount;
112
113 Rate fixing = index->fixing(fixingDates[n-1]);
114 Time span = index->dayCounter().yearFraction(valueDates[n-1], date);
115 compoundFactor *= (1.0 + fixing * span);
116 }
117 }
118
119 const Rate rate = (compoundFactor - 1.0) / coupon_->accruedPeriod(date);
120 return coupon_->gearing() * rate + coupon_->spread();
121 }
122
123 Rate swapletRate() const override {
124 return averageRate(coupon_->accrualEndDate());
125 }
126
127 Real swapletPrice() const override { QL_FAIL("swapletPrice not available"); }
128 Real capletPrice(Rate) const override { QL_FAIL("capletPrice not available"); }
129 Rate capletRate(Rate) const override { QL_FAIL("capletRate not available"); }
130 Real floorletPrice(Rate) const override { QL_FAIL("floorletPrice not available"); }
131 Rate floorletRate(Rate) const override { QL_FAIL("floorletRate not available"); }
132
133 protected:
134 const OvernightIndexedCoupon* coupon_;
135 };
136 }
137
139 const Date& paymentDate,
140 Real nominal,
141 const Date& startDate,
142 const Date& endDate,
143 const ext::shared_ptr<OvernightIndex>& overnightIndex,
144 Real gearing,
145 Spread spread,
146 const Date& refPeriodStart,
147 const Date& refPeriodEnd,
148 const DayCounter& dayCounter,
149 bool telescopicValueDates,
150 RateAveraging::Type averagingMethod)
151 : FloatingRateCoupon(paymentDate, nominal, startDate, endDate,
152 overnightIndex ? overnightIndex->fixingDays() : 0,
153 overnightIndex,
154 gearing, spread,
155 refPeriodStart, refPeriodEnd,
156 dayCounter, false) {
157
158 // value dates
159 Date tmpEndDate = endDate;
160
161 /* For the coupon's valuation only the first and last future valuation
162 dates matter, therefore we can avoid to construct the whole series
163 of valuation dates, a front and back stub will do. However notice
164 that if the global evaluation date moves forward it might run past
165 the front stub of valuation dates we build here (which incorporates
166 a grace period of 7 business after the evaluation date). This will
167 lead to false coupon projections (see the warning the class header). */
168
169 if (telescopicValueDates) {
170 // build optimised value dates schedule: front stub goes
171 // from start date to max(evalDate,startDate) + 7bd
173 tmpEndDate = overnightIndex->fixingCalendar().advance(
174 std::max(startDate, evalDate), 7, Days, Following);
175 tmpEndDate = std::min(tmpEndDate, endDate);
176 }
177 Schedule sch =
179 .from(startDate)
180 // .to(endDate)
181 .to(tmpEndDate)
182 .withTenor(1 * Days)
183 .withCalendar(overnightIndex->fixingCalendar())
184 .withConvention(overnightIndex->businessDayConvention())
185 .backwards();
186 valueDates_ = sch.dates();
187
188 if (telescopicValueDates) {
189 // build optimised value dates schedule: back stub
190 // contains at least two dates
191 Date tmp = overnightIndex->fixingCalendar().advance(
192 endDate, -1, Days, Preceding);
193 if (tmp != valueDates_.back())
194 valueDates_.push_back(tmp);
195 tmp = overnightIndex->fixingCalendar().adjust(
196 endDate, overnightIndex->businessDayConvention());
197 if (tmp != valueDates_.back())
198 valueDates_.push_back(tmp);
199 }
200
201 QL_ENSURE(valueDates_.size()>=2, "degenerate schedule");
202
203 // fixing dates
204 n_ = valueDates_.size()-1;
205 if (overnightIndex->fixingDays()==0) {
206 fixingDates_ = vector<Date>(valueDates_.begin(),
207 valueDates_.end() - 1);
208 } else {
209 fixingDates_.resize(n_);
210 for (Size i=0; i<n_; ++i)
211 fixingDates_[i] = overnightIndex->fixingDate(valueDates_[i]);
212 }
213
214 // accrual (compounding) periods
215 dt_.resize(n_);
216 const DayCounter& dc = overnightIndex->dayCounter();
217 for (Size i=0; i<n_; ++i)
218 dt_[i] = dc.yearFraction(valueDates_[i], valueDates_[i+1]);
219
220 switch (averagingMethod) {
222 setPricer(ext::shared_ptr<FloatingRateCouponPricer>(
223 new ArithmeticAveragedOvernightIndexedCouponPricer(telescopicValueDates)));
224 break;
226 setPricer(
227 ext::shared_ptr<FloatingRateCouponPricer>(new OvernightIndexedCouponPricer));
228 break;
229 default:
230 QL_FAIL("unknown compounding convention (" << Integer(averagingMethod) << ")");
231 }
232 }
233
235 if (d <= accrualStartDate_ || d > paymentDate_) {
236 // out of coupon range
237 return 0.0;
238 } else if (tradingExCoupon(d)) {
239 return nominal() * averageRate(d) * accruedPeriod(d);
240 } else {
241 // usual case
242 return nominal() * averageRate(std::min(d, accrualEndDate_)) * accruedPeriod(d);
243 }
244 }
245
247 QL_REQUIRE(pricer_, "pricer not set");
248 pricer_->initialize(*this);
249 const auto overnightIndexPricer = ext::dynamic_pointer_cast<OvernightIndexedCouponPricer>(pricer_);
250 if (overnightIndexPricer)
251 return overnightIndexPricer->averageRate(d);
252
253 return pricer_->swapletRate();
254 }
255
256 const vector<Rate>& OvernightIndexedCoupon::indexFixings() const {
257 fixings_.resize(n_);
258 for (Size i=0; i<n_; ++i)
259 fixings_[i] = index_->fixing(fixingDates_[i]);
260 return fixings_;
261 }
262
264 auto* v1 = dynamic_cast<Visitor<OvernightIndexedCoupon>*>(&v);
265 if (v1 != nullptr) {
266 v1->visit(*this);
267 } else {
269 }
270 }
271
272 OvernightLeg::OvernightLeg(const Schedule& schedule, ext::shared_ptr<OvernightIndex> i)
273 : schedule_(schedule), overnightIndex_(std::move(i)), paymentCalendar_(schedule.calendar()) {
274 QL_REQUIRE(overnightIndex_, "no index provided");
275 }
276
278 notionals_ = vector<Real>(1, notional);
279 return *this;
280 }
281
282 OvernightLeg& OvernightLeg::withNotionals(const vector<Real>& notionals) {
283 notionals_ = notionals;
284 return *this;
285 }
286
289 return *this;
290 }
291
294 paymentAdjustment_ = convention;
295 return *this;
296 }
297
299 paymentCalendar_ = cal;
300 return *this;
301 }
302
304 paymentLag_ = lag;
305 return *this;
306 }
307
309 gearings_ = vector<Real>(1,gearing);
310 return *this;
311 }
312
313 OvernightLeg& OvernightLeg::withGearings(const vector<Real>& gearings) {
314 gearings_ = gearings;
315 return *this;
316 }
317
319 spreads_ = vector<Spread>(1,spread);
320 return *this;
321 }
322
323 OvernightLeg& OvernightLeg::withSpreads(const vector<Spread>& spreads) {
324 spreads_ = spreads;
325 return *this;
326 }
327
329 telescopicValueDates_ = telescopicValueDates;
330 return *this;
331 }
332
334 averagingMethod_ = averagingMethod;
335 return *this;
336 }
337
338 OvernightLeg::operator Leg() const {
339
340 QL_REQUIRE(!notionals_.empty(), "no notional given");
341
342 Leg cashflows;
343
344 // the following is not always correct
345 Calendar calendar = schedule_.calendar();
346
347 Date refStart, start, refEnd, end;
348 Date paymentDate;
349
350 Size n = schedule_.size()-1;
351 for (Size i=0; i<n; ++i) {
352 refStart = start = schedule_.date(i);
353 refEnd = end = schedule_.date(i+1);
354 paymentDate = paymentCalendar_.advance(end, paymentLag_, Days, paymentAdjustment_);
355
356 if (i == 0 && schedule_.hasIsRegular() && !schedule_.isRegular(i+1))
357 refStart = calendar.adjust(end - schedule_.tenor(),
358 paymentAdjustment_);
359 if (i == n-1 && schedule_.hasIsRegular() && !schedule_.isRegular(i+1))
360 refEnd = calendar.adjust(start + schedule_.tenor(),
361 paymentAdjustment_);
362
363 cashflows.push_back(ext::shared_ptr<CashFlow>(new
364 OvernightIndexedCoupon(paymentDate,
365 detail::get(notionals_, i,
366 notionals_.back()),
367 start, end,
368 overnightIndex_,
369 detail::get(gearings_, i, 1.0),
370 detail::get(spreads_, i, 0.0),
371 refStart, refEnd,
372 paymentDayCounter_,
373 telescopicValueDates_,
374 averagingMethod_)));
375 }
376 return cashflows;
377 }
378
379}
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
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
const TimeSeries< Real > & getHistory(const std::string &name) const
returns the (possibly empty) history of the index fixings
MakeSchedule & withConvention(BusinessDayConvention)
Definition: schedule.cpp:557
MakeSchedule & backwards()
Definition: schedule.cpp:578
MakeSchedule & to(const Date &terminationDate)
Definition: schedule.cpp:537
MakeSchedule & withTenor(const Period &)
Definition: schedule.cpp:542
MakeSchedule & from(const Date &effectiveDate)
Definition: schedule.cpp:532
MakeSchedule & withCalendar(const Calendar &)
Definition: schedule.cpp:552
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)
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
Rate averageRate(const Date &date) const
helper class building a sequence of overnight coupons
ext::shared_ptr< OvernightIndex > overnightIndex_
BusinessDayConvention paymentAdjustment_
OvernightLeg & withGearings(Real gearing)
OvernightLeg & withPaymentCalendar(const Calendar &)
OvernightLeg & withTelescopicValueDates(bool telescopicValueDates)
OvernightLeg & withPaymentAdjustment(BusinessDayConvention)
std::vector< Spread > spreads_
OvernightLeg & withNotionals(Real notional)
OvernightLeg(const Schedule &schedule, ext::shared_ptr< OvernightIndex > overnightIndex)
RateAveraging::Type averagingMethod_
OvernightLeg & withAveragingMethod(RateAveraging::Type averagingMethod)
OvernightLeg & withPaymentDayCounter(const DayCounter &)
OvernightLeg & withSpreads(Spread spread)
OvernightLeg & withPaymentLag(Natural lag)
Payment schedule.
Definition: schedule.hpp:40
const std::vector< Date > & dates() const
Definition: schedule.hpp:75
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
BusinessDayConvention
Business Day conventions.
detail::percent_holder rate(Rate)
output rates and spreads as percentages
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
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:35
Definition: any.hpp:35
std::vector< ext::shared_ptr< CashFlow > > Leg
Sequence of cash-flows.
Definition: cashflow.hpp:78
STL namespace.