Skip to content

Commit 487e1c5

Browse files
pcaspersjenkins
authored andcommitted
QPR-11773 add remaining implementations to lgm vectorised
1 parent a0b454b commit 487e1c5

2 files changed

Lines changed: 114 additions & 33 deletions

File tree

QuantExt/qle/models/lgmvectorised.cpp

Lines changed: 109 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -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

322348
RandomVariable 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

420473
RandomVariable 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

508590
RandomVariable 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

QuantExt/qle/models/lgmvectorised.hpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,13 @@ class LgmVectorised {
8181
/* Exact if no cap/floors are present and t <= first value date.
8282
Approximations are applied for t > first value date or when cap / floors are present. */
8383
RandomVariable averagedBmaRate(const boost::shared_ptr<BMAIndex>& index, const std::vector<Date>& fixingDates,
84-
const Date& accrualStartDate, const Date& accrualEndDate, const Real spread,
85-
const Real gearing, const Real cap, const Real floor, const bool nakedOption,
86-
const Time t, const RandomVariable& x) const;
84+
const Date& accrualStartDate, const Date& accrualEndDate, const bool includeSpread,
85+
const Real spread, const Real gearing, const Real cap, const Real floor,
86+
const bool nakedOption, const Time t, const RandomVariable& x) const;
8787

88-
/* Exact if no cap/floors are present and t <= first fixing date.
89-
Approximations are applied for t > first value date or when cap / floors are present. */
88+
/* Approximation via plain Ibor coupon with fixing date = first fixing date and the fixing() method above. */
9089
RandomVariable subPeriodsRate(const boost::shared_ptr<InterestRateIndex>& index,
91-
const std::vector<Date>& fixingDates, const Real cap, const Real floor,
92-
const bool nakedOption, const Time t, const RandomVariable& x) const;
90+
const std::vector<Date>& fixingDates, const Time t, const RandomVariable& x) const;
9391

9492
private:
9593
boost::shared_ptr<IrLgm1fParametrization> p_;

0 commit comments

Comments
 (0)