Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
discountingfxforwardenginedeltagamma.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2020 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
23
24#include <ql/cashflows/simplecashflow.hpp>
25#include <ql/event.hpp>
26
27namespace QuantExt {
28using namespace QuantLib;
29
31 const Currency& domCcy, const Handle<YieldTermStructure>& domCurve, const Currency& forCcy,
32 const Handle<YieldTermStructure>& forCurve, const Handle<Quote>& spotFx, const std::vector<Time>& bucketTimes,
33 const bool computeDelta, const bool computeGamma, const bool linearInZero,
34 boost::optional<bool> includeSettlementDateFlows, const Date& settlementDate, const Date& npvDate,
35 const bool applySimmExemptions)
36 : domCcy_(domCcy), forCcy_(forCcy), domCurve_(domCurve), forCurve_(forCurve), spotFx_(spotFx),
37 bucketTimes_(bucketTimes), computeDelta_(computeDelta), computeGamma_(computeGamma), linearInZero_(linearInZero),
38 includeSettlementDateFlows_(includeSettlementDateFlows), settlementDate_(settlementDate), npvDate_(npvDate),
39 applySimmExemptions_(applySimmExemptions) {
40 registerWith(domCurve_);
41 registerWith(forCurve_);
42 registerWith(spotFx_);
43}
44
46
47 QL_REQUIRE(!domCurve_.empty(), "domestic curve is empty");
48 QL_REQUIRE(!forCurve_.empty(), "foreign curve is empty");
49 QL_REQUIRE(!spotFx_.empty(), "FX quote is empty");
50
51 // we build this engine similar to the currency swap engine
52
53 std::vector<Leg> legs;
54 legs.push_back(Leg(1, QuantLib::ext::make_shared<SimpleCashFlow>(arguments_.nominal1, arguments_.maturityDate)));
55 legs.push_back(Leg(1, QuantLib::ext::make_shared<SimpleCashFlow>(arguments_.nominal2, arguments_.maturityDate)));
56
57 std::vector<Currency> currencies = {arguments_.currency1, arguments_.currency2};
58
59 std::vector<Real> payer = {arguments_.payCurrency1 ? -1.0 : 1.0, arguments_.payCurrency1 ? 1.0 : -1.0};
60
61 results_.value = 0.0;
62
63 std::map<Currency, std::map<Date, Real>, CurrencyComparator> deltaDiscountRaw, gammaDiscountRaw;
64 std::map<Currency, Real, CurrencyComparator> fxSpot, fxSpotDelta;
65 std::map<Date, Real> empty;
66 std::map<std::pair<Date, Date>, Real> empty2;
67 Real empty3 = 0.0;
68
69 Real domFlow = 0, forFlow = 0, domNPV = 0, forNPV = 0;
70 for (Size i = 0; i < 2; ++i) {
71 try {
72 Handle<YieldTermStructure> yts;
73 if (currencies[i] == domCcy_)
74 yts = domCurve_;
75 else if (currencies[i] == forCcy_)
76 yts = forCurve_;
77 else {
78 QL_FAIL("ccy " << currencies[i] << " not handled.");
79 }
80 Real npv = 0.0, bps = 0.0, simpleCashFlowNpv = 0.0;
82 yts, payer[i], npv, bps, computeDelta_, computeGamma_, false, deltaDiscountRaw[currencies[i]], empty,
83 empty, gammaDiscountRaw[currencies[i]], empty2, empty2, empty, empty3,
84 applySimmExemptions_ && arguments_.isPhysicallySettled, simpleCashFlowNpv);
85 for (Size ii = 0; ii < legs[i].size(); ++ii) {
86 CashFlow& cf = *legs[i][ii];
87 if (cf.date() <= yts->referenceDate()) {
88 continue;
89 }
90 cf.accept(calc);
91 if (currencies[i] == domCcy_)
92 domFlow = cf.amount();
93 if (currencies[i] == forCcy_)
94 forFlow = cf.amount();
95 }
96 if (currencies[i] == domCcy_) {
97 domNPV = npv;
98 results_.additionalResults["npvDom"] = npv;
99 results_.value += npv + simpleCashFlowNpv;
100 } else {
101 forNPV = npv;
102 results_.additionalResults["npvFor"] = npv;
103 results_.value += (npv + simpleCashFlowNpv) * spotFx_->value();
104 fxSpot[currencies[i]] = spotFx_->value();
105 fxSpotDelta[currencies[i]] += npv;
106 }
107 } catch (const std::exception& e) {
108 QL_FAIL("DiscountingFxForwardEngineDeltaGamma, leg " << i << ": " << e.what());
109 }
110 } // for i = 0, 1 (legs)
111
112 results_.additionalResults["fxSpot"] = fxSpot;
113 results_.additionalResults["deltaFxSpot"] = fxSpotDelta;
114
115 Date npvDate = npvDate_;
116 if (npvDate == Null<Date>()) {
117 npvDate = domCurve_->referenceDate();
118 }
119 Date settlementDate = settlementDate_;
120 if (settlementDate == Null<Date>()) {
121 settlementDate = npvDate;
122 }
123
124 // convert raw deltas to given bucketing structure
125 if (computeDelta_) {
126 std::map<Currency, std::vector<Real>, CurrencyComparator> deltaDiscount;
127 for (std::map<Currency, std::map<Date, Real>, CurrencyComparator>::const_iterator i = deltaDiscountRaw.begin();
128 i != deltaDiscountRaw.end(); ++i) {
129 Handle<YieldTermStructure> yts = i->first == domCcy_ ? domCurve_ : forCurve_;
130 deltaDiscount[i->first] =
131 detail::rebucketDeltas(bucketTimes_, i->second, yts->referenceDate(), yts->dayCounter(), linearInZero_);
132 }
133 results_.additionalResults["deltaDiscount"] = deltaDiscount;
134 results_.additionalResults["bucketTimes"] = bucketTimes_;
135 }
136
137 // convert raw gammas to given bucketing structure
138 if (computeGamma_) {
139 std::map<Currency, Matrix, CurrencyComparator> gamma;
140 for (std::vector<Currency>::const_iterator i = currencies.begin(); i != currencies.end(); ++i) {
141 Handle<YieldTermStructure> yts = *i == domCcy_ ? domCurve_ : forCurve_;
142 Matrix tmp = detail::rebucketGammas(bucketTimes_, gammaDiscountRaw[*i], empty2, empty2, false,
143 yts->referenceDate(), yts->dayCounter(), linearInZero_);
144 gamma[*i] = tmp;
145 }
146 results_.additionalResults["gamma"] = gamma;
147 results_.additionalResults["bucketTimes"] = bucketTimes_;
148 }
149
150 // Align notional with ISDA AANA/GRID guidance as of November 2020 for deliverable forwards
151 if (fabs(domNPV) > fabs(forNPV) * spotFx_->value()) {
152 results_.additionalResults["currentNotional"] = domFlow;
153 results_.additionalResults["notionalCurrency"] = domCcy_.code();
154 } else {
155 results_.additionalResults["currentNotional"] = forFlow;
156 results_.additionalResults["notionalCurrency"] = forCcy_.code();
157 }
158
159} // calculate
160
161} // namespace QuantExt
const Instrument::results * results_
Definition: cdsoption.cpp:81
DiscountingFxForwardEngineDeltaGamma(const Currency &domCcy, const Handle< YieldTermStructure > &domCurve, const Currency &forCcy, const Handle< YieldTermStructure > &forCurve, const Handle< Quote > &spotFx, const std::vector< Time > &bucketTimes=std::vector< Time >(), const bool computeDelta=false, const bool computeGamma=false, const bool linearInZero=true, boost::optional< bool > includeSettlementDateFlows=boost::none, const Date &settlementDate=Date(), const Date &npvDate=Date(), const bool applySimmExemptions=false)
Compare currencies by currency code.
Engine to value an FX Forward off two yield curves.
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_