/** * Returns the FX rate for a scenario. * * @param scenarioIndex the index of the scenario * @return the FX rate for the specified scenario * @throws IndexOutOfBoundsException if the index is invalid */ @Override public FxRate get(int scenarioIndex) { return FxRate.of(pair, rates.get(scenarioIndex)); }
public void test_crossRate() { FxRate gbpUsd = FxRate.of(GBP, USD, 5d / 4d); FxRate usdGbp = FxRate.of(USD, GBP, 4d / 5d); FxRate eurUsd = FxRate.of(EUR, USD, 8d / 7d); FxRate usdEur = FxRate.of(USD, EUR, 7d / 8d); FxRate eurGbp = FxRate.of(EUR, GBP, (8d / 7d) * (4d / 5d)); FxRate gbpGbp = FxRate.of(GBP, GBP, 1d); FxRate usdUsd = FxRate.of(USD, USD, 1d); assertEquals(eurUsd.crossRate(usdGbp), eurGbp); assertEquals(eurUsd.crossRate(gbpUsd), eurGbp); assertEquals(usdEur.crossRate(usdGbp), eurGbp); assertEquals(usdEur.crossRate(gbpUsd), eurGbp); assertEquals(gbpUsd.crossRate(usdEur), eurGbp); assertEquals(gbpUsd.crossRate(eurUsd), eurGbp); assertEquals(usdGbp.crossRate(usdEur), eurGbp); assertEquals(usdGbp.crossRate(eurUsd), eurGbp); assertThrowsIllegalArg(() -> gbpGbp.crossRate(gbpUsd)); // identity assertThrowsIllegalArg(() -> usdUsd.crossRate(gbpUsd)); // identity assertThrowsIllegalArg(() -> gbpUsd.crossRate(gbpUsd)); // same currencies assertThrowsIllegalArg(() -> gbpUsd.crossRate(usdGbp)); // same currencies assertThrowsIllegalArg(() -> gbpUsd.crossRate(FxRate.of(EUR, CAD, 12d / 5d))); // no common currency }
/** * Creates an {@code FxSwap} using decimal forward points. * <p> * The FX rate at the near date is specified as {@code nearRate}. * The FX rate at the far date is equal to {@code nearRate + forwardPoints}. * Thus "FX forward spread" might be a better name for the concept. * <p> * The two currencies are specified by the near FX rate. * The amount must be specified using one of the currencies of the near FX rate. * The near date must be before the far date. * Conventions will be used to determine the base and counter currency. * * @param amount the amount being exchanged, positive if being received in the near leg, negative if being paid * @param nearRate the near FX rate * @param decimalForwardPoints the decimal forward points, where the far FX rate is {@code (nearRate + forwardPoints)} * @param nearDate the near value date * @param farDate the far value date * @return the FX swap * @throws IllegalArgumentException if the FX rate and amount do not have a currency in common */ public static FxSwap ofForwardPoints( CurrencyAmount amount, FxRate nearRate, double decimalForwardPoints, LocalDate nearDate, LocalDate farDate) { FxRate farRate = FxRate.of(nearRate.getPair(), nearRate.fxRate(nearRate.getPair()) + decimalForwardPoints); return of(amount, nearRate, nearDate, farRate, farDate); }
@Override public SwapTrade trade(double quantity, MarketData marketData, ReferenceData refData) { double marketQuote = marketData.getValue(spreadId) + additionalSpread; FxRate fxRate = marketData.getValue(fxRateId); double rate = fxRate.fxRate(template.getCurrencyPair()); BuySell buySell = quantity > 0 ? BuySell.SELL : BuySell.BUY; return template.createTrade(marketData.getValuationDate(), buySell, Math.abs(quantity), rate, marketQuote, refData); }
private static FxRate computeCross(FxRate fx1, FxRate fx2, CurrencyPair crossPairAC) { // aim is to convert AAA/BBB and BBB/CCC to AAA/CCC Currency currA = crossPairAC.getBase(); Currency currC = crossPairAC.getCounter(); // given the conventional cross rate pair, order the two rates to match boolean crossBaseCurrencyInFx1 = fx1.pair.contains(currA); FxRate fxABorBA = crossBaseCurrencyInFx1 ? fx1 : fx2; FxRate fxBCorCB = crossBaseCurrencyInFx1 ? fx2 : fx1; // extract the rates, taking the inverse if the pair is in the inverse order double rateAB = fxABorBA.getPair().getBase().equals(currA) ? fxABorBA.rate : 1d / fxABorBA.rate; double rateBC = fxBCorCB.getPair().getCounter().equals(currC) ? fxBCorCB.rate : 1d / fxBCorCB.rate; return FxRate.of(crossPairAC, rateAB * rateBC); }
@Override protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { switch (propertyName.hashCode()) { case 3433178: // pair return ((FxRate) bean).getPair(); case 3493088: // rate return ((FxRate) bean).getRate(); } return super.propertyGet(bean, propertyName, quiet); }
return rate.get().fxRate(baseCurrency, counterCurrency); Optional<FxRate> rateBase2 = marketData.findValue(FxRateId.of(triangulationCurrency, counterCurrency, fxRatesSource)); if (rateBase1.isPresent() && rateBase2.isPresent()) { return rateBase1.get().crossRate(rateBase2.get()).fxRate(baseCurrency, counterCurrency); Optional<FxRate> rateBase2 = marketData.findValue(FxRateId.of(triangularBaseCcy, counterCurrency, fxRatesSource)); if (rateBase1.isPresent() && rateBase2.isPresent()) { return rateBase1.get().crossRate(rateBase2.get()).fxRate(baseCurrency, counterCurrency); Optional<FxRate> rateCounter2 = marketData.findValue(FxRateId.of(triangularCounterCcy, counterCurrency, fxRatesSource)); if (rateCounter1.isPresent() && rateCounter2.isPresent()) { return rateCounter1.get().crossRate(rateCounter2.get()).fxRate(baseCurrency, counterCurrency); marketData.findValue(FxRateId.of(triangularBaseCcy, triangularCounterCcy, fxRatesSource)); if (rateTriangular2.isPresent()) { return rateBase1.get().crossRate(rateTriangular2.get()).crossRate(rateCounter2.get()) .fxRate(baseCurrency, counterCurrency);
@Override public FxSwapTrade trade(double quantity, MarketData marketData, ReferenceData refData) { FxRate fxRate = marketData.getValue(fxRateId); double rate = fxRate.fxRate(template.getCurrencyPair()); double fxPts = marketData.getValue(farForwardPointsId); BuySell buySell = quantity > 0 ? BuySell.BUY : BuySell.SELL; return template.createTrade(marketData.getValuationDate(), buySell, Math.abs(quantity), rate, fxPts, refData); }
public void test_fxRate_forPair() { FxRate test = FxRate.of(GBP, USD, 1.25d); assertEquals(test.fxRate(GBP, USD), 1.25d); assertEquals(test.fxRate(USD, GBP), 1d / 1.25d); assertEquals(test.fxRate(GBP, GBP), 1d); assertEquals(test.fxRate(USD, USD), 1d); assertEquals(test.fxRate(AUD, AUD), 1d); assertThrowsIllegalArg(() -> test.fxRate(AUD, GBP)); assertThrowsIllegalArg(() -> test.fxRate(GBP, AUD)); assertThrowsIllegalArg(() -> test.fxRate(AUD, USD)); assertThrowsIllegalArg(() -> test.fxRate(USD, AUD)); assertThrowsIllegalArg(() -> test.fxRate(EUR, AUD)); }
/** * Gets the non-deliverable currency. * <p> * Returns the currency that is not the settlement currency. * * @return the currency that is not to be settled */ public Currency getNonDeliverableCurrency() { Currency base = agreedFxRate.getPair().getBase(); return base.equals(getSettlementCurrency()) ? agreedFxRate.getPair().getCounter() : base; }
/** * Returns an FX rate object representing the market convention rate between the two currencies. * <p> * If the currency pair is the market convention pair, this method returns {@code this}, otherwise * it returns an {@code FxRate} with the inverse currency pair and reciprocal rate. * * @return an FX rate object representing the market convention rate between the two currencies */ public FxRate toConventional() { return pair.isConventional() ? this : FxRate.of(pair.toConventional(), 1 / rate); }