Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
discountingcurrencyswapenginedeltagamma.cpp
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
21
22#include <ql/cashflows/cashflows.hpp>
23#include <ql/cashflows/floatingratecoupon.hpp>
24#include <ql/exchangerate.hpp>
25#include <ql/utilities/dataformatters.hpp>
26
27#include <ql/cashflows/cashflows.hpp>
28#include <ql/errors.hpp>
29
30#include <boost/unordered_map.hpp>
31
32namespace QuantExt {
33
35 const std::vector<Handle<YieldTermStructure>>& discountCurves, const std::vector<Handle<Quote>>& fxQuotes,
36 const std::vector<Currency>& currencies, const Currency& npvCurrency, const std::vector<Time>& bucketTimes,
37 const bool computeDelta, const bool computeGamma, const bool linearInZero, const bool applySimmExemptions)
38 : discountCurves_(discountCurves), fxQuotes_(fxQuotes), currencies_(currencies), npvCurrency_(npvCurrency),
39 bucketTimes_(bucketTimes), computeDelta_(computeDelta), computeGamma_(computeGamma), linearInZero_(linearInZero),
40 applySimmExemptions_(applySimmExemptions) {
41
42 QL_REQUIRE(discountCurves_.size() == currencies_.size(), "Number of "
43 "currencies does not match number of discount curves.");
44 QL_REQUIRE(fxQuotes_.size() == currencies_.size(), "Number of "
45 "currencies does not match number of FX quotes.");
46
47 for (Size i = 0; i < discountCurves_.size(); i++) {
48 registerWith(discountCurves_[i]);
49 registerWith(fxQuotes_[i]);
50 }
51
52 QL_REQUIRE(!bucketTimes_.empty() || (!computeDelta && !computeGamma),
53 "bucket times are empty, although sensitivities have to be calculated");
54}
55
56Handle<YieldTermStructure> DiscountingCurrencySwapEngineDeltaGamma::fetchTS(Currency ccy) const {
57 std::vector<Currency>::const_iterator i = std::find(currencies_.begin(), currencies_.end(), ccy);
58 if (i == currencies_.end())
59 return Handle<YieldTermStructure>();
60 else
61 return discountCurves_[i - currencies_.begin()];
62}
63
64Handle<Quote> DiscountingCurrencySwapEngineDeltaGamma::fetchFX(Currency ccy) const {
65 std::vector<Currency>::const_iterator i = std::find(currencies_.begin(), currencies_.end(), ccy);
66 if (i == currencies_.end())
67 return Handle<Quote>();
68 else
69 return fxQuotes_[i - currencies_.begin()];
70}
71
73
74 for (Size i = 0; i < arguments_.currency.size(); i++) {
75 Currency ccy = arguments_.currency[i];
76 Handle<YieldTermStructure> yts = fetchTS(ccy);
77 QL_REQUIRE(!yts.empty(), "Discounting term structure is "
78 "empty for "
79 << ccy.name());
80 Handle<Quote> fxQuote = fetchFX(ccy);
81 QL_REQUIRE(!fxQuote.empty(), "FX quote is empty "
82 "for "
83 << ccy.name());
84 }
85
86 // Prepare the results containers
87 Size numLegs = arguments_.legs.size();
88
89 // - Instrument::results
90 results_.value = 0.0;
91 results_.errorEstimate = Null<Real>();
92
93 // - CurrencySwap::results
94 results_.legNPV.resize(numLegs);
95 results_.inCcyLegNPV.resize(numLegs);
96
97 // compute npv and raw deltas
98
99 std::map<Currency, std::map<Date, Real>, CurrencyComparator> deltaDiscountRaw, deltaForwardRaw, gammaDiscountRaw;
100 std::map<Currency, std::map<std::pair<Date, Date>, Real>, CurrencyComparator> gammaForwardRaw, gammaDscFwdRaw;
101 std::map<Currency, Real, CurrencyComparator> fxLinkedForeignNpv; // foreign ccy => npv in foreign ccy
102 std::map<Currency, Real, CurrencyComparator> fxSpot, fxSpotDelta;
103 std::set<Currency, CurrencyComparator> currencies;
104 std::map<Date, Real> empty, fxLinkedDeltaEmpty;
105
106 for (Size i = 0; i < numLegs; ++i) {
107 try {
108 Currency ccy = arguments_.currency[i];
109
110 // look for second ccy, we need this for FX Linked Coupons - the assumption is then that there are
111 // exactly two currencies in the swap; if we don't find a second ccy, we do not collect contributions
112 // from fx linked coupons below
113 Currency ccy2;
114 Real fx2 = 1.0;
115 for (Size j = 0; j < numLegs; ++j) {
116 if (arguments_.currency[j] != ccy) {
117 ccy2 = arguments_.currency[j];
118 fx2 = fetchFX(ccy2)->value();
119 fxSpot[ccy2] = fx2;
120 }
121 }
122
123 currencies.insert(ccy);
124 Handle<YieldTermStructure> yts = fetchTS(ccy);
125 Real npv = 0.0, bps = 0.0, simpleCashFlowNpv = 0.0;
126 Real fxLinkedForeignNpvTmp = 0.0;
128 yts, arguments_.payer[i], npv, bps, computeDelta_, computeGamma_, false, deltaDiscountRaw[ccy],
129 deltaForwardRaw[ccy], empty, gammaDiscountRaw[ccy], gammaForwardRaw[ccy], gammaDscFwdRaw[ccy], empty,
130 fxLinkedForeignNpvTmp,
131 applySimmExemptions_ && arguments_.isPhysicallySettled && !arguments_.isResettable, simpleCashFlowNpv);
132 Leg& leg = arguments_.legs[i];
133 for (Size ii = 0; ii < leg.size(); ++ii) {
134 CashFlow& cf = *leg[ii];
135 if (cf.date() <= yts->referenceDate()) {
136 continue;
137 }
138 cf.accept(calc);
139 }
140 Real fx = fetchFX(ccy)->value();
141 fxSpotDelta[ccy] += npv;
142 fxSpot[ccy] = fx;
143 results_.inCcyLegNPV[i] = npv + simpleCashFlowNpv;
144 results_.legNPV[i] = results_.inCcyLegNPV[i] * fx;
145 results_.value += results_.legNPV[i];
146 // handle contribution from FX Linked Coupon:
147 // - these should be subtracted from the fx spot delta in the converted ccy,
148 // - and added to the fx spot delta in the original ccy.
149 if (!ccy2.empty()) {
150 fxSpotDelta[ccy] -= fxLinkedForeignNpvTmp * fx2 / fx;
151 fxLinkedForeignNpv[ccy2] += fxLinkedForeignNpvTmp;
152 }
153 } catch (std::exception& e) {
154 QL_FAIL("DiscountingCurrencySwapEngineDeltaGamma, leg " << i << ": " << e.what());
155 }
156 } // i = 0, ... ,numlegs
157
158 // contributions from FX Linked Coupons to fx spot delta
159
160 for (auto const& f : fxLinkedForeignNpv) {
161 fxSpotDelta[f.first] += f.second;
162 }
163
164 // set results
165
166 results_.additionalResults["fxSpot"] = fxSpot;
167 results_.additionalResults["deltaFxSpot"] = fxSpotDelta;
168
169 // convert raw deltas to given bucketing structure
170
171 results_.additionalResults["bucketTimes"] = bucketTimes_;
172
173 if (computeDelta_) {
174 std::map<Currency, std::vector<Real>, CurrencyComparator> deltaDiscount, deltaForward;
175 for (std::map<Currency, std::map<Date, Real>, CurrencyComparator>::const_iterator i = deltaDiscountRaw.begin();
176 i != deltaDiscountRaw.end(); ++i) {
177 Handle<YieldTermStructure> yts = fetchTS(i->first);
178 deltaDiscount[i->first] =
179 detail::rebucketDeltas(bucketTimes_, i->second, yts->referenceDate(), yts->dayCounter(), linearInZero_);
180 }
181 results_.additionalResults["deltaDiscount"] = deltaDiscount;
182
183 for (std::map<Currency, std::map<Date, Real>, CurrencyComparator>::const_iterator i = deltaForwardRaw.begin();
184 i != deltaForwardRaw.end(); ++i) {
185 Handle<YieldTermStructure> yts = fetchTS(i->first);
186 deltaForward[i->first] =
187 detail::rebucketDeltas(bucketTimes_, i->second, yts->referenceDate(), yts->dayCounter(), linearInZero_);
188 }
189 results_.additionalResults["deltaForward"] = deltaForward;
190 }
191
192 // convert raw gammas to given bucketing structure
193
194 if (computeGamma_) {
195 std::map<Currency, Matrix, CurrencyComparator> gamma;
196 for (std::set<Currency>::const_iterator i = currencies.begin(); i != currencies.end(); ++i) {
197 Handle<YieldTermStructure> yts = fetchTS(*i);
198 Matrix tmp =
199 detail::rebucketGammas(bucketTimes_, gammaDiscountRaw[*i], gammaForwardRaw[*i], gammaDscFwdRaw[*i],
200 true, yts->referenceDate(), yts->dayCounter(), linearInZero_);
201 gamma[*i] = tmp;
202 }
203 results_.additionalResults["gamma"] = gamma;
204 }
205
206} // calculate
207
208} // namespace QuantExt
const Instrument::results * results_
Definition: cdsoption.cpp:81
const std::vector< Handle< YieldTermStructure > > discountCurves_
DiscountingCurrencySwapEngineDeltaGamma(const std::vector< Handle< YieldTermStructure > > &discountCurves, const std::vector< Handle< Quote > > &fxQuotes, const std::vector< Currency > &currencies, const Currency &npvCurrency, const std::vector< Time > &bucketTimes=std::vector< Time >(), const bool computeDelta=false, const bool computeGamma=false, const bool linearInZero=true, const bool applySimmExemptions=false)
discounting currency swap engine providing analytical deltas and gammas for vanilla swaps
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)
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_