1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2004 StatPro Italia srl
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include "exchangerate.hpp"
21#include "utilities.hpp"
22#include <ql/exchangerate.hpp>
23#include <ql/currencies/europe.hpp>
24#include <ql/currencies/america.hpp>
25#include <ql/currencies/asia.hpp>
26#include <ql/currencies/exchangeratemanager.hpp>
27
28using namespace QuantLib;
29using namespace boost::unit_test_framework;
30
31void ExchangeRateTest::testDirect() {
32
33 BOOST_TEST_MESSAGE("Testing direct exchange rates...");
34
35 Currency EUR = EURCurrency(), USD = USDCurrency();
36
37 ExchangeRate eur_usd = ExchangeRate(EUR, USD, 1.2042);
38
39 Money m1 = 50000.0 * EUR;
40 Money m2 = 100000.0 * USD;
41
42 Money::Settings::instance().conversionType() = Money::NoConversion;
43
44 Money calculated = eur_usd.exchange(amount: m1);
45 Money expected(m1.value()*eur_usd.rate(), USD);
46
47 if (!close(calculated,expected)) {
48 BOOST_FAIL("Wrong result: \n"
49 << " expected: " << expected << "\n"
50 << " calculated: " << calculated);
51 }
52
53 calculated = eur_usd.exchange(amount: m2);
54 expected = Money(m2.value()/eur_usd.rate(), EUR);
55
56 if (!close(calculated,expected)) {
57 BOOST_FAIL("Wrong result: \n"
58 << " expected: " << expected << "\n"
59 << " calculated: " << calculated);
60 }
61}
62
63void ExchangeRateTest::testDerived() {
64
65 BOOST_TEST_MESSAGE("Testing derived exchange rates...");
66
67 Currency EUR = EURCurrency(), USD = USDCurrency(), GBP = GBPCurrency();
68
69 ExchangeRate eur_usd = ExchangeRate(EUR, USD, 1.2042);
70 ExchangeRate eur_gbp = ExchangeRate(EUR, GBP, 0.6612);
71
72 ExchangeRate derived = ExchangeRate::chain(r1: eur_usd, r2: eur_gbp);
73
74 Money m1 = 50000.0 * GBP;
75 Money m2 = 100000.0 * USD;
76
77 Money::Settings::instance().conversionType() = Money::NoConversion;
78
79 Money calculated = derived.exchange(amount: m1);
80 Money expected(m1.value()*eur_usd.rate()/eur_gbp.rate(), USD);
81
82 if (!close(calculated,expected)) {
83 BOOST_FAIL("Wrong result: \n"
84 << " expected: " << expected << "\n"
85 << " calculated: " << calculated);
86 }
87
88 calculated = derived.exchange(amount: m2);
89 expected = Money(m2.value()*eur_gbp.rate()/eur_usd.rate(), GBP);
90
91 if (!close(calculated,expected)) {
92 BOOST_FAIL("Wrong result: \n"
93 << " expected: " << expected << "\n"
94 << " calculated: " << calculated);
95 }
96}
97
98void ExchangeRateTest::testDirectLookup() {
99
100 BOOST_TEST_MESSAGE("Testing lookup of direct exchange rates...");
101
102 ExchangeRateManager& rateManager = ExchangeRateManager::instance();
103 rateManager.clear();
104
105 Currency EUR = EURCurrency(), USD = USDCurrency();
106
107 ExchangeRate eur_usd1 = ExchangeRate(EUR, USD, 1.1983);
108 ExchangeRate eur_usd2 = ExchangeRate(USD, EUR, 1.0/1.2042);
109 rateManager.add(eur_usd1, startDate: Date(4,August,2004));
110 rateManager.add(eur_usd2, startDate: Date(5,August,2004));
111
112 Money m1 = 50000.0 * EUR;
113 Money m2 = 100000.0 * USD;
114
115 Money::Settings::instance().conversionType() = Money::NoConversion;
116
117 ExchangeRate eur_usd = rateManager.lookup(source: EUR, target: USD,
118 date: Date(4,August,2004),
119 type: ExchangeRate::Direct);
120 Money calculated = eur_usd.exchange(amount: m1);
121 Money expected(m1.value()*eur_usd1.rate(), USD);
122
123 if (!close(calculated,expected)) {
124 BOOST_FAIL("Wrong result: \n"
125 << " expected: " << expected << "\n"
126 << " calculated: " << calculated);
127 }
128
129 eur_usd = rateManager.lookup(source: EUR, target: USD,
130 date: Date(5,August,2004),
131 type: ExchangeRate::Direct);
132 calculated = eur_usd.exchange(amount: m1);
133 expected = Money(m1.value()/eur_usd2.rate(), USD);
134
135 if (!close(calculated,expected)) {
136 BOOST_FAIL("Wrong result: \n"
137 << " expected: " << expected << "\n"
138 << " calculated: " << calculated);
139 }
140
141 ExchangeRate usd_eur = rateManager.lookup(source: USD, target: EUR,
142 date: Date(4,August,2004),
143 type: ExchangeRate::Direct);
144
145 calculated = usd_eur.exchange(amount: m2);
146 expected = Money(m2.value()/eur_usd1.rate(), EUR);
147
148 if (!close(calculated,expected)) {
149 BOOST_FAIL("Wrong result: \n"
150 << " expected: " << expected << "\n"
151 << " calculated: " << calculated);
152 }
153
154 usd_eur = rateManager.lookup(source: USD, target: EUR,
155 date: Date(5,August,2004),
156 type: ExchangeRate::Direct);
157
158 calculated = usd_eur.exchange(amount: m2);
159 expected = Money(m2.value()*eur_usd2.rate(), EUR);
160
161 if (!close(calculated,expected)) {
162 BOOST_FAIL("Wrong result: \n"
163 << " expected: " << expected << "\n"
164 << " calculated: " << calculated);
165 }
166}
167
168void ExchangeRateTest::testTriangulatedLookup() {
169
170 BOOST_TEST_MESSAGE("Testing lookup of triangulated exchange rates...");
171
172 ExchangeRateManager& rateManager = ExchangeRateManager::instance();
173 rateManager.clear();
174
175 Currency EUR = EURCurrency(), USD = USDCurrency(), ITL = ITLCurrency();
176
177 ExchangeRate eur_usd1 = ExchangeRate(EUR, USD, 1.1983);
178 ExchangeRate eur_usd2 = ExchangeRate(EUR, USD, 1.2042);
179 rateManager.add(eur_usd1, startDate: Date(4,August,2004));
180 rateManager.add(eur_usd2, startDate: Date(5,August,2004));
181
182 Money m1 = 50000000.0 * ITL;
183 Money m2 = 100000.0 * USD;
184
185 Money::Settings::instance().conversionType() = Money::NoConversion;
186
187 ExchangeRate itl_usd = rateManager.lookup(source: ITL, target: USD,
188 date: Date(4,August,2004));
189 Money calculated = itl_usd.exchange(amount: m1);
190 Money expected(m1.value()*eur_usd1.rate()/1936.27, USD);
191
192 if (!close(calculated,expected)) {
193 BOOST_FAIL("Wrong result: \n"
194 << " expected: " << expected << "\n"
195 << " calculated: " << calculated);
196 }
197
198 itl_usd = rateManager.lookup(source: ITL, target: USD,
199 date: Date(5,August,2004));
200 calculated = itl_usd.exchange(amount: m1);
201 expected = Money(m1.value()*eur_usd2.rate()/1936.27, USD);
202
203 if (!close(calculated,expected)) {
204 BOOST_FAIL("Wrong result: \n"
205 << " expected: " << expected << "\n"
206 << " calculated: " << calculated);
207 }
208
209 ExchangeRate usd_itl = rateManager.lookup(source: USD, target: ITL,
210 date: Date(4,August,2004));
211
212 calculated = usd_itl.exchange(amount: m2);
213 expected = Money(m2.value()*1936.27/eur_usd1.rate(), ITL);
214
215 if (!close(calculated,expected)) {
216 BOOST_FAIL("Wrong result: \n"
217 << " expected: " << expected << "\n"
218 << " calculated: " << calculated);
219 }
220
221 usd_itl = rateManager.lookup(source: USD, target: ITL,
222 date: Date(5,August,2004));
223
224 calculated = usd_itl.exchange(amount: m2);
225 expected = Money(m2.value()*1936.27/eur_usd2.rate(), ITL);
226
227 if (!close(calculated,expected)) {
228 BOOST_FAIL("Wrong result: \n"
229 << " expected: " << expected << "\n"
230 << " calculated: " << calculated);
231 }
232}
233
234void ExchangeRateTest::testSmartLookup() {
235
236 BOOST_TEST_MESSAGE("Testing lookup of derived exchange rates...");
237
238 Currency EUR = EURCurrency(), USD = USDCurrency(), GBP = GBPCurrency(),
239 CHF = CHFCurrency(), SEK = SEKCurrency(), JPY = JPYCurrency();
240
241 ExchangeRateManager& rateManager = ExchangeRateManager::instance();
242 rateManager.clear();
243
244 ExchangeRate eur_usd1 = ExchangeRate(EUR, USD, 1.1983);
245 ExchangeRate eur_usd2 = ExchangeRate(USD, EUR, 1.0/1.2042);
246 rateManager.add(eur_usd1, startDate: Date(4,August,2004));
247 rateManager.add(eur_usd2, startDate: Date(5,August,2004));
248
249 ExchangeRate eur_gbp1 = ExchangeRate(GBP, EUR, 1.0/0.6596);
250 ExchangeRate eur_gbp2 = ExchangeRate(EUR, GBP, 0.6612);
251 rateManager.add(eur_gbp1, startDate: Date(4,August,2004));
252 rateManager.add(eur_gbp2, startDate: Date(5,August,2004));
253
254 ExchangeRate usd_chf1 = ExchangeRate(USD, CHF, 1.2847);
255 ExchangeRate usd_chf2 = ExchangeRate(CHF, USD, 1.0/1.2774);
256 rateManager.add(usd_chf1, startDate: Date(4,August,2004));
257 rateManager.add(usd_chf2, startDate: Date(5,August,2004));
258
259 ExchangeRate chf_sek1 = ExchangeRate(SEK, CHF, 0.1674);
260 ExchangeRate chf_sek2 = ExchangeRate(CHF, SEK, 1.0/0.1677);
261 rateManager.add(chf_sek1, startDate: Date(4,August,2004));
262 rateManager.add(chf_sek2, startDate: Date(5,August,2004));
263
264 ExchangeRate jpy_sek1 = ExchangeRate(SEK, JPY, 14.5450);
265 ExchangeRate jpy_sek2 = ExchangeRate(JPY, SEK, 1.0/14.6110);
266 rateManager.add(jpy_sek1, startDate: Date(4,August,2004));
267 rateManager.add(jpy_sek2, startDate: Date(5,August,2004));
268
269 Money m1 = 100000.0 * USD;
270 Money m2 = 100000.0 * EUR;
271 Money m3 = 100000.0 * GBP;
272 Money m4 = 100000.0 * CHF;
273 Money m5 = 100000.0 * SEK;
274 Money m6 = 100000.0 * JPY;
275
276 Money::Settings::instance().conversionType() = Money::NoConversion;
277
278 // two-rate chain
279
280 ExchangeRate usd_sek = rateManager.lookup(source: USD, target: SEK,
281 date: Date(4,August,2004));
282 Money calculated = usd_sek.exchange(amount: m1);
283 Money expected(m1.value()*usd_chf1.rate()/chf_sek1.rate(), SEK);
284
285 if (!close(calculated,expected)) {
286 BOOST_FAIL("Wrong result: \n"
287 << " expected: " << expected << "\n"
288 << " calculated: " << calculated);
289 }
290
291 usd_sek = rateManager.lookup(source: SEK, target: USD, date: Date(5,August,2004));
292 calculated = usd_sek.exchange(amount: m5);
293 expected = Money(m5.value()*usd_chf2.rate()/chf_sek2.rate(), USD);
294
295 if (!close(calculated,expected)) {
296 BOOST_FAIL("Wrong result: \n"
297 << " expected: " << expected << "\n"
298 << " calculated: " << calculated);
299 }
300
301 // three-rate chain
302
303 ExchangeRate eur_sek = rateManager.lookup(source: EUR, target: SEK,
304 date: Date(4,August,2004));
305 calculated = eur_sek.exchange(amount: m2);
306 expected = Money(m2.value()*eur_usd1.rate()
307 *usd_chf1.rate()/chf_sek1.rate(), SEK);
308
309 if (!close(calculated,expected)) {
310 BOOST_FAIL("Wrong result: \n"
311 << " expected: " << expected << "\n"
312 << " calculated: " << calculated);
313 }
314
315 eur_sek = rateManager.lookup(source: SEK, target: EUR, date: Date(5,August,2004));
316 calculated = eur_sek.exchange(amount: m5);
317 expected = Money(m5.value()*eur_usd2.rate()
318 *usd_chf2.rate()/chf_sek2.rate(), EUR);
319
320 if (!close(calculated,expected)) {
321 BOOST_FAIL("Wrong result: \n"
322 << " expected: " << expected << "\n"
323 << " calculated: " << calculated);
324 }
325
326 // four-rate chain
327
328 ExchangeRate eur_jpy = rateManager.lookup(source: EUR, target: JPY,
329 date: Date(4,August,2004));
330 calculated = eur_jpy.exchange(amount: m2);
331 expected = Money(m2.value()*eur_usd1.rate()*usd_chf1.rate()
332 *jpy_sek1.rate()/chf_sek1.rate(), JPY);
333
334 if (!close(calculated,expected)) {
335 BOOST_FAIL("Wrong result: \n"
336 << " expected: " << expected << "\n"
337 << " calculated: " << calculated);
338 }
339
340 eur_jpy = rateManager.lookup(source: JPY, target: EUR, date: Date(5,August,2004));
341 calculated = eur_jpy.exchange(amount: m6);
342 expected = Money(m6.value()*jpy_sek2.rate()*eur_usd2.rate()
343 *usd_chf2.rate()/chf_sek2.rate(), EUR);
344
345 if (!close(calculated,expected)) {
346 BOOST_FAIL("Wrong result: \n"
347 << " expected: " << expected << "\n"
348 << " calculated: " << calculated);
349 }
350
351 // five-rate chain
352
353 ExchangeRate gbp_jpy = rateManager.lookup(source: GBP, target: JPY,
354 date: Date(4,August,2004));
355 calculated = gbp_jpy.exchange(amount: m3);
356 expected = Money(m3.value()*eur_gbp1.rate()*eur_usd1.rate()*usd_chf1.rate()
357 *jpy_sek1.rate()/chf_sek1.rate(), JPY);
358
359 if (!close(calculated,expected)) {
360 BOOST_FAIL("Wrong result: \n"
361 << " expected: " << expected << "\n"
362 << " calculated: " << calculated);
363 }
364
365 gbp_jpy = rateManager.lookup(source: JPY, target: GBP, date: Date(5,August,2004));
366 calculated = gbp_jpy.exchange(amount: m6);
367 expected = Money(m6.value()*jpy_sek2.rate()*eur_usd2.rate()*usd_chf2.rate()
368 *eur_gbp2.rate()/chf_sek2.rate(), GBP);
369
370 if (!close(calculated,expected)) {
371 BOOST_FAIL("Wrong result: \n"
372 << " expected: " << expected << "\n"
373 << " calculated: " << calculated);
374 }
375}
376
377test_suite* ExchangeRateTest::suite() {
378 auto* suite = BOOST_TEST_SUITE("Exchange-rate tests");
379 suite->add(QUANTLIB_TEST_CASE(&ExchangeRateTest::testDirect));
380 suite->add(QUANTLIB_TEST_CASE(&ExchangeRateTest::testDerived));
381 suite->add(QUANTLIB_TEST_CASE(&ExchangeRateTest::testDirectLookup));
382 suite->add(QUANTLIB_TEST_CASE(&ExchangeRateTest::testTriangulatedLookup));
383 suite->add(QUANTLIB_TEST_CASE(&ExchangeRateTest::testSmartLookup));
384 return suite;
385}
386
387

source code of quantlib/test-suite/exchangerate.cpp