19#include <ql/event.hpp>
27 const Currency& ccy1,
const Handle<YieldTermStructure>& currency1Discountcurve,
const Currency& ccy2,
28 const Handle<YieldTermStructure>& currency2Discountcurve,
const Handle<Quote>& spotFX,
29 boost::optional<bool> includeSettlementDateFlows,
const Date& settlementDate,
const Date& npvDate)
30 : ccy1_(ccy1), currency1Discountcurve_(currency1Discountcurve), ccy2_(ccy2),
31 currency2Discountcurve_(currency2Discountcurve), spotFX_(spotFX),
32 includeSettlementDateFlows_(includeSettlementDateFlows), settlementDate_(settlementDate), npvDate_(npvDate) {
40 if (npvDate == Null<Date>()) {
44 if (settlementDate == Null<Date>()) {
45 settlementDate = npvDate;
48 Real tmpNominal1, tmpNominal2;
52 <<
ccy1_ <<
"," <<
ccy2_ <<
") in the engine and ("
54 <<
") in the instrument");
60 "mismatched currency pairs (" <<
ccy1_ <<
"," <<
ccy2_ <<
") in the engine and ("
62 <<
") in the instrument");
69 "Discounting term structure handle is empty.");
72 "Term structures should have the same reference date.");
75 "FX forward maturity should exceed or equal the "
76 "discount curve reference date.");
80 results_.additionalResults[
"fairForwardRate"] = tmpNominal1 / tmpNominal2;
85 bool includeSettlementDateFlows =
arguments_.includeSettlementDateFlows;
87 if (!detail::simple_event(
arguments_.payDate).hasOccurred(settlementDate, includeSettlementDateFlows)) {
92 Real fxfwd = disc1near / disc1far * disc2far / disc2near *
spotFX_->value();
96 bool settleCcy1 =
ccy1_ == settleCcy;
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;
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.");
115 std::vector<CashFlowResults> cashFlowResults;
118 cf1.
type =
"Notional";
120 cf2.
type =
"Notional";
128 cf1.
amount = (tmpPayCurrency1 ? -1.0 : 1.0) * tmpNominal1 / fx1;
129 cf2.
amount = (tmpPayCurrency1 ? -1.0 : 1.0) * (-tmpNominal2 / fx2);
133 cf1.
amount = (tmpPayCurrency1 ? -1.0 : 1.0) * tmpNominal1;
134 cf2.
amount = (tmpPayCurrency1 ? -1.0 : 1.0) * (-tmpNominal2);
141 cashFlowResults.push_back(cf1);
142 cashFlowResults.push_back(cf2);
146 cashFlowResults.push_back(cf2);
147 cashFlowResults.push_back(cf1);
149 results_.additionalResults[
"cashFlowResults"] = cashFlowResults;
151 results_.value = (tmpPayCurrency1 ? -1.0 : 1.0) * discFar / discNear * (tmpNominal1 / fx1 - tmpNominal2 / fx2);
156 results_.additionalResults[
"fairForwardRate"] = fxfwd;
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);
166 if (tmpNominal1 > tmpNominal2 * fxfwd) {
167 results_.additionalResults[
"currentNotional"] = tmpNominal1;
168 results_.additionalResults[
"notionalCurrency"] =
ccy1_.code();
170 results_.additionalResults[
"currentNotional"] = tmpNominal2;
171 results_.additionalResults[
"notionalCurrency"] =
ccy2_.code();
175 results_.additionalResults[
"currentNotional"] =
class holding cashflow-related results
const Instrument::results * results_
void calculate() const override
DiscountingFxForwardEngine(const Currency &ccy1, const Handle< YieldTermStructure > ¤cy1Discountcurve, const Currency &ccy2, const Handle< YieldTermStructure > ¤cy2Discountcurve, const Handle< Quote > &spotFX, boost::optional< bool > includeSettlementDateFlows=boost::none, const Date &settlementDate=Date(), const Date &npvDate=Date())
Handle< YieldTermStructure > currency2Discountcurve_
Handle< YieldTermStructure > currency1Discountcurve_
Engine to value an FX Forward off two yield curves.
QuantLib::Real fixingValue
QuantLib::Date fixingDate
Swap::arguments * arguments_