195 {
196
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.");
200
201 QL_REQUIRE(rateCutoff < dt.size(), "LgmVectorised::compoundedOnRate(): rate cutoff ("
202 << rateCutoff << ") must be less than number of fixings in period ("
203 << dt.size() << ")");
204
205
206
207
208
209
210
211
212
213
214 Size i = 0, n = dt.size();
215 Size nCutoff = n - rateCutoff;
216 Real compoundFactor = 1.0, compoundFactorWithoutSpread = 1.0;
217
218 Date today = Settings::instance().evaluationDate();
219
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)]);
225 if (includeSpread) {
226 compoundFactorWithoutSpread *= (1.0 + pastFixing * dt[i]);
227 pastFixing += spread;
228 }
229 compoundFactor *= (1.0 + pastFixing * dt[i]);
230 ++i;
231 }
232
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>()) {
236 if (includeSpread) {
237 compoundFactorWithoutSpread *= (1.0 + pastFixing * dt[i]);
238 pastFixing += spread;
239 }
240 compoundFactor *= (1.0 + pastFixing * dt[i]);
241 ++i;
242 }
243 }
244
245 RandomVariable compoundFactorLgm(x.size(), compoundFactor),
246 compoundFactorWithoutSpreadLgm(x.size(), compoundFactorWithoutSpread);
247
248 if (i < n) {
249 Handle<YieldTermStructure> curve = index->forwardingTermStructure();
250 QL_REQUIRE(!curve.empty(),
251 "LgmVectorised::compoundedOnRate(): null term structure set to this instance of " << index->name());
252
253 DiscountFactor startDiscount = curve->discount(valueDates[i]);
254 DiscountFactor endDiscount = curve->discount(valueDates[std::max(nCutoff, i)]);
255
256 if (nCutoff < n) {
257 DiscountFactor discountCutoffDate =
258 curve->discount(valueDates[nCutoff] + 1) / curve->discount(valueDates[nCutoff]);
259 endDiscount *= std::pow(discountCutoffDate, valueDates[n] - valueDates[nCutoff]);
260 }
261
262
263
264 Real T1 =
p_->termStructure()->timeFromReference(valueDates[i]);
265 Real T2 =
p_->termStructure()->timeFromReference(valueDates[n]);
266
267
268
269 Real T1_lgm = T1, T2_lgm = T2;
270 if (t > T1) {
271 T1_lgm += t - T1;
272 T2_lgm += t - T1;
273 }
274
275
276
279
280
281
282 disc1 *= RandomVariable(x.size(), startDiscount / curve->discount(T1_lgm));
283 disc2 *= RandomVariable(x.size(), endDiscount / curve->discount(T2_lgm));
284
285
286
287 compoundFactorLgm *= disc1 / disc2;
288
289 if (includeSpread) {
290 compoundFactorWithoutSpreadLgm *= disc1 / disc2;
291 Real tau =
292 index->dayCounter().yearFraction(valueDates[i], valueDates.back()) / (valueDates.back() - valueDates[i]);
293 compoundFactorLgm *= RandomVariable(
294 x.size(), std::pow(1.0 + tau * spread, static_cast<int>(valueDates.back() - valueDates[i])));
295 }
296 }
297
298 Rate tau = index->dayCounter().yearFraction(valueDates.front(), valueDates.back());
299 RandomVariable rate = (compoundFactorLgm - RandomVariable(x.size(), 1.0)) / RandomVariable(x.size(), tau);
300 RandomVariable swapletRate = RandomVariable(x.size(), gearing) * rate;
301 RandomVariable effectiveSpread, effectiveIndexFixing;
302 if (!includeSpread) {
303 swapletRate += RandomVariable(x.size(), spread);
304 effectiveSpread = RandomVariable(x.size(), spread);
305 effectiveIndexFixing = rate;
306 } else {
307 effectiveSpread =
308 rate - (compoundFactorWithoutSpreadLgm - RandomVariable(x.size(), 1.0)) / RandomVariable(x.size(), tau);
309 effectiveIndexFixing = rate - effectiveSpread;
310 }
311
312 if (cap == Null<Real>() && floor == Null<Real>())
313 return swapletRate;
314
315
316
317 if (gearing < 0.0) {
318 std::swap(cap, floor);
319 }
320
321 if (nakedOption)
322 swapletRate = RandomVariable(x.size(), 0.0);
323
324 RandomVariable floorletRate(x.size(), 0.0);
325 RandomVariable capletRate(x.size(), 0.0);
326
327 if (floor != Null<Real>()) {
328
329 RandomVariable effectiveStrike =
330 (RandomVariable(x.size(), floor) - effectiveSpread) / RandomVariable(x.size(), gearing);
331 floorletRate = RandomVariable(x.size(), gearing) *
332 max(RandomVariable(x.size(), 0.0), effectiveStrike - effectiveIndexFixing);
333 }
334
335 if (cap != Null<Real>()) {
336 RandomVariable effectiveStrike =
337 (RandomVariable(x.size(), cap) - effectiveSpread) / RandomVariable(x.size(), gearing);
338 capletRate = RandomVariable(x.size(), gearing) *
339 max(RandomVariable(x.size(), 0.0), effectiveIndexFixing - effectiveStrike);
340 if (nakedOption && floor == Null<Real>())
341 capletRate = -capletRate;
342 }
343
344 return swapletRate + floorletRate - capletRate;
345}
CompiledFormula max(CompiledFormula x, const CompiledFormula &y)