Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
crossccybasismtmresetswap.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2018 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 "toplevelfixture.hpp"
20#include <boost/make_shared.hpp>
21#include <boost/test/unit_test.hpp>
22#include <ql/cashflows/couponpricer.hpp>
23#include <ql/cashflows/floatingratecoupon.hpp>
24#include <ql/currencies/all.hpp>
25#include <ql/indexes/ibor/gbplibor.hpp>
26#include <ql/indexes/ibor/usdlibor.hpp>
27#include <ql/quotes/simplequote.hpp>
28#include <ql/termstructures/yield/discountcurve.hpp>
29#include <ql/time/calendars/all.hpp>
30#include <ql/time/daycounters/actual360.hpp>
31#include <ql/types.hpp>
34
35using namespace std;
36using namespace boost::unit_test_framework;
37using namespace QuantLib;
38using namespace QuantExt;
39
40namespace {
41
42Handle<YieldTermStructure> USDDiscountCurve() {
43
44 vector<Date> dates(27);
45 vector<DiscountFactor> dfs(27);
46 Actual365Fixed dayCounter;
47
48 dates[0] = Date(11, Sep, 2018);
49 dfs[0] = 1;
50 dates[1] = Date(14, Sep, 2018);
51 dfs[1] = 0.99994666951096;
52 dates[2] = Date(20, Sep, 2018);
53 dfs[2] = 0.999627719221066;
54 dates[3] = Date(27, Sep, 2018);
55 dfs[3] = 0.999254084816959;
56 dates[4] = Date(04, Oct, 2018);
57 dfs[4] = 0.998837020905631;
58 dates[5] = Date(15, Oct, 2018);
59 dfs[5] = 0.998176132423265;
60 dates[6] = Date(13, Nov, 2018);
61 dfs[6] = 0.99644587210048;
62 dates[7] = Date(13, Dec, 2018);
63 dfs[7] = 0.994644668243218;
64 dates[8] = Date(14, Jan, 2019);
65 dfs[8] = 0.992596634984033;
66 dates[9] = Date(13, Feb, 2019);
67 dfs[9] = 0.990636503861861;
68 dates[10] = Date(13, Mar, 2019);
69 dfs[10] = 0.988809127958345;
70 dates[11] = Date(13, Jun, 2019);
71 dfs[11] = 0.982417991680868;
72 dates[12] = Date(13, Sep, 2019);
73 dfs[12] = 0.975723193871552;
74 dates[13] = Date(13, Mar, 2020);
75 dfs[13] = 0.96219213956104;
76 dates[14] = Date(14, Sep, 2020);
77 dfs[14] = 0.948588232418325;
78 dates[15] = Date(13, Sep, 2021);
79 dfs[15] = 0.92279636773464;
80 dates[16] = Date(13, Sep, 2022);
81 dfs[16] = 0.898345201557914;
82 dates[17] = Date(13, Sep, 2023);
83 dfs[17] = 0.874715322269088;
84 dates[18] = Date(15, Sep, 2025);
85 dfs[18] = 0.828658611114833;
86 dates[19] = Date(13, Sep, 2028);
87 dfs[19] = 0.763030152740947;
88 dates[20] = Date(13, Sep, 2030);
89 dfs[20] = 0.722238847877756;
90 dates[21] = Date(13, Sep, 2033);
91 dfs[21] = 0.664460629674362;
92 dates[22] = Date(13, Sep, 2038);
93 dfs[22] = 0.580288693473926;
94 dates[23] = Date(14, Sep, 2043);
95 dfs[23] = 0.510857007600479;
96 dates[24] = Date(14, Sep, 2048);
97 dfs[24] = 0.44941525649436;
98 dates[25] = Date(13, Sep, 2058);
99 dfs[25] = 0.352389176933952;
100 dates[26] = Date(13, Sep, 2068);
101 dfs[26] = 0.28183300653329;
102
103 return Handle<YieldTermStructure>(QuantLib::ext::make_shared<DiscountCurve>(dates, dfs, dayCounter));
104}
105
106Handle<YieldTermStructure> USDProjectionCurve() {
107
108 vector<Date> dates(25);
109 vector<DiscountFactor> dfs(25);
110 Actual365Fixed dayCounter;
111
112 dates[0] = Date(11, Sep, 2018);
113 dfs[0] = 1;
114 dates[1] = Date(13, Dec, 2018);
115 dfs[1] = 0.994134145990132;
116 dates[2] = Date(19, Dec, 2018);
117 dfs[2] = 0.993695776146116;
118 dates[3] = Date(20, Mar, 2019);
119 dfs[3] = 0.987047992958673;
120 dates[4] = Date(19, Jun, 2019);
121 dfs[4] = 0.980016364694049;
122 dates[5] = Date(18, Sep, 2019);
123 dfs[5] = 0.972708376777628;
124 dates[6] = Date(18, Dec, 2019);
125 dfs[6] = 0.965277162951128;
126 dates[7] = Date(18, Mar, 2020);
127 dfs[7] = 0.957799302363697;
128 dates[8] = Date(14, Sep, 2020);
129 dfs[8] = 0.943264331984248;
130 dates[9] = Date(13, Sep, 2021);
131 dfs[9] = 0.914816470778467;
132 dates[10] = Date(13, Sep, 2022);
133 dfs[10] = 0.88764714641623;
134 dates[11] = Date(13, Sep, 2023);
135 dfs[11] = 0.861475671008934;
136 dates[12] = Date(13, Sep, 2024);
137 dfs[12] = 0.835944798717806;
138 dates[13] = Date(15, Sep, 2025);
139 dfs[13] = 0.810833947617338;
140 dates[14] = Date(14, Sep, 2026);
141 dfs[14] = 0.78631849267276;
142 dates[15] = Date(13, Sep, 2027);
143 dfs[15] = 0.762267648509673;
144 dates[16] = Date(13, Sep, 2028);
145 dfs[16] = 0.738613627359076;
146 dates[17] = Date(13, Sep, 2029);
147 dfs[17] = 0.715502378943932;
148 dates[18] = Date(13, Sep, 2030);
149 dfs[18] = 0.693380472578176;
150 dates[19] = Date(13, Sep, 2033);
151 dfs[19] = 0.631097994110912;
152 dates[20] = Date(13, Sep, 2038);
153 dfs[20] = 0.540797634630251;
154 dates[21] = Date(14, Sep, 2043);
155 dfs[21] = 0.465599237331079;
156 dates[22] = Date(14, Sep, 2048);
157 dfs[22] = 0.402119473746341;
158 dates[23] = Date(13, Sep, 2058);
159 dfs[23] = 0.303129773289934;
160 dates[24] = Date(13, Sep, 2068);
161 dfs[24] = 0.23210070222569;
162
163 return Handle<YieldTermStructure>(QuantLib::ext::make_shared<DiscountCurve>(dates, dfs, dayCounter));
164}
165
166Handle<YieldTermStructure> GBPDiscountCurve() {
167
168 vector<Date> dates(27);
169 vector<DiscountFactor> dfs(27);
170 Actual365Fixed dayCounter;
171
172 dates[0] = Date(11, Sep, 2018);
173 dfs[0] = 1;
174 dates[1] = Date(14, Sep, 2018);
175 dfs[1] = 0.99994666951096;
176 dates[2] = Date(20, Sep, 2018);
177 dfs[2] = 0.999627719221066;
178 dates[3] = Date(27, Sep, 2018);
179 dfs[3] = 0.999254084816959;
180 dates[4] = Date(04, Oct, 2018);
181 dfs[4] = 0.998837020905631;
182 dates[5] = Date(15, Oct, 2018);
183 dfs[5] = 0.998176132423265;
184 dates[6] = Date(13, Nov, 2018);
185 dfs[6] = 0.99644587210048;
186 dates[7] = Date(13, Dec, 2018);
187 dfs[7] = 0.994644668243218;
188 dates[8] = Date(14, Jan, 2019);
189 dfs[8] = 0.992596634984033;
190 dates[9] = Date(13, Feb, 2019);
191 dfs[9] = 0.990636503861861;
192 dates[10] = Date(13, Mar, 2019);
193 dfs[10] = 0.988809127958345;
194 dates[11] = Date(13, Jun, 2019);
195 dfs[11] = 0.982417991680868;
196 dates[12] = Date(13, Sep, 2019);
197 dfs[12] = 0.975723193871552;
198 dates[13] = Date(13, Mar, 2020);
199 dfs[13] = 0.96219213956104;
200 dates[14] = Date(14, Sep, 2020);
201 dfs[14] = 0.948588232418325;
202 dates[15] = Date(13, Sep, 2021);
203 dfs[15] = 0.92279636773464;
204 dates[16] = Date(13, Sep, 2022);
205 dfs[16] = 0.898345201557914;
206 dates[17] = Date(13, Sep, 2023);
207 dfs[17] = 0.874715322269088;
208 dates[18] = Date(15, Sep, 2025);
209 dfs[18] = 0.828658611114833;
210 dates[19] = Date(13, Sep, 2028);
211 dfs[19] = 0.763030152740947;
212 dates[20] = Date(13, Sep, 2030);
213 dfs[20] = 0.722238847877756;
214 dates[21] = Date(13, Sep, 2033);
215 dfs[21] = 0.664460629674362;
216 dates[22] = Date(13, Sep, 2038);
217 dfs[22] = 0.580288693473926;
218 dates[23] = Date(14, Sep, 2043);
219 dfs[23] = 0.510857007600479;
220 dates[24] = Date(14, Sep, 2048);
221 dfs[24] = 0.44941525649436;
222 dates[25] = Date(13, Sep, 2058);
223 dfs[25] = 0.352389176933952;
224 dates[26] = Date(13, Sep, 2068);
225 dfs[26] = 0.28183300653329;
226
227 return Handle<YieldTermStructure>(QuantLib::ext::make_shared<DiscountCurve>(dates, dfs, dayCounter));
228}
229
230Handle<YieldTermStructure> GBPProjectionCurve() {
231
232 vector<Date> dates(25);
233 vector<DiscountFactor> dfs(25);
234 Actual365Fixed dayCounter;
235
236 dates[0] = Date(11, Sep, 2018);
237 dfs[0] = 1;
238 dates[1] = Date(13, Dec, 2018);
239 dfs[1] = 0.994134145990132;
240 dates[2] = Date(19, Dec, 2018);
241 dfs[2] = 0.993695776146116;
242 dates[3] = Date(20, Mar, 2019);
243 dfs[3] = 0.987047992958673;
244 dates[4] = Date(19, Jun, 2019);
245 dfs[4] = 0.980016364694049;
246 dates[5] = Date(18, Sep, 2019);
247 dfs[5] = 0.972708376777628;
248 dates[6] = Date(18, Dec, 2019);
249 dfs[6] = 0.965277162951128;
250 dates[7] = Date(18, Mar, 2020);
251 dfs[7] = 0.957799302363697;
252 dates[8] = Date(14, Sep, 2020);
253 dfs[8] = 0.943264331984248;
254 dates[9] = Date(13, Sep, 2021);
255 dfs[9] = 0.914816470778467;
256 dates[10] = Date(13, Sep, 2022);
257 dfs[10] = 0.88764714641623;
258 dates[11] = Date(13, Sep, 2023);
259 dfs[11] = 0.861475671008934;
260 dates[12] = Date(13, Sep, 2024);
261 dfs[12] = 0.835944798717806;
262 dates[13] = Date(15, Sep, 2025);
263 dfs[13] = 0.810833947617338;
264 dates[14] = Date(14, Sep, 2026);
265 dfs[14] = 0.78631849267276;
266 dates[15] = Date(13, Sep, 2027);
267 dfs[15] = 0.762267648509673;
268 dates[16] = Date(13, Sep, 2028);
269 dfs[16] = 0.738613627359076;
270 dates[17] = Date(13, Sep, 2029);
271 dfs[17] = 0.715502378943932;
272 dates[18] = Date(13, Sep, 2030);
273 dfs[18] = 0.693380472578176;
274 dates[19] = Date(13, Sep, 2033);
275 dfs[19] = 0.631097994110912;
276 dates[20] = Date(13, Sep, 2038);
277 dfs[20] = 0.540797634630251;
278 dates[21] = Date(14, Sep, 2043);
279 dfs[21] = 0.465599237331079;
280 dates[22] = Date(14, Sep, 2048);
281 dfs[22] = 0.402119473746341;
282 dates[23] = Date(13, Sep, 2058);
283 dfs[23] = 0.303129773289934;
284 dates[24] = Date(13, Sep, 2068);
285 dfs[24] = 0.23210070222569;
286
287 return Handle<YieldTermStructure>(QuantLib::ext::make_shared<DiscountCurve>(dates, dfs, dayCounter));
288}
289
290QuantLib::ext::shared_ptr<CrossCcyBasisMtMResetSwap> makeTestSwap(Rate spotFx, Spread GBPSpread) {
291
292 // USD nominal
293 Real GBPNominal = 10000000.0;
294 Handle<Quote> fxSpotQuote = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(spotFx));
295
296 // Dates and calendars
297 JointCalendar payCalendar = JointCalendar(UnitedStates(UnitedStates::Settlement), UnitedKingdom());
298 Date referenceDate = Settings::instance().evaluationDate();
299 referenceDate = payCalendar.adjust(referenceDate);
300 Date start = payCalendar.advance(referenceDate, 2 * Days);
301 Date end = start + 5 * Years;
302 Schedule schedule(start, end, 3 * Months, payCalendar, ModifiedFollowing, ModifiedFollowing,
303 DateGeneration::Backward, false);
304
305 // Indices
306 QuantLib::ext::shared_ptr<IborIndex> USDindex = QuantLib::ext::make_shared<USDLibor>(3 * Months, USDProjectionCurve());
307 QuantLib::ext::shared_ptr<IborIndex> GBPindex = QuantLib::ext::make_shared<GBPLibor>(3 * Months, GBPProjectionCurve());
308 QuantLib::ext::shared_ptr<FxIndex> fxIndex = QuantLib::ext::make_shared<FxIndex>(
309 "dummy", 0, GBPCurrency(), USDCurrency(), payCalendar, fxSpotQuote, GBPDiscountCurve(), USDDiscountCurve());
310
311 // Create swap
312 return QuantLib::ext::shared_ptr<CrossCcyBasisMtMResetSwap>(new CrossCcyBasisMtMResetSwap(
313 GBPNominal, GBPCurrency(), schedule, GBPindex, GBPSpread, USDCurrency(), schedule, USDindex, 0.0, fxIndex));
314}
315} // namespace
316
317BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)
318
319BOOST_AUTO_TEST_SUITE(CrossCcyBasisMtMResetSwapTest)
320
321BOOST_AUTO_TEST_CASE(testSwapPricing) {
322
323 BOOST_TEST_MESSAGE("Test cross currency MtM resetting swap pricing against known results");
324
325 SavedSettings backup;
326 Settings::instance().evaluationDate() = Date(11, Sep, 2018);
327
328 // Create swap
329 Rate spotFx = 1;
330 Spread spread = 0;
331 QuantLib::ext::shared_ptr<CrossCcyBasisMtMResetSwap> swap = makeTestSwap(spotFx, spread);
332
333 // Attach pricing engine
334 Handle<Quote> fxSpotQuote = Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(spotFx));
335 QuantLib::ext::shared_ptr<PricingEngine> engine = QuantLib::ext::make_shared<CrossCcySwapEngine>(
336 USDCurrency(), USDDiscountCurve(), GBPCurrency(), GBPDiscountCurve(), fxSpotQuote);
337
338 swap->setPricingEngine(engine);
339
340 // Check values
341 Real tol = 0.01;
342
343 BOOST_CHECK_SMALL(swap->NPV(), tol);
344
345 Real expBps = -4670.170509677384; // cached value
346 BOOST_CHECK_SMALL(swap->legBPS(0) - expBps, tol);
347}
348
349BOOST_AUTO_TEST_SUITE_END()
350
351BOOST_AUTO_TEST_SUITE_END()
Cross currency basis MtM resettable swap.
Cross currency basis swap instrument with MTM reset.
Cross currency swap engine.
BOOST_AUTO_TEST_CASE(testSwapPricing)
Fixture that can be used at top level.