21#include <ql/pricingengines/blackformula.hpp>
22#include <ql/termstructures/volatility/optionlet/optionletvolatilitystructure.hpp>
28 QL_REQUIRE(
coupon_,
"BlackOvernightIndexedCouponPricer: CappedFlooredOvernightIndexedCoupon required");
30 index_ = ext::dynamic_pointer_cast<OvernightIndex>(coupon.index());
35 QL_REQUIRE(c,
"BlackOvernightIndexedCouponPricer: CappedFlooredOvernightIndexedCoupon required");
37 QL_FAIL(
"BlackOvernightIndexedCouponPricer: CappedFlooredOvernightIndexedCoupon required");
46 if (lastRelevantFixingDate <= Settings::instance().evaluationDate()) {
49 if (optionType == Option::Call) {
56 return gearing_ * std::max(a - b, 0.0);
59 QL_REQUIRE(!
capletVolatility().empty(),
"BlackOvernightIndexedCouponPricer: missing optionlet volatility");
61 QL_REQUIRE(!fixingDates.empty(),
"BlackOvernightIndexedCouponPricer: empty fixing dates");
65 Real effectiveTime =
capletVolatility()->timeFromReference(fixingDates.back());
68 stdDev =
capletVolatility()->volatility(fixingDates.back(), effStrike) * std::sqrt(effectiveTime);
74 Real fixingStartTime =
capletVolatility()->timeFromReference(fixingDates.front());
75 Real fixingEndTime =
capletVolatility()->timeFromReference(fixingDates.back());
77 std::max(fixingDates.front(),
capletVolatility()->referenceDate() + 1), effStrike);
78 Real T = std::max(fixingStartTime, 0.0);
80 T += std::pow(fixingEndTime - T, 3.0) / std::pow(fixingEndTime - fixingStartTime, 2.0) / 3.0;
81 stdDev = sigma * std::sqrt(T);
83 if (optionType == Option::Type::Call)
87 Real fixing = shiftedLn ? blackFormula(optionType, effStrike,
effectiveIndexFixing_, stdDev, 1.0, shift)
94Real cappedFlooredRate(Real r, Option::Type optionType, Real k) {
95 if (optionType == Option::Call) {
96 return std::min(r, k);
98 return std::max(r, k);
106 "BlackAverageONIndexedCouponPricer::optionletRateLocal() does not support effective volatility input.");
126 ext::shared_ptr<OvernightIndex> index = ext::dynamic_pointer_cast<OvernightIndex>(
coupon_->index());
135 <<
") must be less than number of fixings in period (" << n <<
")");
138 Real compoundFactor = 1.0, compoundFactorRaw = 1.0;
141 Date today = Settings::instance().evaluationDate();
142 while (i < n && fixingDates[std::min(i, nCutoff)] < today) {
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)]);
148 pastFixing +=
coupon_->spread();
150 compoundFactor *= 1.0 + cappedFlooredRate(pastFixing, optionType, absStrike) * dt[i];
151 compoundFactorRaw *= 1.0 + pastFixing * dt[i];
156 if (i < n && fixingDates[std::min(i, nCutoff)] == today) {
159 Rate pastFixing = index->pastFixing(today);
160 if (pastFixing != Null<Real>()) {
162 pastFixing +=
coupon_->spread();
164 compoundFactor *= 1.0 + cappedFlooredRate(pastFixing, optionType, absStrike) * dt[i];
165 compoundFactorRaw *= 1.0 + pastFixing * dt[i];
178 Handle<YieldTermStructure> curve = index->forwardingTermStructure();
179 QL_REQUIRE(!curve.empty(),
"null term structure set to this instance of " << index->name());
181 DiscountFactor startDiscount = curve->discount(dates[i]);
182 DiscountFactor endDiscount = curve->discount(dates[std::max(nCutoff, i)]);
187 DiscountFactor discountCutoffDate = curve->discount(dates[nCutoff] + 1) / curve->discount(dates[nCutoff]);
189 endDiscount *= std::pow(discountCutoffDate, dates[n] - dates[nCutoff]);
193 Real tau =
coupon_->dayCounter().yearFraction(dates[i], dates.back());
194 Real averageRate = -std::log(endDiscount / startDiscount) / tau;
201 Real stdDev =
capletVolatility()->volatility(midPoint, effStrike) * std::sqrt(midPoint);
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)
218 Real averageRateRaw = averageRate;
219 averageRate += optionType == Option::Call ? (-cfValue) : cfValue;
224 coupon_->
underlying()->dayCounter().yearFraction(dates[i], dates.back()) / (dates.back() - dates[i]);
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]));
232 :
coupon_->dayCounter().yearFraction(dates.front(), dates.back());
233 Rate rate = (compoundFactor - 1.0) / tau;
234 Rate rawRate = (compoundFactorRaw - 1.0) / tau;
247 return (optionType == Option::Call ? -1.0 : 1.0) * (rate - rawRate);
263 QL_FAIL(
"BlackOvernightIndexedCouponPricer::swapletPrice() not provided");
266 QL_FAIL(
"BlackOvernightIndexedCouponPricer::capletPrice() not provided");
269 QL_FAIL(
"BlackOvernightIndexedCouponPricer::floorletPrice() not provided");
274 QL_REQUIRE(
coupon_,
"BlackAverageONIndexedCouponPricer: CappedFlooredAverageONIndexedCoupon required");
276 index_ = ext::dynamic_pointer_cast<OvernightIndex>(coupon.index());
281 QL_REQUIRE(c,
"BlackAverageONIndexedCouponPricer: CappedFlooredAverageONIndexedCoupon required");
283 QL_FAIL(
"BlackAverageONIndexedCouponPricer: CappedFlooredAverageONIndexedCoupon required");
292 if (lastRelevantFixingDate <= Settings::instance().evaluationDate()) {
295 if (optionType == Option::Call) {
302 return gearing_ * std::max(a - b, 0.0);
305 QL_REQUIRE(!
capletVolatility().empty(),
"BlackAverageONIndexedCouponPricer: missing optionlet volatility");
307 QL_REQUIRE(!fixingDates.empty(),
"BlackAverageONIndexedCouponPricer: empty fixing dates");
311 Real effectiveTime =
capletVolatility()->timeFromReference(fixingDates.back());
314 stdDev =
capletVolatility()->volatility(fixingDates.back(), effStrike) * std::sqrt(effectiveTime);
320 Real fixingStartTime =
capletVolatility()->timeFromReference(fixingDates.front());
321 Real fixingEndTime =
capletVolatility()->timeFromReference(fixingDates.back());
323 std::max(fixingDates.front(),
capletVolatility()->referenceDate() + 1), effStrike);
324 Real T = std::max(fixingStartTime, 0.0);
326 T += std::pow(fixingEndTime - T, 3.0) / std::pow(fixingEndTime - fixingStartTime, 2.0) / 3.0;
327 stdDev = sigma * std::sqrt(T);
329 if (optionType == Option::Type::Call)
333 Real fixing = shiftedLn ? blackFormula(optionType, effStrike,
forwardRate_, stdDev, 1.0, shift)
334 : bachelierBlackFormula(optionType, effStrike,
forwardRate_, stdDev, 1.0);
342 "BlackAverageONIndexedCouponPricer::optionletRateLocal() does not support effective volatility input.");
362 ext::shared_ptr<OvernightIndex> index = ext::dynamic_pointer_cast<OvernightIndex>(
coupon_->index());
371 <<
") must be less than number of fixings in period (" << n <<
")");
374 Real accumulatedRate = 0.0, accumulatedRateRaw = 0.0;
377 Date today = Settings::instance().evaluationDate();
378 while (i < n && fixingDates[std::min(i, nCutoff)] < today) {
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)]);
384 pastFixing +=
coupon_->spread();
386 accumulatedRate += cappedFlooredRate(pastFixing, optionType, absStrike) * dt[i];
387 accumulatedRateRaw += pastFixing * dt[i];
392 if (i < n && fixingDates[std::min(i, nCutoff)] == today) {
395 Rate pastFixing = index->pastFixing(today);
396 if (pastFixing != Null<Real>()) {
398 pastFixing +=
coupon_->spread();
400 accumulatedRate += cappedFlooredRate(pastFixing, optionType, absStrike) * dt[i];
401 accumulatedRateRaw += pastFixing * dt[i];
414 Handle<YieldTermStructure> curve = index->forwardingTermStructure();
415 QL_REQUIRE(!curve.empty(),
"null term structure set to this instance of " << index->name());
417 DiscountFactor startDiscount = curve->discount(dates[i]);
418 DiscountFactor endDiscount = curve->discount(dates[std::max(nCutoff, i)]);
423 DiscountFactor discountCutoffDate = curve->discount(dates[nCutoff] + 1) / curve->discount(dates[nCutoff]);
425 endDiscount *= std::pow(discountCutoffDate, dates[n] - dates[nCutoff]);
429 Real tau =
coupon_->dayCounter().yearFraction(dates[i], dates.back());
430 Real averageRate = -std::log(endDiscount / startDiscount) / tau;
437 Real stdDev =
capletVolatility()->volatility(midPoint, effStrike) * std::sqrt(midPoint);
440 Rate cfValue = shiftedLn ? blackFormula(optionType, effStrike, averageRate, stdDev, 1.0, shift)
441 : bachelierBlackFormula(optionType, effStrike, averageRate, stdDev, 1.0);
443 Real effectiveTime =
capletVolatility()->timeFromReference(fixingDates.back());
444 if (optionType == Option::Type::Call)
455 Real averageRateRaw = averageRate;
456 averageRate += optionType == Option::Call ? (-cfValue) : cfValue;
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]);
468 :
coupon_->dayCounter().yearFraction(dates.front(), dates.back());
469 Rate rate = accumulatedRate / tau;
470 Rate rawRate = accumulatedRateRaw / tau;
483 return (optionType == Option::Call ? -1.0 : 1.0) * (rate - rawRate);
499 QL_FAIL(
"BlackAverageONIndexedCouponPricer::swapletPrice() not provided");
502 QL_FAIL(
"BlackAverageONIndexedCouponPricer::capletPrice() not provided");
505 QL_FAIL(
"BlackAverageONIndexedCouponPricer::floorletPrice() not provided");
black coupon pricer for capped / floored ON indexed coupons
Real optionletRateGlobal(Option::Type optionType, Real effStrike) const
Real capletPrice(Rate effectiveCap) const override
Rate floorletRate(Rate effectiveFloor) const override
Real optionletRateLocal(Option::Type optionType, Real effStrike) const
void initialize(const FloatingRateCoupon &coupon) override
Rate swapletRate() const override
Real floorletPrice(Rate effectiveFloor) const override
Real swapletPrice() const override
const CappedFlooredAverageONIndexedCoupon * coupon_
Rate capletRate(Rate effectiveCap) const override
ext::shared_ptr< IborIndex > index_
Real optionletRateGlobal(Option::Type optionType, Real effStrike) const
Real capletPrice(Rate effectiveCap) const override
Rate floorletRate(Rate effectiveFloor) const override
Real optionletRateLocal(Option::Type optionType, Real effStrike) const
void initialize(const FloatingRateCoupon &coupon) override
Real effectiveIndexFixing_
const CappedFlooredOvernightIndexedCoupon * coupon_
Rate swapletRate() const override
Real floorletPrice(Rate effectiveFloor) const override
Real swapletPrice() const override
Rate capletRate(Rate effectiveCap) const override
ext::shared_ptr< IborIndex > index_
bool effectiveVolatilityInput() const
Real effectiveCapletVolatility_
Handle< OptionletVolatilityStructure > capletVolatility() const
Real effectiveFloorletVolatility_
capped floored overnight indexed coupon
bool includeSpread() const
ext::shared_ptr< AverageONIndexedCoupon > underlying() const
bool localCapFloor() const
capped floored overnight indexed coupon
ext::shared_ptr< OvernightIndexedCoupon > underlying() const
bool localCapFloor() const
bool effectiveVolatilityInput() const
Real effectiveCapletVolatility_
Handle< OptionletVolatilityStructure > capletVolatility() const
Real effectiveFloorletVolatility_
Filter close_enough(const RandomVariable &x, const RandomVariable &y)