Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Classes | Public Member Functions | Static Public Member Functions | Protected Member Functions | Static Protected Member Functions | Protected Attributes | List of all members
NumericLgmMultiLegOptionEngineBase Class Reference

#include <qle/pricingengines/numericlgmmultilegoptionengine.hpp>

+ Inheritance diagram for NumericLgmMultiLegOptionEngineBase:
+ Collaboration diagram for NumericLgmMultiLegOptionEngineBase:

Classes

struct  CashflowInfo
 

Public Member Functions

 NumericLgmMultiLegOptionEngineBase (const QuantLib::ext::shared_ptr< LgmBackwardSolver > &solver, const Handle< YieldTermStructure > &discountCurve=Handle< YieldTermStructure >(), const Size americanExerciseTimeStepsPerYear=24)
 

Static Public Member Functions

static bool instrumentIsHandled (const MultiLegOption &m, std::vector< std::string > &messages)
 

Protected Member Functions

CashflowInfo buildCashflowInfo (const Size i, const Size j) const
 
void calculate () const
 

Static Protected Member Functions

static bool instrumentIsHandled (const std::vector< Leg > &legs, const std::vector< bool > &payer, const std::vector< Currency > &currency, const QuantLib::ext::shared_ptr< Exercise > &exercise, const Settlement::Type &settlementType, const Settlement::Method &settlementMethod, std::vector< std::string > &messages)
 

Protected Attributes

QuantLib::ext::shared_ptr< LgmBackwardSolversolver_
 
Handle< YieldTermStructure > discountCurve_
 
Size americanExerciseTimeStepsPerYear_
 
std::vector< Leg > legs_
 
std::vector< boolpayer_
 
std::vector< Currency > currency_
 
QuantLib::ext::shared_ptr< Exercise > exercise_
 
Settlement::Type settlementType_
 
Settlement::Method settlementMethod_
 
Real npv_
 
Real underlyingNpv_
 
std::map< std::string, boost::any > additionalResults_
 

Detailed Description

Definition at line 32 of file numericlgmmultilegoptionengine.hpp.

Constructor & Destructor Documentation

◆ NumericLgmMultiLegOptionEngineBase()

NumericLgmMultiLegOptionEngineBase ( const QuantLib::ext::shared_ptr< LgmBackwardSolver > &  solver,
const Handle< YieldTermStructure > &  discountCurve = Handle<YieldTermStructure>(),
const Size  americanExerciseTimeStepsPerYear = 24 
)

Definition at line 268 of file numericlgmmultilegoptionengine.cpp.

271 : solver_(solver), discountCurve_(discountCurve),
272 americanExerciseTimeStepsPerYear_(americanExerciseTimeStepsPerYear) {}
QuantLib::ext::shared_ptr< LgmBackwardSolver > solver_

Member Function Documentation

◆ instrumentIsHandled() [1/2]

bool instrumentIsHandled ( const MultiLegOption m,
std::vector< std::string > &  messages 
)
static

Definition at line 274 of file numericlgmmultilegoptionengine.cpp.

275 {
276 return instrumentIsHandled(m.legs(), m.payer(), m.currency(), m.exercise(), m.settlementType(),
277 m.settlementMethod(), messages);
278}
static bool instrumentIsHandled(const MultiLegOption &m, std::vector< std::string > &messages)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ instrumentIsHandled() [2/2]

bool instrumentIsHandled ( const std::vector< Leg > &  legs,
const std::vector< bool > &  payer,
const std::vector< Currency > &  currency,
const QuantLib::ext::shared_ptr< Exercise > &  exercise,
const Settlement::Type &  settlementType,
const Settlement::Method &  settlementMethod,
std::vector< std::string > &  messages 
)
staticprotected

Definition at line 280 of file numericlgmmultilegoptionengine.cpp.

283 {
284
285 bool isHandled = true;
286
287 // is there a unique pay currency and all interest rate indices are in this same currency?
288
289 for (Size i = 1; i < currency.size(); ++i) {
290 if (currency[0] != currency[i]) {
291 messages.push_back("NumericLgmMultilegOptionEngine: can only handle single currency underlyings, got " +
292 currency[0].code() + " on leg #1 and " + currency[i].code() + " on leg #" +
293 std::to_string(i + 1));
294 isHandled = false;
295 }
296 }
297
298 for (Size i = 0; i < legs.size(); ++i) {
299 for (Size j = 0; j < legs[i].size(); ++j) {
300 if (auto cpn = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(legs[i][j])) {
301 if (cpn->index()->currency() != currency[0]) {
302 messages.push_back("NumericLgmMultilegOptionEngine: can only handle indices (" +
303 cpn->index()->name() + ") with same currency as unqiue pay currency (" +
304 currency[0].code());
305 }
306 }
307 }
308 }
309
310 // check coupon types
311
312 for (Size i = 0; i < legs.size(); ++i) {
313 for (Size j = 0; j < legs[i].size(); ++j) {
314 if (auto c = QuantLib::ext::dynamic_pointer_cast<Coupon>(legs[i][j])) {
315 if (!(QuantLib::ext::dynamic_pointer_cast<IborCoupon>(c) || QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(c) ||
316 QuantLib::ext::dynamic_pointer_cast<QuantExt::OvernightIndexedCoupon>(c) ||
317 QuantLib::ext::dynamic_pointer_cast<QuantExt::AverageONIndexedCoupon>(c) ||
318 QuantLib::ext::dynamic_pointer_cast<QuantLib::AverageBMACoupon>(c) ||
319 QuantLib::ext::dynamic_pointer_cast<QuantExt::CappedFlooredOvernightIndexedCoupon>(c) ||
320 QuantLib::ext::dynamic_pointer_cast<QuantExt::CappedFlooredAverageONIndexedCoupon>(c) ||
321 QuantLib::ext::dynamic_pointer_cast<QuantExt::CappedFlooredAverageBMACoupon>(c) ||
322 QuantLib::ext::dynamic_pointer_cast<QuantExt::SubPeriodsCoupon1>(c) ||
323 (QuantLib::ext::dynamic_pointer_cast<QuantLib::CappedFlooredCoupon>(c) &&
324 QuantLib::ext::dynamic_pointer_cast<QuantLib::IborCoupon>(
325 QuantLib::ext::dynamic_pointer_cast<QuantLib::CappedFlooredCoupon>(c)->underlying())))) {
326 messages.push_back(
327 "NumericLgmMultilegOptionEngine: coupon type not handled, supported coupon types: Fix, "
328 "(capfloored) Ibor, (capfloored) ON comp, (capfloored) ON avg, BMA/SIFMA, subperiod. leg = " +
329 std::to_string(i) + " cf = " + std::to_string(j));
330 isHandled = false;
331 }
332 }
333 }
334 }
335
336 return isHandled;
337}

◆ buildCashflowInfo()

NumericLgmMultiLegOptionEngineBase::CashflowInfo buildCashflowInfo ( const Size  i,
const Size  j 
) const
protected

Definition at line 76 of file numericlgmmultilegoptionengine.cpp.

76 {
77
78 CashflowInfo info;
79 auto const& ts = solver_->model()->parametrization()->termStructure();
80 auto const& c = legs_[i][j];
81 Real payrec = payer_[i] ? -1.0 : 1.0;
82
83 Real T = solver_->model()->parametrization()->termStructure()->timeFromReference(c->date());
84
85 if (auto cpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(c)) {
86 bool done = false;
87 if (exercise_->type() == Exercise::American) {
88 // american exercise implies that we can exercise into broken periods
89 info.belongsToUnderlyingMaxTime_ = ts->timeFromReference(cpn->accrualEndDate());
90 } else {
91 // bermudan exercise implies that we always exercise into whole periods
92 info.belongsToUnderlyingMaxTime_ = ts->timeFromReference(cpn->accrualStartDate());
93 }
94 info.couponStartTime_ = ts->timeFromReference(cpn->accrualStartDate());
95 info.couponEndTime_ = ts->timeFromReference(cpn->accrualEndDate());
96 if (auto ibor = QuantLib::ext::dynamic_pointer_cast<IborCoupon>(c)) {
97 info.maxEstimationTime_ = ts->timeFromReference(ibor->fixingDate());
98 info.calculator_ = [ibor, T, payrec](const LgmVectorised& lgm, const Real t, const RandomVariable& x,
99 const Handle<YieldTermStructure>& discountCurve) {
100 return (RandomVariable(x.size(), ibor->gearing()) *
101 lgm.fixing(ibor->index(), ibor->fixingDate(), t, x) +
102 RandomVariable(x.size(), ibor->spread())) *
103 RandomVariable(x.size(), ibor->accrualPeriod() * ibor->nominal() * payrec) *
104 lgm.reducedDiscountBond(t, T, x, discountCurve);
105 };
106 done = true;
107 } else if (auto fix = QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(cpn)) {
108 info.maxEstimationTime_ = ts->timeFromReference(fix->date());
109 info.calculator_ = [fix, T, payrec](const LgmVectorised& lgm, const Real t, const RandomVariable& x,
110 const Handle<YieldTermStructure>& discountCurve) {
111 return RandomVariable(x.size(), fix->amount() * payrec) *
112 lgm.reducedDiscountBond(t, T, x, discountCurve);
113 };
114 done = true;
115 } else if (auto on = QuantLib::ext::dynamic_pointer_cast<QuantExt::OvernightIndexedCoupon>(cpn)) {
116 info.maxEstimationTime_ = ts->timeFromReference(on->fixingDates().front());
117 info.calculator_ = [on, T, payrec](const LgmVectorised& lgm, const Real t, const RandomVariable& x,
118 const Handle<YieldTermStructure>& discountCurve) {
119 return lgm.compoundedOnRate(QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(on->index()), on->fixingDates(),
120 on->valueDates(), on->dt(), on->rateCutoff(), on->includeSpread(),
121 on->spread(), on->gearing(), on->lookback(), Null<Real>(), Null<Real>(),
122 false, false, t, x) *
123 RandomVariable(x.size(), on->accrualPeriod() * on->nominal() * payrec) *
124 lgm.reducedDiscountBond(t, T, x, discountCurve);
125 };
126 done = true;
127 } else if (auto av = QuantLib::ext::dynamic_pointer_cast<QuantExt::AverageONIndexedCoupon>(cpn)) {
128 info.maxEstimationTime_ = ts->timeFromReference(av->fixingDates().front());
129 info.calculator_ = [av, T, payrec](const LgmVectorised& lgm, const Real t, const RandomVariable& x,
130 const Handle<YieldTermStructure>& discountCurve) {
131 return lgm.averagedOnRate(QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(av->index()), av->fixingDates(),
132 av->valueDates(), av->dt(), av->rateCutoff(), false, av->spread(),
133 av->gearing(), av->lookback(), Null<Real>(), Null<Real>(), false, false, t,
134 x) *
135 RandomVariable(x.size(), av->accrualPeriod() * av->nominal() * payrec) *
136 lgm.reducedDiscountBond(t, T, x, discountCurve);
137 };
138 done = true;
139 } else if (auto bma = QuantLib::ext::dynamic_pointer_cast<QuantLib::AverageBMACoupon>(cpn)) {
140 info.maxEstimationTime_ = ts->timeFromReference(bma->fixingDates().front());
141 info.calculator_ = [bma, T, payrec](const LgmVectorised& lgm, const Real t, const RandomVariable& x,
142 const Handle<YieldTermStructure>& discountCurve) {
143 return lgm.averagedBmaRate(QuantLib::ext::dynamic_pointer_cast<BMAIndex>(bma->index()), bma->fixingDates(),
144 bma->accrualStartDate(), bma->accrualEndDate(), false, bma->spread(),
145 bma->gearing(), Null<Real>(), Null<Real>(), false, t, x) *
146 RandomVariable(x.size(), bma->accrualPeriod() * bma->nominal() * payrec) *
147 lgm.reducedDiscountBond(t, T, x, discountCurve);
148 };
149 done = true;
150 } else if (auto cf = QuantLib::ext::dynamic_pointer_cast<QuantLib::CappedFlooredCoupon>(cpn)) {
151 auto und = cf->underlying();
152 if (auto undibor = QuantLib::ext::dynamic_pointer_cast<QuantLib::IborCoupon>(und)) {
153 info.exactEstimationTime_ = ts->timeFromReference(und->fixingDate());
154 info.calculator_ = [cf, undibor, T, payrec](const LgmVectorised& lgm, const Real t,
155 const RandomVariable& x,
156 const Handle<YieldTermStructure>& discountCurve) {
157 RandomVariable cap(x.size(), cf->cap() == Null<Real>() ? QL_MAX_REAL : cf->cap());
158 RandomVariable floor(x.size(), cf->floor() == Null<Real>() ? -QL_MAX_REAL : cf->floor());
159
160 return max(floor, min(cap, (RandomVariable(x.size(), undibor->gearing()) *
161 lgm.fixing(undibor->index(), undibor->fixingDate(), t, x) +
162 RandomVariable(x.size(), undibor->spread())))) *
163 RandomVariable(x.size(), undibor->accrualPeriod() * undibor->nominal() * payrec) *
164 lgm.reducedDiscountBond(t, T, x, discountCurve);
165 };
166 done = true;
167 }
168 } else if (auto cfon = QuantLib::ext::dynamic_pointer_cast<QuantExt::CappedFlooredOvernightIndexedCoupon>(cpn)) {
169 auto und = cfon->underlying();
170 info.exactEstimationTime_ = ts->timeFromReference(und->fixingDates().front());
171 info.calculator_ = [cfon, und, T, payrec](const LgmVectorised& lgm, const Real t, const RandomVariable& x,
172 const Handle<YieldTermStructure>& discountCurve) {
173 return lgm.compoundedOnRate(QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(und->index()),
174 und->fixingDates(), und->valueDates(), und->dt(), und->rateCutoff(),
175 und->includeSpread(), und->spread(), und->gearing(), und->lookback(),
176 cfon->cap(), cfon->floor(), cfon->localCapFloor(), cfon->nakedOption(), t,
177 x) *
178 RandomVariable(x.size(), cfon->accrualPeriod() * cfon->nominal() * payrec) *
179 lgm.reducedDiscountBond(t, T, x, discountCurve);
180 };
181 done = true;
182 } else if (auto cfav = QuantLib::ext::dynamic_pointer_cast<QuantExt::CappedFlooredAverageONIndexedCoupon>(cpn)) {
183 auto und = cfav->underlying();
184 info.exactEstimationTime_ = ts->timeFromReference(und->fixingDates().front());
185 info.calculator_ = [cfav, und, T, payrec](const LgmVectorised& lgm, const Real t, const RandomVariable& x,
186 const Handle<YieldTermStructure>& discountCurve) {
187 return lgm.averagedOnRate(QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(und->index()), und->fixingDates(),
188 und->valueDates(), und->dt(), und->rateCutoff(), cfav->includeSpread(),
189 und->spread(), und->gearing(), und->lookback(), cfav->cap(), cfav->floor(),
190 cfav->localCapFloor(), cfav->nakedOption(), t, x) *
191 RandomVariable(x.size(), cfav->accrualPeriod() * cfav->nominal() * payrec) *
192 lgm.reducedDiscountBond(t, T, x, discountCurve);
193 };
194 done = true;
195 } else if (auto cfbma = QuantLib::ext::dynamic_pointer_cast<QuantExt::CappedFlooredAverageBMACoupon>(cpn)) {
196 auto und = cfbma->underlying();
197 info.exactEstimationTime_ = ts->timeFromReference(und->fixingDates().front());
198 info.calculator_ = [cfbma, und, T, payrec](const LgmVectorised& lgm, const Real t, const RandomVariable& x,
199 const Handle<YieldTermStructure>& discountCurve) {
200 return lgm.averagedBmaRate(QuantLib::ext::dynamic_pointer_cast<BMAIndex>(und->index()), und->fixingDates(),
201 und->accrualStartDate(), und->accrualEndDate(), cfbma->includeSpread(),
202 und->spread(), und->gearing(), cfbma->cap(), cfbma->floor(),
203 cfbma->nakedOption(), t, x) *
204 RandomVariable(x.size(), cfbma->accrualPeriod() * cfbma->nominal() * payrec) *
205 lgm.reducedDiscountBond(t, T, x, discountCurve);
206 };
207 done = true;
208 } else if (auto sub = QuantLib::ext::dynamic_pointer_cast<QuantExt::SubPeriodsCoupon1>(cpn)) {
209 info.maxEstimationTime_ = ts->timeFromReference(sub->fixingDates().front());
210 info.calculator_ = [sub, T, payrec](const LgmVectorised& lgm, const Real t, const RandomVariable& x,
211 const Handle<YieldTermStructure>& discountCurve) {
212 return lgm.subPeriodsRate(sub->index(), sub->fixingDates(), t, x) *
213 RandomVariable(x.size(), sub->accrualPeriod() * sub->nominal() * payrec) *
214 lgm.reducedDiscountBond(t, T, x, discountCurve);
215 };
216 done = true;
217 }
218 QL_REQUIRE(done, "NumericLgmMultiLegOptionEngineBase: coupon type not handled, supported coupon types: Fix, "
219 "(capfloored) Ibor, (capfloored) ON comp, (capfloored) ON avg, BMA/SIFMA, subperiod. leg = "
220 << i << " cf = " << j);
221 } else {
222 // can not cast to coupon
223 info.belongsToUnderlyingMaxTime_ = ts->timeFromReference(c->date());
224 info.maxEstimationTime_ = ts->timeFromReference(c->date());
225 info.calculator_ = [c, T, payrec](const LgmVectorised& lgm, const Real t, const RandomVariable& x,
226 const Handle<YieldTermStructure>& discountCurve) {
227 return RandomVariable(x.size(), c->amount() * payrec) * lgm.reducedDiscountBond(t, T, x, discountCurve);
228 };
229 }
230
231 // some postprocessing and checks
232
233 info.maxEstimationTime_ = std::max(0.0, info.maxEstimationTime_);
234 info.exactEstimationTime_ = std::max(0.0, info.exactEstimationTime_);
235
236 QL_REQUIRE(
237 info.belongsToUnderlyingMaxTime_ != Null<Real>(),
238 "NumericLgmMultiLegOptionEngineBase: internal error: cashflow info: belongsToUnderlyingMaxTime_ is null. leg = "
239 << i << " cf = " << j);
240 QL_REQUIRE(info.maxEstimationTime_ != Null<Real>() || info.exactEstimationTime_ != Null<Real>(),
241 "NumericLgmMultiLegOptionEngineBase: internal error: both maxEstimationTime_ and exactEstimationTime_ "
242 "is null. leg = "
243 << i << " cf = " << j);
244 return info;
245}
CompiledFormula min(CompiledFormula x, const CompiledFormula &y)
CompiledFormula max(CompiledFormula x, const CompiledFormula &y)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ calculate()

void calculate ( ) const
protected

Definition at line 339 of file numericlgmmultilegoptionengine.cpp.

339 {
340
341 std::vector<std::string> messages;
342 QL_REQUIRE(
344 "NumericLgmMultiLegOptionEngineBase::calculate(): instrument is not handled: " << boost::join(messages, ", "));
345
346 // handle empty exercise
347
348 if (exercise_ == nullptr) {
349 npv_ = 0.0;
350 for (Size i = 0; i < legs_.size(); ++i) {
351 for (Size j = 0; j < legs_[i].size(); ++j) {
352 npv_ += legs_[i][j]->amount() * discountCurve_->discount(legs_[i][j]->date());
353 }
354 }
356 return;
357 }
358
359 // we have a non-empty exercise
360
361 auto rebatedExercise = QuantLib::ext::dynamic_pointer_cast<QuantExt::RebatedExercise>(exercise_);
362 auto const& ts = solver_->model()->parametrization()->termStructure();
363 Date refDate = ts->referenceDate();
364
365 /* Build the cashflow info */
366
367 enum class CashflowStatus { Open, Cached, Done };
368
369 std::vector<CashflowInfo> cashflows;
370 std::vector<CashflowStatus> cashflowStatus;
371
372 for (Size i = 0; i < legs_.size(); ++i) {
373 for (Size j = 0; j < legs_[i].size(); ++j) {
374 cashflows.push_back(buildCashflowInfo(i, j));
375 cashflowStatus.push_back(CashflowStatus::Open);
376 }
377 }
378
379 /* Build the time grid containing the option times */
380
381 std::set<Real> optionTimes;
382 std::map<Real, Date> optionDates;
383
384 if (exercise_->type() == Exercise::Bermudan || exercise_->type() == Exercise::European) {
385 for (auto const& d : exercise_->dates()) {
386 if (d > refDate) {
387 optionTimes.insert(ts->timeFromReference(d));
388 optionDates[ts->timeFromReference(d)] = d;
389 }
390 }
391 } else if (exercise_->type() == Exercise::American) {
392 QL_REQUIRE(exercise_->dates().size() == 2, "NumericLgmMultiLegOptionEngineBase::calculate(): internal error: "
393 "expected 2 dates for AmericanExercise, got "
394 << exercise_->dates().size());
395 Real t1 = std::max(0.0, ts->timeFromReference(exercise_->dates().front()));
396 Real t2 = std::max(t1, ts->timeFromReference(exercise_->dates().back()));
397 Size steps =
398 std::max<Size>(1, static_cast<Size>((t2 - t1) * static_cast<Real>(americanExerciseTimeStepsPerYear_)));
399 optionTimes.insert(t1);
400 for (Size i = 0; i <= steps; ++i) {
401 optionTimes.insert(t1 + static_cast<Real>(i) * (t2 - t1) / static_cast<Real>(steps));
402 }
403 } else {
404 QL_FAIL("NumericLgmMultiLegOptionEngineBase::calculate(): internal error: exercise type "
405 << static_cast<int>(exercise_->type()) << " not handled.");
406 }
407
408 /* Add specific times required to simulate cashflows */
409
410 std::set<Real> requiredCfSimTimes;
411
412 for (auto const& c : cashflows) {
413 if (Real t = c.requiredSimulationTime(); t != Null<Real>())
414 requiredCfSimTimes.insert(t);
415 }
416
417 /* Join the two grids to get the time grid which we use for the backward run */
418
419 std::set<Real> timeGrid{0.0};
420 timeGrid.insert(optionTimes.begin(), optionTimes.end());
421 timeGrid.insert(requiredCfSimTimes.begin(), requiredCfSimTimes.end());
422
423 /* Step backwards through the grid and compute the option npv */
424
425 LgmVectorised lgm(solver_->model()->parametrization());
426
427 RandomVariable underlyingNpv(solver_->gridSize(), 0.0);
428 RandomVariable optionNpv(solver_->gridSize(), 0.0);
429 RandomVariable provisionalNpv(solver_->gridSize(), 0.0);
430
431 std::vector<RandomVariable> cache(cashflows.size());
432
433 for (auto it = timeGrid.rbegin(); it != timeGrid.rend(); ++it) {
434
435 Real t_from = *it;
436 Real t_to = (it != std::next(timeGrid.rend(), -1)) ? *std::next(it, 1) : t_from;
437
438 RandomVariable state = solver_->stateGrid(t_from);
439
440 // update cashflows on current time
441
442 provisionalNpv = RandomVariable(solver_->gridSize(), 0.0);
443
444 for (Size i = 0; i < cashflows.size(); ++i) {
445 if (cashflowStatus[i] == CashflowStatus::Done)
446 continue;
447 if (cashflows[i].isPartOfUnderlying(t_from)) {
448 RandomVariable cpnRatio(solver_->gridSize(), cashflows[i].couponRatio(t_from));
449 bool isBrokenCoupon = !QuantLib::close_enough(cpnRatio.at(0), 1.0);
450 if (cashflowStatus[i] == CashflowStatus::Cached) {
451 if (isBrokenCoupon) {
452 provisionalNpv += cache[i] * cpnRatio;
453 } else {
454 underlyingNpv += cache[i];
455 cache[i].clear();
456 cashflowStatus[i] = CashflowStatus::Done;
457 }
458 } else if (cashflows[i].canBeEstimated(t_from)) {
459 if (isBrokenCoupon) {
460 cache[i] = cashflows[i].pv(lgm, t_from, state, discountCurve_);
461 cashflowStatus[i] = CashflowStatus::Cached;
462 provisionalNpv += cache[i] * cpnRatio;
463 } else {
464 underlyingNpv += cashflows[i].pv(lgm, t_from, state, discountCurve_);
465 cashflowStatus[i] = CashflowStatus::Done;
466 }
467 } else {
468 provisionalNpv += cashflows[i].pv(lgm, t_from, state, discountCurve_) * cpnRatio;
469 }
470 } else if (cashflows[i].mustBeEstimated(t_from) && cashflowStatus[i] == CashflowStatus::Open) {
471 cache[i] = cashflows[i].pv(lgm, t_from, state, discountCurve_);
472 cashflowStatus[i] = CashflowStatus::Cached;
473 }
474 }
475
476 // process optionality
477
478 if (optionTimes.find(t_from) != optionTimes.end()) {
479 auto rebateNpv =
480 getRebatePv(lgm, t_from, state, discountCurve_, rebatedExercise,
481 exercise_->type() == Exercise::American ? Null<Date>() : optionDates.at(t_from));
482 optionNpv = max(optionNpv, underlyingNpv + provisionalNpv + rebateNpv);
483 }
484
485 // roll back
486
487 if (t_from != t_to) {
488 underlyingNpv = solver_->rollback(underlyingNpv, t_from, t_to);
489 optionNpv = solver_->rollback(optionNpv, t_from, t_to);
490 for (auto& c : cache) {
491 if (!c.initialised())
492 continue;
493 c = solver_->rollback(c, t_from, t_to);
494 }
495 // need to roll back provisionalNpv only for the last step t_1 -> t_0 = 0
496 if (it == std::next(timeGrid.rend(), -1))
497 provisionalNpv = solver_->rollback(provisionalNpv, t_from, t_to);
498 }
499 }
500
501 /* Set the results */
502
503 npv_ = optionNpv.at(0);
504 underlyingNpv_ = underlyingNpv.at(0);
505 for (auto const& c : cache) {
506 if (c.initialised())
507 underlyingNpv_ += c.at(0);
508 }
509 underlyingNpv_ += provisionalNpv.at(0);
510
511 additionalResults_ = getAdditionalResultsMap(solver_->model()->getCalibrationInfo());
512
513 if (rebatedExercise) {
514 for (Size i = 0; i < rebatedExercise->dates().size(); ++i) {
515 std::ostringstream d;
516 d << QuantLib::io::iso_date(rebatedExercise->dates()[i]);
517 additionalResults_["exerciseFee_" + d.str()] = -rebatedExercise->rebate(i);
518 }
519 }
520
521} // NumericLgmMultiLegOptionEngineBase::calculate()
CashflowInfo buildCashflowInfo(const Size i, const Size j) const
std::map< std::string, boost::any > getAdditionalResultsMap(const LgmCalibrationInfo &info)
RandomVariable getRebatePv(const LgmVectorised &lgm, const Real t, const RandomVariable &x, const Handle< YieldTermStructure > &discountCurve, const QuantLib::ext::shared_ptr< RebatedExercise > &exercise, const Date &d)
std::vector< Size > steps
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ solver_

QuantLib::ext::shared_ptr<LgmBackwardSolver> solver_
protected

Definition at line 69 of file numericlgmmultilegoptionengine.hpp.

◆ discountCurve_

Handle<YieldTermStructure> discountCurve_
protected

Definition at line 70 of file numericlgmmultilegoptionengine.hpp.

◆ americanExerciseTimeStepsPerYear_

Size americanExerciseTimeStepsPerYear_
protected

Definition at line 71 of file numericlgmmultilegoptionengine.hpp.

◆ legs_

std::vector<Leg> legs_
mutableprotected

Definition at line 74 of file numericlgmmultilegoptionengine.hpp.

◆ payer_

std::vector<bool> payer_
mutableprotected

Definition at line 75 of file numericlgmmultilegoptionengine.hpp.

◆ currency_

std::vector<Currency> currency_
mutableprotected

Definition at line 76 of file numericlgmmultilegoptionengine.hpp.

◆ exercise_

QuantLib::ext::shared_ptr<Exercise> exercise_
mutableprotected

Definition at line 77 of file numericlgmmultilegoptionengine.hpp.

◆ settlementType_

Settlement::Type settlementType_
mutableprotected

Definition at line 78 of file numericlgmmultilegoptionengine.hpp.

◆ settlementMethod_

Settlement::Method settlementMethod_
mutableprotected

Definition at line 79 of file numericlgmmultilegoptionengine.hpp.

◆ npv_

Real npv_
mutableprotected

Definition at line 82 of file numericlgmmultilegoptionengine.hpp.

◆ underlyingNpv_

Real underlyingNpv_
protected

Definition at line 82 of file numericlgmmultilegoptionengine.hpp.

◆ additionalResults_

std::map<std::string, boost::any> additionalResults_
mutableprotected

Definition at line 83 of file numericlgmmultilegoptionengine.hpp.