/**
* 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.MultiCurrencyAmount;
import com.opengamma.strata.market.param.CurrencyParameterSensitivities;
import com.opengamma.strata.market.sensitivity.PointSensitivities;
import com.opengamma.strata.pricer.rate.RatesProvider;
import com.opengamma.strata.pricer.sensitivity.RatesFiniteDifferenceSensitivityCalculator;
import com.opengamma.strata.product.fx.ResolvedFxSwap;
/**
* Test {@link DiscountingFxSwapProductPricer}.
*/
@Test
public class DiscountingFxSwapProductPricerTest {
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_NEAR = RatesProviderFxDataSets.VAL_DATE_2014_01_22.plusWeeks(1);
private static final LocalDate PAYMENT_DATE_FAR = PAYMENT_DATE_NEAR.plusMonths(1);
private static final LocalDate PAYMENT_DATE_PAST = PAYMENT_DATE_NEAR.minusMonths(1);
private static final LocalDate PAYMENT_DATE_LONG_PAST = PAYMENT_DATE_NEAR.minusMonths(2);
private static final double NOMINAL_USD = 100_000_000;
private static final double FX_RATE = 1109.5;
private static final double FX_FWD_POINTS = 4.45;
private static final ResolvedFxSwap SWAP_PRODUCT = ResolvedFxSwap.ofForwardPoints(
CurrencyAmount.of(USD, NOMINAL_USD), KRW, FX_RATE, FX_FWD_POINTS, PAYMENT_DATE_NEAR, PAYMENT_DATE_FAR);
private static final DiscountingFxSwapProductPricer PRICER = DiscountingFxSwapProductPricer.DEFAULT;
private static final double TOL = 1.0e-12;
private static final double EPS_FD = 1E-7;
private static final double TOLERANCE_SPREAD_DELTA = 1.0e-4;
private static final RatesFiniteDifferenceSensitivityCalculator CAL_FD =
new RatesFiniteDifferenceSensitivityCalculator(EPS_FD);
//-------------------------------------------------------------------------
public void test_presentValue_beforeStart() {
MultiCurrencyAmount computed = PRICER.presentValue(SWAP_PRODUCT, PROVIDER);
double expected_usd = NOMINAL_USD *
(PROVIDER.discountFactor(USD, PAYMENT_DATE_NEAR) - PROVIDER.discountFactor(USD, PAYMENT_DATE_FAR));
double expected_krw = NOMINAL_USD *
(-FX_RATE * PROVIDER.discountFactor(KRW, PAYMENT_DATE_NEAR)
+ (FX_RATE + FX_FWD_POINTS) * PROVIDER.discountFactor(KRW, PAYMENT_DATE_FAR));
assertEquals(computed.getAmount(USD).getAmount(), expected_usd, NOMINAL_USD * TOL);
assertEquals(computed.getAmount(KRW).getAmount(), expected_krw, NOMINAL_USD * FX_RATE * TOL);
// currency exposure
MultiCurrencyAmount exposure = PRICER.currencyExposure(SWAP_PRODUCT, PROVIDER);
assertEquals(exposure, computed);
}
public void test_presentValue_started() {
ResolvedFxSwap product = ResolvedFxSwap.ofForwardPoints(
CurrencyAmount.of(USD, NOMINAL_USD), KRW, FX_RATE, FX_FWD_POINTS, PAYMENT_DATE_PAST, PAYMENT_DATE_NEAR);
MultiCurrencyAmount computed = PRICER.presentValue(product, PROVIDER);
double expected_usd = -NOMINAL_USD * PROVIDER.discountFactor(USD, PAYMENT_DATE_NEAR);
double expected_krw = NOMINAL_USD * (FX_RATE + FX_FWD_POINTS) * PROVIDER.discountFactor(KRW, PAYMENT_DATE_NEAR);
assertEquals(computed.getAmount(USD).getAmount(), expected_usd, NOMINAL_USD * TOL);
assertEquals(computed.getAmount(KRW).getAmount(), expected_krw, NOMINAL_USD * FX_RATE * TOL);
// currency exposure
MultiCurrencyAmount exposure = PRICER.currencyExposure(product, PROVIDER);
assertEquals(exposure, computed);
}
public void test_presentValue_ended() {
ResolvedFxSwap product = ResolvedFxSwap.ofForwardPoints(
CurrencyAmount.of(USD, NOMINAL_USD), KRW, FX_RATE, FX_FWD_POINTS, PAYMENT_DATE_LONG_PAST, PAYMENT_DATE_PAST);
MultiCurrencyAmount computed = PRICER.presentValue(product, PROVIDER);
assertEquals(computed, MultiCurrencyAmount.empty());
// currency exposure
MultiCurrencyAmount exposure = PRICER.currencyExposure(product, PROVIDER);
assertEquals(exposure, computed);
}
//-------------------------------------------------------------------------
public void test_parSpread_beforeStart() {
double parSpread = PRICER.parSpread(SWAP_PRODUCT, PROVIDER);
ResolvedFxSwap product = ResolvedFxSwap.ofForwardPoints(
CurrencyAmount.of(USD, NOMINAL_USD), KRW, FX_RATE, FX_FWD_POINTS + parSpread, PAYMENT_DATE_NEAR, PAYMENT_DATE_FAR);
MultiCurrencyAmount pv = PRICER.presentValue(product, PROVIDER);
assertEquals(pv.convertedTo(USD, PROVIDER).getAmount(), 0d, NOMINAL_USD * TOL);
}
public void test_parSpread_started() {
ResolvedFxSwap product = ResolvedFxSwap.ofForwardPoints(
CurrencyAmount.of(USD, NOMINAL_USD), KRW, FX_RATE, FX_FWD_POINTS, PAYMENT_DATE_PAST, PAYMENT_DATE_NEAR);
double parSpread = PRICER.parSpread(product, PROVIDER);
ResolvedFxSwap productPar = ResolvedFxSwap.ofForwardPoints(
CurrencyAmount.of(USD, NOMINAL_USD), KRW, FX_RATE, FX_FWD_POINTS + parSpread, PAYMENT_DATE_PAST, PAYMENT_DATE_NEAR);
MultiCurrencyAmount pv = PRICER.presentValue(productPar, PROVIDER);
assertEquals(pv.convertedTo(USD, PROVIDER).getAmount(), 0d, NOMINAL_USD * TOL);
}
public void test_parSpread_ended() {
ResolvedFxSwap product = ResolvedFxSwap.ofForwardPoints(
CurrencyAmount.of(USD, NOMINAL_USD), KRW, FX_RATE, FX_FWD_POINTS, PAYMENT_DATE_LONG_PAST, PAYMENT_DATE_PAST);
double parSpread = PRICER.parSpread(product, PROVIDER);
assertEquals(parSpread, 0d, TOL);
}
//-------------------------------------------------------------------------
public void test_presentValueSensitivity_beforeStart() {
PointSensitivities point = PRICER.presentValueSensitivity(SWAP_PRODUCT, PROVIDER);
CurrencyParameterSensitivities computed = PROVIDER.parameterSensitivity(point);
CurrencyParameterSensitivities expectedUsd = CAL_FD.sensitivity(
PROVIDER, (p) -> PRICER.presentValue(SWAP_PRODUCT, (p)).getAmount(USD));
CurrencyParameterSensitivities expectedKrw = CAL_FD.sensitivity(
PROVIDER, (p) -> PRICER.presentValue(SWAP_PRODUCT, (p)).getAmount(KRW));
assertTrue(computed.equalWithTolerance(expectedUsd.combinedWith(expectedKrw), NOMINAL_USD * FX_RATE * EPS_FD));
}
public void test_presentValueSensitivity_started() {
ResolvedFxSwap product = ResolvedFxSwap.ofForwardPoints(CurrencyAmount.of(
USD, NOMINAL_USD), KRW, FX_RATE, FX_FWD_POINTS, PAYMENT_DATE_PAST, PAYMENT_DATE_NEAR);
PointSensitivities point = PRICER.presentValueSensitivity(product, PROVIDER);
CurrencyParameterSensitivities computed = PROVIDER.parameterSensitivity(point);
CurrencyParameterSensitivities expectedUsd = CAL_FD.sensitivity(
PROVIDER, (p) -> PRICER.presentValue(product, (p)).getAmount(USD));
CurrencyParameterSensitivities expectedKrw = CAL_FD.sensitivity(
PROVIDER, (p) -> PRICER.presentValue(product, (p)).getAmount(KRW));
assertTrue(computed.equalWithTolerance(expectedUsd.combinedWith(expectedKrw), NOMINAL_USD * FX_RATE * EPS_FD));
}
public void test_presentValueSensitivity_ended() {
ResolvedFxSwap product = ResolvedFxSwap.ofForwardPoints(
CurrencyAmount.of(USD, NOMINAL_USD), KRW, FX_RATE, FX_FWD_POINTS, PAYMENT_DATE_LONG_PAST, PAYMENT_DATE_PAST);
PointSensitivities computed = PRICER.presentValueSensitivity(product, PROVIDER);
assertEquals(computed, PointSensitivities.empty());
}
//-------------------------------------------------------------------------
public void test_parSpreadSensitivity_beforeStart() {
PointSensitivities pts = PRICER.parSpreadSensitivity(SWAP_PRODUCT, PROVIDER);
CurrencyParameterSensitivities computed = PROVIDER.parameterSensitivity(pts);
CurrencyParameterSensitivities expected = CAL_FD.sensitivity(
PROVIDER, (p) -> CurrencyAmount.of(KRW, PRICER.parSpread(SWAP_PRODUCT, p)));
assertTrue(computed.equalWithTolerance(expected, TOLERANCE_SPREAD_DELTA));
}
public void test_parSpreadSensitivity_started() {
ResolvedFxSwap product = ResolvedFxSwap.ofForwardPoints(
CurrencyAmount.of(USD, NOMINAL_USD), KRW, FX_RATE, FX_FWD_POINTS, PAYMENT_DATE_PAST, PAYMENT_DATE_NEAR);
PointSensitivities pts = PRICER.parSpreadSensitivity(product, PROVIDER);
CurrencyParameterSensitivities computed = PROVIDER.parameterSensitivity(pts);
CurrencyParameterSensitivities expected = CAL_FD.sensitivity(
PROVIDER, (p) -> CurrencyAmount.of(KRW, PRICER.parSpread(product, p)));
assertTrue(computed.equalWithTolerance(expected, TOLERANCE_SPREAD_DELTA));
}
public void test_parSpreadSensitivity_ended() {
ResolvedFxSwap product = ResolvedFxSwap.ofForwardPoints(
CurrencyAmount.of(USD, NOMINAL_USD), KRW, FX_RATE, FX_FWD_POINTS, PAYMENT_DATE_LONG_PAST, PAYMENT_DATE_PAST);
PointSensitivities pts = PRICER.parSpreadSensitivity(product, PROVIDER);
CurrencyParameterSensitivities computed = PROVIDER.parameterSensitivity(pts);
assertTrue(computed.equalWithTolerance(CurrencyParameterSensitivities.empty(), TOLERANCE_SPREAD_DELTA));
}
//-------------------------------------------------------------------------
public void test_currentCash_zero() {
MultiCurrencyAmount computed = PRICER.currentCash(SWAP_PRODUCT, PROVIDER.getValuationDate());
assertEquals(computed, MultiCurrencyAmount.empty());
}
public void test_currentCash_firstPayment() {
MultiCurrencyAmount computed = PRICER.currentCash(SWAP_PRODUCT, PAYMENT_DATE_NEAR);
assertEquals(computed, MultiCurrencyAmount.of(
SWAP_PRODUCT.getNearLeg().getBaseCurrencyPayment().getValue(),
SWAP_PRODUCT.getNearLeg().getCounterCurrencyPayment().getValue()));
}
public void test_currentCash_secondPayment() {
MultiCurrencyAmount computed = PRICER.currentCash(SWAP_PRODUCT, PAYMENT_DATE_FAR);
assertEquals(computed, MultiCurrencyAmount.of(
SWAP_PRODUCT.getFarLeg().getBaseCurrencyPayment().getValue(),
SWAP_PRODUCT.getFarLeg().getCounterCurrencyPayment().getValue()));
}
}