69 {
70
71 Date today =
model()->parametrization()->termStructure()->referenceDate();
73
74
75
76 QL_REQUIRE(
fixedNominal.size() > 0,
"NumericLgmFlexiSwapEngine::calculate(): fixed nominal size is zero");
77 QL_REQUIRE(
floatingNominal.size() > 0,
"NumericLgmFlexiSwapEngine::calculate(): floating nominal size is zero");
79 std::vector<Real> times;
80 std::vector<Date> dates;
81 std::vector<Size> fixCpnIndex, fltCpnIndex;
82 std::vector<Real> fixPayTime, fltPayTime;
83 Size firstAliveIndex = Null<Size>();
86 if (d > today) {
87 if (firstAliveIndex == Null<Size>())
88 firstAliveIndex = i;
89 times.push_back(
model()->parametrization()->termStructure()->timeFromReference(d));
90 dates.push_back(d);
91 fltCpnIndex.push_back(i);
92 fltPayTime.push_back(
model()->parametrization()->termStructure()->timeFromReference(
floatingPayDates[i]));
93 if (i % legRatio == 0) {
94 Size idx = static_cast<Size>(i / legRatio);
95 fixCpnIndex.push_back(idx);
96 fixPayTime.push_back(
98 } else {
99 fixCpnIndex.push_back(Null<Size>());
100 fixPayTime.push_back(Null<Real>());
101 }
102 }
103 }
104
105 int n = times.size();
106
107
108
109 std::vector<Real> swaptionVolTmp;
110 std::vector<Size> swaptionStartIdx, swaptionEndIdx;
111
112
113 Size i = 0;
116 ++i;
117 Size firstIndex = i;
119
120 Real currentVolUpper =
123 if (!QuantLib::close_enough(currentVolUpper, currentVolLower)) {
126 if (nextNotional < currentVolUpper && !QuantLib::close_enough(currentVolLower, currentVolUpper)) {
127 Real tmpVol = std::min(currentVolUpper - nextNotional, currentVolUpper - currentVolLower);
128 if (!QuantLib::close_enough(tmpVol, 0.0)) {
129 swaptionStartIdx.push_back(i);
130 swaptionEndIdx.push_back(j + 1);
131 swaptionVolTmp.push_back(tmpVol);
132 currentVolUpper = std::max(nextNotional, currentVolLower);
133 }
134 }
135 }
136 QL_REQUIRE(QuantLib::close_enough(currentVolUpper, currentVolLower),
137 "NumericLgmFlexiSwapEngine:calculate(): currentVolUpper ("
138 << currentVolUpper << ") does not match currentVolLower (" << currentVolLower
139 << "), this is unexpected");
140 }
141 }
142
143 int m = swaptionVolTmp.size();
144
145
146
147
148 Real fullGridSwaptions = 0.0;
149 for (int i = 0; i < m; ++i) {
150 fullGridSwaptions += static_cast<Size>(swaptionEndIdx[i] - swaptionStartIdx[i]);
151 }
152 fullGridSwaptions /= static_cast<Real>(n);
157
158
159 if (m == 0)
161
162
163 std::vector<Array> underlyingMultiplier(n, Array(m, 0.0));
164
165 std::vector<Array> exerciseIndicator(n, Array(m, 0.0));
166
167 Array notionals(m);
168
169 for (int i = 0; i < m; ++i) {
170 notionals[i] = swaptionVolTmp[i];
171 for (Size j = swaptionStartIdx[i]; j < swaptionEndIdx[i]; ++j) {
172 Size index = j * legRatio;
174 index -= firstAliveIndex;
175 exerciseIndicator[index][i] = 1.0;
176 for (Size k = 0; k < legRatio; ++k) {
177 underlyingMultiplier[index + k][i] = swaptionVolTmp[i];
178 }
179 }
180 }
181 }
182
183
184
187
188
189
190
191 std::vector<Array> u_a, v_a;
192 std::vector<Real> u_s, v_s;
196 } else {
197 u_a.resize(
gridSize(), Array(m, 0.0));
198 v_a.resize(
gridSize(), Array(m, 0.0));
199 }
200
201 Real undValAll0 = 0.0;
202 int undValAllIdx = n + 1;
203 Array value0(m, 0.0);
204
205
207
208
209 std::vector<Real> uAll(
gridSize(), 0.0);
210
211
212
213
214
216 QL_REQUIRE(swaptionEndIdx[sw] * legRatio >= firstAliveIndex,
217 "swaptionEndIndex[" << sw << "] * legRatio (" << legRatio << ") < firstAliveIndex ("
218 << firstAliveIndex << ") - this is unexpected.");
219 n = swaptionEndIdx[sw] * legRatio - firstAliveIndex;
220 }
221
223 for (Size k = 0; k <
gridSize(); ++k) {
224 Real tmp =
underlyingValue(states[k], times[n - 1], dates[n - 1], fltCpnIndex[n - 1], fixCpnIndex[n - 1],
225 fltPayTime[n - 1], fixPayTime[n - 1]);
226
227 if (n < undValAllIdx) {
229 }
231 u_s[k] = tmp * underlyingMultiplier[n - 1][sw];
232 v_s[k] = exerciseIndicator[n - 1][sw] * std::max(-phi * u_s[k], 0.0);
233 } else {
234 u_a[k] = tmp * underlyingMultiplier[n - 1];
235 v_a[k] = exerciseIndicator[n - 1] *
max(-phi * u_a[k], 0.0);
236 }
237 }
238
239
240
241
242
243 int minIndex = 0;
245 QL_REQUIRE(swaptionStartIdx[sw] * legRatio >= firstAliveIndex,
246 "swaptionStartIndex[" << sw << "] * legRatio (" << legRatio << ") < firstAliveIndex ("
247 << firstAliveIndex << ") - this is unexpected.");
248 minIndex = swaptionStartIdx[sw] * legRatio - firstAliveIndex;
249 }
250
251 for (int j = n - 1; j > minIndex; j--) {
252
255 u_s =
rollback(u_s, times[j], times[j - 1]);
256 v_s =
rollback(v_s, times[j], times[j - 1]);
257 } else {
258 u_a =
rollback(u_a, times[j], times[j - 1], Array(m, 0.0));
259 v_a =
rollback(v_a, times[j], times[j - 1], Array(m, 0.0));
260 }
261 if (j < undValAllIdx) {
262 uAll =
rollback(uAll, times[j], times[j - 1]);
263 }
264
265 for (Size k = 0; k <
gridSize(); ++k) {
266 Real tmp =
underlyingValue(states[k], times[j - 1], dates[j - 1], fltCpnIndex[j - 1],
267 fixCpnIndex[j - 1], fltPayTime[j - 1], fixPayTime[j - 1]);
268 uAll[k] += (j < undValAllIdx ? tmp *
floatingNominal[fltCpnIndex[j - 1]] : 0.0);
270 u_s[k] += tmp * underlyingMultiplier[j - 1][sw];
271 v_s[k] = exerciseIndicator[j - 1][sw] * std::max(v_s[k], -phi * u_s[k]) +
272 (1.0 - exerciseIndicator[j - 1][sw]) * v_s[k];
273 } else {
274 u_a[k] += tmp * underlyingMultiplier[j - 1];
275 v_a[k] = exerciseIndicator[j - 1] *
max(v_a[k], -phi * u_a[k]) +
276 (1.0 - exerciseIndicator[j - 1]) * v_a[k];
277 }
278 }
279 }
280
281
282
284 v_s =
rollback(v_s, times[minIndex], 0.0);
285 } else {
286 v_a =
rollback(v_a, times[minIndex], 0.0, Array(m, 0.0));
287 }
288 uAll =
rollback(uAll, times[minIndex], 0.0);
289
290
291 undValAllIdx = minIndex + 1;
292
293
295 value0[sw] = v_s[0];
296 else
297 value0 = v_a[0];
298
299
300 undValAll0 += uAll[0];
301
302 }
303
304
305
306 Size minFltCpnIdx = fltCpnIndex.empty() ? 0 : *std::min_element(fltCpnIndex.begin(), fltCpnIndex.end());
307 Size minFixCpnIdx = fixCpnIndex.empty() ? 0 : *std::min_element(fixCpnIndex.begin(), fixCpnIndex.end());
308
314 }
315 }
316
320 "NumericLgmFlexiSwapEngineBase: no floating coupon provided for fixing date "
325 }
326 }
327
328
329 Real sumOptions = std::accumulate(value0.begin(), value0.end(), 0.0);
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358 return std::make_pair(phi * sumOptions + undValAll0, undValAll0);
359
360}
std::vector< ValueType > rollback(const std::vector< ValueType > &v, const Real t1, const Real t0, const ValueType zero=ValueType(0.0)) const
std::vector< Real > stateGrid(const Real t) const
QuantLib::ext::shared_ptr< IborIndex > iborIndex
QuantLib::ext::shared_ptr< LgmImpliedYieldTermStructure > iborModelCurve_
QuantLib::ext::shared_ptr< IborIndex > iborModelIndex_
std::vector< Date > floatingFixingDates
Real underlyingValue(const Real, const Real, const Date &, const Size, const Size, const Real, const Real) const
std::vector< Date > fixedPayDates
std::vector< Real > fixedNominal
std::vector< Real > floatingNominal
QuantLib::Position::Type optionPosition
std::vector< Real > floatingCoupons
std::vector< bool > notionalCanBeDecreased
std::vector< Real > lowerNotionalBound
std::vector< Real > fixedCoupons
std::vector< Date > floatingPayDates
CompiledFormula max(CompiledFormula x, const CompiledFormula &y)