Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
crossccyfixfloatmtmresetswap.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2021 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
22
23#include <boost/make_shared.hpp>
24#include <ql/cashflows/fixedratecoupon.hpp>
25#include <ql/cashflows/iborcoupon.hpp>
26#include <ql/cashflows/simplecashflow.hpp>
27
28using namespace QuantLib;
29
30namespace QuantExt {
31
33 Real nominal, const Currency& fixedCurrency, const Schedule& fixedSchedule,
34 Rate fixedRate, const DayCounter& fixedDayCount, const BusinessDayConvention& fixedPaymentBdc,
35 Natural fixedPaymentLag, const Calendar& fixedPaymentCalendar, const Currency& floatCurrency,
36 const Schedule& floatSchedule, const QuantLib::ext::shared_ptr<IborIndex>& floatIndex, Spread floatSpread,
37 const BusinessDayConvention& floatPaymentBdc, Natural floatPaymentLag, const Calendar& floatPaymentCalendar,
38 const QuantLib::ext::shared_ptr<FxIndex>& fxIdx, bool resetsOnFloatLeg, bool receiveFixed)
39 : CrossCcySwap(3), nominal_(nominal), fixedCurrency_(fixedCurrency),
40 fixedSchedule_(fixedSchedule), fixedRate_(fixedRate), fixedDayCount_(fixedDayCount),
41 fixedPaymentBdc_(fixedPaymentBdc), fixedPaymentLag_(fixedPaymentLag), fixedPaymentCalendar_(fixedPaymentCalendar),
42 floatCurrency_(floatCurrency), floatSchedule_(floatSchedule), floatIndex_(floatIndex),
43 floatSpread_(floatSpread), floatPaymentBdc_(floatPaymentBdc),
44 floatPaymentLag_(floatPaymentLag), floatPaymentCalendar_(floatPaymentCalendar),
45 fxIndex_(fxIdx), resetsOnFloatLeg_(resetsOnFloatLeg), receiveFixed_(receiveFixed) {
46
47 registerWith(floatIndex_);
48 registerWith(fxIndex_);
49 initialize();
50}
51
53
54 // if resets on floating leg, set notional to zero, else the fixed
55 Real floatNotional, fixedNotional;
57 floatNotional = 0.0;
58 fixedNotional = nominal_;
59 } else {
60 floatNotional = nominal_;
61 fixedNotional = 0.0;
62 }
63
64 // Build the float leg
65 Leg floatLeg = IborLeg(floatSchedule_, floatIndex_)
66 .withNotionals(floatNotional)
67 .withSpreads(floatSpread_)
68 .withPaymentAdjustment(floatPaymentBdc_)
69 .withPaymentLag(floatPaymentLag_)
70 .withPaymentCalendar(floatPaymentCalendar_);
71
72 // Register with each floating rate coupon
73 for (Leg::const_iterator it = floatLeg.begin(); it < floatLeg.end(); ++it)
74 registerWith(*it);
75
76 // Build the fixed rate leg
77 Leg fixedLeg = FixedRateLeg(fixedSchedule_)
78 .withNotionals(fixedNotional)
79 .withCouponRates(fixedRate_, fixedDayCount_)
80 .withPaymentAdjustment(fixedPaymentBdc_)
81 .withPaymentLag(fixedPaymentLag_)
82 .withPaymentCalendar(fixedPaymentCalendar_);
83
85 // Notional exchanges for fixed leg
86 // Initial notional exchange
87 Date aDate = fixedSchedule_.dates().front();
88 aDate = fixedPaymentCalendar_.adjust(aDate, fixedPaymentBdc_);
89 QuantLib::ext::shared_ptr<CashFlow> aCashflow = QuantLib::ext::make_shared<SimpleCashFlow>(-fixedNotional, aDate);
90 fixedLeg.insert(fixedLeg.begin(), aCashflow);
91
92 // Final notional exchange
93 aDate = fixedLeg.back()->date();
94 aCashflow = QuantLib::ext::make_shared<SimpleCashFlow>(fixedNotional, aDate);
95 fixedLeg.push_back(aCashflow);
96
97 // resetting floating leg
98 for (Size j = 0; j < floatLeg.size(); ++j) {
99 QuantLib::ext::shared_ptr<FloatingRateCoupon> coupon = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(floatLeg[j]);
100 Date fixingDate = fxIndex_->fixingCalendar().advance(coupon->accrualStartDate(),
101 -static_cast<Integer>(fxIndex_->fixingDays()), Days);
102 QuantLib::ext::shared_ptr<FloatingRateFXLinkedNotionalCoupon> fxLinkedCoupon =
103 QuantLib::ext::make_shared<FloatingRateFXLinkedNotionalCoupon>(fixingDate, fixedNotional, fxIndex_, coupon);
104 floatLeg[j] = fxLinkedCoupon;
105 }
106
107 // now build a separate leg to store the resetting notionals
108 receiveFixed_ ? payer_[2] = -1.0 : payer_[2] = +1.0;
110 for (Size j = 0; j < floatLeg.size(); j++) {
111 QuantLib::ext::shared_ptr<Coupon> c = QuantLib::ext::dynamic_pointer_cast<Coupon>(floatLeg[j]);
112 QL_REQUIRE(c, "Resetting XCCY - expected Coupon");
113 // build a pair of notional flows, one at the start and one at the end of
114 // the accrual period. Both with the same FX fixing date
115 Date fixingDate = fxIndex_->fixingCalendar().advance(c->accrualStartDate(),
116 -static_cast<Integer>(fxIndex_->fixingDays()), Days);
117 legs_[2].push_back(QuantLib::ext::shared_ptr<CashFlow>(
118 new FXLinkedCashFlow(c->accrualStartDate(), fixingDate, -fixedNotional, fxIndex_)));
119 legs_[2].push_back(QuantLib::ext::shared_ptr<CashFlow>(
120 new FXLinkedCashFlow(c->accrualEndDate(), fixingDate, fixedNotional, fxIndex_)));
121 }
122 } else {
123 // Notional exchanges for floating leg
124 // Initial notional exchange
125 Date aDate = floatSchedule_.dates().front();
126 aDate = floatPaymentCalendar_.adjust(aDate, floatPaymentBdc_);
127 QuantLib::ext::shared_ptr<CashFlow> aCashflow = QuantLib::ext::make_shared<SimpleCashFlow>(-floatNotional, aDate);
128 floatLeg.insert(floatLeg.begin(), aCashflow);
129
130 // Final notional exchange
131 aDate = fixedLeg.back()->date();
132 aCashflow = QuantLib::ext::make_shared<SimpleCashFlow>(floatNotional, aDate);
133 floatLeg.push_back(aCashflow);
134
135 // resetting fixed leg
136 for (Size j = 0; j < fixedLeg.size(); ++j) {
137 QuantLib::ext::shared_ptr<FixedRateCoupon> coupon = QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(fixedLeg[j]);
138 Date fixingDate = fxIndex_->fixingCalendar().advance(coupon->accrualStartDate(),
139 -static_cast<Integer>(fxIndex_->fixingDays()), Days);
140 QuantLib::ext::shared_ptr<FixedRateFXLinkedNotionalCoupon> fxLinkedCoupon =
141 QuantLib::ext::make_shared<FixedRateFXLinkedNotionalCoupon>(fixingDate, floatNotional, fxIndex_, coupon);
142 floatLeg[j] = fxLinkedCoupon;
143 }
144
145 // now build a separate leg to store the resetting notionals
146 receiveFixed_ ? payer_[2] = -1.0 : payer_[2] = +1.0;
148 for (Size j = 0; j < fixedLeg.size(); j++) {
149 QuantLib::ext::shared_ptr<Coupon> c = QuantLib::ext::dynamic_pointer_cast<Coupon>(fixedLeg[j]);
150 QL_REQUIRE(c, "Resetting XCCY - expected Coupon");
151 // build a pair of notional flows, one at the start and one at the end of
152 // the accrual period. Both with the same FX fixing date
153 Date fixingDate = fxIndex_->fixingCalendar().advance(c->accrualStartDate(),
154 -static_cast<Integer>(fxIndex_->fixingDays()), Days);
155 legs_[2].push_back(QuantLib::ext::shared_ptr<CashFlow>(
156 new FXLinkedCashFlow(c->accrualStartDate(), fixingDate, -floatNotional, fxIndex_)));
157 legs_[2].push_back(QuantLib::ext::shared_ptr<CashFlow>(
158 new FXLinkedCashFlow(c->accrualEndDate(), fixingDate, floatNotional, fxIndex_)));
159 }
160 }
161
162 // Deriving from cross currency swap where:
163 // First leg should hold the pay flows
164 // Second leg should hold the receive flows
165 payer_[0] = -1.0;
166 payer_[1] = 1.0;
167 if (receiveFixed_) {
168 legs_[1] = fixedLeg;
170 legs_[0] = floatLeg;
172 } else {
173 legs_[0] = fixedLeg;
175 legs_[1] = floatLeg;
177 }
178
179 // Register the instrument with all cashflows on each leg.
180 for (Size legNo = 0; legNo < legs_.size(); legNo++) {
181 Leg::iterator it;
182 for (it = legs_[legNo].begin(); it != legs_[legNo].end(); ++it) {
183 registerWith(*it);
184 }
185 }
186}
187
189
191
193 args->fixedRate = fixedRate_;
194 args->spread = floatSpread_;
195 }
196}
197
198void CrossCcyFixFloatMtMResetSwap::fetchResults(const PricingEngine::results* r) const {
199
201
202 // Depending on the pricing engine used, we may have CrossCcyFixFloatSwap::results
203 if (const CrossCcyFixFloatMtMResetSwap::results* res = dynamic_cast<const CrossCcyFixFloatMtMResetSwap::results*>(r)) {
204 // If we have CrossCcyFixFloatSwap::results from the pricing engine
205 fairFixedRate_ = res->fairFixedRate;
206 fairSpread_ = res->fairSpread;
207 } else {
208 // If not, set them to Null to indicate a calculation is needed below
209 fairFixedRate_ = Null<Rate>();
210 fairSpread_ = Null<Spread>();
211 }
212
213 // Calculate fair rate and spread if they are still Null here
214 static Spread basisPoint = 1.0e-4;
215
216 Size idxFixed = receiveFixed_ ? 1 : 0;
217 if (fairFixedRate_ == Null<Rate>() && legBPS_[idxFixed] != Null<Real>())
218 fairFixedRate_ = fixedRate_ - NPV_ / (legBPS_[idxFixed] / basisPoint);
219
220 Size idxFloat = receiveFixed_ ? 0 : 1;
221 if (fairSpread_ == Null<Spread>() && legBPS_[idxFloat] != Null<Real>())
222 fairSpread_ = floatSpread_ - NPV_ / (legBPS_[idxFloat] / basisPoint);
223}
224
227 fairFixedRate_ = Null<Rate>();
228 fairSpread_ = Null<Spread>();
229}
230
233 QL_REQUIRE(fixedRate != Null<Rate>(), "Fixed rate cannot be null");
234 QL_REQUIRE(spread != Null<Spread>(), "Spread cannot be null");
235}
236
239 fairFixedRate = Null<Rate>();
240 fairSpread = Null<Spread>();
241}
242} // namespace QuantExt
QuantLib::ext::shared_ptr< QuantLib::IborIndex > floatIndex_
QuantLib::ext::shared_ptr< FxIndex > fxIndex_
void setupArguments(PricingEngine::arguments *args) const override
CrossCcyFixFloatMtMResetSwap(QuantLib::Real nominal, const QuantLib::Currency &fixedCurrency, const QuantLib::Schedule &fixedSchedule, QuantLib::Rate fixedRate, const QuantLib::DayCounter &fixedDayCount, const QuantLib::BusinessDayConvention &fixedPaymentBdc, QuantLib::Natural fixedPaymentLag, const QuantLib::Calendar &fixedPaymentCalendar, const QuantLib::Currency &floatCurrency, const QuantLib::Schedule &floatSchedule, const QuantLib::ext::shared_ptr< QuantLib::IborIndex > &floatIndex, QuantLib::Spread floatSpread, const QuantLib::BusinessDayConvention &floatPaymentBdc, QuantLib::Natural floatPaymentLag, const QuantLib::Calendar &floatPaymentCalendar, const QuantLib::ext::shared_ptr< FxIndex > &fxIdx, bool resetsOnFloatLeg=true, bool receiveFixed=true)
void fetchResults(const PricingEngine::results *) const override
void validate() const override
Cross currency swap.
void setupArguments(PricingEngine::arguments *args) const override
void setupExpired() const override
void fetchResults(const PricingEngine::results *) const override
std::vector< Currency > currencies_
Cross currency fix float swap instrument with MTM reset.
Coupon paying a fixed rate but with an FX linked notional.
Coupon paying a Libor-type index but with an FX linked notional.