QuantLib: Automatic Conversion with the Exchange Rate Manager

In earlier posts I have talked about the Money class and ExchangeRates. Exchange rates allow you to exchange money between two currencies. They are also involved in calculations involving money of different currencies. Consider the following code.

Money::conversionType = Money::AutomatedConversion;
Money eur(100, EURCurrency());
Money dem(150, DEMCurrency());
std::cout << eur << " + " << dem << " = " << eur+dem << std::endl;

This will run without problems and produce the following, correct, output.

EUR 100.00 + 150.00 DM = EUR 176.69

The code works even though we have not specified any exchange rate between the two currencies. The mechanism by which this is achieved is the ExchangeRateManager. The ExchangeRateManager will be invoked for currency conversion, if Money::conversionType is set to Money::AutomatedConversion.

ExchangeRateManager is a Singleton class which stores all the exchange rates together with date intervals, when those exchange rates are valid. Being a singleton, you cannot create ExchangeRateManager objects directly. You can only access the single existing ExchangeRateManager by the static method

ExchangeRateManager &ExchangeRateManager::instance();

The public interface of the ExchangeRateManager defines only three operations.

void add(const ExchangeRate&,
         const Date& startDate = Date::minDate(),
         const Date& endDate = Date::maxDate());

ExchangeRate lookup(const Currency& source,
                    const Currency& target,
                    Date date = Date(),
                    ExchangeRate::Type type =
                                       ExchangeRate::Derived) const;
void clear();

The function add adds an exchange rate and allows a date interval to be set as well.

Money::conversionType = Money::AutomatedConversion;
Currency usd = USDCurrency();
Currency gbp = GBPCurrency();
Currency eur = EURCurrency();

ExchangeRate usdXgbp(usd, gbp, 0.6176);
ExchangeRate usdXeur(usd, eur, 0.7671);

      Date(25, August, 2012), Date(3, December, 2012));

Money m_eur = 100*eur;
Money m_gbp = 150*gbp;
std::cout << m_eur << " + " << m_gbp << " = " 
          << m_eur+m_gbp << std::endl;

This piece of code will add two exchange rates, one between USD and GBP and another between USD and EUR. The exchange rate between USD and GBP is valid for all times, whereas the exchange rate between USD and EUR is only valid from 25 Aug 2012 and 3rd Dec 2012. The output of this program, if run before 4th Dec 2012 is

EUR 100.00 + £ 150.00 = EUR 286.31

If run after 3rd Dec 2012 the program will fail with a message such as

terminate called after throwing an instance of 'QuantLib::Error'
exchangeratemanager.cpp:191: In function `QuantLib::ExchangeRate 
QuantLib::ExchangeRateManager::smartLookup(const QuantLib::Currency&,
const QuantLib::Currency&, const QuantLib::Date&, std::list) const':
no conversion available from GBP to EUR for January 14th, 2013

The exchange rate manager will always add a few known exchange rates, which do not have to be specified by the user. These include the fixed exchange rates of the currencies taking part in the Euro, which are valid indefinately, starting from 1st January 1999.

The lookup method provided by the ExchangeRateManager implements the functionality of looking up an exchange rate. lookup tries to find an exchange rate between the two currencies that is valid at the specified date. In general that exchange rate does not have to be one of the exchange rate that was stored in the ExchangeRateManager. The lookup method will try to create an exchange rate between the two currencies by chaining exchange rates together. The algorithm to find such a chained exchange rate does this as follows.

  •  If the source currency defines a triangulation currency and , then first a direct conversion from the source to the triangulation currency must be found. Otherwise the algorithm fails. The algorithm then continues to look for a conversion from the triangulation currency to the target.
  •  Likewise, if the target currency defines a triangulation currency, then a direct conversion from the target to the triangulation currency must be found. Otherwise the algorithm fails. The algorithm then continues to look for a conversion from the source to the triangulation currency.
  •  If there is an exchange rate for the currency pair already stored in the exchange rate manager, then that exchange rate is used.
  •  Otherwise the algorithm attempts to find the shortest sequence of conversions between the currency pair using a graph searching algorithm.

This algorithm will find an exchange rate if there is one that satisfies the conditions imposed by the currencies.

In order to circumvent the algorithm and look only for a direct conversion between the source and the target, a fourth parameter can be passed to the lookup function. If the type parameter is set to ExchangeRate::Direct then only a conversion stored directly in the exchange rate manager will be returned. This ignores any triangulation currencies specified by the Currency. If no direct conversion exists, the method will fail.

Finally, the clear method will clear all exchange rates added to the manager. This will not clear the set of known exchange rates, such as the Euro currencies conversion.