/src/quantlib/ql/currencies/exchangeratemanager.cpp
Line | Count | Source |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2004, 2005, 2006, 2007, 2008 StatPro Italia srl |
5 | | Copyright (C) 2004 Decillion Pty(Ltd) |
6 | | |
7 | | This file is part of QuantLib, a free-software/open-source library |
8 | | for financial quantitative analysts and developers - http://quantlib.org/ |
9 | | |
10 | | QuantLib is free software: you can redistribute it and/or modify it |
11 | | under the terms of the QuantLib license. You should have received a |
12 | | copy of the license along with this program; if not, please email |
13 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
14 | | <https://www.quantlib.org/license.shtml>. |
15 | | |
16 | | This program is distributed in the hope that it will be useful, but WITHOUT |
17 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
18 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
19 | | */ |
20 | | |
21 | | #include <ql/currencies/exchangeratemanager.hpp> |
22 | | #include <ql/currencies/europe.hpp> |
23 | | #include <ql/currencies/america.hpp> |
24 | | #include <ql/settings.hpp> |
25 | | #include <algorithm> |
26 | | |
27 | | namespace QuantLib { |
28 | | |
29 | | namespace { |
30 | | |
31 | | struct valid_at { |
32 | | Date d; |
33 | 0 | explicit valid_at(const Date& d) : d(d) {} |
34 | 0 | bool operator()(const ExchangeRateManager::Entry& e) const { |
35 | 0 | return d >= e.startDate && d <= e.endDate; |
36 | 0 | } |
37 | | }; |
38 | | |
39 | | } |
40 | | |
41 | 0 | ExchangeRateManager::ExchangeRateManager() { |
42 | 0 | addKnownRates(); |
43 | 0 | } |
44 | | |
45 | | void ExchangeRateManager::add(const ExchangeRate& rate, |
46 | | const Date& startDate, |
47 | 0 | const Date& endDate) { |
48 | 0 | Key k = hash(rate.source(), rate.target()); |
49 | 0 | data_[k].emplace_front(rate,startDate,endDate); |
50 | 0 | } |
51 | | |
52 | | ExchangeRate ExchangeRateManager::lookup(const Currency& source, |
53 | | const Currency& target, |
54 | | Date date, |
55 | 0 | ExchangeRate::Type type) const { |
56 | |
|
57 | 0 | if (source == target) |
58 | 0 | return ExchangeRate(source,target,1.0); |
59 | | |
60 | 0 | if (date == Date()) |
61 | 0 | date = Settings::instance().evaluationDate(); |
62 | |
|
63 | 0 | if (type == ExchangeRate::Direct) { |
64 | 0 | return directLookup(source,target,date); |
65 | 0 | } else if (!source.triangulationCurrency().empty()) { |
66 | 0 | const Currency& link = source.triangulationCurrency(); |
67 | 0 | if (link == target) |
68 | 0 | return directLookup(source,link,date); |
69 | 0 | else |
70 | 0 | return ExchangeRate::chain(directLookup(source,link,date), |
71 | 0 | lookup(link,target,date)); |
72 | 0 | } else if (!target.triangulationCurrency().empty()) { |
73 | 0 | const Currency& link = target.triangulationCurrency(); |
74 | 0 | if (source == link) |
75 | 0 | return directLookup(link,target,date); |
76 | 0 | else |
77 | 0 | return ExchangeRate::chain(lookup(source,link,date), |
78 | 0 | directLookup(link,target,date)); |
79 | 0 | } else { |
80 | 0 | return smartLookup(source,target,date); |
81 | 0 | } |
82 | 0 | } |
83 | | |
84 | 0 | void ExchangeRateManager::clear() { |
85 | 0 | data_.clear(); |
86 | 0 | addKnownRates(); |
87 | 0 | } |
88 | | |
89 | | ExchangeRateManager::Key ExchangeRateManager::hash( |
90 | 0 | const Currency& c1, const Currency& c2) const { |
91 | 0 | return Key(std::min(c1.numericCode(),c2.numericCode()))*1000 |
92 | 0 | + Key(std::max(c1.numericCode(),c2.numericCode())); |
93 | 0 | } |
94 | | |
95 | | bool ExchangeRateManager::hashes(ExchangeRateManager::Key k, |
96 | 0 | const Currency& c) const { |
97 | 0 | return c.numericCode() == k % 1000 || c.numericCode() == k/1000; |
98 | 0 | } |
99 | | |
100 | 0 | void ExchangeRateManager::addKnownRates() { |
101 | | // currencies obsoleted by Euro |
102 | 0 | add(ExchangeRate(EURCurrency(), ATSCurrency(), 13.7603), |
103 | 0 | Date(1,January,1999), Date::maxDate()); |
104 | 0 | add(ExchangeRate(EURCurrency(), BEFCurrency(), 40.3399), |
105 | 0 | Date(1,January,1999), Date::maxDate()); |
106 | 0 | add(ExchangeRate(EURCurrency(), DEMCurrency(), 1.95583), |
107 | 0 | Date(1,January,1999), Date::maxDate()); |
108 | 0 | add(ExchangeRate(EURCurrency(), ESPCurrency(), 166.386), |
109 | 0 | Date(1,January,1999), Date::maxDate()); |
110 | 0 | add(ExchangeRate(EURCurrency(), FIMCurrency(), 5.94573), |
111 | 0 | Date(1,January,1999), Date::maxDate()); |
112 | 0 | add(ExchangeRate(EURCurrency(), FRFCurrency(), 6.55957), |
113 | 0 | Date(1,January,1999), Date::maxDate()); |
114 | 0 | add(ExchangeRate(EURCurrency(), GRDCurrency(), 340.750), |
115 | 0 | Date(1,January,2001), Date::maxDate()); |
116 | 0 | add(ExchangeRate(EURCurrency(), IEPCurrency(), 0.787564), |
117 | 0 | Date(1,January,1999), Date::maxDate()); |
118 | 0 | add(ExchangeRate(EURCurrency(), ITLCurrency(), 1936.27), |
119 | 0 | Date(1,January,1999), Date::maxDate()); |
120 | 0 | add(ExchangeRate(EURCurrency(), LUFCurrency(), 40.3399), |
121 | 0 | Date(1,January,1999), Date::maxDate()); |
122 | 0 | add(ExchangeRate(EURCurrency(), NLGCurrency(), 2.20371), |
123 | 0 | Date(1,January,1999), Date::maxDate()); |
124 | 0 | add(ExchangeRate(EURCurrency(), PTECurrency(), 200.482), |
125 | 0 | Date(1,January,1999), Date::maxDate()); |
126 | | // other obsoleted currencies |
127 | 0 | add(ExchangeRate(TRYCurrency(), TRLCurrency(), 1000000.0), |
128 | 0 | Date(1,January,2005), Date::maxDate()); |
129 | 0 | add(ExchangeRate(RONCurrency(), ROLCurrency(), 10000.0), |
130 | 0 | Date(1,July,2005), Date::maxDate()); |
131 | 0 | add(ExchangeRate(PENCurrency(), PEICurrency(), 1000000.0), |
132 | 0 | Date(1,July,1991), Date::maxDate()); |
133 | 0 | add(ExchangeRate(PEICurrency(), PEHCurrency(), 1000.0), |
134 | 0 | Date(1,February,1985), Date::maxDate()); |
135 | 0 | } |
136 | | |
137 | | ExchangeRate ExchangeRateManager::directLookup(const Currency& source, |
138 | | const Currency& target, |
139 | 0 | const Date& date) const { |
140 | 0 | if (const ExchangeRate* rate = fetch(source,target,date)) |
141 | 0 | return *rate; |
142 | 0 | else |
143 | 0 | QL_FAIL("no direct conversion available from " |
144 | 0 | << source.code() << " to " << target.code() |
145 | 0 | << " for " << date); |
146 | 0 | } |
147 | | |
148 | | ExchangeRate ExchangeRateManager::smartLookup( |
149 | | const Currency& source, |
150 | | const Currency& target, |
151 | | const Date& date, |
152 | 0 | std::list<Integer> forbidden) const { |
153 | | // direct exchange rates are preferred. |
154 | 0 | if (const ExchangeRate* direct = fetch(source,target,date)) |
155 | 0 | return *direct; |
156 | | |
157 | | // if none is found, turn to smart lookup. The source currency |
158 | | // is forbidden to subsequent lookups in order to avoid cycles. |
159 | 0 | forbidden.push_back(source.numericCode()); |
160 | 0 | std::map<Key, std::list<Entry> >::const_iterator i; |
161 | 0 | for (i = data_.begin(); i != data_.end(); ++i) { |
162 | | // we look for exchange-rate data which involve our source |
163 | | // currency... |
164 | 0 | if (hashes(i->first, source) && !(i->second.empty())) { |
165 | | // ...whose other currency is not forbidden... |
166 | 0 | const Entry& e = i->second.front(); |
167 | 0 | const Currency& other = |
168 | 0 | source == e.rate.source() ? |
169 | 0 | e.rate.target() : e.rate.source(); |
170 | 0 | if (std::find(forbidden.begin(),forbidden.end(), |
171 | 0 | other.numericCode()) == forbidden.end()) { |
172 | | // ...and which carries information for the requested date. |
173 | 0 | if (const ExchangeRate* head = fetch(source,other,date)) { |
174 | | // if we can get to the target from here... |
175 | 0 | try { |
176 | 0 | ExchangeRate tail = smartLookup(other,target,date, |
177 | 0 | forbidden); |
178 | | // ..we're done. |
179 | 0 | return ExchangeRate::chain(*head,tail); |
180 | 0 | } catch (Error&) { |
181 | | // otherwise, we just discard this rate. |
182 | 0 | ; |
183 | 0 | } |
184 | 0 | } |
185 | 0 | } |
186 | 0 | } |
187 | 0 | } |
188 | | // if the loop completed, we have no way to return the requested rate. |
189 | 0 | QL_FAIL("no conversion available from " |
190 | 0 | << source.code() << " to " << target.code() |
191 | 0 | << " for " << date); |
192 | 0 | } |
193 | | |
194 | | const ExchangeRate* ExchangeRateManager::fetch(const Currency& source, |
195 | | const Currency& target, |
196 | 0 | const Date& date) const { |
197 | 0 | const std::list<Entry>& rates = data_[hash(source,target)]; |
198 | 0 | auto i = std::find_if(rates.begin(), rates.end(), valid_at(date)); |
199 | 0 | return i == rates.end() ? (const ExchangeRate*)nullptr : &(i->rate); |
200 | 0 | } |
201 | | |
202 | | } |
203 | | |