Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Public Member Functions | Private Member Functions | Private Attributes | List of all members
FXTriangulation Class Reference

#include <ored/marketdata/fxtriangulation.hpp>

+ Collaboration diagram for FXTriangulation:

Public Member Functions

 FXTriangulation ()
 
 FXTriangulation (std::map< std::string, QuantLib::Handle< QuantLib::Quote > > quotes)
 
QuantLib::Handle< QuantLib::Quote > getQuote (const std::string &pair) const
 
QuantLib::Handle< QuantExt::FxIndexgetIndex (const std::string &indexOrPair, const Market *market, const std::string &configuration) const
 

Private Member Functions

std::vector< std::string > getPath (const std::string &forCcy, const std::string &domCcy) const
 
Handle< Quote > getQuote (const std::string &forCcy, const std::string &domCcy) const
 
std::string getAllQuotes () const
 

Private Attributes

std::map< std::string, QuantLib::Handle< QuantLib::Quote > > quotes_
 
std::map< std::string, QuantLib::Handle< QuantLib::Quote > > quoteCache_
 
std::map< std::pair< std::string, std::string >, QuantLib::Handle< QuantExt::FxIndex > > indexCache_
 
std::vector< std::string > nodeToCcy_
 
std::map< std::string, std::size_t > ccyToNode_
 
std::vector< std::set< std::size_t > > neighbours_
 

Detailed Description

Definition at line 39 of file fxtriangulation.hpp.

Constructor & Destructor Documentation

◆ FXTriangulation() [1/2]

Set up empty repository

Definition at line 42 of file fxtriangulation.hpp.

42{}

◆ FXTriangulation() [2/2]

FXTriangulation ( std::map< std::string, QuantLib::Handle< QuantLib::Quote > >  quotes)
explicit

Set up fx quote repository with available market quotes ccypair => quote

Member Function Documentation

◆ getQuote() [1/2]

Handle< Quote > getQuote ( const std::string &  pair) const

Get quote, possibly via triangulation If you need an exact handling of spot lag differences, use getIndex() instead.

Definition at line 115 of file fxtriangulation.cpp.

115 {
116
117 // do we have a cached result?
118
119 if (auto it = quoteCache_.find(pair); it != quoteCache_.end())
120 return it->second;
121
122 // we need to construct the quote from the input quotes
123
124 Handle<Quote> result;
125 auto [ccy1, ccy2] = splitPair(pair);
126
127 // handle trivial case
128
129 if (ccy1 == ccy2)
130 return Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.0));
131
132 // get the path from ccy1 to ccy2
133
134 auto path = getPath(ccy1, ccy2);
135
136 if (path.size() == 2) {
137
138 // we can use a direct or inverted quote, but do not need a composite
139
140 result = getQuote(path[0], path[1]);
141
142 } else {
143
144 // we need a composite quote
145
146 std::vector<Handle<Quote>> quotes;
147
148 // collect the quotes on the path and check consistency of the settlement dates
149
150 for (Size i = 0; i < path.size() - 1; ++i) {
151 quotes.push_back(getQuote(path[i], path[i + 1]));
152 }
153
154 // build the composite quote
155
156 auto f = [](const std::vector<Real>& quotes) {
157 return std::accumulate(quotes.begin(), quotes.end(), 1.0, std::multiplies());
158 };
159 result = Handle<Quote>(QuantLib::ext::make_shared<CompositeVectorQuote<decltype(f)>>(quotes, f));
160 }
161
162 // add the result to the lookup cache and return it
163
164 quoteCache_[pair] = result;
165 return result;
166}
std::map< std::string, QuantLib::Handle< QuantLib::Quote > > quoteCache_
std::vector< std::string > getPath(const std::string &forCcy, const std::string &domCcy) const
QuantLib::Handle< QuantLib::Quote > getQuote(const std::string &pair) const
+ Here is the caller graph for this function:

◆ getIndex()

Handle< FxIndex > getIndex ( const std::string &  indexOrPair,
const Market market,
const std::string &  configuration 
) const

Get fx index, possibly via triangulation. The index name can be of the form FX-TAG-CCY1-CCY2 or also be just a currency pair CCY1CCY2. In the latter case, the fixing source is set to TAG = GENERIC. The fx index requires discount curves from a market. The assumption is that the market provides discount curves consistent with cross-currency discounting under the specified configuration. If the triangulation is not possible or required curves are not available an exception is thrown.

Definition at line 168 of file fxtriangulation.cpp.

169 {
170
171 // do we have a cached result?
172
173 if (auto it = indexCache_.find(std::make_pair(indexOrPair, configuration)); it != indexCache_.end()) {
174 return it->second;
175 }
176
177 // otherwise we need to construct the index
178
179 Handle<FxIndex> result;
180
181 std::string familyName;
182 std::string forCcy;
183 std::string domCcy;
184
185 if (isFxIndex(indexOrPair)) {
186 auto ind = parseFxIndex(indexOrPair);
187 familyName = ind->familyName();
188 forCcy = ind->sourceCurrency().code();
189 domCcy = ind->targetCurrency().code();
190 } else {
191 familyName = "GENERIC";
192 std::tie(forCcy, domCcy) = splitPair(indexOrPair);
193 }
194
195 // get the conventions of the result index
196
197 auto [fixingDays, fixingCalendar, bdc] = getFxIndexConventions(indexOrPair);
198
199 // get the discount curves for the result index
200
201 auto sourceYts = getMarketDiscountCurve(market, forCcy, configuration);
202 auto targetYts = getMarketDiscountCurve(market, domCcy, configuration);
203
204 // get the path from ccy1 to ccy2
205
206 auto path = getPath(forCcy, domCcy);
207
208 if (path.size() == 2) {
209
210 // we can use a direct or inverted quote, but do not need a composite
211
212 auto fxSpot = getQuote(path[0], path[1]);
213 result = Handle<FxIndex>(QuantLib::ext::make_shared<FxIndex>(familyName, fixingDays, parseCurrency(forCcy),
214 parseCurrency(domCcy), fixingCalendar, fxSpot, sourceYts,
215 targetYts));
216
217 } else {
218
219 // we need a composite quote
220
221 std::vector<Handle<Quote>> quotes;
222
223 // collect the quotes on the path and store them as FxRate quotes ("as of today" - quotes)
224
225 for (Size i = 0; i < path.size() - 1; ++i) {
226
227 auto q = getQuote(path[i], path[i + 1]);
228
229 // we store a quote "as of today" to account for possible spot lag differences
230
231 auto [fd, fc, bdc] = getFxIndexConventions(path[i] + path[i + 1]);
232 auto s_yts = getMarketDiscountCurve(market, path[i], configuration);
233 auto t_yts = getMarketDiscountCurve(market, path[i + 1], configuration);
234 quotes.push_back(Handle<Quote>(QuantLib::ext::make_shared<FxRateQuote>(q, s_yts, t_yts, fd, fc)));
235 }
236
237 // build the composite quote "as of today"
238
239 auto f = [](const std::vector<Real>& quotes) {
240 return std::accumulate(quotes.begin(), quotes.end(), 1.0, std::multiplies());
241 };
242 Handle<Quote> compQuote(QuantLib::ext::make_shared<CompositeVectorQuote<decltype(f)>>(quotes, f));
243
244 // build the spot quote
245
246 Handle<Quote> spotQuote(
247 QuantLib::ext::make_shared<FxSpotQuote>(compQuote, sourceYts, targetYts, fixingDays, fixingCalendar));
248
249 // build the idnex
250
251 result = Handle<FxIndex>(QuantLib::ext::make_shared<FxIndex>(familyName, fixingDays, parseCurrency(forCcy),
252 parseCurrency(domCcy), fixingCalendar, spotQuote,
253 sourceYts, targetYts));
254 }
255
256 // add the result to the lookup cache and return it
257
258 indexCache_[std::make_pair(indexOrPair, configuration)] = result;
259 return result;
260}
std::map< std::pair< std::string, std::string >, QuantLib::Handle< QuantExt::FxIndex > > indexCache_
QuantLib::ext::shared_ptr< FxIndex > parseFxIndex(const string &s, const Handle< Quote > &fxSpot, const Handle< YieldTermStructure > &sourceYts, const Handle< YieldTermStructure > &targetYts, const bool useConventions)
Convert std::string to QuantExt::FxIndex.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:290
bool isFxIndex(const std::string &indexName)
std::tuple< Natural, Calendar, BusinessDayConvention > getFxIndexConventions(const string &index)
Definition: marketdata.cpp:160
+ Here is the call graph for this function:

◆ getPath()

std::vector< std::string > getPath ( const std::string &  forCcy,
const std::string &  domCcy 
) const
private

Definition at line 262 of file fxtriangulation.cpp.

262 {
263
264 // see https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
265
266 Size sourceNode, targetNode;
267
268 if (auto it = ccyToNode_.find(forCcy); it != ccyToNode_.end()) {
269 sourceNode = it->second;
270 } else {
271 QL_FAIL("FXTriangulation: no conversion from '"
272 << forCcy << "' to '" << domCcy << "' possible, since '" << forCcy
273 << "' is not available as one of the currencies in any of the quotes (" << getAllQuotes() << ")");
274 }
275
276 if (auto it = ccyToNode_.find(domCcy); it != ccyToNode_.end()) {
277 targetNode = it->second;
278 } else {
279 QL_FAIL("FXTriangulation: no conversion from '"
280 << forCcy << "' to '" << domCcy << "' possible, since '" << domCcy
281 << "' is not available as one of the currencies in any of the quotes (" << getAllQuotes() << ")");
282 }
283
284 // previous node on the current shortest path
285 std::vector<Size> prev(nodeToCcy_.size(), Null<Size>());
286 // distance per node
287 std::vector<Size> dist(nodeToCcy_.size(), std::numeric_limits<Size>::max());
288 // visited flag
289 std::vector<bool> visited(nodeToCcy_.size(), false);
290
291 // init source
292 dist[sourceNode] = 0;
293
294 // main loop
295 Size noVisited = 0;
296 while (noVisited < nodeToCcy_.size()) {
297 Size u = Null<Size>(), min = std::numeric_limits<Size>::max();
298 for (Size i = 0; i < dist.size(); ++i) {
299 if (!visited[i] && dist[i] < min) {
300 u = i;
301 min = dist[i];
302 }
303 }
304 QL_REQUIRE(u != Null<Size>(), "FXTriangulation: internal error, no minimum found in dist array for '"
305 << forCcy << "' to '" << domCcy << "'. Quotes = " << getAllQuotes());
306 if (u == targetNode)
307 break;
308 visited[u] = true;
309 ++noVisited;
310 for (auto const& n : neighbours_[u]) {
311 if (visited[n])
312 continue;
313 Size alt = dist[u] + 1;
314 if (alt < dist[n]) {
315 dist[n] = alt;
316 prev[n] = u;
317 }
318 }
319 }
320
321 // did we find a path?
322 if (dist[targetNode] < std::numeric_limits<Size>::max()) {
323 std::vector<std::string> result;
324 Size u = targetNode;
325 while (u != sourceNode) {
326 result.insert(result.begin(), nodeToCcy_[u]);
327 u = prev[u];
328 QL_REQUIRE(u != Null<Size>(), "FXTriangulation: internal error u == null for '"
329 << forCcy << "' to '" << domCcy
330 << "'. Contact dev. Quotes = " << getAllQuotes() << ".");
331 }
332 result.insert(result.begin(), nodeToCcy_[sourceNode]);
333 TLOG("FXTriangulation: found path of length "
334 << result.size() - 1 << " from '" << forCcy << "' to '" << domCcy << "': "
335 << std::accumulate(
336 result.begin(), result.end(), std::string(),
337 [](const std::string& s1, const std::string& s2) { return s1.empty() ? s2 : s1 + "-" + s2; }));
338 return result;
339 }
340
341 QL_FAIL("FXTriangulation: no path from '" << forCcy << "' to '" << domCcy
342 << "' found. Quotes = " << getAllQuotes());
343}
std::string getAllQuotes() const
std::map< std::string, std::size_t > ccyToNode_
std::vector< std::set< std::size_t > > neighbours_
std::vector< std::string > nodeToCcy_
#define TLOG(text)
Logging Macro (Level = Data)
Definition: log.hpp:556
RandomVariable min(RandomVariable x, const RandomVariable &y)
+ Here is the call graph for this function:

◆ getQuote() [2/2]

Handle< Quote > getQuote ( const std::string &  forCcy,
const std::string &  domCcy 
) const
private

Definition at line 345 of file fxtriangulation.cpp.

345 {
346 if (auto it = quotes_.find(forCcy + domCcy); it != quotes_.end()) {
347 return it->second;
348 }
349 if (auto it = quotes_.find(domCcy + forCcy); it != quotes_.end()) {
350 auto f = [](Real x) { return 1.0 / x; };
351 return Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(f)>>(it->second, f));
352 }
353 QL_FAIL(
354 "FXTriangulation::getQuote(" << forCcy << domCcy
355 << ") - no such quote available. This is an internal error. Contact dev. Quotes = "
356 << getAllQuotes());
357}
std::map< std::string, QuantLib::Handle< QuantLib::Quote > > quotes_

◆ getAllQuotes()

std::string getAllQuotes ( ) const
private

Definition at line 359 of file fxtriangulation.cpp.

359 {
360 std::string result;
361 if (quotes_.size() > 0) {
362 for (auto const& d : quotes_) {
363 result += d.first + ",";
364 }
365 result.erase(std::next(result.end(), -1));
366 }
367 return result;
368}

Member Data Documentation

◆ quotes_

std::map<std::string, QuantLib::Handle<QuantLib::Quote> > quotes_
private

Definition at line 73 of file fxtriangulation.hpp.

◆ quoteCache_

std::map<std::string, QuantLib::Handle<QuantLib::Quote> > quoteCache_
mutableprivate

Definition at line 76 of file fxtriangulation.hpp.

◆ indexCache_

std::map<std::pair<std::string, std::string>, QuantLib::Handle<QuantExt::FxIndex> > indexCache_
mutableprivate

Definition at line 77 of file fxtriangulation.hpp.

◆ nodeToCcy_

std::vector<std::string> nodeToCcy_
private

Definition at line 80 of file fxtriangulation.hpp.

◆ ccyToNode_

std::map<std::string, std::size_t> ccyToNode_
private

Definition at line 81 of file fxtriangulation.hpp.

◆ neighbours_

std::vector<std::set<std::size_t> > neighbours_
private

Definition at line 82 of file fxtriangulation.hpp.