Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
crossccyswapengine.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
19#include <ql/cashflows/cashflows.hpp>
20#include <ql/exchangerate.hpp>
21#include <ql/utilities/dataformatters.hpp>
22
24
25namespace QuantExt {
26
27CrossCcySwapEngine::CrossCcySwapEngine(const Currency& ccy1, const Handle<YieldTermStructure>& currency1Discountcurve,
28 const Currency& ccy2, const Handle<YieldTermStructure>& currency2Discountcurve,
29 const Handle<Quote>& spotFX, boost::optional<bool> includeSettlementDateFlows,
30 const Date& settlementDate, const Date& npvDate, const Date& spotFXSettleDate)
31 : ccy1_(ccy1), currency1Discountcurve_(currency1Discountcurve), ccy2_(ccy2),
32 currency2Discountcurve_(currency2Discountcurve), spotFX_(spotFX),
33 includeSettlementDateFlows_(includeSettlementDateFlows), settlementDate_(settlementDate), npvDate_(npvDate),
34 spotFXSettleDate_(spotFXSettleDate) {
35
36 registerWith(currency1Discountcurve_);
37 registerWith(currency2Discountcurve_);
38 registerWith(spotFX_);
39}
40
42
43 QL_REQUIRE(!currency1Discountcurve_.empty() && !currency2Discountcurve_.empty(),
44 "Discounting term structure handle is empty.");
45
46 QL_REQUIRE(!spotFX_.empty(), "FX spot quote handle is empty.");
47
48 QL_REQUIRE(currency1Discountcurve_->referenceDate() == currency2Discountcurve_->referenceDate(),
49 "Term structures should have the same reference date.");
50 Date referenceDate = currency1Discountcurve_->referenceDate();
51 Date settlementDate = settlementDate_;
52 if (settlementDate_ == Date()) {
53 settlementDate = referenceDate;
54 } else {
55 QL_REQUIRE(settlementDate >= referenceDate, "Settlement date (" << settlementDate
56 << ") cannot be before discount curve "
57 "reference date ("
58 << referenceDate << ")");
59 }
60
61 Size numLegs = arguments_.legs.size();
62 // - Instrument::Results
63 if (npvDate_ == Date()) {
64 results_.valuationDate = referenceDate;
65 } else {
66 QL_REQUIRE(npvDate_ >= referenceDate, "NPV date (" << npvDate_
67 << ") cannot be before "
68 "discount curve reference date ("
69 << referenceDate << ")");
70 results_.valuationDate = npvDate_;
71 }
72
73 Date spotFXSettleDate = spotFXSettleDate_;
74 if (spotFXSettleDate_ == Date()) {
75 spotFXSettleDate = referenceDate;
76 } else {
77 QL_REQUIRE(spotFXSettleDate >= referenceDate, "FX settlement date (" << spotFXSettleDate
78 << ") cannot be before discount curve "
79 "reference date ("
80 << referenceDate << ")");
81 }
82
83 results_.value = 0.0;
84 results_.errorEstimate = Null<Real>();
85 // - Swap::Results
86 results_.legNPV.resize(numLegs);
87 results_.legBPS.resize(numLegs);
88 results_.startDiscounts.resize(numLegs);
89 results_.endDiscounts.resize(numLegs);
90 // - CrossCcySwap::Results
91 results_.inCcyLegNPV.resize(numLegs);
92 results_.inCcyLegBPS.resize(numLegs);
93 results_.npvDateDiscounts.resize(numLegs);
94
95 bool includeReferenceDateFlows =
96 includeSettlementDateFlows_ ? *includeSettlementDateFlows_ : Settings::instance().includeReferenceDateEvents();
97
98 for (Size legNo = 0; legNo < numLegs; legNo++) {
99 try {
100 // Choose the correct discount curve for the leg.
101 Handle<YieldTermStructure> legDiscountCurve;
102 if (arguments_.currencies[legNo] == ccy1_) {
103 legDiscountCurve = currency1Discountcurve_;
104 } else {
105 QL_REQUIRE(arguments_.currencies[legNo] == ccy2_, "leg ccy (" << arguments_.currencies[legNo]
106 << ") must be ccy1 (" << ccy1_
107 << ") or ccy2 (" << ccy2_ << ")");
108 legDiscountCurve = currency2Discountcurve_;
109 }
110 results_.npvDateDiscounts[legNo] = legDiscountCurve->discount(results_.valuationDate);
111
112 // Calculate the NPV and BPS of each leg in its currency.
113 std::tie(results_.inCcyLegNPV[legNo], results_.inCcyLegBPS[legNo]) =
114 CashFlows::npvbps(arguments_.legs[legNo], **legDiscountCurve, includeReferenceDateFlows, settlementDate,
115 results_.valuationDate);
116 results_.inCcyLegNPV[legNo] *= arguments_.payer[legNo];
117 results_.inCcyLegBPS[legNo] *= arguments_.payer[legNo];
118
119 results_.legNPV[legNo] = results_.inCcyLegNPV[legNo];
120 results_.legBPS[legNo] = results_.inCcyLegBPS[legNo];
121
122 // Convert to NPV currency if necessary.
123 if (arguments_.currencies[legNo] != ccy1_) {
124 // results_.legNPV[legNo] *= spotFX_->value();
125 // results_.legBPS[legNo] *= spotFX_->value();
126 Real spotFXRate = spotFX_->value();
127 if (spotFXSettleDate != referenceDate) {
128 // Use the parity relation between discount factors and fx rates to compute spotFXRate
129 // Generic formula: fx(T1)/fx(T2) = FwdDF_Quote(T1->T2) / FwdDF_Base(T1->T2),
130 // where fx represents the currency ratio Base/Quote
131 Real ccy1DF = currency1Discountcurve_->discount(spotFXSettleDate);
132 Real ccy2DF = currency2Discountcurve_->discount(spotFXSettleDate);
133 QL_REQUIRE(ccy2DF != 0.0, "Discount Factor associated with currency " << ccy2_
134 << " at maturity " << spotFXSettleDate << " cannot be zero");
135 spotFXRate *= ccy1DF / ccy2DF;
136 }
137 results_.legNPV[legNo] *= spotFXRate;
138 results_.legBPS[legNo] *= spotFXRate;
139 }
140
141 // Get start date and end date discount for the leg
142 Date startDate = CashFlows::startDate(arguments_.legs[legNo]);
143 if (startDate >= currency1Discountcurve_->referenceDate()) {
144 results_.startDiscounts[legNo] = legDiscountCurve->discount(startDate);
145 } else {
146 results_.startDiscounts[legNo] = Null<DiscountFactor>();
147 }
148
149 Date maturityDate = CashFlows::maturityDate(arguments_.legs[legNo]);
150 if (maturityDate >= currency1Discountcurve_->referenceDate()) {
151 results_.endDiscounts[legNo] = legDiscountCurve->discount(maturityDate);
152 } else {
153 results_.endDiscounts[legNo] = Null<DiscountFactor>();
154 }
155
156 } catch (std::exception& e) {
157 QL_FAIL(io::ordinal(legNo + 1) << " leg: " << e.what());
158 }
159
160 results_.value += results_.legNPV[legNo];
161 }
162}
163} // namespace QuantExt
const Instrument::results * results_
Definition: cdsoption.cpp:81
boost::optional< bool > includeSettlementDateFlows_
void calculate() const override
CrossCcySwapEngine(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(), const Date &spotFXSettleDate=Date())
Handle< YieldTermStructure > currency2Discountcurve_
Handle< YieldTermStructure > currency1Discountcurve_
Cross currency swap engine.
Swap::arguments * arguments_