@@ -195,9 +195,6 @@ RandomVariable LgmVectorised::compoundedOnRate(const boost::shared_ptr<Overnight
195195 const bool localCapFloor, const bool nakedOption, const Time t,
196196 const RandomVariable& x) const {
197197
198- QL_REQUIRE (!localCapFloor, " LgmVectorised::compoundedOnRate(): localCapFloor = true is not supported" );
199- QL_REQUIRE (!nakedOption, " LgmVectorised::compoundedOnRate(): nakedOption = true is not supported" );
200-
201198 QL_REQUIRE (!includeSpread || QuantLib::close_enough (gearing, 1.0 ),
202199 " LgmVectorised::compoundedOnRate(): if include spread = true, only a gearing 1.0 is allowed - scale "
203200 " the notional in this case instead." );
@@ -305,18 +302,47 @@ RandomVariable LgmVectorised::compoundedOnRate(const boost::shared_ptr<Overnight
305302 // RandomVariable effectiveSpread, effectiveIndexFixing;
306303 if (!includeSpread) {
307304 swapletRate += RandomVariable (x.size (), spread);
308- // effectiveSpread = RandomVariable(x.size(), spread);
309- // effectiveIndexFixing = RandomVaraible(x, rate) ;
305+ effectiveSpread = RandomVariable (x.size (), spread);
306+ effectiveIndexFixing = rate;
310307 } else {
311- // effectiveSpread =
312- // rate - (compoundFactorWithoutSpreadLgm - RandomVariable(x.size() 1.0)) / RandomVariable(x.size(), tau);
313- // effectiveIndexFixing = rate - effectiveSpread_;
308+ effectiveSpread =
309+ rate - (compoundFactorWithoutSpreadLgm - RandomVariable (x.size (), 1.0 )) / RandomVariable (x.size (), tau);
310+ effectiveIndexFixing = rate - effectiveSpread_;
311+ }
312+
313+ if (cap == Null<Real>() && floor == Null<Real>())
314+ return swapletRate;
315+
316+ // handle cap / floor - we compute the intrinsic value only
317+
318+ if (gearing < 0.0 ) {
319+ std::swap (cap, floor);
314320 }
315321
316- RandomVariable floorVal (x. size (), floor == Null<Real>() ? -QL_MAX_REAL : floor);
317- RandomVariable capVal (x.size (), cap == Null<Real>() ? QL_MAX_REAL : cap );
322+ if (nakedOption)
323+ swapletRate = RandomVariable (x.size (), 0.0 );
318324
319- return max (floorVal, min (capVal, swapletRate));
325+ RandomVariable floorletRate (x.size (), 0.0 );
326+ RandomVariable capletRate (x.size (), 0.0 );
327+
328+ if (floor != Null<Real>()) {
329+ // ignore localCapFloor, treat as global
330+ RandomVariable effectiveStrike =
331+ (RandomVariable (x.size (), floor) - effectiveSpread) / RandomVariable (x.size (), gearing);
332+ floorletRate = RandomVariable (x.size (), gearing) *
333+ max (RandomVariable (x.size (), 0.0 ), effectiveStrike - effectiveIndexFixing);
334+ }
335+
336+ if (cap != Null<Real>()) {
337+ RandomVariable effectiveStrike =
338+ (RandomVariable (x.size (), cap) - effectiveSpread) / RandomVariable (x.size (), gearing);
339+ capletRate = RandomVariable (x.size (), gearing) *
340+ max (RandomVariable (x.size (), 0.0 ), effectiveIndexFixing - effectiveStrike);
341+ if (nakedOption && floor == Null<Real>())
342+ capletRate = -capletRate;
343+ }
344+
345+ return swapletRate + floorletRate - capletRate;
320346}
321347
322348RandomVariable LgmVectorised::averagedOnRate (const boost::shared_ptr<OvernightIndex>& index,
@@ -327,9 +353,6 @@ RandomVariable LgmVectorised::averagedOnRate(const boost::shared_ptr<OvernightIn
327353 const Real floor, const bool localCapFloor, const bool nakedOption,
328354 const Time t, const RandomVariable& x) const {
329355
330- QL_REQUIRE (!localCapFloor, " LgmVectorised::averageOnRate(): localCapFloor = true is not supported" );
331- QL_REQUIRE (!nakedOption, " LgmVectorised::averagedOnRate(): nakedOption = true is not supported" );
332-
333356 QL_REQUIRE (!includeSpread || QuantLib::close_enough (gearing, 1.0 ),
334357 " LgmVectorised::averageOnRate(): if include spread = true, only a gearing 1.0 is allowed - scale "
335358 " the notional in this case instead." );
@@ -412,19 +435,46 @@ RandomVariable LgmVectorised::averagedOnRate(const boost::shared_ptr<OvernightIn
412435 Rate tau = accrualDayCounter.yearFraction (valueDates.front (), valueDates.back ());
413436 RandomVariable rate =
414437 RandomVariable (x.size (), gearing / tau) * accumulatedRateLgm + RandomVariable (x.size (), spread);
415- RandomVariable floorVal (x.size (), floor == Null<Real>() ? -QL_MAX_REAL : floor);
416- RandomVariable capVal (x.size (), cap == Null<Real>() ? QL_MAX_REAL : cap);
417- return max (floorVal, min (capVal, rate));
438+
439+ if (cap == Null<Real>() && floor == Null<Real>())
440+ return rate;
441+
442+ // handle cap / floor - we compute the intrinsic value only
443+
444+ if (gearing < 0.0 ) {
445+ std::swap (cap, floor);
446+ }
447+
448+ if (nakedOption)
449+ rate = RandomVariable (x.size (), 0.0 );
450+
451+ RandomVariable forwardRate = (rate - RandomVariable (x.size (), spread)) / RandomVariable (x.size (), gearing);
452+ RandomVariable floorletRate (x.size (), 0.0 );
453+ RandomVariable capletRate (x.size (), 0.0 );
454+
455+ if (floor != Null<Real>()) {
456+ // ignore localCapFloor, treat as global
457+ RandomVariable effectiveStrike = RandomVariable (x.size (), (floor - spread) / gearing);
458+ floorletRate =
459+ RandomVariable (x.size (), gearing) * max (RandomVariable (x.size (), 0.0 ), effectiveStrike - forwardRate);
460+ }
461+
462+ if (cap != Null<Real>()) {
463+ RandomVariable effectiveStrike = RandomVariable (x.size (), (cap - spread) / gearing);
464+ capletRate =
465+ RandomVariable (x.size (), gearing) * max (RandomVariable (x.size (), 0.0 ), forwardRate - effectiveStrike);
466+ if (nakedOption && floor == Null<Real>())
467+ capletRate = -capletRate;
468+ }
469+
470+ return rate + floorletRate - capletRate;
418471}
419472
420473RandomVariable LgmVectorised::averagedBmaRate (const boost::shared_ptr<BMAIndex>& index,
421474 const std::vector<Date>& fixingDates, const Date& accrualStartDate,
422- const Date& accrualEndDate, const Real spread, const Real gearing,
423- const Real cap, const Real floor, const bool nakedOption, const Time t,
424- const RandomVariable& x) const {
425-
426- QL_REQUIRE (cap == Null<Real>() && floor == Null<Real>() && nakedOption == false && spread == 0.0 && gearing == 1.0 ,
427- " LgmVectorised::averagedBmaRate(): implementation of cap, floor, naked option not finished." );
475+ const Date& accrualEndDate, const bool includeSpread, const Real spread,
476+ const Real gearing, const Real cap, const Real floor,
477+ const bool nakedOption, const Time t, const RandomVariable& x) const {
428478
429479 // similar to AverageBMACouponPricer
430480
@@ -500,15 +550,48 @@ RandomVariable LgmVectorised::averagedBmaRate(const boost::shared_ptr<BMAIndex>&
500550 d1 = d2;
501551 }
502552
503- avgBMA /= RandomVariable (x.size (), (endDate - startDate));
553+ avgBMA *= RandomVariable (x.size (), gearing / (endDate - startDate));
554+ avgBMA += RandomVariable (x.size (), spread);
555+
556+ if (cap == Null<Real>() && floor == Null<Real>())
557+ return avgBMA;
504558
505- return avgBMA;
559+ // handle cap / floor - we compute the intrinsic value only
560+
561+ if (gearing < 0.0 ) {
562+ std::swap (cap, floor);
563+ }
564+
565+ if (nakedOption)
566+ rate = RandomVariable (x.size (), 0.0 );
567+
568+ RandomVariable forwardRate = (avgBMA - RandomVariable (x.size (), spread)) / RandomVariable (x.size (), gearing);
569+ RandomVariable floorletRate (x.size (), 0.0 );
570+ RandomVariable capletRate (x.size (), 0.0 );
571+
572+ if (floor != Null<Real>()) {
573+ // ignore localCapFloor, treat as global
574+ RandomVariable effectiveStrike = RandomVariable (x.size (), (floor - spread) / gearing);
575+ floorletRate =
576+ RandomVariable (x.size (), gearing) * max (RandomVariable (x.size (), 0.0 ), effectiveStrike - forwardRate);
577+ }
578+
579+ if (cap != Null<Real>()) {
580+ RandomVariable effectiveStrike = RandomVariable (x.size (), (cap - spread) / gearing);
581+ capletRate =
582+ RandomVariable (x.size (), gearing) * max (RandomVariable (x.size (), 0.0 ), forwardRate - effectiveStrike);
583+ if (nakedOption && floor == Null<Real>())
584+ capletRate = -capletRate;
585+ }
586+
587+ return rate + floorletRate - capletRate;
506588}
507589
508590RandomVariable LgmVectorised::subPeriodsRate (const boost::shared_ptr<InterestRateIndex>& index,
509591 const std::vector<Date>& fixingDates, const Real cap, const Real floor,
510592 const bool nakedOption, const Time t, const RandomVariable& x) const {
511- QL_FAIL (" not implemented yet." );
593+
594+ return fixing (index, fixingDates.front (), t, x);
512595}
513596
514597} // namespace QuantExt
0 commit comments