73 {
74 CashflowInfo info;
75
76
77
78 info.legNo = legNo;
79 info.cfNo = cfNo;
80 info.payTime =
time(flow->date());
81 info.payCcyIndex =
model_->ccyIndex(payCcy);
82 info.payer = payer;
83
84 if (auto cpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(flow)) {
85 QL_REQUIRE(cpn->accrualStartDate() < flow->date(),
86 "McMultiLegBaseEngine::createCashflowInfo(): coupon leg "
87 << legNo << " cashflow " << cfNo << " has accrual start date (" << cpn->accrualStartDate()
88 << ") >= pay date (" << flow->date()
89 << "), which breaks an assumption in the engine. This situation is unexpected.");
90 info.exIntoCriterionTime =
time(cpn->accrualStartDate()) +
tinyTime;
91 } else {
92 info.exIntoCriterionTime = info.payTime;
93 }
94
95
96 if (QuantLib::ext::dynamic_pointer_cast<SimpleCashFlow>(flow) != nullptr) {
97 info.amountCalculator = [flow](const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
98 return RandomVariable(n, flow->amount());
99 };
100 return info;
101 }
102
103
104 if (auto fxl = QuantLib::ext::dynamic_pointer_cast<FXLinkedCashFlow>(flow)) {
105 Date fxLinkedFixingDate = fxl->fxFixingDate();
106 Size fxLinkedSourceCcyIdx =
model_->ccyIndex(fxl->fxIndex()->sourceCurrency());
107 Size fxLinkedTargetCcyIdx =
model_->ccyIndex(fxl->fxIndex()->targetCurrency());
108 if (fxLinkedFixingDate >
today_) {
109 Real fxSimTime =
time(fxLinkedFixingDate);
110 info.simulationTimes.push_back(fxSimTime);
111 info.modelIndices.push_back({});
112 if (fxLinkedSourceCcyIdx > 0) {
113 info.modelIndices.front().push_back(
115 }
116 if (fxLinkedTargetCcyIdx > 0) {
117 info.modelIndices.front().push_back(
119 }
120 }
121 info.amountCalculator = [this, fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx, fxLinkedFixingDate,
122 fxl](const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
123 if (fxLinkedFixingDate <=
today_)
124 return RandomVariable(n, fxl->amount());
125 RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
126 Size fxIdx = 0;
127 if (fxLinkedSourceCcyIdx > 0)
128 fxSource =
exp(*states.at(0).at(fxIdx++));
129 if (fxLinkedTargetCcyIdx > 0)
130 fxTarget =
exp(*states.at(0).at(fxIdx));
131 return RandomVariable(n, fxl->foreignAmount()) * fxSource / fxTarget;
132 };
133
134 return info;
135 }
136
137
138 bool isFxLinked = false;
139 bool isFxIndexed = false;
140 Size fxLinkedSourceCcyIdx = Null<Size>();
141 Size fxLinkedTargetCcyIdx = Null<Size>();
142 Real fxLinkedFixedFxRate = Null<Real>();
143 Real fxLinkedSimTime = Null<Real>();
144 Real fxLinkedForeignNominal = Null<Real>();
145 std::vector<Size> fxLinkedModelIndices;
146
147
148 if (auto indexCpn = QuantLib::ext::dynamic_pointer_cast<IndexedCoupon>(flow)) {
149 if (auto fxIndex = QuantLib::ext::dynamic_pointer_cast<FxIndex>(indexCpn->index())) {
150 isFxIndexed = true;
152 fxLinkedSourceCcyIdx =
model_->ccyIndex(fxIndex->sourceCurrency());
153 fxLinkedTargetCcyIdx =
model_->ccyIndex(fxIndex->targetCurrency());
154 if (fixingDate <=
today_) {
155 fxLinkedFixedFxRate = fxIndex->fixing(fixingDate);
156 } else {
157 fxLinkedSimTime =
time(fixingDate);
158 if (fxLinkedSourceCcyIdx > 0) {
159 fxLinkedModelIndices.push_back(
161 }
162 if (fxLinkedTargetCcyIdx > 0) {
163 fxLinkedModelIndices.push_back(
165 }
166 }
167 flow = indexCpn->underlying();
168 }
169 } else if (auto fxl = QuantLib::ext::dynamic_pointer_cast<FloatingRateFXLinkedNotionalCoupon>(flow)) {
170 isFxLinked = true;
172 fxLinkedSourceCcyIdx =
model_->ccyIndex(fxl->fxIndex()->sourceCurrency());
173 fxLinkedTargetCcyIdx =
model_->ccyIndex(fxl->fxIndex()->targetCurrency());
174 if (fixingDate <=
today_) {
175 fxLinkedFixedFxRate = fxl->fxIndex()->fixing(fixingDate);
176 } else {
177 fxLinkedSimTime =
time(fixingDate);
178 if (fxLinkedSourceCcyIdx > 0) {
180 }
181 if (fxLinkedTargetCcyIdx > 0) {
183 }
184 }
185 flow = fxl->underlying();
186 fxLinkedForeignNominal = fxl->foreignAmount();
187 }
188
189 bool isCapFloored = false;
190 bool isNakedOption = false;
191 Real effCap = Null<Real>(), effFloor = Null<Real>();
192 if (auto stripped = QuantLib::ext::dynamic_pointer_cast<StrippedCappedFlooredCoupon>(flow)) {
193 isNakedOption = true;
194 flow = stripped->underlying();
195 }
196
197 if (auto cf = QuantLib::ext::dynamic_pointer_cast<CappedFlooredCoupon>(flow)) {
198 isCapFloored = true;
199 effCap = cf->effectiveCap();
200 effFloor = cf->effectiveFloor();
201 flow = cf->underlying();
202 }
203
204
205
206 if (QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(flow) != nullptr) {
207
208 if (fxLinkedSimTime != Null<Real>()) {
209 info.simulationTimes.push_back(fxLinkedSimTime);
210 info.modelIndices.push_back(fxLinkedModelIndices);
211 }
212
213 info.amountCalculator = [flow, isFxLinked, isFxIndexed, fxLinkedFixedFxRate,
214 fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx](const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
215 RandomVariable fxFixing(n, 1.0);
216 if (isFxLinked || isFxIndexed) {
217 if (fxLinkedFixedFxRate != Null<Real>()) {
218 fxFixing = RandomVariable(n, fxLinkedFixedFxRate);
219 } else {
220 RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
221 Size fxIdx = 0;
222 if (fxLinkedSourceCcyIdx > 0)
223 fxSource =
exp(*states.at(0).at(fxIdx++));
224 if (fxLinkedTargetCcyIdx > 0)
225 fxTarget =
exp(*states.at(0).at(fxIdx));
226 fxFixing = fxSource / fxTarget;
227 }
228 }
229 return fxFixing * RandomVariable(n, flow->amount());
230 };
231 return info;
232 }
233
234 if (auto ibor = QuantLib::ext::dynamic_pointer_cast<IborCoupon>(flow)) {
235 Real fixedRate =
236 ibor->fixingDate() <=
today_ ? (ibor->rate() - ibor->spread()) / ibor->gearing() : Null<Real>();
237 Size indexCcyIdx =
model_->ccyIndex(ibor->index()->currency());
238 Real simTime =
time(ibor->fixingDate());
239 if (ibor->fixingDate() >
today_) {
240 info.simulationTimes.push_back(simTime);
242 }
243
244 if (fxLinkedSimTime != Null<Real>()) {
245 info.simulationTimes.push_back(fxLinkedSimTime);
246 info.modelIndices.push_back(fxLinkedModelIndices);
247 }
248
249 info.amountCalculator = [this, indexCcyIdx, ibor, simTime, fixedRate, isFxLinked, fxLinkedForeignNominal,
250 fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx, fxLinkedFixedFxRate, isCapFloored,
251 isNakedOption, effFloor, effCap, isFxIndexed](const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
252 RandomVariable fixing = fixedRate != Null<Real>()
253 ? RandomVariable(n, fixedRate)
255 *states.at(0).at(0));
256 RandomVariable fxFixing(n, 1.0);
257 if (isFxLinked || isFxIndexed) {
258 if (fxLinkedFixedFxRate != Null<Real>()) {
259 fxFixing = RandomVariable(n, fxLinkedFixedFxRate);
260 } else {
261 RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
262 Size fxIdx = 0;
263 if (fxLinkedSourceCcyIdx > 0)
264 fxSource =
exp(*states.at(1).at(fxIdx++));
265 if (fxLinkedTargetCcyIdx > 0)
266 fxTarget =
exp(*states.at(1).at(fxIdx));
267 fxFixing = fxSource / fxTarget;
268 }
269 }
270
271 RandomVariable effectiveRate;
272 if (isCapFloored) {
273 RandomVariable swapletRate(n, 0.0);
274 RandomVariable floorletRate(n, 0.0);
275 RandomVariable capletRate(n, 0.0);
276 if (!isNakedOption)
277 swapletRate = RandomVariable(n, ibor->gearing()) * fixing + RandomVariable(n, ibor->spread());
278 if (effFloor != Null<Real>())
279 floorletRate = RandomVariable(n, ibor->gearing()) *
280 max(RandomVariable(n, effFloor) - fixing, RandomVariable(n, 0.0));
281 if (effCap != Null<Real>())
282 capletRate = RandomVariable(n, ibor->gearing()) *
283 max(fixing - RandomVariable(n, effCap), RandomVariable(n, 0.0)) *
284 RandomVariable(n, isNakedOption && effFloor == Null<Real>() ? -1.0 : 1.0);
285 effectiveRate = swapletRate + floorletRate - capletRate;
286 } else {
287 effectiveRate = RandomVariable(n, ibor->gearing()) * fixing + RandomVariable(n, ibor->spread());
288 }
289 return RandomVariable(n, (isFxLinked ? fxLinkedForeignNominal : ibor->nominal()) * ibor->accrualPeriod()) *
290 effectiveRate * fxFixing;
291 };
292
293 return info;
294 }
295
296 if (auto cms = QuantLib::ext::dynamic_pointer_cast<CmsCoupon>(flow)) {
297 Real fixedRate = cms->fixingDate() <=
today_ ? (cms->rate() - cms->spread()) / cms->gearing() : Null<Real>();
298 Size indexCcyIdx =
model_->ccyIndex(cms->index()->currency());
299 Real simTime =
time(cms->fixingDate());
300 if (cms->fixingDate() >
today_) {
301 info.simulationTimes.push_back(simTime);
303 }
304
305 if (fxLinkedSimTime != Null<Real>()) {
306 info.simulationTimes.push_back(fxLinkedSimTime);
307 info.modelIndices.push_back(fxLinkedModelIndices);
308 }
309
310 info.amountCalculator = [this, indexCcyIdx, cms, simTime, fixedRate, isFxLinked, fxLinkedForeignNominal,
311 fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx, fxLinkedFixedFxRate, isCapFloored,
312 isNakedOption, effFloor,
313 effCap, isFxIndexed](const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
314 RandomVariable fixing =
315 fixedRate != Null<Real>()
316 ? RandomVariable(n, fixedRate)
318 RandomVariable fxFixing(n, 1.0);
319 if (isFxLinked || isFxIndexed) {
320 if (fxLinkedFixedFxRate != Null<Real>()) {
321 fxFixing = RandomVariable(n, fxLinkedFixedFxRate);
322 } else {
323 RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
324 Size fxIdx = 0;
325 if (fxLinkedSourceCcyIdx > 0)
326 fxSource =
exp(*states.at(1).at(fxIdx++));
327 if (fxLinkedTargetCcyIdx > 0)
328 fxTarget =
exp(*states.at(1).at(fxIdx));
329 fxFixing = fxSource / fxTarget;
330 }
331 }
332
333 RandomVariable effectiveRate;
334 if (isCapFloored) {
335 RandomVariable swapletRate(n, 0.0);
336 RandomVariable floorletRate(n, 0.0);
337 RandomVariable capletRate(n, 0.0);
338 if (!isNakedOption)
339 swapletRate = RandomVariable(n, cms->gearing()) * fixing + RandomVariable(n, cms->spread());
340 if (effFloor != Null<Real>())
341 floorletRate = RandomVariable(n, cms->gearing()) *
342 max(RandomVariable(n, effFloor) - fixing, RandomVariable(n, 0.0));
343 if (effCap != Null<Real>())
344 capletRate = RandomVariable(n, cms->gearing()) *
345 max(fixing - RandomVariable(n, effCap), RandomVariable(n, 0.0)) *
346 RandomVariable(n, isNakedOption && effFloor == Null<Real>() ? -1.0 : 1.0);
347 effectiveRate = swapletRate + floorletRate - capletRate;
348 } else {
349 effectiveRate = RandomVariable(n, cms->gearing()) * fixing + RandomVariable(n, cms->spread());
350 }
351
352 return RandomVariable(n, (isFxLinked ? fxLinkedForeignNominal : cms->nominal()) * cms->accrualPeriod()) *
353 effectiveRate * fxFixing;
354 };
355
356 return info;
357 }
358
359 if (auto on = QuantLib::ext::dynamic_pointer_cast<OvernightIndexedCoupon>(flow)) {
360 Real simTime = std::max(0.0,
time(on->valueDates().front()));
361 Size indexCcyIdx =
model_->ccyIndex(on->index()->currency());
362 info.simulationTimes.push_back(simTime);
364
365 if (fxLinkedSimTime != Null<Real>()) {
366 info.simulationTimes.push_back(fxLinkedSimTime);
367 info.modelIndices.push_back(fxLinkedModelIndices);
368 }
369
370 info.amountCalculator = [this, indexCcyIdx, on, simTime, isFxLinked, fxLinkedForeignNominal,
371 fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx, fxLinkedFixedFxRate, isFxIndexed](
372 const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
373 RandomVariable effectiveRate =
lgmVectorised_[indexCcyIdx].compoundedOnRate(
374 on->overnightIndex(), on->fixingDates(), on->valueDates(), on->dt(), on->rateCutoff(),
375 on->includeSpread(), on->spread(), on->gearing(), on->lookback(), Null<Real>(), Null<Real>(), false,
376 false, simTime, *states.at(0).at(0));
377 RandomVariable fxFixing(n, 1.0);
378 if (isFxLinked || isFxIndexed) {
379 if (fxLinkedFixedFxRate != Null<Real>()) {
380 fxFixing = RandomVariable(n, fxLinkedFixedFxRate);
381 } else {
382 RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
383 Size fxIdx = 0;
384 if (fxLinkedSourceCcyIdx > 0)
385 fxSource =
exp(*states.at(1).at(fxIdx++));
386 if (fxLinkedTargetCcyIdx > 0)
387 fxTarget =
exp(*states.at(1).at(fxIdx));
388 fxFixing = fxSource / fxTarget;
389 }
390 }
391
392 return RandomVariable(n, (isFxLinked ? fxLinkedForeignNominal : on->nominal()) * on->accrualPeriod()) *
393 effectiveRate * fxFixing;
394 };
395
396 return info;
397 }
398
399 if (auto cfon = QuantLib::ext::dynamic_pointer_cast<CappedFlooredOvernightIndexedCoupon>(flow)) {
400 Real simTime = std::max(0.0,
time(cfon->underlying()->valueDates().front()));
401 Size indexCcyIdx =
model_->ccyIndex(cfon->underlying()->index()->currency());
402 info.simulationTimes.push_back(simTime);
404
405 if (fxLinkedSimTime != Null<Real>()) {
406 info.simulationTimes.push_back(fxLinkedSimTime);
407 info.modelIndices.push_back(fxLinkedModelIndices);
408 }
409
410 info.amountCalculator = [this, indexCcyIdx, cfon, simTime, isFxLinked, fxLinkedForeignNominal,
411 fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx, fxLinkedFixedFxRate, isFxIndexed](
412 const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
413 RandomVariable effectiveRate =
lgmVectorised_[indexCcyIdx].compoundedOnRate(
414 cfon->underlying()->overnightIndex(), cfon->underlying()->fixingDates(),
415 cfon->underlying()->valueDates(), cfon->underlying()->dt(), cfon->underlying()->rateCutoff(),
416 cfon->underlying()->includeSpread(), cfon->underlying()->spread(), cfon->underlying()->gearing(),
417 cfon->underlying()->lookback(), cfon->cap(), cfon->floor(), cfon->localCapFloor(), cfon->nakedOption(),
418 simTime, *states.at(0).at(0));
419 RandomVariable fxFixing(n, 1.0);
420 if (isFxLinked || isFxIndexed) {
421 if (fxLinkedFixedFxRate != Null<Real>()) {
422 fxFixing = RandomVariable(n, fxLinkedFixedFxRate);
423 } else {
424 RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
425 Size fxIdx = 0;
426 if (fxLinkedSourceCcyIdx > 0)
427 fxSource =
exp(*states.at(1).at(fxIdx++));
428 if (fxLinkedTargetCcyIdx > 0)
429 fxTarget =
exp(*states.at(1).at(fxIdx));
430 fxFixing = fxSource / fxTarget;
431 }
432 }
433 return RandomVariable(n, (isFxLinked ? fxLinkedForeignNominal : cfon->nominal()) * cfon->accrualPeriod()) *
434 effectiveRate * fxFixing;
435 };
436
437 return info;
438 }
439
440 if (auto av = QuantLib::ext::dynamic_pointer_cast<AverageONIndexedCoupon>(flow)) {
441 Real simTime = std::max(0.0,
time(av->valueDates().front()));
442 Size indexCcyIdx =
model_->ccyIndex(av->index()->currency());
443 info.simulationTimes.push_back(simTime);
445
446 if (fxLinkedSimTime != Null<Real>()) {
447 info.simulationTimes.push_back(fxLinkedSimTime);
448 info.modelIndices.push_back(fxLinkedModelIndices);
449 }
450
451 info.amountCalculator = [this, indexCcyIdx, av, simTime, isFxLinked, fxLinkedForeignNominal,
452 fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx, fxLinkedFixedFxRate, isFxIndexed](
453 const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
454 RandomVariable effectiveRate =
lgmVectorised_[indexCcyIdx].averagedOnRate(
455 av->overnightIndex(), av->fixingDates(), av->valueDates(), av->dt(), av->rateCutoff(), false,
456 av->spread(), av->gearing(), av->lookback(), Null<Real>(), Null<Real>(), false, false, simTime,
457 *states.at(0).at(0));
458 RandomVariable fxFixing(n, 1.0);
459 if (isFxLinked || isFxIndexed) {
460 if (fxLinkedFixedFxRate != Null<Real>()) {
461 fxFixing = RandomVariable(n, fxLinkedFixedFxRate);
462 } else {
463 RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
464 Size fxIdx = 0;
465 if (fxLinkedSourceCcyIdx > 0)
466 fxSource =
exp(*states.at(1).at(fxIdx++));
467 if (fxLinkedTargetCcyIdx > 0)
468 fxTarget =
exp(*states.at(1).at(fxIdx));
469 fxFixing = fxSource / fxTarget;
470 }
471 }
472 return RandomVariable(n, (isFxLinked ? fxLinkedForeignNominal : av->nominal()) * av->accrualPeriod()) *
473 effectiveRate * fxFixing;
474 };
475
476 return info;
477 }
478
479 if (auto cfav = QuantLib::ext::dynamic_pointer_cast<CappedFlooredAverageONIndexedCoupon>(flow)) {
480 Real simTime = std::max(0.0,
time(cfav->underlying()->valueDates().front()));
481 Size indexCcyIdx =
model_->ccyIndex(cfav->underlying()->index()->currency());
482 info.simulationTimes.push_back(simTime);
484
485 if (fxLinkedSimTime != Null<Real>()) {
486 info.simulationTimes.push_back(fxLinkedSimTime);
487 info.modelIndices.push_back(fxLinkedModelIndices);
488 }
489
490 info.amountCalculator = [this, indexCcyIdx, cfav, simTime, isFxLinked, fxLinkedForeignNominal,
491 fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx, fxLinkedFixedFxRate, isFxIndexed](
492 const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
493 RandomVariable effectiveRate =
lgmVectorised_[indexCcyIdx].averagedOnRate(
494 cfav->underlying()->overnightIndex(), cfav->underlying()->fixingDates(),
495 cfav->underlying()->valueDates(), cfav->underlying()->dt(), cfav->underlying()->rateCutoff(),
496 cfav->includeSpread(), cfav->underlying()->spread(), cfav->underlying()->gearing(),
497 cfav->underlying()->lookback(), cfav->cap(), cfav->floor(), cfav->localCapFloor(), cfav->nakedOption(),
498 simTime, *states.at(0).at(0));
499 RandomVariable fxFixing(n, 1.0);
500 if (isFxLinked || isFxIndexed) {
501 if (fxLinkedFixedFxRate != Null<Real>()) {
502 fxFixing = RandomVariable(n, fxLinkedFixedFxRate);
503 } else {
504 RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
505 Size fxIdx = 0;
506 if (fxLinkedSourceCcyIdx > 0)
507 fxSource =
exp(*states.at(1).at(fxIdx++));
508 if (fxLinkedTargetCcyIdx > 0)
509 fxTarget =
exp(*states.at(1).at(fxIdx));
510 fxFixing = fxSource / fxTarget;
511 }
512 }
513 return RandomVariable(n, (isFxLinked ? fxLinkedForeignNominal : cfav->nominal()) * cfav->accrualPeriod()) *
514 effectiveRate * fxFixing;
515 };
516
517 return info;
518 }
519
520 if (auto bma = QuantLib::ext::dynamic_pointer_cast<AverageBMACoupon>(flow)) {
521 Real simTime = std::max(0.0,
time(bma->fixingDates().front()));
522 Size indexCcyIdx =
model_->ccyIndex(bma->index()->currency());
523 info.simulationTimes.push_back(simTime);
525
526 if (fxLinkedSimTime != Null<Real>()) {
527 info.simulationTimes.push_back(fxLinkedSimTime);
528 info.modelIndices.push_back(fxLinkedModelIndices);
529 }
530 info.amountCalculator = [this, indexCcyIdx, bma, simTime, isFxLinked, fxLinkedForeignNominal,
531 fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx, fxLinkedFixedFxRate, isFxIndexed](
532 const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
533 RandomVariable effectiveRate =
lgmVectorised_[indexCcyIdx].averagedBmaRate(
534 QuantLib::ext::dynamic_pointer_cast<BMAIndex>(bma->index()), bma->fixingDates(), bma->accrualStartDate(),
535 bma->accrualEndDate(), false, bma->spread(), bma->gearing(), Null<Real>(), Null<Real>(), false, simTime,
536 *states.at(0).at(0));
537 RandomVariable fxFixing(n, 1.0);
538 if (isFxLinked || isFxIndexed) {
539 if (fxLinkedFixedFxRate != Null<Real>()) {
540 fxFixing = RandomVariable(n, fxLinkedFixedFxRate);
541 } else {
542 RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
543 Size fxIdx = 0;
544 if (fxLinkedSourceCcyIdx > 0)
545 fxSource =
exp(*states.at(1).at(fxIdx++));
546 if (fxLinkedTargetCcyIdx > 0)
547 fxTarget =
exp(*states.at(1).at(fxIdx));
548 fxFixing = fxSource / fxTarget;
549 }
550 }
551 return RandomVariable(n, (isFxLinked ? fxLinkedForeignNominal : bma->nominal()) * bma->accrualPeriod()) *
552 effectiveRate * fxFixing;
553 };
554
555 return info;
556 }
557
558 if (auto cfbma = QuantLib::ext::dynamic_pointer_cast<CappedFlooredAverageBMACoupon>(flow)) {
559 Real simTime = std::max(0.0,
time(cfbma->underlying()->fixingDates().front()));
560 Size indexCcyIdx =
model_->ccyIndex(cfbma->underlying()->index()->currency());
561 info.simulationTimes.push_back(simTime);
563
564 if (fxLinkedSimTime != Null<Real>()) {
565 info.simulationTimes.push_back(fxLinkedSimTime);
566 info.modelIndices.push_back(fxLinkedModelIndices);
567 }
568 info.amountCalculator = [this, indexCcyIdx, cfbma, simTime, isFxLinked, fxLinkedForeignNominal,
569 fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx, fxLinkedFixedFxRate, isFxIndexed](
570 const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
571 RandomVariable effectiveRate =
lgmVectorised_[indexCcyIdx].averagedBmaRate(
572 QuantLib::ext::dynamic_pointer_cast<BMAIndex>(cfbma->underlying()->index()), cfbma->underlying()->fixingDates(),
573 cfbma->underlying()->accrualStartDate(), cfbma->underlying()->accrualEndDate(), cfbma->includeSpread(),
574 cfbma->underlying()->spread(), cfbma->underlying()->gearing(), cfbma->cap(), cfbma->floor(),
575 cfbma->nakedOption(), simTime, *states.at(0).at(0));
576 RandomVariable fxFixing(n, 1.0);
577 if (isFxLinked || isFxIndexed) {
578 if (fxLinkedFixedFxRate != Null<Real>()) {
579 fxFixing = RandomVariable(n, fxLinkedFixedFxRate);
580 } else {
581 RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
582 Size fxIdx = 0;
583 if (fxLinkedSourceCcyIdx > 0)
584 fxSource =
exp(*states.at(1).at(fxIdx++));
585 if (fxLinkedTargetCcyIdx > 0)
586 fxTarget =
exp(*states.at(1).at(fxIdx));
587 fxFixing = fxSource / fxTarget;
588 }
589 }
590 return RandomVariable(n, (isFxLinked ? fxLinkedForeignNominal : cfbma->underlying()->nominal()) *
591 cfbma->underlying()->accrualPeriod()) *
592 effectiveRate * fxFixing;
593 };
594
595 return info;
596 }
597
598 if (auto sub = QuantLib::ext::dynamic_pointer_cast<SubPeriodsCoupon1>(flow)) {
599 Real simTime = std::max(0.0,
time(sub->fixingDates().front()));
600 Size indexCcyIdx =
model_->ccyIndex(sub->index()->currency());
601 info.simulationTimes.push_back(simTime);
603
604 if (fxLinkedSimTime != Null<Real>()) {
605 info.simulationTimes.push_back(fxLinkedSimTime);
606 info.modelIndices.push_back(fxLinkedModelIndices);
607 }
608
609 info.amountCalculator = [this, indexCcyIdx, sub, simTime, isFxLinked, fxLinkedForeignNominal,
610 fxLinkedSourceCcyIdx, fxLinkedTargetCcyIdx, fxLinkedFixedFxRate, isFxIndexed](
611 const Size n, const std::vector<std::vector<const RandomVariable*>>& states) {
612 RandomVariable fixing =
lgmVectorised_[indexCcyIdx].subPeriodsRate(sub->index(), sub->fixingDates(),
613 simTime, *states.at(0).at(0));
614 RandomVariable fxFixing(n, 1.0);
615 if (isFxLinked || isFxIndexed) {
616 if (fxLinkedFixedFxRate != Null<Real>()) {
617 fxFixing = RandomVariable(n, fxLinkedFixedFxRate);
618 } else {
619 RandomVariable fxSource(n, 1.0), fxTarget(n, 1.0);
620 Size fxIdx = 0;
621 if (fxLinkedSourceCcyIdx > 0)
622 fxSource =
exp(*states.at(1).at(fxIdx++));
623 if (fxLinkedTargetCcyIdx > 0)
624 fxTarget =
exp(*states.at(1).at(fxIdx));
625 fxFixing = fxSource / fxTarget;
626 }
627 }
628 RandomVariable effectiveRate = RandomVariable(n, sub->gearing()) * fixing + RandomVariable(n, sub->spread());
629 return RandomVariable(n, (isFxLinked ? fxLinkedForeignNominal : sub->nominal()) * sub->accrualPeriod()) *
630 effectiveRate * fxFixing;
631 };
632
633 return info;
634 }
635
636 QL_FAIL("McMultiLegBaseEngine::createCashflowInfo(): unhandled coupon leg " << legNo << " cashflow " << cfNo);
637}
QuantLib::Date fixingDate(const QuantLib::Date &d, const QuantLib::Period obsLag, const QuantLib::Frequency freq, bool interpolated)
CompiledFormula exp(CompiledFormula x)
CompiledFormula max(CompiledFormula x, const CompiledFormula &y)