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
89 info.belongsToUnderlyingMaxTime_ = ts->timeFromReference(cpn->accrualEndDate());
90 } else {
91
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
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
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}
QuantLib::ext::shared_ptr< Exercise > exercise_
std::vector< bool > payer_
CompiledFormula min(CompiledFormula x, const CompiledFormula &y)
CompiledFormula max(CompiledFormula x, const CompiledFormula &y)