21#include <ql/instruments/overnightindexedswap.hpp>
22#include <ql/instruments/vanillaswap.hpp>
24#include <ql/cashflows/fixedratecoupon.hpp>
25#include <ql/cashflows/iborcoupon.hpp>
26#include <ql/cashflows/overnightindexedcoupon.hpp>
27#include <ql/indexes/iborindex.hpp>
28#include <ql/indexes/swapindex.hpp>
33 const Handle<YieldTermStructure>& discountCurve)
const {
34 QL_REQUIRE(t >= 0.0,
"t (" << t <<
") >= 0 required in LGMVectorised::numeraire");
38 (discountCurve.empty() ?
p_->termStructure()->discount(t) : discountCurve->discount(t)));
42 const Handle<YieldTermStructure>& discountCurve)
const {
43 if (QuantLib::close_enough(t, T))
45 QL_REQUIRE(T >= t && t >= 0.0,
"T(" << T <<
") >= t(" << t <<
") >= 0 required in LGMVectorised::discountBond");
49 (discountCurve.empty() ?
p_->termStructure()->discount(T) /
p_->termStructure()->discount(t)
50 : discountCurve->discount(T) / discountCurve->discount(t))) *
55 const Handle<YieldTermStructure>& discountCurve)
const {
56 if (QuantLib::close_enough(t, T))
58 QL_REQUIRE(T >= t && t >= 0.0,
59 "T(" << T <<
") >= t(" << t <<
") >= 0 required in LGMVectorised::reducedDiscountBond");
62 (discountCurve.empty() ?
p_->termStructure()->discount(T) : discountCurve->discount(T))) *
68 const Handle<YieldTermStructure>& discountCurve)
const {
69 QL_REQUIRE(T > S && S >= t && t >= 0.0,
70 "T(" << T <<
") > S(" << S <<
") >= t(" << t <<
") >= 0 required in LGMVectorised::discountBondOption");
88 Date today = Settings::instance().evaluationDate();
89 if (fixingDate <= today)
94 if (
auto ibor = QuantLib::ext::dynamic_pointer_cast<IborIndex>(index)) {
98 Date d1 = ibor->valueDate(fixingDate);
99 Date d2 = ibor->maturityDate(d1);
100 Time T1 = std::max(t,
p_->termStructure()->timeFromReference(d1));
101 Time T2 = std::max(T1,
p_->termStructure()->timeFromReference(d2));
102 Time dt = ibor->dayCounter().yearFraction(d1, d2);
107 }
else if (
auto swap = QuantLib::ext::dynamic_pointer_cast<SwapIndex>(index)) {
111 auto swapDiscountCurve =
112 swap->exogenousDiscount() ? swap->discountingTermStructure() : swap->forwardingTermStructure();
113 Leg floatingLeg, fixedLeg;
114 if (
auto ois = QuantLib::ext::dynamic_pointer_cast<OvernightIndexedSwapIndex>(index)) {
115 auto underlying = ois->underlyingSwap(fixingDate);
116 floatingLeg = underlying->overnightLeg();
117 fixedLeg = underlying->fixedLeg();
119 auto underlying = swap->underlyingSwap(fixingDate);
120 floatingLeg = underlying->floatingLeg();
121 fixedLeg = underlying->fixedLeg();
124 for (
auto const& c : floatingLeg) {
125 if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<IborCoupon>(c)) {
126 Date fixingValueDate = swap->iborIndex()->fixingCalendar().advance(
127 cpn->fixingDate(), swap->iborIndex()->fixingDays(), Days);
128 Date fixingEndDate = cpn->fixingEndDate();
129 Time T1 = std::max(t,
p_->termStructure()->timeFromReference(fixingValueDate));
131 T1,
p_->termStructure()->timeFromReference(fixingEndDate));
132 Time T3 = std::max(T2,
p_->termStructure()->timeFromReference(cpn->date()));
136 cpn->dayCounter().yearFraction(cpn->accrualStartDate(), cpn->accrualEndDate(),
137 cpn->referencePeriodStart(), cpn->referencePeriodEnd()) /
138 swap->iborIndex()->dayCounter().yearFraction(fixingValueDate, fixingEndDate);
140 if (!QuantLib::close_enough(adjFactor, 1.0)) {
144 }
else if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<OvernightIndexedCoupon>(c)) {
145 Date start = cpn->valueDates().front();
146 Date end = cpn->valueDates().back();
147 Time T1 = std::max(t,
p_->termStructure()->timeFromReference(start));
148 Time T2 = std::max(T1,
p_->termStructure()->timeFromReference(end));
149 Time T3 = std::max(T2,
p_->termStructure()->timeFromReference(cpn->date()));
153 cpn->dayCounter().yearFraction(cpn->accrualStartDate(), cpn->accrualEndDate(),
154 cpn->referencePeriodStart(), cpn->referencePeriodEnd()) /
155 swap->iborIndex()->dayCounter().yearFraction(start, end);
157 if (cpn->averagingMethod() == RateAveraging::Compound) {
159 }
else if (cpn->averagingMethod() == RateAveraging::Simple) {
162 QL_FAIL(
"LgmVectorised::fixing(): RateAveraging '"
163 <<
static_cast<int>(cpn->averagingMethod())
164 <<
"' not handled - internal error, contact dev.");
166 if (!QuantLib::close_enough(adjFactor, 1.0)) {
171 QL_FAIL(
"LgmVectorised::fixing(): expected ibor coupon");
174 for (
auto const& c : fixedLeg) {
175 auto cpn = QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(c);
176 QL_REQUIRE(cpn,
"LgmVectorised::fixing(): expected fixed coupon");
177 Date d = cpn->date();
178 Time T = std::max(t,
p_->termStructure()->timeFromReference(d));
182 return numerator / denominator;
185 QL_FAIL(
"LgmVectorised::fixing(): index ('" << index->name() <<
"') must be ibor or swap index");
190 const std::vector<Date>& fixingDates,
191 const std::vector<Date>& valueDates,
const std::vector<Real>& dt,
192 const Natural rateCutoff,
const bool includeSpread,
const Real spread,
193 const Real gearing,
const Period lookback, Real cap, Real floor,
194 const bool localCapFloor,
const bool nakedOption,
const Time t,
197 QL_REQUIRE(!includeSpread || QuantLib::close_enough(gearing, 1.0),
198 "LgmVectorised::compoundedOnRate(): if include spread = true, only a gearing 1.0 is allowed - scale "
199 "the notional in this case instead.");
201 QL_REQUIRE(rateCutoff < dt.size(),
"LgmVectorised::compoundedOnRate(): rate cutoff ("
202 << rateCutoff <<
") must be less than number of fixings in period ("
203 << dt.size() <<
")");
214 Size i = 0, n = dt.size();
215 Size nCutoff = n - rateCutoff;
216 Real compoundFactor = 1.0, compoundFactorWithoutSpread = 1.0;
218 Date today = Settings::instance().evaluationDate();
220 while (i < n && fixingDates[std::min(i, nCutoff)] < today) {
221 Rate pastFixing = IndexManager::instance().getHistory(index->name())[fixingDates[std::min(i, nCutoff)]];
222 QL_REQUIRE(pastFixing != Null<Real>(),
"LgmVectorised::compoundedOnRate(): Missing "
223 << index->name() <<
" fixing for "
224 << fixingDates[std::min(i, nCutoff)]);
226 compoundFactorWithoutSpread *= (1.0 + pastFixing * dt[i]);
227 pastFixing += spread;
229 compoundFactor *= (1.0 + pastFixing * dt[i]);
233 if (i < n && fixingDates[std::min(i, nCutoff)] == today) {
234 Rate pastFixing = IndexManager::instance().getHistory(index->name())[fixingDates[std::min(i, nCutoff)]];
235 if (pastFixing != Null<Real>()) {
237 compoundFactorWithoutSpread *= (1.0 + pastFixing * dt[i]);
238 pastFixing += spread;
240 compoundFactor *= (1.0 + pastFixing * dt[i]);
246 compoundFactorWithoutSpreadLgm(x.
size(), compoundFactorWithoutSpread);
249 Handle<YieldTermStructure> curve = index->forwardingTermStructure();
250 QL_REQUIRE(!curve.empty(),
251 "LgmVectorised::compoundedOnRate(): null term structure set to this instance of " << index->name());
253 DiscountFactor startDiscount = curve->discount(valueDates[i]);
254 DiscountFactor endDiscount = curve->discount(valueDates[std::max(nCutoff, i)]);
257 DiscountFactor discountCutoffDate =
258 curve->discount(valueDates[nCutoff] + 1) / curve->discount(valueDates[nCutoff]);
259 endDiscount *= std::pow(discountCutoffDate, valueDates[n] - valueDates[nCutoff]);
264 Real T1 =
p_->termStructure()->timeFromReference(valueDates[i]);
265 Real T2 =
p_->termStructure()->timeFromReference(valueDates[n]);
269 Real T1_lgm = T1, T2_lgm = T2;
287 compoundFactorLgm *= disc1 / disc2;
290 compoundFactorWithoutSpreadLgm *= disc1 / disc2;
292 index->dayCounter().yearFraction(valueDates[i], valueDates.back()) / (valueDates.back() - valueDates[i]);
294 x.
size(), std::pow(1.0 + tau * spread,
static_cast<int>(valueDates.back() - valueDates[i])));
298 Rate tau = index->dayCounter().yearFraction(valueDates.front(), valueDates.back());
302 if (!includeSpread) {
305 effectiveIndexFixing = rate;
309 effectiveIndexFixing = rate - effectiveSpread;
312 if (cap == Null<Real>() && floor == Null<Real>())
318 std::swap(cap, floor);
327 if (floor != Null<Real>()) {
335 if (cap != Null<Real>()) {
340 if (nakedOption && floor == Null<Real>())
341 capletRate = -capletRate;
344 return swapletRate + floorletRate - capletRate;
348 const std::vector<Date>& fixingDates,
const std::vector<Date>& valueDates,
349 const std::vector<Real>& dt,
const Natural rateCutoff,
350 const bool includeSpread,
const Real spread,
const Real gearing,
351 const Period lookback, Real cap, Real floor,
const bool localCapFloor,
352 const bool nakedOption,
const Time t,
const RandomVariable& x)
const {
354 QL_REQUIRE(!includeSpread || QuantLib::close_enough(gearing, 1.0),
355 "LgmVectorised::averageOnRate(): if include spread = true, only a gearing 1.0 is allowed - scale "
356 "the notional in this case instead.");
358 QL_REQUIRE(rateCutoff < dt.size(),
"LgmVectorised::averageOnRate(): rate cutoff ("
359 << rateCutoff <<
") must be less than number of fixings in period ("
360 << dt.size() <<
")");
366 Size i = 0, n = dt.size();
367 Size nCutoff = n - rateCutoff;
368 Real accumulatedRate = 0.0;
370 Date today = Settings::instance().evaluationDate();
372 while (i < n && fixingDates[std::min(i, nCutoff)] < today) {
373 Rate pastFixing = IndexManager::instance().getHistory(index->name())[fixingDates[std::min(i, nCutoff)]];
374 QL_REQUIRE(pastFixing != Null<Real>(),
"LgmVectorised::averageOnRate(): Missing "
375 << index->name() <<
" fixing for "
376 << fixingDates[std::min(i, nCutoff)]);
377 accumulatedRate += pastFixing * dt[i];
381 if (i < n && fixingDates[std::min(i, nCutoff)] == today) {
382 Rate pastFixing = IndexManager::instance().getHistory(index->name())[fixingDates[std::min(i, nCutoff)]];
383 if (pastFixing != Null<Real>()) {
384 accumulatedRate += pastFixing * dt[i];
392 Handle<YieldTermStructure> curve = index->forwardingTermStructure();
393 QL_REQUIRE(!curve.empty(),
394 "LgmVectorised::averageOnRate(): null term structure set to this instance of " << index->name());
396 DiscountFactor startDiscount = curve->discount(valueDates[i]);
397 DiscountFactor endDiscount = curve->discount(valueDates[std::max(nCutoff, i)]);
400 DiscountFactor discountCutoffDate =
401 curve->discount(valueDates[nCutoff] + 1) / curve->discount(valueDates[nCutoff]);
402 endDiscount *= std::pow(discountCutoffDate, valueDates[n] - valueDates[nCutoff]);
407 Real T1 =
p_->termStructure()->timeFromReference(valueDates[i]);
408 Real T2 =
p_->termStructure()->timeFromReference(valueDates[n]);
412 Real T1_lgm = T1, T2_lgm = T2;
430 accumulatedRateLgm +=
log(disc1 / disc2);
433 Rate tau = index->dayCounter().yearFraction(valueDates.front(), valueDates.back());
437 if (cap == Null<Real>() && floor == Null<Real>())
443 std::swap(cap, floor);
453 if (floor != Null<Real>()) {
460 if (cap != Null<Real>()) {
464 if (nakedOption && floor == Null<Real>())
465 capletRate = -capletRate;
468 return rate + floorletRate - capletRate;
472 const std::vector<Date>& fixingDates,
const Date& accrualStartDate,
473 const Date& accrualEndDate,
const bool includeSpread,
const Real spread,
474 const Real gearing, Real cap, Real floor,
const bool nakedOption,
479 Natural cutoffDays = 0;
480 Date startDate = accrualStartDate - cutoffDays;
481 Date endDate = accrualEndDate - cutoffDays;
482 Date d1 = startDate, d2 = startDate;
484 QL_REQUIRE(!fixingDates.empty(),
"LgmVectorised::averagedBmaRate(): fixing date list empty");
485 QL_REQUIRE(index->valueDate(fixingDates.front()) <= startDate,
486 "LgmVectorised::averagedBmaRate(): first fixing date valid after period start");
487 QL_REQUIRE(index->valueDate(fixingDates.back()) >= endDate,
488 "LgmVectorised::averagedBmaRate(): last fixing date valid before period end");
490 Handle<YieldTermStructure> curve = index->forwardingTermStructure();
491 QL_REQUIRE(!curve.empty(),
492 "LgmVectorised::averagedBmaRate(): null term structure set to this instance of " << index->name());
494 Date today = Settings::instance().evaluationDate();
498 for (Size i = 0; i < fixingDates.size() - 1; ++i) {
499 Date valueDate = index->valueDate(fixingDates[i]);
500 Date nextValueDate = index->valueDate(fixingDates[i + 1]);
501 if (fixingDates[i] >= endDate || valueDate >= endDate)
503 if (fixingDates[i + 1] < startDate || nextValueDate <= startDate)
506 d2 = std::min(nextValueDate, endDate);
508 if (fixingDates[i] <= today) {
513 Date start = index->fixingCalendar().advance(fixingDates[i], 1, Days);
514 Date end = index->maturityDate(start);
515 DiscountFactor startDiscount = curve->discount(start);
516 DiscountFactor endDiscount = curve->discount(end);
520 Real T1 =
p_->termStructure()->timeFromReference(start);
521 Real T2 =
p_->termStructure()->timeFromReference(end);
525 Real T1_lgm = T1, T2_lgm = T2;
554 if (cap == Null<Real>() && floor == Null<Real>())
560 std::swap(cap, floor);
570 if (floor != Null<Real>()) {
577 if (cap != Null<Real>()) {
581 if (nakedOption && floor == Null<Real>())
582 capletRate = -capletRate;
585 return avgBMA + floorletRate - capletRate;
589 const std::vector<Date>& fixingDates,
const Time t,
592 return fixing(index, fixingDates.front(), t, x);
QuantLib::ext::shared_ptr< IrLgm1fParametrization > p_
RandomVariable discountBond(const Time t, const Time T, const RandomVariable &x, const Handle< YieldTermStructure > &discountCurve=Handle< YieldTermStructure >()) const
RandomVariable averagedOnRate(const QuantLib::ext::shared_ptr< OvernightIndex > &index, const std::vector< Date > &fixingDates, const std::vector< Date > &valueDates, const std::vector< Real > &dt, const Natural rateCutoff, const bool includeSpread, const Real spread, const Real gearing, const Period lookback, Real cap, Real floor, const bool localCapFloor, const bool nakedOption, const Time t, const RandomVariable &x) const
RandomVariable averagedBmaRate(const QuantLib::ext::shared_ptr< BMAIndex > &index, const std::vector< Date > &fixingDates, const Date &accrualStartDate, const Date &accrualEndDate, const bool includeSpread, const Real spread, const Real gearing, Real cap, Real floor, const bool nakedOption, const Time t, const RandomVariable &x) const
RandomVariable numeraire(const Time t, const RandomVariable &x, const Handle< YieldTermStructure > &discountCurve=Handle< YieldTermStructure >()) const
RandomVariable discountBondOption(Option::Type type, const Real K, const Time t, const Time S, const Time T, const RandomVariable &x, const Handle< YieldTermStructure > &discountCurve) const
RandomVariable fixing(const QuantLib::ext::shared_ptr< InterestRateIndex > &index, const Date &fixingDate, const Time t, const RandomVariable &x) const
RandomVariable reducedDiscountBond(const Time t, const Time T, const RandomVariable &x, const Handle< YieldTermStructure > &discountCurve=Handle< YieldTermStructure >()) const
RandomVariable compoundedOnRate(const QuantLib::ext::shared_ptr< OvernightIndex > &index, const std::vector< Date > &fixingDates, const std::vector< Date > &valueDates, const std::vector< Real > &dt, const Natural rateCutoff, const bool includeSpread, const Real spread, const Real gearing, const Period lookback, Real cap, Real floor, const bool localCapFloor, const bool nakedOption, const Time t, const RandomVariable &x) const
RandomVariable subPeriodsRate(const QuantLib::ext::shared_ptr< InterestRateIndex > &index, const std::vector< Date > &fixingDates, const Time t, const RandomVariable &x) const
vectorised lgm model calculations
CompiledFormula exp(CompiledFormula x)
RandomVariable normalCdf(RandomVariable x)
CompiledFormula max(CompiledFormula x, const CompiledFormula &y)
CompiledFormula log(CompiledFormula x)