net.objectlab.kit.fxcalc.FxRateCalculatorBuilder Maven / Gradle / Ivy
package net.objectlab.kit.fxcalc;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Parameters for an immutable FxRateCalculator.
* The FX Calculator requires Base Rates to return rates, inverse rates or cross rates. There are 3 ways to import rates via the FxRateCalculatorBuilder.
- addRateSnapshot(FxRate rate): add the rate to an internal map per CurrencyPair, an immutable map will be given to the Calculator so the bases rates will NOT change.
- ratesSnapshot(Collection<FxRate> rates): add a collection of rates to an internal map per CurrencyPair, an immutable map will be given to the Calculator so the bases rates will NOT change.
- baseFxRateProvider(BaseFxRateProvider) You then control when the Base Rates change, the Calculator will call the required CurrencyPair you either every time or once (if cacheBaseRates is true).
*
* final FxRateCalculatorBuilder builder = new FxRateCalculatorBuilder() //
.addRateSnapshot(new FxRateImpl(CurrencyPair.of("EUR", "USD"), null, true, BigDecimalUtil.bd("1.6"), BigDecimalUtil.bd("1.61")))//
.addRateSnapshot(new FxRateImpl(CurrencyPair.of("GBP", "CHF"), null, true, BigDecimalUtil.bd("2.1702"), BigDecimalUtil.bd("2.1707")))//
.addRateSnapshot(new FxRateImpl(CurrencyPair.of("EUR", "GBP"), null, true, BigDecimalUtil.bd("0.7374"), BigDecimalUtil.bd("0.7379")))//
.orderedCurrenciesForCross(Lists.newArrayList("GBP", "USD")) // Use GBP as the first cross ccy, if that doesn't work use USD
.majorCurrencyRanking(StandardMajorCurrencyRanking.getdefault())
.precisionForFxRate(6)
.precisionForInverseFxRate(12)
.cacheResults(true) // only calculate a cross Fx once, cache for subsequent requests
.cacheBaseRates(true); // if a BaseFxRateRateProvider is used, cache the rates instead of calling again for same currency pair
*
* @author Benoit Xhenseval
*/
public class FxRateCalculatorBuilder {
/**
* Snapshot of FxRate, typically they are the Base FX Rates (e.g. vs USD)
*/
private Map ratesSnapshot = new HashMap<>();
/**
* If it is important for you to get the latest rates every time, you can provide a rate provider using this interface.
*/
private BaseFxRateProvider baseFxRateProvider;
/**
* The interface to determine which currency is major, defaults to StandardMajorCurrencyRanking.
*/
private MajorCurrencyRanking majorCurrencyRanking = StandardMajorCurrencyRanking.getDefault();
/**
* If the rate required from the calculator is not immediately available, use a cross currency to calculate it; this
* gives you the opportunity to select which currencies to use in which order. Defaulted to USD and then EUR.
*/
private List orderedCurrenciesForCross = new ArrayList<>();
/**
* Number of decimal places to use on a rate, defaulted to 6.
*/
private int precisionForFxRate = 6;
/**
* Number of decimal places to use for a calculation involving an inversed rate, defaulted to 12
*/
private int precisionForInverseFxRate = 12;
/**
* Once a new rate has been calculated, should it be cached for any further request, defaulted to true.
*/
private boolean cacheResults = true;
/**
* If using the baseFxRateProvider, should the rate be cached in the calculator, defaulted to true.
*/
private boolean cacheBaseRates = true;
public FxRateCalculatorBuilder() {
orderedCurrenciesForCross.add("USD");
orderedCurrenciesForCross.add("EUR");
}
/**
* Check if the builder is valid i.e.
* * precisions greater than 1
* * ratesSnapshot not empty or a BaseFxRateProvider was provided
* @throws IllegalArgumentException if the validation fails.
*/
public void checkValid() {
final StringBuilder b = new StringBuilder();
if (precisionForFxRate < 2) {
b.append("Precision for FX should be >=2");
}
if (precisionForInverseFxRate < 2) {
if (b.length() > 0) {
b.append(",");
}
b.append("Precision for 1/FX should be >=2");
}
if (ratesSnapshot.isEmpty() && baseFxRateProvider == null) {
if (b.length() > 0) {
b.append(",");
}
b.append("You must provide Base Rates Snapshots OR a BaseFxRateProvider");
}
if (b.length() > 0) {
throw new IllegalArgumentException(b.toString());
}
}
/**
* If it is important for you to get the latest rates every time, you can provide a rate provider using this interface.
*/
public FxRateCalculatorBuilder baseFxRateProvider(final BaseFxRateProvider baseFxRateProvider) {
this.baseFxRateProvider = baseFxRateProvider;
return this;
}
public MajorCurrencyRanking getMajorCurrencyRanking() {
return majorCurrencyRanking;
}
public List getOrderedCurrenciesForCross() {
return Collections.unmodifiableList(orderedCurrenciesForCross);
}
public int getPrecisionForFxRate() {
return precisionForFxRate;
}
public int getPrecisionForInverseFxRate() {
return precisionForInverseFxRate;
}
public boolean isCacheResults() {
return cacheResults;
}
public boolean isCacheBaseRates() {
return cacheBaseRates;
}
public BaseFxRateProvider getBaseFxRateProvider() {
return baseFxRateProvider;
}
/**
* Once a new rate has been calculated, should it be cached for any further request?
*/
public FxRateCalculatorBuilder cacheResults(final boolean cacheResults) {
this.cacheResults = cacheResults;
return this;
}
/**
* If using the baseFxRateProvider, should the rate be cached in the calculator, defaulted to true.
*/
public FxRateCalculatorBuilder cacheBaseRates(final boolean cacheBaseRates) {
this.cacheBaseRates = cacheBaseRates;
return this;
}
/**
* Number of decimal places to use on a rate, defaulted to 6.
*/
public FxRateCalculatorBuilder precisionForFxRate(final int precisionForFxRate) {
this.precisionForFxRate = precisionForFxRate;
return this;
}
/**
* Number of decimal places to use for a calculation involving an inversed rate, defaulted to 12
*/
public FxRateCalculatorBuilder precisionForInverseFxRate(final int precisionForInverseFxRate) {
this.precisionForInverseFxRate = precisionForInverseFxRate;
return this;
}
/**
* If the rate required from the calculator is not immediately available, use a cross currency to calculate it; this
* gives you the opportunity to select which currencies to use in which order. Defaulted to USD and then EUR.
*/
public FxRateCalculatorBuilder orderedCurrenciesForCross(final List orderedCurrenciesForCross) {
if (orderedCurrenciesForCross != null) {
this.orderedCurrenciesForCross = orderedCurrenciesForCross;
}
return this;
}
/**
* The interface to determine which currency is major, defaults to StandardMajorCurrencyRanking.
*/
public FxRateCalculatorBuilder majorCurrencyRanking(final MajorCurrencyRanking majorCurrencyRanking) {
if (majorCurrencyRanking != null) {
this.majorCurrencyRanking = majorCurrencyRanking;
}
return this;
}
/**
* Snapshot of FxRate, typically they are the Base FX Rates (e.g. vs USD)
*/
public FxRateCalculatorBuilder ratesSnapshot(final Collection rates) {
if (rates != null) {
this.ratesSnapshot.clear();
this.ratesSnapshot = rates.stream().collect(Collectors.toMap(t -> t.getCurrencyPair(), t -> t));
}
return this;
}
/**
* Snapshot of FxRate, typically they are the Base FX Rates (e.g. vs USD)
*/
public FxRateCalculatorBuilder addRateSnapshot(final FxRate rate) {
if (rate != null) {
this.ratesSnapshot.put(rate.getCurrencyPair(), rate);
}
return this;
}
public Map getRatesSnapshot() {
return ratesSnapshot;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy