/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.pricer.fx; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.time.LocalDate; import org.testng.annotations.Test; import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.basics.currency.CurrencyAmount; import com.opengamma.strata.basics.currency.CurrencyPair; import com.opengamma.strata.basics.currency.FxRate; import com.opengamma.strata.basics.currency.MultiCurrencyAmount; import com.opengamma.strata.market.param.CurrencyParameterSensitivities; import com.opengamma.strata.market.sensitivity.PointSensitivities; import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder; import com.opengamma.strata.pricer.rate.RatesProvider; import com.opengamma.strata.pricer.sensitivity.RatesFiniteDifferenceSensitivityCalculator; import com.opengamma.strata.product.fx.ResolvedFxSingle; /** * Test {@link DiscountingFxSingleProductPricer}. */ @Test public class DiscountingFxSingleProductPricerTest { private static final RatesProvider PROVIDER = RatesProviderFxDataSets.createProvider(); private static final Currency KRW = Currency.KRW; private static final Currency USD = Currency.USD; private static final LocalDate PAYMENT_DATE = RatesProviderFxDataSets.VAL_DATE_2014_01_22.plusWeeks(8); private static final LocalDate PAYMENT_DATE_PAST = RatesProviderFxDataSets.VAL_DATE_2014_01_22.minusDays(1); private static final double NOMINAL_USD = 100_000_000; private static final double FX_RATE = 1123.45; private static final ResolvedFxSingle FWD = ResolvedFxSingle.of( CurrencyAmount.of(USD, NOMINAL_USD), FxRate.of(USD, KRW, FX_RATE), PAYMENT_DATE); private static final DiscountingFxSingleProductPricer PRICER = DiscountingFxSingleProductPricer.DEFAULT; private static final double TOL = 1.0e-12; private static final double EPS_FD = 1E-7; private static final RatesFiniteDifferenceSensitivityCalculator CAL_FD = new RatesFiniteDifferenceSensitivityCalculator(EPS_FD); public void test_presentValue() { MultiCurrencyAmount computed = PRICER.presentValue(FWD, PROVIDER); double expected1 = NOMINAL_USD * PROVIDER.discountFactor(USD, PAYMENT_DATE); double expected2 = -NOMINAL_USD * FX_RATE * PROVIDER.discountFactor(KRW, PAYMENT_DATE); assertEquals(computed.getAmount(USD).getAmount(), expected1, NOMINAL_USD * TOL); assertEquals(computed.getAmount(KRW).getAmount(), expected2, NOMINAL_USD * TOL); } public void test_presentValue_ended() { ResolvedFxSingle fwd = ResolvedFxSingle.of(CurrencyAmount.of(USD, NOMINAL_USD), FxRate.of(USD, KRW, FX_RATE), PAYMENT_DATE_PAST); MultiCurrencyAmount computed = PRICER.presentValue(fwd, PROVIDER); assertEquals(computed, MultiCurrencyAmount.empty()); } public void test_parSpread() { double spread = PRICER.parSpread(FWD, PROVIDER); ResolvedFxSingle fwdSp = ResolvedFxSingle.of(CurrencyAmount.of(USD, NOMINAL_USD), FxRate.of(USD, KRW, FX_RATE + spread), PAYMENT_DATE); MultiCurrencyAmount pv = PRICER.presentValue(fwdSp, PROVIDER); assertEquals(pv.convertedTo(USD, PROVIDER).getAmount(), 0d, NOMINAL_USD * TOL); } public void test_parSpread_ended() { ResolvedFxSingle fwd = ResolvedFxSingle.of(CurrencyAmount.of(USD, NOMINAL_USD), FxRate.of(USD, KRW, FX_RATE), PAYMENT_DATE_PAST); double spread = PRICER.parSpread(fwd, PROVIDER); assertEquals(spread, 0d, TOL); } public void test_forwardFxRate() { // forward rate is computed by discounting for any RatesProvider input. FxRate computed = PRICER.forwardFxRate(FWD, PROVIDER); double df1 = PROVIDER.discountFactor(USD, PAYMENT_DATE); double df2 = PROVIDER.discountFactor(KRW, PAYMENT_DATE); double spot = PROVIDER.fxRate(USD, KRW); FxRate expected = FxRate.of(USD, KRW, spot * df1 / df2); assertEquals(computed, expected); } public void test_forwardFxRatePointSensitivity() { PointSensitivityBuilder computed = PRICER.forwardFxRatePointSensitivity(FWD, PROVIDER); FxForwardSensitivity expected = FxForwardSensitivity.of(CurrencyPair.of(USD, KRW), USD, FWD.getPaymentDate(), 1d); assertEquals(computed, expected); } public void test_forwardFxRateSpotSensitivity() { double computed = PRICER.forwardFxRateSpotSensitivity(FWD, PROVIDER); double df1 = PROVIDER.discountFactor(USD, PAYMENT_DATE); double df2 = PROVIDER.discountFactor(KRW, PAYMENT_DATE); assertEquals(computed, df1 / df2); } public void test_presentValueSensitivity() { PointSensitivities point = PRICER.presentValueSensitivity(FWD, PROVIDER); CurrencyParameterSensitivities computed = PROVIDER.parameterSensitivity(point); CurrencyParameterSensitivities expectedUsd = CAL_FD.sensitivity(PROVIDER, (p) -> PRICER.presentValue(FWD, (p)).getAmount(USD)); CurrencyParameterSensitivities expectedKrw = CAL_FD.sensitivity(PROVIDER, (p) -> PRICER.presentValue(FWD, (p)).getAmount(KRW)); assertTrue(computed.equalWithTolerance(expectedUsd.combinedWith(expectedKrw), NOMINAL_USD * FX_RATE * EPS_FD)); } public void test_presentValueSensitivity_ended() { ResolvedFxSingle fwd = ResolvedFxSingle.of(CurrencyAmount.of(USD, NOMINAL_USD), FxRate.of(USD, KRW, FX_RATE), PAYMENT_DATE_PAST); PointSensitivities computed = PRICER.presentValueSensitivity(fwd, PROVIDER); assertEquals(computed, PointSensitivities.empty()); } //------------------------------------------------------------------------- public void test_currencyExposure() { MultiCurrencyAmount computed = PRICER.currencyExposure(FWD, PROVIDER); MultiCurrencyAmount expected = PRICER.presentValue(FWD, PROVIDER); assertEquals(computed, expected); } public void test_currentCash_zero() { MultiCurrencyAmount computed = PRICER.currentCash(FWD, PROVIDER.getValuationDate()); assertEquals(computed, MultiCurrencyAmount.empty()); } public void test_currentCash_onPayment() { MultiCurrencyAmount computed = PRICER.currentCash(FWD, PAYMENT_DATE); assertEquals(computed, MultiCurrencyAmount.of( FWD.getBaseCurrencyPayment().getValue(), FWD.getCounterCurrencyPayment().getValue())); } }