339 {
340
342 "BlackAverageONIndexedCouponPricer::optionletRateLocal() does not support effective volatility input.");
343
344
345
346
347
348
349
350
351
352
353
354
355
357
358
359
360
361
362 ext::shared_ptr<OvernightIndex> index = ext::dynamic_pointer_cast<OvernightIndex>(
coupon_->index());
363
366
367 Size n = dt.size();
368 Size i = 0;
371 << ") must be less than number of fixings in period (" << n << ")");
373
374 Real accumulatedRate = 0.0, accumulatedRateRaw = 0.0;
375
376
377 Date today = Settings::instance().evaluationDate();
378 while (i < n && fixingDates[std::min(i, nCutoff)] < today) {
379
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();
385 }
386 accumulatedRate += cappedFlooredRate(pastFixing, optionType, absStrike) * dt[i];
387 accumulatedRateRaw += pastFixing * dt[i];
388 ++i;
389 }
390
391
392 if (i < n && fixingDates[std::min(i, nCutoff)] == today) {
393
394 try {
395 Rate pastFixing = index->pastFixing(today);
396 if (pastFixing != Null<Real>()) {
398 pastFixing +=
coupon_->spread();
399 }
400 accumulatedRate += cappedFlooredRate(pastFixing, optionType, absStrike) * dt[i];
401 accumulatedRateRaw += pastFixing * dt[i];
402 ++i;
403 } else {
404 ;
405 }
406 } catch (Error&) {
407 ;
408 }
409 }
410
411
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
421 if (nCutoff < n) {
422
423 DiscountFactor discountCutoffDate = curve->discount(dates[nCutoff] + 1) / curve->discount(dates[nCutoff]);
424
425 endDiscount *= std::pow(discountCutoffDate, dates[n] - dates[nCutoff]);
426 }
427
428
429 Real tau =
coupon_->dayCounter().yearFraction(dates[i], dates.back());
430 Real averageRate = -std::log(endDiscount / startDiscount) / tau;
431
432
433
434 Time midPoint =
436 2.0;
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);
442
443 Real effectiveTime =
capletVolatility()->timeFromReference(fixingDates.back());
444 if (optionType == Option::Type::Call)
446 else
448
449
452 }
453
454
455 Real averageRateRaw = averageRate;
456 averageRate += optionType == Option::Call ? (-cfValue) : cfValue;
457
458
459
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
468 :
coupon_->dayCounter().yearFraction(dates.front(), dates.back());
469 Rate rate = accumulatedRate / tau;
470 Rate rawRate = accumulatedRateRaw / tau;
471
474
478 }
479
480
481
482
483 return (optionType == Option::Call ? -1.0 : 1.0) * (rate - rawRate);
484}
bool includeSpread() const