Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Public Member Functions | Private Attributes | List of all members
DiscountingFxForwardEngine Class Reference

Discounting FX Forward Engine. More...

#include <qle/pricingengines/discountingfxforwardengine.hpp>

+ Inheritance diagram for DiscountingFxForwardEngine:
+ Collaboration diagram for DiscountingFxForwardEngine:

Public Member Functions

 DiscountingFxForwardEngine (const Currency &ccy1, const Handle< YieldTermStructure > &currency1Discountcurve, const Currency &ccy2, const Handle< YieldTermStructure > &currency2Discountcurve, const Handle< Quote > &spotFX, boost::optional< bool > includeSettlementDateFlows=boost::none, const Date &settlementDate=Date(), const Date &npvDate=Date())
 
void calculate () const override
 
const Handle< YieldTermStructure > & currency1Discountcurve () const
 
const Handle< YieldTermStructure > & currency2Discountcurve () const
 
const Currency & currency1 () const
 
const Currency & currency2 () const
 
const Handle< Quote > & spotFX () const
 

Private Attributes

Currency ccy1_
 
Handle< YieldTermStructure > currency1Discountcurve_
 
Currency ccy2_
 
Handle< YieldTermStructure > currency2Discountcurve_
 
Handle< Quote > spotFX_
 
boost::optional< boolincludeSettlementDateFlows_
 
Date settlementDate_
 
Date npvDate_
 

Detailed Description

Discounting FX Forward Engine.

This class implements pricing of FX Forwards by discounting the future nominal cash flows using the respective yield curves. The npv is expressed in ccy1. The given currencies ccy1 and ccy2 are matched to the correct fx forward legs. The evaluation date is the reference date of either discounting curve (which must be equal).

    \ingroup engines

Definition at line 44 of file discountingfxforwardengine.hpp.

Constructor & Destructor Documentation

◆ DiscountingFxForwardEngine()

DiscountingFxForwardEngine ( const Currency &  ccy1,
const Handle< YieldTermStructure > &  currency1Discountcurve,
const Currency &  ccy2,
const Handle< YieldTermStructure > &  currency2Discountcurve,
const Handle< Quote > &  spotFX,
boost::optional< bool includeSettlementDateFlows = boost::none,
const Date &  settlementDate = Date(),
const Date &  npvDate = Date() 
)
Parameters
ccy1,currency1DiscountcurveCurrency 1 and its discount curve.y
ccy2,currency2DiscountcurveCurrency 2 and its discount curve.
spotFXThe market spot rate quote, given as units of ccy1 for one unit of ccy2. The spot rate must be given w.r.t. a settlement equal to the npv date.
includeSettlementDateFlows,settlementDateIf includeSettlementDateFlows is true (false), cashflows on the settlementDate are (not) included in the NPV. If not given the settlement date is set to the npv date.
npvDateDiscount to this date. If not given the npv date is set to the evaluation date

Definition at line 26 of file discountingfxforwardengine.cpp.

32 includeSettlementDateFlows_(includeSettlementDateFlows), settlementDate_(settlementDate), npvDate_(npvDate) {
33 registerWith(currency1Discountcurve_);
34 registerWith(currency2Discountcurve_);
35 registerWith(spotFX_);
36}
const Handle< YieldTermStructure > & currency2Discountcurve() const
Handle< YieldTermStructure > currency2Discountcurve_
Handle< YieldTermStructure > currency1Discountcurve_
const Handle< YieldTermStructure > & currency1Discountcurve() const

Member Function Documentation

◆ calculate()

void calculate ( ) const
override

Definition at line 38 of file discountingfxforwardengine.cpp.

38 {
39 Date npvDate = npvDate_;
40 if (npvDate == Null<Date>()) {
41 npvDate = currency1Discountcurve_->referenceDate();
42 }
43 Date settlementDate = settlementDate_;
44 if (settlementDate == Null<Date>()) {
45 settlementDate = npvDate;
46 }
47
48 Real tmpNominal1, tmpNominal2;
49 bool tmpPayCurrency1;
50 if (ccy1_ == arguments_.currency1) {
51 QL_REQUIRE(ccy2_ == arguments_.currency2, "mismatched currency pairs ("
52 << ccy1_ << "," << ccy2_ << ") in the engine and ("
53 << arguments_.currency1 << "," << arguments_.currency2
54 << ") in the instrument");
55 tmpNominal1 = arguments_.nominal1;
56 tmpNominal2 = arguments_.nominal2;
57 tmpPayCurrency1 = arguments_.payCurrency1;
58 } else {
59 QL_REQUIRE(ccy1_ == arguments_.currency2 && ccy2_ == arguments_.currency1,
60 "mismatched currency pairs (" << ccy1_ << "," << ccy2_ << ") in the engine and ("
61 << arguments_.currency1 << "," << arguments_.currency2
62 << ") in the instrument");
63 tmpNominal1 = arguments_.nominal2;
64 tmpNominal2 = arguments_.nominal1;
65 tmpPayCurrency1 = !arguments_.payCurrency1;
66 }
67
68 QL_REQUIRE(!currency1Discountcurve_.empty() && !currency2Discountcurve_.empty(),
69 "Discounting term structure handle is empty.");
70
71 QL_REQUIRE(currency1Discountcurve_->referenceDate() == currency2Discountcurve_->referenceDate(),
72 "Term structures should have the same reference date.");
73
74 QL_REQUIRE(arguments_.payDate >= currency1Discountcurve_->referenceDate(),
75 "FX forward maturity should exceed or equal the "
76 "discount curve reference date.");
77
78 results_.value = 0.0;
79 results_.fairForwardRate = ExchangeRate(ccy2_, ccy1_, tmpNominal1 / tmpNominal2); // strike rate
80 results_.additionalResults["fairForwardRate"] = tmpNominal1 / tmpNominal2;
81 results_.additionalResults["currency[1]"] = ccy1_.code();
82 results_.additionalResults["currency[2]"] = ccy2_.code();
83
84 // The instrument flag overrides what is passed to the engine c'tor
85 bool includeSettlementDateFlows = arguments_.includeSettlementDateFlows;
86
87 if (!detail::simple_event(arguments_.payDate).hasOccurred(settlementDate, includeSettlementDateFlows)) {
88 Real disc1near = currency1Discountcurve_->discount(npvDate);
89 Real disc1far = currency1Discountcurve_->discount(arguments_.payDate);
90 Real disc2near = currency2Discountcurve_->discount(npvDate);
91 Real disc2far = currency2Discountcurve_->discount(arguments_.payDate);
92 Real fxfwd = disc1near / disc1far * disc2far / disc2near * spotFX_->value();
93
94 // settle ccy is ccy1 if no pay ccy provided
95 Currency settleCcy = arguments_.payCcy.empty() ? ccy1_ : arguments_.payCcy;
96 bool settleCcy1 = ccy1_ == settleCcy;
97
98 Real discNear = settleCcy1 ? disc1near : disc2near;
99 Real discFar = settleCcy1 ? disc1far : disc2far;
100 Real fx1 = settleCcy1 ? 1.0 : fxfwd;
101 Real fx2 = settleCcy1 ? 1 / fxfwd : 1.0;
102
103 QL_REQUIRE(arguments_.isPhysicallySettled || arguments_.payDate <= arguments_.fixingDate ||
104 arguments_.fxIndex != nullptr,
105 "If pay date (" << arguments_.payDate << ") is strictly after fixing date (" << arguments_.fixingDate
106 << "), an FX Index must be given for a cash-settled FX Forward.");
107 if (!arguments_.isPhysicallySettled && arguments_.payDate >= arguments_.fixingDate &&
108 arguments_.fxIndex != nullptr) {
109 fx1 = settleCcy1 ? 1.0 : arguments_.fxIndex->fixing(arguments_.fixingDate);
110 fx2 = settleCcy1 ? arguments_.fxIndex->fixing(arguments_.fixingDate) : 1.0;
111 fxfwd = arguments_.fxIndex->fixing(arguments_.fixingDate);
112 }
113
114 // populate cashflow results
115 std::vector<CashFlowResults> cashFlowResults;
116 CashFlowResults cf1, cf2;
117 cf1.payDate = arguments_.payDate;
118 cf1.type = "Notional";
119 cf2.payDate = arguments_.payDate;
120 cf2.type = "Notional";
121 if (!arguments_.isPhysicallySettled) {
122 if (arguments_.payDate >= arguments_.fixingDate) {
123 cf1.fixingDate = arguments_.fixingDate;
124 cf2.fixingDate = arguments_.fixingDate;
125 }
126 cf1.fixingValue = 1.0 / fx1;
127 cf2.fixingValue = 1.0 / fx2;
128 cf1.amount = (tmpPayCurrency1 ? -1.0 : 1.0) * tmpNominal1 / fx1;
129 cf2.amount = (tmpPayCurrency1 ? -1.0 : 1.0) * (-tmpNominal2 / fx2);
130 cf1.currency = settleCcy.code();
131 cf2.currency = settleCcy.code();
132 } else {
133 cf1.amount = (tmpPayCurrency1 ? -1.0 : 1.0) * tmpNominal1;
134 cf2.amount = (tmpPayCurrency1 ? -1.0 : 1.0) * (-tmpNominal2);
135 cf1.currency = ccy1_.code();
136 cf2.currency = ccy2_.code();
137 }
138 if (ccy1_ == arguments_.currency1) {
139 cf1.legNumber = 0;
140 cf2.legNumber = 1;
141 cashFlowResults.push_back(cf1);
142 cashFlowResults.push_back(cf2);
143 } else {
144 cf1.legNumber = 1;
145 cf2.legNumber = 0;
146 cashFlowResults.push_back(cf2);
147 cashFlowResults.push_back(cf1);
148 }
149 results_.additionalResults["cashFlowResults"] = cashFlowResults;
150
151 results_.value = (tmpPayCurrency1 ? -1.0 : 1.0) * discFar / discNear * (tmpNominal1 / fx1 - tmpNominal2 / fx2);
152
153 results_.npv = Money(settleCcy, results_.value);
154
155 results_.fairForwardRate = ExchangeRate(ccy2_, ccy1_, fxfwd);
156 results_.additionalResults["fairForwardRate"] = fxfwd;
157 results_.additionalResults["fxSpot"] = spotFX_->value();
158 results_.additionalResults["discountFactor[1]"] = disc1far;
159 results_.additionalResults["discountFactor[2]"] = disc2far;
160 results_.additionalResults["legNPV[1]"] = (tmpPayCurrency1 ? -1.0 : 1.0) * discFar / discNear * tmpNominal1 / fx1;
161 results_.additionalResults["legNPV[2]"] = (tmpPayCurrency1 ? -1.0 : 1.0) * discFar / discNear * (-tmpNominal2 / fx2);
162
163 // set notional
164 if (arguments_.isPhysicallySettled) {
165 // Align notional with ISDA AANA/GRID guidance as of November 2020 for deliverable forwards
166 if (tmpNominal1 > tmpNominal2 * fxfwd) {
167 results_.additionalResults["currentNotional"] = tmpNominal1;
168 results_.additionalResults["notionalCurrency"] = ccy1_.code();
169 } else {
170 results_.additionalResults["currentNotional"] = tmpNominal2;
171 results_.additionalResults["notionalCurrency"] = ccy2_.code();
172 }
173 } else {
174 // for cash settled forwards we take the notional from the settlement ccy leg
175 results_.additionalResults["currentNotional"] =
176 arguments_.currency1 == arguments_.payCcy ? arguments_.nominal1 : arguments_.nominal2;
177 results_.additionalResults["notionalCurrency"] = arguments_.payCcy.code();
178 }
179 }
180
181} // calculate
const Instrument::results * results_
Definition: cdsoption.cpp:81
Swap::arguments * arguments_

◆ currency1Discountcurve()

const Handle< YieldTermStructure > & currency1Discountcurve ( ) const

Definition at line 71 of file discountingfxforwardengine.hpp.

◆ currency2Discountcurve()

const Handle< YieldTermStructure > & currency2Discountcurve ( ) const

Definition at line 73 of file discountingfxforwardengine.hpp.

◆ currency1()

const Currency & currency1 ( ) const

Definition at line 75 of file discountingfxforwardengine.hpp.

75{ return ccy1_; }

◆ currency2()

const Currency & currency2 ( ) const

Definition at line 76 of file discountingfxforwardengine.hpp.

76{ return ccy2_; }

◆ spotFX()

const Handle< Quote > & spotFX ( ) const

Definition at line 78 of file discountingfxforwardengine.hpp.

78{ return spotFX_; }

Member Data Documentation

◆ ccy1_

Currency ccy1_
private

Definition at line 81 of file discountingfxforwardengine.hpp.

◆ currency1Discountcurve_

Handle<YieldTermStructure> currency1Discountcurve_
private

Definition at line 82 of file discountingfxforwardengine.hpp.

◆ ccy2_

Currency ccy2_
private

Definition at line 83 of file discountingfxforwardengine.hpp.

◆ currency2Discountcurve_

Handle<YieldTermStructure> currency2Discountcurve_
private

Definition at line 84 of file discountingfxforwardengine.hpp.

◆ spotFX_

Handle<Quote> spotFX_
private

Definition at line 85 of file discountingfxforwardengine.hpp.

◆ includeSettlementDateFlows_

boost::optional<bool> includeSettlementDateFlows_
private

Definition at line 86 of file discountingfxforwardengine.hpp.

◆ settlementDate_

Date settlementDate_
private

Definition at line 87 of file discountingfxforwardengine.hpp.

◆ npvDate_

Date npvDate_
private

Definition at line 88 of file discountingfxforwardengine.hpp.