21#include <ql/instruments/vanillaswap.hpp>
27template <
class Key> Real&
getMapEntry(std::map<Key, Real>& map,
const Key& key) {
28 auto f = map.find(key);
30 return map.insert(std::make_pair(key, 0.0)).first->second;
37 Real& bps,
const bool computeDelta,
const bool computeGamma,
38 const bool computeBPS, std::map<Date, Real>& deltaDiscount,
39 std::map<Date, Real>& deltaForward, std::map<Date, Real>& deltaBPS,
40 std::map<Date, Real>& gammaDiscount,
41 std::map<std::pair<Date, Date>, Real>& gammaForward,
42 std::map<std::pair<Date, Date>, Real>& gammaDscFwd,
43 std::map<Date, Real>& gammaBPS, Real& fxLinkedForeignNpv,
44 const bool excludeSimpleCashFlowsFromSensis, Real& simpleCashFlowNpv)
45 : discountCurve_(discountCurve), payer_(payer), npv_(npv), bps_(bps), computeDelta_(computeDelta),
46 computeGamma_(computeGamma), computeBPS_(computeBPS), deltaDiscount_(deltaDiscount), deltaForward_(deltaForward),
47 deltaBPS_(deltaBPS), gammaDiscount_(gammaDiscount), gammaForward_(gammaForward), gammaDscFwd_(gammaDscFwd),
48 gammaBPS_(gammaBPS), fxLinkedForeignNpv_(fxLinkedForeignNpv),
49 excludeSimpleCashFlowsFromSensis_(excludeSimpleCashFlowsFromSensis), simpleCashFlowNpv_(simpleCashFlowNpv) {}
53 Real a =
payer_ * c.amount() * dsc;
68 Real a =
payer_ * c.amount() * dsc;
72 visit(
static_cast<CashFlow&
>(c));
77 Real a =
payer_ * c.amount() * dsc;
87 Real tau = c.accrualPeriod();
100 Real a =
payer_ * c.amount() * dsc;
111 Real tau = c.accrualPeriod();
120 Date fixing = c.fixingDate();
124 (fixing ==
discountCurve_->referenceDate() && c.index()->pastFixing(fixing) == Null<Real>())) {
125 Date d1 = c.index()->valueDate(fixing);
127 if (IborCoupon::Settings::instance().usingAtParCoupons() && fixing <= c.accrualStartDate()) {
129 Date nextFixingDate =
130 c.index()->fixingCalendar().advance(c.accrualEndDate(), -
static_cast<Integer
>(c.fixingDays()), Days);
131 d2 = c.index()->fixingCalendar().advance(nextFixingDate, c.fixingDays(), Days);
132 }
else if (IborCoupon::Settings::instance().usingAtParCoupons()) {
134 d2 = c.index()->maturityDate(d1);
137 d2 = c.index()->maturityDate(d1);
147 (c.nominal() * c.accrualPeriod() *
148 (c.gearing() / c.index()->dayCounter().yearFraction(d1, d2) - c.spread()));
171 Real tmp = c.
fxIndex()->forecastFixing(0.0);
192 Real tmp = c.
fxIndex()->forecastFixing(0.0);
203std::vector<Real>
rebucketDeltas(
const std::vector<Time>& deltaTimes,
const std::map<Date, Real>& deltaRaw,
204 const Date& referenceDate,
const DayCounter& dc,
const bool linearInZero) {
205 std::vector<Real> delta(deltaTimes.size(), 0.0);
206 for (std::map<Date, Real>::const_iterator i = deltaRaw.begin(); i != deltaRaw.end(); ++i) {
207 Real t = dc.yearFraction(referenceDate, i->first);
208 Size b = std::upper_bound(deltaTimes.begin(), deltaTimes.end(), t) - deltaTimes.begin();
210 delta[0] += i->second;
211 }
else if (b == deltaTimes.size()) {
212 delta.back() += i->second;
214 Real tmp = (deltaTimes[b] - t) / (deltaTimes[b] - deltaTimes[b - 1]);
216 delta[b - 1] += i->second * tmp;
217 delta[b] += i->second * (1.0 - tmp);
219 delta[b - 1] += i->second * tmp * deltaTimes[b - 1] / t;
220 delta[b] += i->second * (1.0 - tmp) * deltaTimes[b] / t;
227Matrix
rebucketGammas(
const std::vector<Time>& gammaTimes,
const std::map<Date, Real>& gammaDscRaw,
228 std::map<std::pair<Date, Date>, Real>& gammaForward,
229 std::map<std::pair<Date, Date>, Real>& gammaDscFwd,
const bool forceFullMatrix,
230 const Date& referenceDate,
const DayCounter& dc,
const bool linearInZero) {
231 int n = gammaTimes.size();
233 Size n2 = !forceFullMatrix && gammaForward.empty() && gammaDscFwd.empty() ? n : 2 * n;
234 Matrix gamma(n2, n2, 0.0);
236 for (std::map<Date, Real>::const_iterator i = gammaDscRaw.begin(); i != gammaDscRaw.end(); ++i) {
237 Real t = dc.yearFraction(referenceDate, i->first);
238 int b = (int)(std::upper_bound(gammaTimes.begin(), gammaTimes.end(), t) - gammaTimes.begin());
240 gamma[0][0] += i->second;
242 gamma[n - 1][n - 1] += i->second;
244 Real tmp = (gammaTimes[b] - t) / (gammaTimes[b] - gammaTimes[b - 1]);
246 gamma[b - 1][b - 1] += i->second * tmp * tmp;
247 gamma[b - 1][b] += i->second * (1.0 - tmp) * tmp;
248 gamma[b][b - 1] += i->second * tmp * (1.0 - tmp);
249 gamma[b][b] += i->second * (1.0 - tmp) * (1.0 - tmp);
251 gamma[b - 1][b - 1] += i->second * tmp * tmp * gammaTimes[b - 1] * gammaTimes[b - 1] / (t * t);
252 gamma[b - 1][b] += i->second * (1.0 - tmp) * tmp * gammaTimes[b] * gammaTimes[b - 1] / (t * t);
253 gamma[b][b - 1] += i->second * tmp * (1.0 - tmp) * gammaTimes[b - 1] * gammaTimes[b] / (t * t);
254 gamma[b][b] += i->second * (1.0 - tmp) * (1.0 - tmp) * gammaTimes[b] * gammaTimes[b] / (t * t);
259 if (!gammaDscFwd.empty()) {
260 Matrix gammadf(n, n, 0.0);
261 for (std::map<std::pair<Date, Date>, Real>::const_iterator i = gammaDscFwd.begin(); i != gammaDscFwd.end();
263 Real t1 = dc.yearFraction(referenceDate, i->first.first);
264 Real t2 = dc.yearFraction(referenceDate, i->first.second);
265 int b1 = (int)(std::upper_bound(gammaTimes.begin(), gammaTimes.end(), t1) - gammaTimes.begin());
266 int b2 = (int)(std::upper_bound(gammaTimes.begin(), gammaTimes.end(), t2) - gammaTimes.begin());
267 Real w1 = 0.0, w2 = 0.0;
272 }
else if (b1 == n) {
276 w1 = (gammaTimes[b1] - t1) / (gammaTimes[b1] - gammaTimes[b1 - 1]);
282 }
else if (b2 == n) {
286 w2 = (gammaTimes[b2] - t2) / (gammaTimes[b2] - gammaTimes[b2 - 1]);
291 gammadf[i1][i2 + 1] += w1 * (1.0 - w2) * i->second *
292 (linearInZero ? 1.0 : gammaTimes[b1 - 1] * gammaTimes[b2] / (t1 * t2));
294 gammadf[i1][i2] += w1 * w2 * i->second *
295 (linearInZero ? 1.0 : gammaTimes[b1 - 1] * gammaTimes[b2 - 1] / (t1 * t2));
298 if (i2 >= 0 && i1 < n - 1) {
299 gammadf[i1 + 1][i2] += (1.0 - w1) * w2 * i->second *
300 (linearInZero ? 1.0 : gammaTimes[b1] * gammaTimes[b2 - 1] / (t1 * t2));
302 if (i1 < n - 1 && i2 < n - 1) {
303 gammadf[i1 + 1][i2 + 1] += (1.0 - w1) * (1.0 - w2) * i->second *
304 (linearInZero ? 1.0 : gammaTimes[b1] * gammaTimes[b2] / (t1 * t2));
307 for (
int i = 0; i < n; ++i) {
308 for (
int j = 0; j < n; ++j) {
309 gamma[i][n + j] = gamma[n + j][i] = gammadf[i][j];
314 for (std::map<std::pair<Date, Date>, Real>::const_iterator i = gammaForward.begin(); i != gammaForward.end(); ++i) {
315 Real t1 = dc.yearFraction(referenceDate, i->first.first);
316 Real t2 = dc.yearFraction(referenceDate, i->first.second);
317 int b1 = (int)(std::upper_bound(gammaTimes.begin(), gammaTimes.end(), t1) - gammaTimes.begin());
318 int b2 = (int)(std::upper_bound(gammaTimes.begin(), gammaTimes.end(), t2) - gammaTimes.begin());
319 Real tmp = 0.5 * i->second;
320 Real w1 = 0.0, w2 = 0.0;
325 }
else if (b1 == n) {
329 w1 = (gammaTimes[b1] - t1) / (gammaTimes[b1] - gammaTimes[b1 - 1]);
335 }
else if (b2 == n) {
339 w2 = (gammaTimes[b2] - t2) / (gammaTimes[b2] - gammaTimes[b2 - 1]);
344 gamma[n + i1][n + i2 + 1] +=
345 w1 * (1.0 - w2) * tmp * (linearInZero ? 1.0 : gammaTimes[b1 - 1] * gammaTimes[b2] / (t1 * t2));
346 gamma[n + i2 + 1][n + i1] +=
347 w1 * (1.0 - w2) * tmp * (linearInZero ? 1.0 : gammaTimes[b1 - 1] * gammaTimes[b2] / (t1 * t2));
350 gamma[n + i1][n + i2] +=
351 w1 * w2 * tmp * (linearInZero ? 1.0 : gammaTimes[b1 - 1] * gammaTimes[b2 - 1] / (t1 * t2));
352 gamma[n + i2][n + i1] +=
353 w1 * w2 * tmp * (linearInZero ? 1.0 : gammaTimes[b1 - 1] * gammaTimes[b2 - 1] / (t1 * t2));
356 if (i2 >= 0 && i1 < n - 1) {
357 gamma[n + i1 + 1][n + i2] +=
358 (1.0 - w1) * w2 * tmp * (linearInZero ? 1.0 : gammaTimes[b1] * gammaTimes[b2 - 1] / (t1 * t2));
359 gamma[n + i2][n + i1 + 1] +=
360 (1.0 - w1) * w2 * tmp * (linearInZero ? 1.0 : gammaTimes[b1] * gammaTimes[b2 - 1] / (t1 * t2));
362 if (i1 < n - 1 && i2 < n - 1) {
363 gamma[n + i1 + 1][n + i2 + 1] +=
364 (1.0 - w1) * (1.0 - w2) * tmp * (linearInZero ? 1.0 : gammaTimes[b1] * gammaTimes[b2] / (t1 * t2));
365 gamma[n + i2 + 1][n + i1 + 1] +=
366 (1.0 - w1) * (1.0 - w2) * tmp * (linearInZero ? 1.0 : gammaTimes[b1] * gammaTimes[b2] / (t1 * t2));
376 const std::vector<Time>& bucketTimes,
377 const bool computeDelta,
const bool computeGamma,
378 const bool computeBPS,
const bool linearInZero)
379 : discountCurve_(discountCurve), bucketTimes_(bucketTimes), computeDelta_(computeDelta),
380 computeGamma_(computeGamma), computeBPS_(computeBPS), linearInZero_(linearInZero) {
382 QL_REQUIRE(!
bucketTimes_.empty() || (!computeDelta && !computeGamma),
383 "bucket times are empty, although sensitivities have to be calculated");
387 QL_REQUIRE(!
discountCurve_.empty(),
"discounting term structure handle is empty");
392 results_.errorEstimate = Null<Real>();
397 std::map<Date, Real> deltaDiscountRaw, deltaForwardRaw, gammaDiscountRaw;
398 std::map<std::pair<Date, Date>, Real> gammaForwardRaw, gammaDscFwdRaw;
400 std::vector<std::vector<Real>> deltaBPS;
401 std::vector<Matrix> gammaBPS;
405 for (Size j = 0; j <
arguments_.legs.size(); ++j) {
406 Real npv = 0.0, bps = 0.0;
407 std::map<Date, Real> deltaBPSRaw, gammaBPSRaw;
410 gammaDiscountRaw, gammaForwardRaw, gammaDscFwdRaw, gammaBPSRaw, empty,
413 for (Size i = 0; i < leg.size(); ++i) {
414 CashFlow& cf = *leg[i];
423 std::map<std::pair<Date, Date>, Real> empty;
429 deltaBPS.push_back(tmp);
433 gammaBPS.push_back(tmp2);
442 std::vector<Real> deltaDiscount =
445 std::vector<Real> deltaForward =
449 results_.additionalResults[
"deltaDiscount"] = deltaDiscount;
450 results_.additionalResults[
"deltaForward"] = deltaForward;
452 results_.additionalResults[
"deltaBPS"] = deltaBPS;
462 results_.additionalResults[
"gamma"] = gamma;
464 results_.additionalResults[
"gammaBPS"] = gammaBPS;
const Instrument::results * results_
const std::vector< Real > bucketTimes_
Handle< YieldTermStructure > discountCurve_
void calculate() const override
DiscountingSwapEngineDeltaGamma(const Handle< YieldTermStructure > &discountCurve=Handle< YieldTermStructure >(), const std::vector< Time > &bucketTimes=std::vector< Time >(), const bool computeDelta=false, const bool computeGamma=false, const bool computeBPS=false, const bool linearInZero=true)
Real amount() const override
Date date() const override
const QuantLib::ext::shared_ptr< FxIndex > & fxIndex() const
Date fxFixingDate() const
Handle< YieldTermStructure > discountCurve_
std::map< Date, Real > & deltaBPS_
std::map< Date, Real > & deltaDiscount_
std::map< Date, Real > & deltaForward_
std::map< std::pair< Date, Date >, Real > & gammaDscFwd_
std::map< Date, Real > & gammaBPS_
const bool excludeSimpleCashFlowsFromSensis_
NpvDeltaGammaCalculator(Handle< YieldTermStructure > discountCurve, const Real payer, Real &npv, Real &bps, const bool computeDelta, const bool computeGamma, const bool computeBPS, std::map< Date, Real > &deltaDiscount, std::map< Date, Real > &deltaForward, std::map< Date, Real > &deltaBPS, std::map< Date, Real > &gammaDiscount, std::map< std::pair< Date, Date >, Real > &gammaForward, std::map< std::pair< Date, Date >, Real > &gammaDscFwd, std::map< Date, Real > &gammaBPS, Real &fxLinkedForeignNpv, const bool excludeSimpleCashFlowsFromSensis, Real &simpleCashFlowNpv)
std::map< std::pair< Date, Date >, Real > & gammaForward_
void visit(CashFlow &c) override
Real & fxLinkedForeignNpv_
void processIborCoupon(FloatingRateCoupon &c)
std::map< Date, Real > & gammaDiscount_
Real & simpleCashFlowNpv_
Swap engine providing analytical deltas and gammas for vanilla swaps.
Matrix rebucketGammas(const std::vector< Time > &gammaTimes, const std::map< Date, Real > &gammaDscRaw, std::map< std::pair< Date, Date >, Real > &gammaForward, std::map< std::pair< Date, Date >, Real > &gammaDscFwd, const bool forceFullMatrix, const Date &referenceDate, const DayCounter &dc, const bool linearInZero)
Real & getMapEntry(std::map< Key, Real > &map, const Key &key)
std::vector< Real > rebucketDeltas(const std::vector< Time > &deltaTimes, const std::map< Date, Real > &deltaRaw, const Date &referenceDate, const DayCounter &dc, const bool linearInZero)
Swap::arguments * arguments_