QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
gaussian1dswaptionengine.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2013 Peter Caspers
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include <ql/pricingengines/swaption/gaussian1dswaptionengine.hpp>
21#include <ql/math/interpolations/cubicinterpolation.hpp>
22#include <ql/payoff.hpp>
23
24namespace QuantLib {
25
27
28 QL_REQUIRE(arguments_.settlementMethod != Settlement::ParYieldCurve,
29 "cash settled (ParYieldCurve) swaptions not priced with "
30 "Gaussian1dSwaptionEngine");
31
32 QL_REQUIRE(arguments_.nominal != Null<Real>(),
33 "non-constant nominals are not supported yet");
34
35 Date settlement = model_->termStructure()->referenceDate();
36
37 if (arguments_.exercise->dates().back() <=
38 settlement) { // swaption is expired, possibly generated swap is not
39 // valued
40 results_.value = 0.0;
41 return;
42 }
43
44 int idx = static_cast<int>(arguments_.exercise->dates().size()) - 1;
45 int minIdxAlive = static_cast<int>(
46 std::upper_bound(arguments_.exercise->dates().begin(),
47 arguments_.exercise->dates().end(), settlement) -
48 arguments_.exercise->dates().begin());
49
51 Option::Type type =
53 const Schedule& fixedSchedule = swap.fixedSchedule();
54 const Schedule& floatSchedule = swap.floatingSchedule();
55
56 Array npv0(2 * integrationPoints_ + 1, 0.0),
57 npv1(2 * integrationPoints_ + 1, 0.0);
59 Array p(z.size(), 0.0);
60
61 // for probability computation
62 std::vector<Array> npvp0, npvp1;
63 if (probabilities_ != None) {
64 for (int i = 0; i < idx - minIdxAlive + 2; ++i) {
65 Array npvTmp0(2 * integrationPoints_ + 1, 0.0);
66 Array npvTmp1(2 * integrationPoints_ + 1, 0.0);
67 npvp0.push_back(npvTmp0);
68 npvp1.push_back(npvTmp1);
69 }
70 }
71 // end probabkility computation
72
73 Date expiry1 = Null<Date>(), expiry0;
74 Time expiry1Time = Null<Real>(), expiry0Time;
75
76 do {
77
78 if (idx == minIdxAlive - 1)
79 expiry0 = settlement;
80 else
81 expiry0 = arguments_.exercise->dates()[idx];
82
83 expiry0Time = std::max(
84 model_->termStructure()->timeFromReference(expiry0), 0.0);
85
86 Size j1 =
87 std::upper_bound(fixedSchedule.dates().begin(),
88 fixedSchedule.dates().end(), expiry0 - 1) -
89 fixedSchedule.dates().begin();
90 Size k1 =
91 std::upper_bound(floatSchedule.dates().begin(),
92 floatSchedule.dates().end(), expiry0 - 1) -
93 floatSchedule.dates().begin();
94
95 // a lazy object is not thread safe, neither is the caching
96 // in gsrprocess. therefore we trigger computations here such
97 // that neither lazy object recalculation nor write access
98 // during caching occurs in the parallized loop below.
99 // this is known to work for the gsr and markov functional
100 // model implementations of Gaussian1dModel
101#ifdef _OPENMP
102 if (expiry1Time != Null<Real>())
103 model_->yGrid(stddevs_, integrationPoints_, expiry1Time,
104 expiry0Time, 0.0);
105 if (expiry0 > settlement) {
106 for (Size l = k1; l < arguments_.floatingCoupons.size(); l++) {
107 model_->forwardRate(arguments_.floatingFixingDates[l],
108 expiry0, 0.0,
109 arguments_.swap->iborIndex());
110 model_->zerobond(arguments_.floatingPayDates[l], expiry0,
111 0.0, discountCurve_);
112 }
113 for (Size l = j1; l < arguments_.fixedCoupons.size(); l++) {
114 model_->zerobond(arguments_.fixedPayDates[l], expiry0, 0.0,
116 }
117 model_->numeraire(expiry0Time, 0.0, discountCurve_);
118 }
119#endif
120
121#pragma omp parallel for default(shared) firstprivate(p) if(expiry0>settlement)
122 for (long k = 0; k < (expiry0 > settlement ? (long)npv0.size() : 1);
123 k++) {
124
125 Real price = 0.0;
126 if (expiry1Time != Null<Real>()) {
128 expiry1Time, expiry0Time,
129 expiry0 > settlement ? z[k] : 0.0);
130 CubicInterpolation payoff0(
131 z.begin(), z.end(), npv1.begin(),
135 for (Size i = 0; i < yg.size(); i++) {
136 p[i] = payoff0(yg[i], true);
137 }
138 CubicInterpolation payoff1(
139 z.begin(), z.end(), p.begin(),
143 for (Size i = 0; i < z.size() - 1; i++) {
145 0.0, payoff1.cCoefficients()[i],
146 payoff1.bCoefficients()[i],
147 payoff1.aCoefficients()[i], p[i], z[i], z[i],
148 z[i + 1]);
149 }
150 if (extrapolatePayoff_) {
153 0.0, 0.0, 0.0, 0.0, p[z.size() - 2],
154 z[z.size() - 2], z[z.size() - 1], 100.0);
156 0.0, 0.0, 0.0, 0.0, p[0], z[0], -100.0, z[0]);
157 } else {
158 if (type == Option::Call)
159 price +=
161 0.0,
162 payoff1.cCoefficients()[z.size() - 2],
163 payoff1.bCoefficients()[z.size() - 2],
164 payoff1.aCoefficients()[z.size() - 2],
165 p[z.size() - 2], z[z.size() - 2],
166 z[z.size() - 1], 100.0);
167 if (type == Option::Put)
168 price +=
170 0.0, payoff1.cCoefficients()[0],
171 payoff1.bCoefficients()[0],
172 payoff1.aCoefficients()[0], p[0], z[0],
173 -100.0, z[0]);
174 }
175 }
176 }
177
178 npv0[k] = price;
179
180 // for probability computation
181 if (probabilities_ != None) {
182 for (Size m = 0; m < npvp0.size(); m++) {
183 Real price = 0.0;
184 if (expiry1Time != Null<Real>()) {
185 Array yg = model_->yGrid(
186 stddevs_, integrationPoints_, expiry1Time,
187 expiry0Time, expiry0 > settlement ? z[k] : 0.0);
188 CubicInterpolation payoff0(
189 z.begin(), z.end(), npvp1[m].begin(),
193 for (Size i = 0; i < yg.size(); i++) {
194 p[i] = payoff0(yg[i], true);
195 }
196 CubicInterpolation payoff1(
197 z.begin(), z.end(), p.begin(),
201 for (Size i = 0; i < z.size() - 1; i++) {
202 price +=
204 0.0, payoff1.cCoefficients()[i],
205 payoff1.bCoefficients()[i],
206 payoff1.aCoefficients()[i], p[i], z[i],
207 z[i], z[i + 1]);
208 }
209 if (extrapolatePayoff_) {
211 price +=
213 0.0, 0.0, 0.0, 0.0,
214 p[z.size() - 2],
215 z[z.size() - 2],
216 z[z.size() - 1], 100.0);
217 price +=
219 0.0, 0.0, 0.0, 0.0, p[0],
220 z[0], -100.0, z[0]);
221 } else {
222 if (type == Option::Call)
223 price +=
225 0.0,
226 payoff1.cCoefficients()
227 [z.size() - 2],
228 payoff1.bCoefficients()
229 [z.size() - 2],
230 payoff1.aCoefficients()
231 [z.size() - 2],
232 p[z.size() - 2],
233 z[z.size() - 2],
234 z[z.size() - 1], 100.0);
235 if (type == Option::Put)
236 price +=
238 0.0,
239 payoff1
240 .cCoefficients()[0],
241 payoff1
242 .bCoefficients()[0],
243 payoff1
244 .aCoefficients()[0],
245 p[0], z[0], -100.0, z[0]);
246 }
247 }
248 }
249
250 npvp0[m][k] = price;
251 }
252 }
253 // end probability computation
254
255 if (expiry0 > settlement) {
256 Real floatingLegNpv = 0.0;
257 for (Size l = k1; l < arguments_.floatingCoupons.size();
258 l++) {
259 floatingLegNpv +=
260 arguments_.nominal *
261 arguments_.floatingAccrualTimes[l] *
262 (arguments_.floatingSpreads[l] +
263 model_->forwardRate(
264 arguments_.floatingFixingDates[l], expiry0,
265 z[k], arguments_.swap->iborIndex())) *
266 model_->zerobond(arguments_.floatingPayDates[l],
267 expiry0, z[k], discountCurve_);
268 }
269 Real fixedLegNpv = 0.0;
270 for (Size l = j1; l < arguments_.fixedCoupons.size(); l++) {
271 fixedLegNpv +=
272 arguments_.fixedCoupons[l] *
273 model_->zerobond(arguments_.fixedPayDates[l],
274 expiry0, z[k], discountCurve_);
275 }
276 Real exerciseValue =
277 (type == Option::Call ? 1.0 : -1.0) *
278 (floatingLegNpv - fixedLegNpv) /
279 model_->numeraire(expiry0Time, z[k], discountCurve_);
280
281 // for probability computation
282 if (probabilities_ != None) {
283 if (idx == static_cast<int>(
284 arguments_.exercise->dates().size()) -
285 1) // if true we are at the latest date,
286 // so we init
287 // the no call probability
288 npvp0.back()[k] =
290 ? Real(1.0)
291 : 1.0 / (model_->zerobond(expiry0Time, 0.0,
292 0.0,
294 model_->numeraire(expiry0, z[k],
296 if (exerciseValue >= npv0[k]) {
297 npvp0[idx - minIdxAlive][k] =
299 ? Real(1.0)
300 : 1.0 /
301 (model_->zerobond(expiry0Time, 0.0,
302 0.0,
304 model_->numeraire(expiry0Time, z[k],
306 for (Size ii = idx - minIdxAlive + 1;
307 ii < npvp0.size(); ii++)
308 npvp0[ii][k] = 0.0;
309 }
310 }
311 // end probability computation
312
313 npv0[k] = std::max(npv0[k], exerciseValue);
314 }
315 }
316
317 npv1.swap(npv0);
318
319 // for probability computation
320 if (probabilities_ != None) {
321 for (Size i = 0; i < npvp0.size(); i++)
322 npvp1[i].swap(npvp0[i]);
323 }
324 // end probability computation
325
326 expiry1 = expiry0;
327 expiry1Time = expiry0Time;
328
329 } while (--idx >= minIdxAlive - 1);
330
331 results_.value = npv1[0] * model_->numeraire(0.0, 0.0, discountCurve_);
332
333 // for probability computation
334 if (probabilities_ != None) {
335 std::vector<Real> prob(npvp0.size());
336 for (Size i = 0; i < npvp0.size(); i++) {
337 prob[i] = npvp1[i][0] *
339 ? 1.0
340 : model_->numeraire(0.0, 0.0, discountCurve_));
341 }
342 results_.additionalResults["probabilities"] = prob;
343 }
344 // end probability computation
345 }
346}
1-D array used in linear algebra.
Definition: array.hpp:52
void swap(Array &) noexcept
Definition: array.hpp:546
const_iterator end() const
Definition: array.hpp:511
Size size() const
dimension of the array
Definition: array.hpp:495
const_iterator begin() const
Definition: array.hpp:503
Cubic interpolation between discrete points.
const std::vector< Real > & cCoefficients() const
const std::vector< Real > & bCoefficients() const
const std::vector< Real > & aCoefficients() const
Concrete date class.
Definition: date.hpp:125
static Real gaussianShiftedPolynomialIntegral(Real a, Real b, Real c, Real d, Real e, Real h, Real x0, Real x1)
const Handle< YieldTermStructure > discountCurve_
template class providing a null value for a given type.
Definition: null.hpp:76
Payment schedule.
Definition: schedule.hpp:40
const std::vector< Date > & dates() const
Definition: schedule.hpp:75
Plain-vanilla swap: fix vs ibor leg.
Definition: vanillaswap.hpp:65
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
QL_REAL Real
real number
Definition: types.hpp:50
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
void swap(Array &v, Array &w) noexcept
Definition: array.hpp:903