Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
blackswaptionenginedeltagamma.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19/*! \file qle/pricingengines/blackswaptionenginedeltagamma.hpp
20 \brief Swaption engine providing analytical deltas for vanilla swaps
21
22 \ingroup engines
23*/
24
25#ifndef quantext_pricers_black_swaption_deltagamma_hpp
26#define quantext_pricers_black_swaption_deltagamma_hpp
27
29
30#include <ql/cashflows/cashflows.hpp>
31#include <ql/cashflows/fixedratecoupon.hpp>
32#include <ql/exercise.hpp>
33#include <ql/indexes/iborindex.hpp>
34#include <ql/instruments/swaption.hpp>
35#include <ql/math/distributions/normaldistribution.hpp>
36#include <ql/pricingengines/blackformula.hpp>
37#include <ql/pricingengines/swap/discountingswapengine.hpp>
38#include <ql/termstructures/volatility/swaption/swaptionconstantvol.hpp>
39#include <ql/termstructures/volatility/swaption/swaptionvolstructure.hpp>
40#include <ql/time/calendars/nullcalendar.hpp>
41
42#include <boost/make_shared.hpp>
43
44namespace QuantLib {
45class Quote;
46}
47
48namespace QuantExt {
49using namespace QuantLib;
50namespace detail {
51
52/*! Generic Black-style-formula swaption engine
53 This is the base class for the Black and Bachelier swaption engines
54 See also discountingswapenginedeltagamma.hpp. The vega is rebucketed as well (linear in volatility), w.r.t
55 the given bucketTimesVega, although this is only one number. The interest rate deltas are sticky strike deltas.
56
57 The additional results of this engine are
58
59 deltaDiscount (vector<Real> ): Delta on discount curve, rebucketed on time grid
60 deltaForward (vector<Real> ): Delta on forward curve, rebucketed on time grid
61 vega (Matrix ): Vega, rebucketed on time grid (rows = opt, cols = und)
62
63 gamma (Matrix ): Gamma matrix with blocks | dsc-dsc dsc-fwd |
64 | dsc-fwd fwd-fwd |
65
66 theta (Real ): Theta
67
68 bucketTimesDeltaGamma (vector<Real> ): Bucketing grid for deltas and gammas
69 bucketTimesVegaOpt (vector<Real> ): Bucketing grid for vega (option)
70 bucketTimesVegaUnd (vector<Real> ): Bucketing grid for vega (underlying)
71
72 \warning Cash settled swaption are priced, but the annuity used is the one from physical settlement currently
73*/
74
75template <class Spec> class BlackStyleSwaptionEngineDeltaGamma : public QuantLib::Swaption::engine {
76public:
77 BlackStyleSwaptionEngineDeltaGamma(const Handle<YieldTermStructure>& discountCurve, Volatility vol,
78 const DayCounter& dc = Actual365Fixed(), Real displacement = 0.0,
79 const std::vector<Time>& bucketTimesDeltaGamma = std::vector<Time>(),
80 const std::vector<Time>& bucketTimesVegaOpt = std::vector<Time>(),
81 const std::vector<Time>& bucketTimesVegaUnd = std::vector<Time>(),
82 const bool computeDeltaVega = false, const bool computeGamma = false,
83 const bool linearInZero = true);
84 BlackStyleSwaptionEngineDeltaGamma(const Handle<YieldTermStructure>& discountCurve, const Handle<Quote>& vol,
85 const DayCounter& dc = Actual365Fixed(), Real displacement = 0.0,
86 const std::vector<Time>& bucketTimesDeltaGamma = std::vector<Time>(),
87 const std::vector<Time>& bucketTimesVegaOpt = std::vector<Time>(),
88 const std::vector<Time>& bucketTimesVegaUnd = std::vector<Time>(),
89 const bool computeDeltaVega = false, const bool computeGamma = false,
90 const bool linearInZero = true);
91 BlackStyleSwaptionEngineDeltaGamma(const Handle<YieldTermStructure>& discountCurve,
92 const Handle<SwaptionVolatilityStructure>& vol,
93 const std::vector<Time>& bucketTimesDeltaGamma = std::vector<Time>(),
94 const std::vector<Time>& bucketTimesVegaOpt = std::vector<Time>(),
95 const std::vector<Time>& bucketTimesVegaUnd = std::vector<Time>(),
96 const bool computeDeltaVega = false, const bool computeGamma = false,
97 const bool linearInZero = true);
98 void calculate() const override;
99 Handle<YieldTermStructure> termStructure() { return discountCurve_; }
100 Handle<SwaptionVolatilityStructure> volatility() { return vol_; }
101
102private:
103 Handle<YieldTermStructure> discountCurve_;
104 Handle<SwaptionVolatilityStructure> vol_;
105 const Real displacement_;
108};
109
110// shifted lognormal type engine
112 static const VolatilityType type = ShiftedLognormal;
113 Real value(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity,
114 const Real displacement) {
115 return blackFormula(type, strike, atmForward, stdDev, annuity, displacement);
116 }
117 Real vega(const Real strike, const Real atmForward, const Real stdDev, const Real exerciseTime, const Real annuity,
118 const Real displacement) {
119 return std::sqrt(exerciseTime) *
120 blackFormulaStdDevDerivative(strike, atmForward, stdDev, annuity, displacement);
121 }
122 Real delta(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity,
123 const Real displacement) {
124 QuantLib::CumulativeNormalDistribution cnd;
125 Real d1 = std::log((atmForward + displacement) / (strike + displacement)) / stdDev + 0.5 * stdDev;
126 Real w = type == Option::Call ? 1.0 : -1.0;
127 return annuity * w * cnd(w * d1);
128 }
129 Real gamma(const Real strike, const Real atmForward, const Real stdDev, const Real annuity,
130 const Real displacement) {
131 QuantLib::CumulativeNormalDistribution cnd;
132 Real d1 = std::log((atmForward + displacement) / (strike + displacement)) / stdDev + 0.5 * stdDev;
133 return annuity * cnd.derivative(d1) / ((atmForward + displacement) * stdDev);
134 }
135 Real theta(const Real strike, const Real atmForward, const Real stdDev, const Real exerciseTime, const Real annuity,
136 const Real displacement) {
137 QuantLib::CumulativeNormalDistribution cnd;
138 Real d1 = std::log((atmForward + displacement) / (strike + displacement)) / stdDev + 0.5 * stdDev;
139 return -0.5 * annuity * cnd.derivative(d1) * (atmForward + displacement) * stdDev / exerciseTime;
140 }
141};
142
143// normal type engine
145 static const VolatilityType type = Normal;
146 Real value(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity,
147 const Real) {
148 return bachelierBlackFormula(type, strike, atmForward, stdDev, annuity);
149 }
150 Real vega(const Real strike, const Real atmForward, const Real stdDev, const Real exerciseTime, const Real annuity,
151 const Real) {
152 return std::sqrt(exerciseTime) * bachelierBlackFormulaStdDevDerivative(strike, atmForward, stdDev, annuity);
153 }
154 Real delta(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity,
155 const Real displacement) {
156 QuantLib::CumulativeNormalDistribution cnd;
157 Real d1 = (atmForward - strike) / stdDev;
158 Real w = type == Option::Call ? 1.0 : -1.0;
159 return annuity * w * cnd(w * d1);
160 }
161 Real gamma(const Real strike, const Real atmForward, const Real stdDev, const Real annuity,
162 const Real displacement) {
163 QuantLib::CumulativeNormalDistribution cnd;
164 Real d1 = (atmForward - strike) / stdDev;
165 return annuity * cnd.derivative(d1) / stdDev;
166 }
167 Real theta(const Real strike, const Real atmForward, const Real stdDev, const Real exerciseTime, const Real annuity,
168 const Real displacement) {
169 QuantLib::CumulativeNormalDistribution cnd;
170 Real d1 = (atmForward - strike) / stdDev;
171 return -0.5 * annuity * cnd.derivative(d1) * stdDev / exerciseTime;
172 }
173};
174
175} // namespace detail
176
177//! Shifted Lognormal Black-formula swaption engine
178/*! \ingroup swaptionengines
179
180 \warning The engine assumes that the exercise date equals the
181 start date of the passed swap.
182*/
183
185public:
186 BlackSwaptionEngineDeltaGamma(const Handle<YieldTermStructure>& discountCurve, Volatility vol,
187 const DayCounter& dc = Actual365Fixed(), Real displacement = 0.0,
188 const std::vector<Time>& bucketTimesDeltaGamma = std::vector<Time>(),
189 const std::vector<Time>& bucketTimesVegaOpt = std::vector<Time>(),
190 const std::vector<Time>& bucketTimesVegaUnd = std::vector<Time>(),
191 const bool computeDeltaVega = false, const bool computeGamma = false,
192 const bool linearInZero = true);
193 BlackSwaptionEngineDeltaGamma(const Handle<YieldTermStructure>& discountCurve, const Handle<Quote>& vol,
194 const DayCounter& dc = Actual365Fixed(), Real displacement = 0.0,
195 const std::vector<Time>& bucketTimesDeltaGamma = std::vector<Time>(),
196 const std::vector<Time>& bucketTimesVegaOpt = std::vector<Time>(),
197 const std::vector<Time>& bucketTimesVegaUnd = std::vector<Time>(),
198 const bool computeDeltaVega = false, const bool computeGamma = false,
199 const bool linearInZero = true);
200 BlackSwaptionEngineDeltaGamma(const Handle<YieldTermStructure>& discountCurve,
201 const Handle<SwaptionVolatilityStructure>& vol,
202 const std::vector<Time>& bucketTimesDeltaGamma = std::vector<Time>(),
203 const std::vector<Time>& bucketTimesVegaOpt = std::vector<Time>(),
204 const std::vector<Time>& bucketTimesVegaUnd = std::vector<Time>(),
205 const bool computeDeltaVega = false, const bool computeGamma = false,
206 const bool linearInZero = true);
207};
208
209//! Normal Bachelier-formula swaption engine
210/*! \ingroup swaptionengines
211
212 \warning The engine assumes that the exercise date equals the
213 start date of the passed swap.
214*/
215
217public:
218 BachelierSwaptionEngineDeltaGamma(const Handle<YieldTermStructure>& discountCurve, Volatility vol,
219 const DayCounter& dc = Actual365Fixed(),
220 const std::vector<Time>& bucketTimesDeltaGamma = std::vector<Time>(),
221 const std::vector<Time>& bucketTimesVegaOpt = std::vector<Time>(),
222 const std::vector<Time>& bucketTimesVegaUnd = std::vector<Time>(),
223 const bool computeDeltaVega = false, const bool computeGamma = false,
224 const bool linearInZero = true);
225 BachelierSwaptionEngineDeltaGamma(const Handle<YieldTermStructure>& discountCurve, const Handle<Quote>& vol,
226 const DayCounter& dc = Actual365Fixed(),
227 const std::vector<Time>& bucketTimesDeltaGamma = std::vector<Time>(),
228 const std::vector<Time>& bucketTimesVegaOpt = std::vector<Time>(),
229 const std::vector<Time>& bucketTimesVegaUnd = std::vector<Time>(),
230 const bool computeDeltaVega = false, const bool computeGamma = false,
231 const bool linearInZero = true);
232 BachelierSwaptionEngineDeltaGamma(const Handle<YieldTermStructure>& discountCurve,
233 const Handle<SwaptionVolatilityStructure>& vol,
234 const std::vector<Time>& bucketTimesDeltaGamma = std::vector<Time>(),
235 const std::vector<Time>& bucketTimesVegaOpt = std::vector<Time>(),
236 const std::vector<Time>& bucketTimesVegaUnd = std::vector<Time>(),
237 const bool computeDeltaVega = false, const bool computeGamma = false,
238 const bool linearInZero = true);
239};
240
241// implementation
242
243namespace detail {
244
245template <class Spec>
247 const Handle<YieldTermStructure>& discountCurve, Volatility vol, const DayCounter& dc, Real displacement,
248 const std::vector<Time>& bucketTimesDeltaGamma, const std::vector<Time>& bucketTimesVegaOpt,
249 const std::vector<Time>& bucketTimesVegaUnd, const bool computeDeltaVega, const bool computeGamma,
250 const bool linearInZero)
251 : discountCurve_(discountCurve), vol_(QuantLib::ext::shared_ptr<SwaptionVolatilityStructure>(new ConstantSwaptionVolatility(
252 0, NullCalendar(), Following, vol, dc, Spec().type, displacement))),
253 displacement_(displacement), bucketTimesDeltaGamma_(bucketTimesDeltaGamma),
254 bucketTimesVegaOpt_(bucketTimesVegaOpt), bucketTimesVegaUnd_(bucketTimesVegaUnd),
255 computeDeltaVega_(computeDeltaVega), computeGamma_(computeGamma), linearInZero_(linearInZero) {
256 registerWith(discountCurve_);
257 QL_REQUIRE((!bucketTimesDeltaGamma_.empty() && !bucketTimesVegaOpt_.empty() && !bucketTimesVegaUnd_.empty()) ||
258 (!computeDeltaVega && !computeGamma),
259 "bucket times are empty, although sensitivities have to be calculated");
260}
261
262template <class Spec>
264 const Handle<YieldTermStructure>& discountCurve, const Handle<Quote>& vol, const DayCounter& dc, Real displacement,
265 const std::vector<Time>& bucketTimesDeltaGamma, const std::vector<Time>& bucketTimesVegaOpt,
266 const std::vector<Time>& bucketTimesVegaUnd, const bool computeDeltaVega, const bool computeGamma,
267 const bool linearInZero)
268 : discountCurve_(discountCurve), vol_(QuantLib::ext::shared_ptr<SwaptionVolatilityStructure>(new ConstantSwaptionVolatility(
269 0, NullCalendar(), Following, vol, dc, Spec().type, displacement))),
270 displacement_(displacement), bucketTimesDeltaGamma_(bucketTimesDeltaGamma),
271 bucketTimesVegaOpt_(bucketTimesVegaOpt), bucketTimesVegaUnd_(bucketTimesVegaUnd),
272 computeDeltaVega_(computeDeltaVega), computeGamma_(computeGamma), linearInZero_(linearInZero) {
273 registerWith(discountCurve_);
274 registerWith(vol_);
275 QL_REQUIRE((!bucketTimesDeltaGamma_.empty() && !bucketTimesVegaOpt_.empty() && !bucketTimesVegaUnd_.empty()) ||
276 (!computeDeltaVega && !computeGamma),
277 "bucket times are empty, although sensitivities have to be calculated");
278}
279
280template <class Spec>
282 const Handle<YieldTermStructure>& discountCurve, const Handle<SwaptionVolatilityStructure>& volatility,
283 const std::vector<Time>& bucketTimesDeltaGamma, const std::vector<Time>& bucketTimesVegaOpt,
284 const std::vector<Time>& bucketTimesVegaUnd, const bool computeDeltaVega, const bool computeGamma,
285 const bool linearInZero)
286 : discountCurve_(discountCurve), vol_(volatility), displacement_(0.0),
287 bucketTimesDeltaGamma_(bucketTimesDeltaGamma), bucketTimesVegaOpt_(bucketTimesVegaOpt),
288 bucketTimesVegaUnd_(bucketTimesVegaUnd), computeDeltaVega_(computeDeltaVega), computeGamma_(computeGamma),
289 linearInZero_(linearInZero) {
290 registerWith(discountCurve_);
291 registerWith(vol_);
292 QL_REQUIRE((!bucketTimesDeltaGamma_.empty() && !bucketTimesVegaOpt_.empty() && !bucketTimesVegaUnd_.empty()) ||
293 (!computeDeltaVega && !computeGamma),
294 "bucket times are empty, although sensitivities have to be calculated");
295}
296
297template <class Spec> void BlackStyleSwaptionEngineDeltaGamma<Spec>::calculate() const {
298 Date exerciseDate = arguments_.exercise->date(0);
299 VanillaSwap swap = *arguments_.swap;
300 Rate strike = swap.fixedRate();
301
302 std::vector<Leg> floatLeg(1, swap.leg(1)), fixedLeg(1, swap.leg(0));
303 std::vector<bool> payerFloat(1, false), payerFixed(1, false);
304 QuantLib::Swap swapFloatLeg(floatLeg, payerFloat), swapFixedLeg(fixedLeg, payerFixed);
305
306 QuantLib::ext::shared_ptr<PricingEngine> engine = QuantLib::ext::make_shared<DiscountingSwapEngine>(discountCurve_);
307 QuantLib::ext::shared_ptr<PricingEngine> engine1 = QuantLib::ext::make_shared<DiscountingSwapEngineDeltaGamma>(
308 discountCurve_, bucketTimesDeltaGamma_, computeDeltaVega_, computeGamma_, false, linearInZero_);
309 QuantLib::ext::shared_ptr<PricingEngine> engine2 = QuantLib::ext::make_shared<DiscountingSwapEngineDeltaGamma>(
310 discountCurve_, bucketTimesDeltaGamma_, computeDeltaVega_, computeGamma_, true, linearInZero_);
311
312 swap.setPricingEngine(engine);
313 swapFloatLeg.setPricingEngine(engine1);
314 swapFixedLeg.setPricingEngine(engine2);
315
316 Rate atmForward = swapFloatLeg.NPV() / swapFixedLeg.legBPS(0);
317
318 // If we allow for non-zero spreads, more adjustments are needed than below, investigate this later
319 QL_REQUIRE(QuantLib::close_enough(swap.spread(), 0.0), "BlackSwaptionEngineDeltaGamma requires zero spread");
320
321 // Volatilities are quoted for zero-spreaded swaps.
322 // Therefore, any spread on the floating leg must be removed
323 // with a corresponding correction on the fixed leg.
324 // if (swap.spread() != 0.0) {
325 // Spread correction = swap.spread() * std::fabs(swap.floatingLegBPS() / swap.fixedLegBPS());
326 // strike -= correction;
327 // atmForward -= correction;
328 // results_.additionalResults["spreadCorrection"] = correction;
329 // } else {
330 // results_.additionalResults["spreadCorrection"] = 0.0;
331 // }
332
333 results_.additionalResults["strike"] = strike;
334 results_.additionalResults["atmForward"] = atmForward;
335
336 swap.setPricingEngine(QuantLib::ext::shared_ptr<PricingEngine>(new DiscountingSwapEngine(discountCurve_, false)));
337
338 // TODO this is for physical settlement only, add pricing + sensitivities for cash settlement
339 Real annuity = std::fabs(swap.fixedLegBPS()) / 1.0E-4;
340 results_.additionalResults["annuity"] = annuity;
341
342 Time swapLength = vol_->swapLength(swap.floatingSchedule().dates().front(), swap.floatingSchedule().dates().back());
343 results_.additionalResults["swapLength"] = swapLength;
344
345 Real variance = vol_->blackVariance(exerciseDate, swapLength, strike);
346 Real stdDev = std::sqrt(variance);
347 results_.additionalResults["stdDev"] = stdDev;
348 Option::Type w = (arguments_.type == VanillaSwap::Payer) ? Option::Call : Option::Put;
349 results_.value = Spec().value(w, strike, atmForward, stdDev, annuity, displacement_);
350
351 // sensitivity calculation
352 QL_REQUIRE(!computeGamma_ || computeDeltaVega_,
353 "BlackSwaptionEngineDeltaGamma, gamma can only be computed if delta is computed as well");
354 if (computeDeltaVega_) {
355 Time exerciseTime = vol_->timeFromReference(exerciseDate);
356 // vega
357 int n1 = bucketTimesVegaOpt_.size();
358 int n2 = bucketTimesVegaUnd_.size();
359 int b1 =
360 static_cast<int>(std::upper_bound(bucketTimesVegaOpt_.begin(), bucketTimesVegaOpt_.end(), exerciseTime) -
361 bucketTimesVegaOpt_.begin());
362 int b2 = static_cast<int>(std::upper_bound(bucketTimesVegaUnd_.begin(), bucketTimesVegaUnd_.end(), swapLength) -
363 bucketTimesVegaUnd_.begin());
364 Real w1, w2;
365 int i1, i2;
366 if (b1 == 0) {
367 w1 = 1.0;
368 i1 = 0;
369 } else if (b1 == n1) {
370 w1 = 0.0;
371 i1 = n1 - 2;
372 } else {
373 w1 = (bucketTimesVegaOpt_[b1] - exerciseTime) / (bucketTimesVegaOpt_[b1] - bucketTimesVegaOpt_[b1 - 1]);
374 i1 = b1 - 1;
375 }
376 if (b2 == 0) {
377 w2 = 1.0;
378 i2 = 0;
379 } else if (b2 == n2) {
380 w2 = 0.0;
381 i2 = n2 - 2;
382 } else {
383 w2 = (bucketTimesVegaUnd_[b2] - swapLength) / (bucketTimesVegaUnd_[b2] - bucketTimesVegaUnd_[b2 - 1]);
384 i2 = b2 - 1;
385 }
386 Real singleVega = Spec().vega(strike, atmForward, stdDev, exerciseTime, annuity, displacement_);
387 Matrix vega(n1, n2, 0.0);
388 if (i1 >= 0) {
389 if (i2 < n2)
390 vega[i1][i2 + 1] = w1 * (1.0 - w2) * singleVega;
391 if (i2 >= 0) {
392 vega[i1][i2] = w1 * w2 * singleVega;
393 }
394 }
395 if (i2 >= 0 && i1 < n1) {
396 vega[i1 + 1][i2] = (1.0 - w1) * w2 * singleVega;
397 }
398 if (i1 < n1 && i2 < n2)
399 vega[i1 + 1][i2 + 1] = (1.0 - w1) * (1.0 - w2) * singleVega;
400 results_.additionalResults["vega"] = vega;
401 // delta
402 Real mu = swapFloatLeg.NPV();
403 Real black = results_.value / annuity;
404 Real blackDelta = Spec().delta(w, strike, atmForward, stdDev, 1.0, displacement_);
405 std::vector<Real> A_s_1 = swapFixedLeg.result<std::vector<std::vector<Real>>>("deltaBPS")[0];
406 Array A_s(A_s_1.begin(), A_s_1.end());
407 std::vector<Real> mu_sd_1 = swapFloatLeg.result<std::vector<Real>>("deltaDiscount");
408 std::vector<Real> mu_sf_1 = swapFloatLeg.result<std::vector<Real>>("deltaForward");
409 Array mu_sd(mu_sd_1.begin(), mu_sd_1.end());
410 Array mu_sf(mu_sf_1.begin(), mu_sf_1.end());
411 Array F_sd = 1.0 / annuity * mu_sd - 1.0 / (annuity * annuity) * mu * A_s;
412 Array F_sf = 1.0 / annuity * mu_sf;
413 Array deltaDiscount = black * A_s + annuity * blackDelta * F_sd;
414 Array deltaForward = annuity * blackDelta * F_sf;
415 std::vector<Real> deltaDiscount1(deltaDiscount.begin(), deltaDiscount.end());
416 std::vector<Real> deltaForward1(deltaForward.begin(), deltaForward.end());
417 results_.additionalResults["deltaDiscount"] = deltaDiscount1;
418 results_.additionalResults["deltaForward"] = deltaForward1;
419 // theta
420 results_.additionalResults["theta"] =
421 annuity * Spec().theta(strike, atmForward, stdDev, exerciseTime, 1.0, displacement_);
422 if (computeGamma_) {
423 // gamma
424 Size n = bucketTimesDeltaGamma_.size();
425 Real blackGamma = Spec().gamma(strike, atmForward, stdDev, 1.0, displacement_);
426 Matrix A_ss = swapFixedLeg.result<std::vector<Matrix>>("gammaBPS")[0];
427 Matrix mu_ss = swapFloatLeg.result<Matrix>("gamma");
428 Matrix result(2 * n, 2 * n, 0.0);
429 for (Size i = 0; i < 2 * n; ++i) {
430 bool iIsDsc = i < n;
431 Real Fi = iIsDsc ? (mu_sd[i] / annuity - mu * A_s[i] / (annuity * annuity)) : (mu_sf[i - n] / annuity);
432 for (Size j = 0; j <= i; ++j) {
433 bool jIsDsc = j < n;
434 Real Fj =
435 jIsDsc ? (mu_sd[j] / annuity - mu * A_s[j] / (annuity * annuity)) : (mu_sf[j - n] / annuity);
436 Real Fij = mu_ss[i][j] / annuity;
437 if (iIsDsc) {
438 if (jIsDsc) {
439 Fij += -mu * A_ss[i][j] / (annuity * annuity);
440 result[i][j] += A_ss[i][j] * black;
441 }
442 Fij -= (jIsDsc ? mu_sd[j] : mu_sf[j - n]) * A_s[i] / (annuity * annuity);
443 result[i][j] += A_s[i] * blackDelta * Fj;
444 }
445 if (jIsDsc) {
446 Fij += (iIsDsc ? mu_sd[i] : mu_sf[i - n]) * A_s[j] / (annuity * annuity);
447 Fij -= 2.0 * A_s[j] * (iIsDsc ? mu_sd[i] : mu_sf[i - n]) / (annuity * annuity);
448 if (iIsDsc) {
449 Fij += 2.0 * A_s[j] * mu * A_s[i] / (annuity * annuity * annuity);
450 }
451 result[i][j] += A_s[j] * blackDelta * Fi;
452 }
453 result[i][j] += annuity * (blackGamma * Fi * Fj + blackDelta * Fij);
454 }
455 }
456 // mirror
457 for (Size i = 0; i < 2 * n; ++i) {
458 for (Size j = i + 1; j < 2 * n; ++j) {
459 result[i][j] = result[j][i];
460 }
461 }
462 results_.additionalResults["gamma"] = result;
463 }
464 }
465
466} // calculate()
467
468} // namespace detail
469} // namespace QuantExt
470
471#endif
QuantLib::ext::shared_ptr< SimpleQuote > vol_
Definition: cdsoption.cpp:80
const Instrument::results * results_
Definition: cdsoption.cpp:81
Shifted Lognormal Black-formula swaption engine.
BlackStyleSwaptionEngineDeltaGamma(const Handle< YieldTermStructure > &discountCurve, Volatility vol, const DayCounter &dc=Actual365Fixed(), Real displacement=0.0, const std::vector< Time > &bucketTimesDeltaGamma=std::vector< Time >(), const std::vector< Time > &bucketTimesVegaOpt=std::vector< Time >(), const std::vector< Time > &bucketTimesVegaUnd=std::vector< Time >(), const bool computeDeltaVega=false, const bool computeGamma=false, const bool linearInZero=true)
BlackStyleSwaptionEngineDeltaGamma(const Handle< YieldTermStructure > &discountCurve, const Handle< SwaptionVolatilityStructure > &vol, const std::vector< Time > &bucketTimesDeltaGamma=std::vector< Time >(), const std::vector< Time > &bucketTimesVegaOpt=std::vector< Time >(), const std::vector< Time > &bucketTimesVegaUnd=std::vector< Time >(), const bool computeDeltaVega=false, const bool computeGamma=false, const bool linearInZero=true)
BlackStyleSwaptionEngineDeltaGamma(const Handle< YieldTermStructure > &discountCurve, const Handle< Quote > &vol, const DayCounter &dc=Actual365Fixed(), Real displacement=0.0, const std::vector< Time > &bucketTimesDeltaGamma=std::vector< Time >(), const std::vector< Time > &bucketTimesVegaOpt=std::vector< Time >(), const std::vector< Time > &bucketTimesVegaUnd=std::vector< Time >(), const bool computeDeltaVega=false, const bool computeGamma=false, const bool linearInZero=true)
Swap engine providing analytical deltas and gammas for vanilla swaps.
RandomVariable variance(const RandomVariable &r)
RandomVariable black(const RandomVariable &omega, const RandomVariable &t, const RandomVariable &strike, const RandomVariable &forward, const RandomVariable &impliedVol)
Real vega(const Real strike, const Real atmForward, const Real stdDev, const Real exerciseTime, const Real annuity, const Real)
Real value(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity, const Real)
Real theta(const Real strike, const Real atmForward, const Real stdDev, const Real exerciseTime, const Real annuity, const Real displacement)
Real gamma(const Real strike, const Real atmForward, const Real stdDev, const Real annuity, const Real displacement)
Real delta(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity, const Real displacement)
Real theta(const Real strike, const Real atmForward, const Real stdDev, const Real exerciseTime, const Real annuity, const Real displacement)
Real value(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity, const Real displacement)
Real vega(const Real strike, const Real atmForward, const Real stdDev, const Real exerciseTime, const Real annuity, const Real displacement)
Real gamma(const Real strike, const Real atmForward, const Real stdDev, const Real annuity, const Real displacement)
Real delta(const Option::Type type, const Real strike, const Real atmForward, const Real stdDev, const Real annuity, const Real displacement)
Swap::arguments * arguments_