Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
blackovernightindexedcouponpricer.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2020 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
20
21#include <ql/pricingengines/blackformula.hpp>
22#include <ql/termstructures/volatility/optionlet/optionletvolatilitystructure.hpp>
23
24namespace QuantExt {
25
27 coupon_ = dynamic_cast<const CappedFlooredOvernightIndexedCoupon*>(&coupon);
28 QL_REQUIRE(coupon_, "BlackOvernightIndexedCouponPricer: CappedFlooredOvernightIndexedCoupon required");
29 gearing_ = coupon.gearing();
30 index_ = ext::dynamic_pointer_cast<OvernightIndex>(coupon.index());
31 if (!index_) {
32 // check if the coupon was right
34 dynamic_cast<const CappedFlooredOvernightIndexedCoupon*>(&coupon);
35 QL_REQUIRE(c, "BlackOvernightIndexedCouponPricer: CappedFlooredOvernightIndexedCoupon required");
36 // coupon was right, index is not
37 QL_FAIL("BlackOvernightIndexedCouponPricer: CappedFlooredOvernightIndexedCoupon required");
38 }
39 swapletRate_ = coupon_->underlying()->rate();
40 effectiveIndexFixing_ = coupon_->underlying()->effectiveIndexFixing();
42}
43
44Real BlackOvernightIndexedCouponPricer::optionletRateGlobal(Option::Type optionType, Real effStrike) const {
45 Date lastRelevantFixingDate = coupon_->underlying()->fixingDate();
46 if (lastRelevantFixingDate <= Settings::instance().evaluationDate()) {
47 // the amount is determined
48 Real a, b;
49 if (optionType == Option::Call) {
51 b = effStrike;
52 } else {
53 a = effStrike;
55 }
56 return gearing_ * std::max(a - b, 0.0);
57 } else {
58 // not yet determined, use Black model
59 QL_REQUIRE(!capletVolatility().empty(), "BlackOvernightIndexedCouponPricer: missing optionlet volatility");
60 std::vector<Date> fixingDates = coupon_->underlying()->fixingDates();
61 QL_REQUIRE(!fixingDates.empty(), "BlackOvernightIndexedCouponPricer: empty fixing dates");
62 bool shiftedLn = capletVolatility()->volatilityType() == ShiftedLognormal;
63 Real shift = capletVolatility()->displacement();
64 Real stdDev;
65 Real effectiveTime = capletVolatility()->timeFromReference(fixingDates.back());
67 // vol input is effective, i.e. we use a plain black model
68 stdDev = capletVolatility()->volatility(fixingDates.back(), effStrike) * std::sqrt(effectiveTime);
69 } else {
70 // vol input is not effective:
71 // for the standard deviation see Lyashenko, Mercurio, Looking forward to backward looking rates,
72 // section 6.3. the idea is to dampen the average volatility sigma between the fixing start and fixing end
73 // date by a linear function going from (fixing start, 1) to (fixing end, 0)
74 Real fixingStartTime = capletVolatility()->timeFromReference(fixingDates.front());
75 Real fixingEndTime = capletVolatility()->timeFromReference(fixingDates.back());
76 Real sigma = capletVolatility()->volatility(
77 std::max(fixingDates.front(), capletVolatility()->referenceDate() + 1), effStrike);
78 Real T = std::max(fixingStartTime, 0.0);
79 if (!close_enough(fixingEndTime, T))
80 T += std::pow(fixingEndTime - T, 3.0) / std::pow(fixingEndTime - fixingStartTime, 2.0) / 3.0;
81 stdDev = sigma * std::sqrt(T);
82 }
83 if (optionType == Option::Type::Call)
84 effectiveCapletVolatility_ = stdDev / std::sqrt(effectiveTime);
85 else
86 effectiveFloorletVolatility_ = stdDev / std::sqrt(effectiveTime);
87 Real fixing = shiftedLn ? blackFormula(optionType, effStrike, effectiveIndexFixing_, stdDev, 1.0, shift)
88 : bachelierBlackFormula(optionType, effStrike, effectiveIndexFixing_, stdDev, 1.0);
89 return gearing_ * fixing;
90 }
91}
92
93namespace {
94Real cappedFlooredRate(Real r, Option::Type optionType, Real k) {
95 if (optionType == Option::Call) {
96 return std::min(r, k);
97 } else {
98 return std::max(r, k);
99 }
100}
101} // namespace
102
103Real BlackOvernightIndexedCouponPricer::optionletRateLocal(Option::Type optionType, Real effStrike) const {
104
105 QL_REQUIRE(!effectiveVolatilityInput(),
106 "BlackAverageONIndexedCouponPricer::optionletRateLocal() does not support effective volatility input.");
107
108 // We compute a rate and a rawRate such that
109 // rate * tau * nominal is the amount of the coupon with locally (i.e. daily) capped / floored rates
110 // rawRate * tau * nominal is the amount of the coupon without capping / flooring the rate
111 // We will then return the difference between rate and rawRate (with the correct sign, see below)
112 // as the option component of the coupon.
113
114 // See CappedFlooredOvernightIndexedCoupon::effectiveCap(), Floor() for what is passed in as effStrike.
115 // From this we back out the absolute strike at which the
116 // - daily rate + spread (spread included) or the
117 // - daily rate (spread excluded)
118 // is capped / floored.
119
120 Real absStrike = coupon_->underlying()->includeSpread() ? effStrike + coupon_->underlying()->spread() : effStrike;
121
122 // This following code is inevitably quite similar to the plain ON coupon pricer code, possibly we can refactor
123 // this, but as a first step it seems safer to add the full modified code explicitly here and leave the original
124 // code alone.
125
126 ext::shared_ptr<OvernightIndex> index = ext::dynamic_pointer_cast<OvernightIndex>(coupon_->index());
127
128 const std::vector<Date>& fixingDates = coupon_->underlying()->fixingDates();
129 const std::vector<Time>& dt = coupon_->underlying()->dt();
130
131 Size n = dt.size();
132 Size i = 0;
133 QL_REQUIRE(coupon_->underlying()->rateCutoff() < n,
134 "rate cutoff (" << coupon_->underlying()->rateCutoff()
135 << ") must be less than number of fixings in period (" << n << ")");
136 Size nCutoff = n - coupon_->underlying()->rateCutoff();
137
138 Real compoundFactor = 1.0, compoundFactorRaw = 1.0;
139
140 // already fixed part
141 Date today = Settings::instance().evaluationDate();
142 while (i < n && fixingDates[std::min(i, nCutoff)] < today) {
143 // rate must have been fixed
144 Rate pastFixing = index->pastFixing(fixingDates[std::min(i, nCutoff)]);
145 QL_REQUIRE(pastFixing != Null<Real>(),
146 "Missing " << index->name() << " fixing for " << fixingDates[std::min(i, nCutoff)]);
147 if (coupon_->underlying()->includeSpread()) {
148 pastFixing += coupon_->spread();
149 }
150 compoundFactor *= 1.0 + cappedFlooredRate(pastFixing, optionType, absStrike) * dt[i];
151 compoundFactorRaw *= 1.0 + pastFixing * dt[i];
152 ++i;
153 }
154
155 // today is a border case
156 if (i < n && fixingDates[std::min(i, nCutoff)] == today) {
157 // might have been fixed
158 try {
159 Rate pastFixing = index->pastFixing(today);
160 if (pastFixing != Null<Real>()) {
161 if (coupon_->underlying()->includeSpread()) {
162 pastFixing += coupon_->spread();
163 }
164 compoundFactor *= 1.0 + cappedFlooredRate(pastFixing, optionType, absStrike) * dt[i];
165 compoundFactorRaw *= 1.0 + pastFixing * dt[i];
166 ++i;
167 } else {
168 ; // fall through and forecast
169 }
170 } catch (Error&) {
171 ; // fall through and forecast
172 }
173 }
174
175 // forward part, approximation by pricing a cap / floor in the middle of the future period
176 const std::vector<Date>& dates = coupon_->underlying()->valueDates();
177 if (i < n) {
178 Handle<YieldTermStructure> curve = index->forwardingTermStructure();
179 QL_REQUIRE(!curve.empty(), "null term structure set to this instance of " << index->name());
180
181 DiscountFactor startDiscount = curve->discount(dates[i]);
182 DiscountFactor endDiscount = curve->discount(dates[std::max(nCutoff, i)]);
183
184 // handle the rate cutoff period (if there is any, i.e. if nCutoff < n)
185 if (nCutoff < n) {
186 // forward discount factor for one calendar day on the cutoff date
187 DiscountFactor discountCutoffDate = curve->discount(dates[nCutoff] + 1) / curve->discount(dates[nCutoff]);
188 // keep the above forward discount factor constant during the cutoff period
189 endDiscount *= std::pow(discountCutoffDate, dates[n] - dates[nCutoff]);
190 }
191
192 // estimate the average daily rate over the future period (approximate the continuously compounded rate)
193 Real tau = coupon_->dayCounter().yearFraction(dates[i], dates.back());
194 Real averageRate = -std::log(endDiscount / startDiscount) / tau;
195
196 // compute the value of a cap or floor with fixing in the middle of the future period
197 // (but accounting for the rate cutoff here)
198 Time midPoint =
199 (capletVolatility()->timeFromReference(dates[i]) + capletVolatility()->timeFromReference(dates[nCutoff])) /
200 2.0;
201 Real stdDev = capletVolatility()->volatility(midPoint, effStrike) * std::sqrt(midPoint);
202 Real shift = capletVolatility()->displacement();
203 bool shiftedLn = capletVolatility()->volatilityType() == ShiftedLognormal;
204 Rate cfValue = shiftedLn ? blackFormula(optionType, effStrike, averageRate, stdDev, 1.0, shift)
205 : bachelierBlackFormula(optionType, effStrike, averageRate, stdDev, 1.0);
206 Real effectiveTime = capletVolatility()->timeFromReference(fixingDates.back());
207 if (optionType == Option::Type::Call)
208 effectiveCapletVolatility_ = stdDev / std::sqrt(effectiveTime);
209 else
210 effectiveFloorletVolatility_ = stdDev / std::sqrt(effectiveTime);
211
212 // add spread to average rate
213 if (coupon_->underlying()->includeSpread()) {
214 averageRate += coupon_->underlying()->spread();
215 }
216
217 // incorporate cap/floor into average rate
218 Real averageRateRaw = averageRate;
219 averageRate += optionType == Option::Call ? (-cfValue) : cfValue;
220
221 // now assume the averageRate is the effective rate over the future period and update the compoundFactor
222 // this is an approximation, see "Ester / Daily Spread Curve Setup in ORE": set tau to avg value
223 Real dailyTau =
224 coupon_->underlying()->dayCounter().yearFraction(dates[i], dates.back()) / (dates.back() - dates[i]);
225 // now use formula (4) from the paper
226 compoundFactor *= std::pow(1.0 + dailyTau * averageRate, static_cast<int>(dates.back() - dates[i]));
227 compoundFactorRaw *= std::pow(1.0 + dailyTau * averageRateRaw, static_cast<int>(dates.back() - dates[i]));
228 }
229
230 Rate tau = coupon_->underlying()->lookback() == 0 * Days
231 ? coupon_->accrualPeriod()
232 : coupon_->dayCounter().yearFraction(dates.front(), dates.back());
233 Rate rate = (compoundFactor - 1.0) / tau;
234 Rate rawRate = (compoundFactorRaw - 1.0) / tau;
235
236 rate *= coupon_->underlying()->gearing();
237 rawRate *= coupon_->underlying()->gearing();
238
239 if (!coupon_->underlying()->includeSpread()) {
240 rate += coupon_->underlying()->spread();
241 rawRate += coupon_->underlying()->spread();
242 }
243
244 // return optionletRate := r - rawRate, i.e. the option component only
245 // (see CappedFlooredOvernightIndexedCoupon::rate() for the signs of the capletRate / flooredRate)
246
247 return (optionType == Option::Call ? -1.0 : 1.0) * (rate - rawRate);
248}
249
251
253 return coupon_->localCapFloor() ? optionletRateLocal(Option::Call, effectiveCap)
254 : optionletRateGlobal(Option::Call, effectiveCap);
255}
256
257Rate BlackOvernightIndexedCouponPricer::floorletRate(Rate effectiveFloor) const {
258 return coupon_->localCapFloor() ? optionletRateLocal(Option::Put, effectiveFloor)
259 : optionletRateGlobal(Option::Put, effectiveFloor);
260}
261
263 QL_FAIL("BlackOvernightIndexedCouponPricer::swapletPrice() not provided");
264}
266 QL_FAIL("BlackOvernightIndexedCouponPricer::capletPrice() not provided");
267}
269 QL_FAIL("BlackOvernightIndexedCouponPricer::floorletPrice() not provided");
270}
271
273 coupon_ = dynamic_cast<const CappedFlooredAverageONIndexedCoupon*>(&coupon);
274 QL_REQUIRE(coupon_, "BlackAverageONIndexedCouponPricer: CappedFlooredAverageONIndexedCoupon required");
275 gearing_ = coupon.gearing();
276 index_ = ext::dynamic_pointer_cast<OvernightIndex>(coupon.index());
277 if (!index_) {
278 // check if the coupon was right
280 dynamic_cast<const CappedFlooredAverageONIndexedCoupon*>(&coupon);
281 QL_REQUIRE(c, "BlackAverageONIndexedCouponPricer: CappedFlooredAverageONIndexedCoupon required");
282 // coupon was right, index is not
283 QL_FAIL("BlackAverageONIndexedCouponPricer: CappedFlooredAverageONIndexedCoupon required");
284 }
285 swapletRate_ = coupon_->underlying()->rate();
286 forwardRate_ = (swapletRate_ - coupon_->underlying()->spread()) / coupon_->underlying()->gearing();
288}
289
290Real BlackAverageONIndexedCouponPricer::optionletRateGlobal(Option::Type optionType, Real effStrike) const {
291 Date lastRelevantFixingDate = coupon_->underlying()->fixingDate();
292 if (lastRelevantFixingDate <= Settings::instance().evaluationDate()) {
293 // the amount is determined
294 Real a, b;
295 if (optionType == Option::Call) {
296 a = forwardRate_;
297 b = effStrike;
298 } else {
299 a = effStrike;
300 b = forwardRate_;
301 }
302 return gearing_ * std::max(a - b, 0.0);
303 } else {
304 // not yet determined, use Black model
305 QL_REQUIRE(!capletVolatility().empty(), "BlackAverageONIndexedCouponPricer: missing optionlet volatility");
306 std::vector<Date> fixingDates = coupon_->underlying()->fixingDates();
307 QL_REQUIRE(!fixingDates.empty(), "BlackAverageONIndexedCouponPricer: empty fixing dates");
308 bool shiftedLn = capletVolatility()->volatilityType() == ShiftedLognormal;
309 Real shift = capletVolatility()->displacement();
310 Real stdDev;
311 Real effectiveTime = capletVolatility()->timeFromReference(fixingDates.back());
313 // vol input is effective, i.e. we use a plain black model
314 stdDev = capletVolatility()->volatility(fixingDates.back(), effStrike) * std::sqrt(effectiveTime);
315 } else {
316 // vol input is not effective:
317 // for the standard deviation see Lyashenko, Mercurio, Looking forward to backward looking rates,
318 // section 6.3. the idea is to dampen the average volatility sigma between the fixing start and fixing end
319 // date by a linear function going from (fixing start, 1) to (fixing end, 0)
320 Real fixingStartTime = capletVolatility()->timeFromReference(fixingDates.front());
321 Real fixingEndTime = capletVolatility()->timeFromReference(fixingDates.back());
322 Real sigma = capletVolatility()->volatility(
323 std::max(fixingDates.front(), capletVolatility()->referenceDate() + 1), effStrike);
324 Real T = std::max(fixingStartTime, 0.0);
325 if (!close_enough(fixingEndTime, T))
326 T += std::pow(fixingEndTime - T, 3.0) / std::pow(fixingEndTime - fixingStartTime, 2.0) / 3.0;
327 stdDev = sigma * std::sqrt(T);
328 }
329 if (optionType == Option::Type::Call)
330 effectiveCapletVolatility_ = stdDev / std::sqrt(effectiveTime);
331 else
332 effectiveFloorletVolatility_ = stdDev / std::sqrt(effectiveTime);
333 Real fixing = shiftedLn ? blackFormula(optionType, effStrike, forwardRate_, stdDev, 1.0, shift)
334 : bachelierBlackFormula(optionType, effStrike, forwardRate_, stdDev, 1.0);
335 return gearing_ * fixing;
336 }
337}
338
339Real BlackAverageONIndexedCouponPricer::optionletRateLocal(Option::Type optionType, Real effStrike) const {
340
341 QL_REQUIRE(!effectiveVolatilityInput(),
342 "BlackAverageONIndexedCouponPricer::optionletRateLocal() does not support effective volatility input.");
343
344 // We compute a rate and a rawRate such that
345 // rate * tau * nominal is the amount of the coupon with locally (i.e. daily) capped / floored rates
346 // rawRate * tau * nominal is the amount of the coupon without capping / flooring the rate
347 // We will then return the difference between rate and rawRate (with the correct sign, see below)
348 // as the option component of the coupon.
349
350 // See CappedFlooredOvernightIndexedCoupon::effectiveCap(), Floor() for what is passed in as effStrike.
351 // From this we back out the absolute strike at which the
352 // - daily rate + spread (spread included) or the
353 // - daily rate (spread excluded)
354 // is capped / floored.
355
356 Real absStrike = coupon_->includeSpread() ? effStrike + coupon_->underlying()->spread() : effStrike;
357
358 // This following code is inevitably quite similar to the plain ON coupon pricer code, possibly we can refactor
359 // this, but as a first step it seems safer to add the full modified code explicitly here and leave the original
360 // code alone.
361
362 ext::shared_ptr<OvernightIndex> index = ext::dynamic_pointer_cast<OvernightIndex>(coupon_->index());
363
364 const std::vector<Date>& fixingDates = coupon_->underlying()->fixingDates();
365 const std::vector<Time>& dt = coupon_->underlying()->dt();
366
367 Size n = dt.size();
368 Size i = 0;
369 QL_REQUIRE(coupon_->underlying()->rateCutoff() < n,
370 "rate cutoff (" << coupon_->underlying()->rateCutoff()
371 << ") must be less than number of fixings in period (" << n << ")");
372 Size nCutoff = n - coupon_->underlying()->rateCutoff();
373
374 Real accumulatedRate = 0.0, accumulatedRateRaw = 0.0;
375
376 // already fixed part
377 Date today = Settings::instance().evaluationDate();
378 while (i < n && fixingDates[std::min(i, nCutoff)] < today) {
379 // rate must have been fixed
380 Rate pastFixing = index->pastFixing(fixingDates[std::min(i, nCutoff)]);
381 QL_REQUIRE(pastFixing != Null<Real>(),
382 "Missing " << index->name() << " fixing for " << fixingDates[std::min(i, nCutoff)]);
383 if (coupon_->includeSpread()) {
384 pastFixing += coupon_->spread();
385 }
386 accumulatedRate += cappedFlooredRate(pastFixing, optionType, absStrike) * dt[i];
387 accumulatedRateRaw += pastFixing * dt[i];
388 ++i;
389 }
390
391 // today is a border case
392 if (i < n && fixingDates[std::min(i, nCutoff)] == today) {
393 // might have been fixed
394 try {
395 Rate pastFixing = index->pastFixing(today);
396 if (pastFixing != Null<Real>()) {
397 if (coupon_->includeSpread()) {
398 pastFixing += coupon_->spread();
399 }
400 accumulatedRate += cappedFlooredRate(pastFixing, optionType, absStrike) * dt[i];
401 accumulatedRateRaw += pastFixing * dt[i];
402 ++i;
403 } else {
404 ; // fall through and forecast
405 }
406 } catch (Error&) {
407 ; // fall through and forecast
408 }
409 }
410
411 // forward part, approximation by pricing a cap / floor in the middle of the future period
412 const std::vector<Date>& dates = coupon_->underlying()->valueDates();
413 if (i < n) {
414 Handle<YieldTermStructure> curve = index->forwardingTermStructure();
415 QL_REQUIRE(!curve.empty(), "null term structure set to this instance of " << index->name());
416
417 DiscountFactor startDiscount = curve->discount(dates[i]);
418 DiscountFactor endDiscount = curve->discount(dates[std::max(nCutoff, i)]);
419
420 // handle the rate cutoff period (if there is any, i.e. if nCutoff < n)
421 if (nCutoff < n) {
422 // forward discount factor for one calendar day on the cutoff date
423 DiscountFactor discountCutoffDate = curve->discount(dates[nCutoff] + 1) / curve->discount(dates[nCutoff]);
424 // keep the above forward discount factor constant during the cutoff period
425 endDiscount *= std::pow(discountCutoffDate, dates[n] - dates[nCutoff]);
426 }
427
428 // estimate the average daily rate over the future period (approximate the continuously compounded rate)
429 Real tau = coupon_->dayCounter().yearFraction(dates[i], dates.back());
430 Real averageRate = -std::log(endDiscount / startDiscount) / tau;
431
432 // compute the value of a cap or floor with fixing in the middle of the future period
433 // (but accounting for the rate cutoff here)
434 Time midPoint =
435 (capletVolatility()->timeFromReference(dates[i]) + capletVolatility()->timeFromReference(dates[nCutoff])) /
436 2.0;
437 Real stdDev = capletVolatility()->volatility(midPoint, effStrike) * std::sqrt(midPoint);
438 Real shift = capletVolatility()->displacement();
439 bool shiftedLn = capletVolatility()->volatilityType() == ShiftedLognormal;
440 Rate cfValue = shiftedLn ? blackFormula(optionType, effStrike, averageRate, stdDev, 1.0, shift)
441 : bachelierBlackFormula(optionType, effStrike, averageRate, stdDev, 1.0);
442
443 Real effectiveTime = capletVolatility()->timeFromReference(fixingDates.back());
444 if (optionType == Option::Type::Call)
445 effectiveCapletVolatility_ = stdDev / std::sqrt(effectiveTime);
446 else
447 effectiveFloorletVolatility_ = stdDev / std::sqrt(effectiveTime);
448
449 // add spread to average rate
450 if (coupon_->includeSpread()) {
451 averageRate += coupon_->underlying()->spread();
452 }
453
454 // incorporate cap/floor into average rate
455 Real averageRateRaw = averageRate;
456 averageRate += optionType == Option::Call ? (-cfValue) : cfValue;
457
458 // now assume the averageRate is the effective rate over the future period and update the average rate
459 // this is an approximation, see "Ester / Daily Spread Curve Setup in ORE": set tau to avg value
460 Real dailyTau =
461 coupon_->underlying()->dayCounter().yearFraction(dates[i], dates.back()) / (dates.back() - dates[i]);
462 accumulatedRate += dailyTau * averageRate * static_cast<Real>(dates.back() - dates[i]);
463 accumulatedRateRaw += dailyTau * averageRateRaw * static_cast<Real>(dates.back() - dates[i]);
464 }
465
466 Rate tau = coupon_->underlying()->lookback() == 0 * Days
467 ? coupon_->accrualPeriod()
468 : coupon_->dayCounter().yearFraction(dates.front(), dates.back());
469 Rate rate = accumulatedRate / tau;
470 Rate rawRate = accumulatedRateRaw / tau;
471
472 rate *= coupon_->underlying()->gearing();
473 rawRate *= coupon_->underlying()->gearing();
474
475 if (!coupon_->includeSpread()) {
476 rate += coupon_->underlying()->spread();
477 rawRate += coupon_->underlying()->spread();
478 }
479
480 // return optionletRate := r - rawRate, i.e. the option component only
481 // (see CappedFlooredAverageONIndexedCoupon::rate() for the signs of the capletRate / flooredRate)
482
483 return (optionType == Option::Call ? -1.0 : 1.0) * (rate - rawRate);
484}
485
487
489 return coupon_->localCapFloor() ? optionletRateLocal(Option::Call, effectiveCap)
490 : optionletRateGlobal(Option::Call, effectiveCap);
491}
492
493Rate BlackAverageONIndexedCouponPricer::floorletRate(Rate effectiveFloor) const {
494 return coupon_->localCapFloor() ? optionletRateLocal(Option::Put, effectiveFloor)
495 : optionletRateGlobal(Option::Put, effectiveFloor);
496}
497
499 QL_FAIL("BlackAverageONIndexedCouponPricer::swapletPrice() not provided");
500}
502 QL_FAIL("BlackAverageONIndexedCouponPricer::capletPrice() not provided");
503}
505 QL_FAIL("BlackAverageONIndexedCouponPricer::floorletPrice() not provided");
506}
507
508} // namespace QuantExt
black coupon pricer for capped / floored ON indexed coupons
Real optionletRateGlobal(Option::Type optionType, Real effStrike) const
Real optionletRateLocal(Option::Type optionType, Real effStrike) const
void initialize(const FloatingRateCoupon &coupon) override
Real floorletPrice(Rate effectiveFloor) const override
const CappedFlooredAverageONIndexedCoupon * coupon_
Real optionletRateGlobal(Option::Type optionType, Real effStrike) const
Real optionletRateLocal(Option::Type optionType, Real effStrike) const
void initialize(const FloatingRateCoupon &coupon) override
const CappedFlooredOvernightIndexedCoupon * coupon_
Real floorletPrice(Rate effectiveFloor) const override
Handle< OptionletVolatilityStructure > capletVolatility() const
capped floored overnight indexed coupon
ext::shared_ptr< AverageONIndexedCoupon > underlying() const
capped floored overnight indexed coupon
ext::shared_ptr< OvernightIndexedCoupon > underlying() const
Handle< OptionletVolatilityStructure > capletVolatility() const
Filter close_enough(const RandomVariable &x, const RandomVariable &y)