public void testDirect() { Currency EUR = new EURCurrency(), USD = new USDCurrency(); ExchangeRate eur_usd = new ExchangeRate(EUR, USD, 1.2042); Money m1 = 50000.0 * EUR; Money m2 = 100000.0 * USD; Money.conversionType = Money.ConversionType.NoConversion; Money calculated = eur_usd.exchange(m1); Money expected = new Money(m1.value*eur_usd.rate, USD); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } calculated = eur_usd.exchange(m2); expected = new Money(m2.value/eur_usd.rate, EUR); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } }
public void testBaseCurrency() { Currency EUR = new EURCurrency(), GBP = new GBPCurrency(), USD = new USDCurrency(); Money m1 = 50000.0 * GBP; Money m2 = 100000.0 * EUR; Money m3 = 500000.0 * USD; ExchangeRateManager.Instance.clear(); ExchangeRate eur_usd = new ExchangeRate(EUR, USD, 1.2042); ExchangeRate eur_gbp = new ExchangeRate(EUR, GBP, 0.6612); ExchangeRateManager.Instance.add(eur_usd); ExchangeRateManager.Instance.add(eur_gbp); Money.conversionType = Money.ConversionType.BaseCurrencyConversion; Money.baseCurrency = EUR; Money calculated = m1 * 3.0 + 2.5 * m2 - m3 / 5.0; Rounding round = Money.baseCurrency.rounding; double x = round.Round(m1.value * 3.0 / eur_gbp.rate) + 2.5 * m2.value - round.Round(m3.value / (5.0 * eur_usd.rate)); Money expected = new Money(x, EUR); Money.conversionType = Money.ConversionType.NoConversion; if (calculated != expected) { Assert.Fail("Wrong result: expected: " + expected + "calculated: " + calculated); } }
public void testDerived() { Currency EUR = new EURCurrency(), USD = new USDCurrency(), GBP = new GBPCurrency(); ExchangeRate eur_usd = new ExchangeRate(EUR, USD, 1.2042); ExchangeRate eur_gbp = new ExchangeRate(EUR, GBP, 0.6612); ExchangeRate derived = ExchangeRate.chain(eur_usd, eur_gbp); Money m1 = 50000.0 * GBP; Money m2 = 100000.0 * USD; Money.conversionType = Money.ConversionType.NoConversion; Money calculated = derived.exchange(m1); Money expected = new Money(m1.value*eur_usd.rate/eur_gbp.rate, USD); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } calculated = derived.exchange(m2); expected = new Money(m2.value*eur_gbp.rate/eur_usd.rate, GBP); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } }
/// <summary> /// Add an exchange rate. /// </summary> /// <param name="rate"></param> /// <param name="startDate"></param> /// <param name="endDate"></param> /// <remarks> /// The given rate is valid between the given dates. /// If two rates are given between the same currencies /// and with overlapping date ranges, the latest one /// added takes precedence during lookup. /// </remarks> private void add(ExchangeRate rate, Date startDate, Date endDate) { int k = hash(rate.source, rate.target); if (data_.ContainsKey(k)) { data_[k].Insert(0, new Entry(rate, startDate, endDate)); } else { data_[k] = new List <Entry>(); data_[k].Add(new Entry(rate, startDate, endDate)); } }
private ExchangeRate smartLookup(Currency source, Currency target, Date date, List <int> forbidden) { // direct exchange rates are preferred. ExchangeRate direct = fetch(source, target, date); if (direct.HasValue) { return(direct); } // if none is found, turn to smart lookup. The source currency // is forbidden to subsequent lookups in order to avoid cycles. forbidden.Add(source.numericCode); foreach (KeyValuePair <int, List <Entry> > i in data_) { // we look for exchange-rate data which involve our source // currency... if (hashes(i.Key, source) && (i.Value.Count != 0)) { // ...whose other currency is not forbidden... Entry e = i.Value[0];// front(); Currency other = source == e.rate.source ? e.rate.target : e.rate.source; if (!forbidden.Contains(other.numericCode)) { // ...and which carries information for the requested date. ExchangeRate head = fetch(source, other, date); if (((Nullable <double>)head.rate).HasValue) { // if we can get to the target from here... try { ExchangeRate tail = smartLookup(other, target, date, forbidden); // ..we're done. return(ExchangeRate.chain(head, tail)); } catch (Exception) { // otherwise, we just discard this rate. ; } } } } } // if the loop completed, we have no way to return the requested rate. throw new Exception("no conversion available from " + source.code + " to " + target.code + " for " + date); }
/// <summary> /// Lookup the exchange rate between two currencies at a given /// date. If the given type is Direct, only direct exchange /// rates will be returned if available; if Derived, direct /// rates are still preferred but derived rates are allowed. /// </summary> /// <remarks> /// if two or more exchange-rate chains are possible /// which allow to specify a requested rate, it is /// unspecified which one is returned. /// </remarks> /// <param name="source"></param> /// <param name="target"></param> /// <param name="date"></param> /// <param name="type"></param> /// <returns></returns> public ExchangeRate lookup(Currency source, Currency target, Date date, ExchangeRate.Type type) { if (source == target) { return(new ExchangeRate(source, target, 1.0)); } if (date == new Date()) { date = Settings.evaluationDate(); } if (type == ExchangeRate.Type.Direct) { return(directLookup(source, target, date)); } else if (!source.triangulationCurrency.empty()) { Currency link = source.triangulationCurrency; if (link == target) { return(directLookup(source, link, date)); } else { return(ExchangeRate.chain(directLookup(source, link, date), lookup(link, target, date))); } } else if (!target.triangulationCurrency.empty()) { Currency link = target.triangulationCurrency; if (source == link) { return(directLookup(link, target, date)); } else { return(ExchangeRate.chain(lookup(source, link, date), directLookup(link, target, date))); } } else { return(smartLookup(source, target, date)); } }
/// <summary> /// chain two exchange rates /// </summary> /// <param name="r1"></param> /// <param name="r2"></param> /// <returns></returns> public static ExchangeRate chain(ExchangeRate r1, ExchangeRate r2) { ExchangeRate result = new ExchangeRate(); result.type_ = Type.Derived; result.rateChain_ = new KeyValuePair <ExchangeRate, ExchangeRate>(r1, r2); if (r1.source_ == r2.source_) { result.source_ = r1.target_; result.target_ = r2.target_; result.rate_ = r2.rate_ / r1.rate_; } else if (r1.source_ == r2.target_) { result.source_ = r1.target_; result.target_ = r2.source_; result.rate_ = 1.0 / (r1.rate_ * r2.rate_); } else if (r1.target_ == r2.source_) { result.source_ = r1.source_; result.target_ = r2.target_; result.rate_ = r1.rate_ * r2.rate_; } else if (r1.target_ == r2.target_) { result.source_ = r1.source_; result.target_ = r2.source_; result.rate_ = r1.rate_ / r2.rate_; } else { Utils.QL_FAIL("exchange rates not chainable"); } return(result); }
public void testTriangulatedLookup() { ExchangeRateManager rateManager = ExchangeRateManager.Instance; rateManager.clear(); Currency EUR = new EURCurrency(), USD = new USDCurrency(), ITL = new ITLCurrency(); ExchangeRate eur_usd1 = new ExchangeRate(EUR, USD, 1.1983); ExchangeRate eur_usd2 = new ExchangeRate(EUR, USD, 1.2042); rateManager.add(eur_usd1, new Date(4,Month.August,2004)); rateManager.add(eur_usd2, new Date(5,Month.August,2004)); Money m1 = 50000000.0 * ITL; Money m2 = 100000.0 * USD; Money.conversionType = Money.ConversionType.NoConversion; ExchangeRate itl_usd = rateManager.lookup(ITL, USD,new Date(4,Month.August,2004)); Money calculated = itl_usd.exchange(m1); Money expected = new Money(m1.value*eur_usd1.rate/1936.27, USD); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } itl_usd = rateManager.lookup(ITL, USD,new Date(5,Month.August,2004)); calculated = itl_usd.exchange(m1); expected = new Money(m1.value*eur_usd2.rate/1936.27, USD); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } ExchangeRate usd_itl = rateManager.lookup(USD, ITL, new Date(4, Month.August, 2004)); calculated = usd_itl.exchange(m2); expected = new Money(m2.value*1936.27/eur_usd1.rate, ITL); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } usd_itl = rateManager.lookup(USD, ITL, new Date(5, Month.August, 2004)); calculated = usd_itl.exchange(m2); expected = new Money(m2.value*1936.27/eur_usd2.rate, ITL); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } }
public void testSmartLookup() { Currency EUR = new EURCurrency(), USD = new USDCurrency(), GBP = new GBPCurrency(), CHF = new CHFCurrency(), SEK = new SEKCurrency(), JPY = new JPYCurrency(); ExchangeRateManager rateManager = ExchangeRateManager.Instance; rateManager.clear(); ExchangeRate eur_usd1 = new ExchangeRate(EUR, USD, 1.1983); ExchangeRate eur_usd2 = new ExchangeRate(USD, EUR, 1.0/1.2042); rateManager.add(eur_usd1, new Date(4,Month.August,2004)); rateManager.add(eur_usd2, new Date(5,Month.August,2004)); ExchangeRate eur_gbp1 = new ExchangeRate(GBP, EUR, 1.0 / 0.6596); ExchangeRate eur_gbp2 = new ExchangeRate(EUR, GBP, 0.6612); rateManager.add(eur_gbp1, new Date(4,Month.August,2004)); rateManager.add(eur_gbp2, new Date(5,Month.August,2004)); ExchangeRate usd_chf1 = new ExchangeRate(USD, CHF, 1.2847); ExchangeRate usd_chf2 = new ExchangeRate(CHF, USD, 1.0 / 1.2774); rateManager.add(usd_chf1, new Date(4,Month.August,2004)); rateManager.add(usd_chf2, new Date(5,Month.August,2004)); ExchangeRate chf_sek1 = new ExchangeRate(SEK, CHF, 0.1674); ExchangeRate chf_sek2 = new ExchangeRate(CHF, SEK, 1.0 / 0.1677); rateManager.add(chf_sek1, new Date(4,Month.August,2004)); rateManager.add(chf_sek2, new Date(5,Month.August,2004)); ExchangeRate jpy_sek1 = new ExchangeRate(SEK, JPY, 14.5450); ExchangeRate jpy_sek2 = new ExchangeRate(JPY, SEK, 1.0 / 14.6110); rateManager.add(jpy_sek1, new Date(4,Month.August,2004)); rateManager.add(jpy_sek2, new Date(5,Month.August,2004)); Money m1 = 100000.0 * USD; Money m2 = 100000.0 * EUR; Money m3 = 100000.0 * GBP; Money m4 = 100000.0 * CHF; Money m5 = 100000.0 * SEK; Money m6 = 100000.0 * JPY; Money.conversionType = Money.ConversionType.NoConversion; // two-rate chain ExchangeRate usd_sek = rateManager.lookup(USD, SEK, new Date(4,Month.August,2004)); Money calculated = usd_sek.exchange(m1); Money expected = new Money(m1.value*usd_chf1.rate/chf_sek1.rate, SEK); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } usd_sek = rateManager.lookup(SEK, USD, new Date(5,Month.August,2004)); calculated = usd_sek.exchange(m5); expected = new Money(m5.value*usd_chf2.rate/chf_sek2.rate, USD); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } // three-rate chain ExchangeRate eur_sek = rateManager.lookup(EUR, SEK,new Date(4,Month.August,2004)); calculated = eur_sek.exchange(m2); expected = new Money(m2.value*eur_usd1.rate*usd_chf1.rate/chf_sek1.rate, SEK); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } eur_sek = rateManager.lookup(SEK, EUR, new Date(5,Month.August,2004)); calculated = eur_sek.exchange(m5); expected = new Money(m5.value*eur_usd2.rate*usd_chf2.rate/chf_sek2.rate, EUR); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } // four-rate chain ExchangeRate eur_jpy = rateManager.lookup(EUR, JPY,new Date(4,Month.August,2004)); calculated = eur_jpy.exchange(m2); expected = new Money(m2.value*eur_usd1.rate*usd_chf1.rate*jpy_sek1.rate/chf_sek1.rate, JPY); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } eur_jpy = rateManager.lookup(JPY, EUR, new Date(5,Month.August,2004)); calculated = eur_jpy.exchange(m6); expected = new Money(m6.value*jpy_sek2.rate*eur_usd2.rate*usd_chf2.rate/chf_sek2.rate, EUR); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } // five-rate chain ExchangeRate gbp_jpy = rateManager.lookup(GBP, JPY,new Date(4,Month.August,2004)); calculated = gbp_jpy.exchange(m3); expected = new Money(m3.value*eur_gbp1.rate*eur_usd1.rate*usd_chf1.rate*jpy_sek1.rate/chf_sek1.rate, JPY); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } gbp_jpy = rateManager.lookup(JPY, GBP, new Date(5,Month.August,2004)); calculated = gbp_jpy.exchange(m6); expected = new Money(m6.value*jpy_sek2.rate*eur_usd2.rate*usd_chf2.rate*eur_gbp2.rate/chf_sek2.rate, GBP); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } }
/// <summary> /// Lookup the exchange rate between two currencies at a given /// date. If the given type is Direct, only direct exchange /// rates will be returned if available; if Derived, direct /// rates are still preferred but derived rates are allowed. /// </summary> /// <remarks> /// if two or more exchange-rate chains are possible /// which allow to specify a requested rate, it is /// unspecified which one is returned. /// </remarks> /// <param name="source"></param> /// <param name="target"></param> /// <param name="date"></param> /// <param name="type"></param> /// <returns></returns> public ExchangeRate lookup(Currency source, Currency target, Date date, ExchangeRate.Type type) { if (source == target) return new ExchangeRate(source, target, 1.0); if (date == new Date()) date = Settings.evaluationDate(); if (type == ExchangeRate.Type.Direct) { return directLookup(source, target, date); } else if (!source.triangulationCurrency.empty()) { Currency link = source.triangulationCurrency; if (link == target) return directLookup(source, link, date); else return ExchangeRate.chain(directLookup(source, link, date), lookup(link, target, date)); } else if (!target.triangulationCurrency.empty()) { Currency link = target.triangulationCurrency; if (source == link) return directLookup(link, target, date); else return ExchangeRate.chain(lookup(source, link, date), directLookup(link, target, date)); } else { return smartLookup(source, target, date); } }
public void add(ExchangeRate rate) { add(rate, Date.minDate(), Date.maxDate()); }
public void add(ExchangeRate rate, Date startDate) { add(rate, startDate, Date.maxDate()); }
public Entry(ExchangeRate r, Date s, Date e) { rate = r; startDate = s; endDate = e; }
/// <summary> /// chain two exchange rates /// </summary> /// <param name="r1"></param> /// <param name="r2"></param> /// <returns></returns> public static ExchangeRate chain(ExchangeRate r1, ExchangeRate r2) { ExchangeRate result = new ExchangeRate(); result.type_ = Type.Derived; result.rateChain_ = new KeyValuePair<ExchangeRate,ExchangeRate>(r1,r2); if (r1.source_ == r2.source_) { result.source_ = r1.target_; result.target_ = r2.target_; result.rate_ = r2.rate_ / r1.rate_; } else if (r1.source_ == r2.target_) { result.source_ = r1.target_; result.target_ = r2.source_; result.rate_ = 1.0 / (r1.rate_ * r2.rate_); } else if (r1.target_ == r2.source_) { result.source_ = r1.source_; result.target_ = r2.target_; result.rate_ = r1.rate_ * r2.rate_; } else if (r1.target_ == r2.target_) { result.source_ = r1.source_; result.target_ = r2.source_; result.rate_ = r1.rate_ / r2.rate_; } else { throw new Exception ("exchange rates not chainable"); } return result; }
public void testDirectLookup() { ExchangeRateManager rateManager = ExchangeRateManager.Instance; rateManager.clear(); Currency EUR = new EURCurrency(), USD = new USDCurrency(); ExchangeRate eur_usd1 = new ExchangeRate(EUR, USD, 1.1983); ExchangeRate eur_usd2 = new ExchangeRate(USD, EUR, 1.0/1.2042); rateManager.add(eur_usd1, new Date(4,Month.August,2004)); rateManager.add(eur_usd2, new Date(5,Month.August,2004)); Money m1 = 50000.0 * EUR; Money m2 = 100000.0 * USD; Money.conversionType = Money.ConversionType.NoConversion; ExchangeRate eur_usd = rateManager.lookup(EUR, USD,new Date(4,Month.August,2004),ExchangeRate.Type.Direct); Money calculated = eur_usd.exchange(m1); Money expected = new Money(m1.value*eur_usd1.rate, USD); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } eur_usd = rateManager.lookup(EUR, USD,new Date(5,Month.August,2004),ExchangeRate.Type.Direct); calculated = eur_usd.exchange(m1); expected = new Money(m1.value/eur_usd2.rate, USD); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } ExchangeRate usd_eur = rateManager.lookup(USD, EUR,new Date(4,Month.August,2004),ExchangeRate.Type.Direct); calculated = usd_eur.exchange(m2); expected = new Money(m2.value/eur_usd1.rate, EUR); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } usd_eur = rateManager.lookup(USD, EUR,new Date(5,Month.August,2004),ExchangeRate.Type.Direct); calculated = usd_eur.exchange(m2); expected = new Money(m2.value*eur_usd2.rate, EUR); if (!Utils.close(calculated, expected)) { Assert.Fail("Wrong result: expected: " + expected + " calculated: " + calculated); } }
/// <summary> /// Add an exchange rate. /// </summary> /// <param name="rate"></param> /// <param name="startDate"></param> /// <param name="endDate"></param> /// <remarks> /// The given rate is valid between the given dates. /// If two rates are given between the same currencies /// and with overlapping date ranges, the latest one /// added takes precedence during lookup. /// </remarks> private void add(ExchangeRate rate, Date startDate, Date endDate) { int k = hash(rate.source, rate.target); if (data_.ContainsKey(k)) { data_[k].Insert(0,new Entry(rate, startDate, endDate)); } else { data_[k] = new List<Entry>() ; data_[k].Add(new Entry(rate, startDate, endDate)); } }