/** * Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.pricer.fxopt; import static com.opengamma.strata.basics.currency.Currency.EUR; import static com.opengamma.strata.basics.currency.Currency.USD; import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; import org.testng.annotations.Test; import com.opengamma.strata.basics.currency.CurrencyAmount; import com.opengamma.strata.basics.currency.MultiCurrencyAmount; import com.opengamma.strata.basics.currency.Payment; import com.opengamma.strata.market.param.CurrencyParameterSensitivities; import com.opengamma.strata.pricer.DiscountingPaymentPricer; import com.opengamma.strata.pricer.fx.RatesProviderFxDataSets; import com.opengamma.strata.pricer.rate.ImmutableRatesProvider; import com.opengamma.strata.pricer.sensitivity.RatesFiniteDifferenceSensitivityCalculator; import com.opengamma.strata.product.common.LongShort; import com.opengamma.strata.product.fx.ResolvedFxSingle; import com.opengamma.strata.product.fxopt.ResolvedFxSingleBarrierOption; import com.opengamma.strata.product.fxopt.ResolvedFxSingleBarrierOptionTrade; import com.opengamma.strata.product.fxopt.ResolvedFxVanillaOption; import com.opengamma.strata.product.option.BarrierType; import com.opengamma.strata.product.option.KnockType; import com.opengamma.strata.product.option.SimpleConstantContinuousBarrier; /** * Test {@link ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer}. */ @Test public class ImpliedTrinomialTreeFxSingleBarrierOptionProductPricerTest { private static final ZoneId ZONE = ZoneId.of("Z"); private static final LocalDate VAL_DATE = LocalDate.of(2011, 6, 13); private static final ZonedDateTime VAL_DATETIME = VAL_DATE.atStartOfDay(ZONE); private static final LocalDate PAY_DATE = LocalDate.of(2014, 9, 15); private static final LocalDate EXPIRY_DATE = LocalDate.of(2014, 9, 15); private static final ZonedDateTime EXPIRY_DATETIME = EXPIRY_DATE.atStartOfDay(ZONE); // providers - flat private static final ImmutableRatesProvider RATE_PROVIDER_FLAT = RatesProviderFxDataSets.createProviderEurUsdFlat(VAL_DATE); private static final BlackFxOptionSmileVolatilities VOLS_FLAT = FxVolatilitySmileDataSet.createVolatilitySmileProvider5FlatFlat(VAL_DATETIME); // providers private static final ImmutableRatesProvider RATE_PROVIDER = RatesProviderFxDataSets.createProviderEURUSD(VAL_DATE); private static final BlackFxOptionSmileVolatilities VOLS = FxVolatilitySmileDataSet.createVolatilitySmileProvider5(VAL_DATETIME); // providers - after maturity private static final ImmutableRatesProvider RATE_PROVIDER_AFTER = RatesProviderFxDataSets.createProviderEURUSD(EXPIRY_DATE.plusDays(1)); private static final BlackFxOptionSmileVolatilities VOLS_AFTER = FxVolatilitySmileDataSet.createVolatilitySmileProvider5(EXPIRY_DATETIME.plusDays(1)); private static final double NOTIONAL = 100_000_000d; private static final double LEVEL_LOW = 1.25; private static final double LEVEL_HIGH = 1.6; private static final SimpleConstantContinuousBarrier BARRIER_DKO = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_OUT, LEVEL_LOW); private static final SimpleConstantContinuousBarrier BARRIER_UKI = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_IN, LEVEL_HIGH); private static final double REBATE_AMOUNT = 5_000_000d; // large rebate for testing private static final CurrencyAmount REBATE = CurrencyAmount.of(USD, REBATE_AMOUNT); private static final CurrencyAmount REBATE_BASE = CurrencyAmount.of(EUR, REBATE_AMOUNT); private static final double STRIKE_RATE_HIGH = 1.45; private static final double STRIKE_RATE_LOW = 1.35; // call private static final CurrencyAmount EUR_AMOUNT_REC = CurrencyAmount.of(EUR, NOTIONAL); private static final CurrencyAmount USD_AMOUNT_PAY = CurrencyAmount.of(USD, -NOTIONAL * STRIKE_RATE_LOW); private static final ResolvedFxSingle FX_PRODUCT = ResolvedFxSingle.of(EUR_AMOUNT_REC, USD_AMOUNT_PAY, PAY_DATE); private static final ResolvedFxVanillaOption CALL = ResolvedFxVanillaOption.builder() .longShort(LongShort.LONG) .expiry(EXPIRY_DATETIME) .underlying(FX_PRODUCT) .build(); private static final CurrencyAmount EUR_AMOUNT_PAY = CurrencyAmount.of(EUR, -NOTIONAL); private static final CurrencyAmount USD_AMOUNT_REC = CurrencyAmount.of(USD, NOTIONAL * STRIKE_RATE_HIGH); private static final ResolvedFxSingle FX_PRODUCT_INV = ResolvedFxSingle.of(EUR_AMOUNT_PAY, USD_AMOUNT_REC, PAY_DATE); private static final ResolvedFxVanillaOption PUT = ResolvedFxVanillaOption.builder() .longShort(LongShort.SHORT) .expiry(EXPIRY_DATETIME) .underlying(FX_PRODUCT_INV) .build(); private static final ResolvedFxSingleBarrierOption CALL_DKO = ResolvedFxSingleBarrierOption.of(CALL, BARRIER_DKO); private static final ResolvedFxSingleBarrierOption CALL_UKI_C = ResolvedFxSingleBarrierOption.of(CALL, BARRIER_UKI, REBATE); // pricers and pre-calibration private static final ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer PRICER_39 = new ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer(39); private static final RecombiningTrinomialTreeData DATA_39 = PRICER_39.getCalibrator().calibrateTrinomialTree(CALL, RATE_PROVIDER, VOLS); private static final ImpliedTrinomialTreeFxSingleBarrierOptionTradePricer TRADE_PRICER_39 = new ImpliedTrinomialTreeFxSingleBarrierOptionTradePricer(PRICER_39, DiscountingPaymentPricer.DEFAULT); private static final ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer PRICER_70 = new ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer(70); private static final RecombiningTrinomialTreeData DATA_70_FLAT = PRICER_70.getCalibrator().calibrateTrinomialTree(CALL, RATE_PROVIDER_FLAT, VOLS_FLAT); private static final BlackFxSingleBarrierOptionProductPricer BLACK_PRICER = BlackFxSingleBarrierOptionProductPricer.DEFAULT; private static final BlackFxVanillaOptionProductPricer VANILLA_PRICER = BlackFxVanillaOptionProductPricer.DEFAULT; @Test public void test_black() { double tol = 1.0e-2; for (int i = 0; i < 11; ++i) { // up barrier double lowerBarrier = 1.1 + 0.025 * i; SimpleConstantContinuousBarrier dko = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_OUT, lowerBarrier); ResolvedFxSingleBarrierOption optionDko = ResolvedFxSingleBarrierOption.of(CALL, dko); double priceDkoBlack = BLACK_PRICER.price(optionDko, RATE_PROVIDER_FLAT, VOLS_FLAT); double priceDko = PRICER_70.price(optionDko, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEqualsRelative(priceDko, priceDkoBlack, tol); SimpleConstantContinuousBarrier dki = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_IN, lowerBarrier); ResolvedFxSingleBarrierOption optionDki = ResolvedFxSingleBarrierOption.of(CALL, dki); double priceDkiBlack = BLACK_PRICER.price(optionDki, RATE_PROVIDER_FLAT, VOLS_FLAT); double priceDki = PRICER_70.price(optionDki, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEqualsRelative(priceDki, priceDkiBlack, tol); // down barrier double higherBarrier = 1.45 + 0.025 * i; SimpleConstantContinuousBarrier uko = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_OUT, higherBarrier); ResolvedFxSingleBarrierOption optionUko = ResolvedFxSingleBarrierOption.of(CALL, uko); double priceUkoBlack = BLACK_PRICER.price(optionUko, RATE_PROVIDER_FLAT, VOLS_FLAT); double priceUko = PRICER_70.price(optionUko, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEqualsRelative(priceUko, priceUkoBlack, tol); SimpleConstantContinuousBarrier uki = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_IN, higherBarrier); ResolvedFxSingleBarrierOption optionUki = ResolvedFxSingleBarrierOption.of(CALL, uki); double priceUkiBlack = BLACK_PRICER.price(optionUki, RATE_PROVIDER_FLAT, VOLS_FLAT); double priceUki = PRICER_70.price(optionUki, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEqualsRelative(priceUki, priceUkiBlack, tol); } } @Test public void test_black_currencyExposure() { double tol = 7.0e-2; // large tol due to approximated delta for (int i = 0; i < 8; ++i) { // up barrier double lowerBarrier = 1.1 + 0.025 * i; SimpleConstantContinuousBarrier dko = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_OUT, lowerBarrier); ResolvedFxSingleBarrierOption optionDko = ResolvedFxSingleBarrierOption.of(CALL, dko, REBATE_BASE); MultiCurrencyAmount ceDkoBlack = BLACK_PRICER.currencyExposure(optionDko, RATE_PROVIDER_FLAT, VOLS_FLAT); MultiCurrencyAmount ceDko = PRICER_70.currencyExposure(optionDko, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEquals(ceDko.getAmount(EUR).getAmount(), ceDkoBlack.getAmount(EUR).getAmount(), NOTIONAL * tol); assertEquals(ceDko.getAmount(USD).getAmount(), ceDkoBlack.getAmount(USD).getAmount(), NOTIONAL * tol); SimpleConstantContinuousBarrier dki = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_IN, lowerBarrier); ResolvedFxSingleBarrierOption optionDki = ResolvedFxSingleBarrierOption.of(CALL, dki, REBATE); MultiCurrencyAmount ceDkiBlack = BLACK_PRICER.currencyExposure(optionDki, RATE_PROVIDER_FLAT, VOLS_FLAT); MultiCurrencyAmount ceDki = PRICER_70.currencyExposure(optionDki, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEquals(ceDki.getAmount(EUR).getAmount(), ceDkiBlack.getAmount(EUR).getAmount(), NOTIONAL * tol); assertEquals(ceDki.getAmount(USD).getAmount(), ceDkiBlack.getAmount(USD).getAmount(), NOTIONAL * tol); // down barrier double higherBarrier = 1.45 + 0.025 * i; SimpleConstantContinuousBarrier uko = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_OUT, higherBarrier); ResolvedFxSingleBarrierOption optionUko = ResolvedFxSingleBarrierOption.of(CALL, uko, REBATE); MultiCurrencyAmount ceUkoBlack = BLACK_PRICER.currencyExposure(optionUko, RATE_PROVIDER_FLAT, VOLS_FLAT); MultiCurrencyAmount ceUko = PRICER_70.currencyExposure(optionUko, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEquals(ceUko.getAmount(EUR).getAmount(), ceUkoBlack.getAmount(EUR).getAmount(), NOTIONAL * tol); assertEquals(ceUko.getAmount(USD).getAmount(), ceUkoBlack.getAmount(USD).getAmount(), NOTIONAL * tol); SimpleConstantContinuousBarrier uki = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_IN, higherBarrier); ResolvedFxSingleBarrierOption optionUki = ResolvedFxSingleBarrierOption.of(CALL, uki, REBATE_BASE); MultiCurrencyAmount ceUkiBlack = BLACK_PRICER.currencyExposure(optionUki, RATE_PROVIDER_FLAT, VOLS_FLAT); MultiCurrencyAmount ceUki = PRICER_70.currencyExposure(optionUki, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEquals(ceUki.getAmount(EUR).getAmount(), ceUkiBlack.getAmount(EUR).getAmount(), NOTIONAL * tol); assertEquals(ceUki.getAmount(USD).getAmount(), ceUkiBlack.getAmount(USD).getAmount(), NOTIONAL * tol); } } @Test public void test_black_rebate() { double tol = 1.5e-2; for (int i = 0; i < 11; ++i) { // up barrier double lowerBarrier = 1.1 + 0.025 * i; SimpleConstantContinuousBarrier dko = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_OUT, lowerBarrier); ResolvedFxSingleBarrierOption optionDko = ResolvedFxSingleBarrierOption.of(PUT, dko, REBATE_BASE); double priceDkoBlack = BLACK_PRICER.price(optionDko, RATE_PROVIDER_FLAT, VOLS_FLAT); double priceDko = PRICER_70.price(optionDko, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEqualsRelative(priceDko, priceDkoBlack, tol); SimpleConstantContinuousBarrier dki = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_IN, lowerBarrier); ResolvedFxSingleBarrierOption optionDki = ResolvedFxSingleBarrierOption.of(PUT, dki, REBATE_BASE); double priceDkiBlack = BLACK_PRICER.price(optionDki, RATE_PROVIDER_FLAT, VOLS_FLAT); double priceDki = PRICER_70.price(optionDki, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEqualsRelative(priceDki, priceDkiBlack, tol); // down barrier double higherBarrier = 1.45 + 0.025 * i; SimpleConstantContinuousBarrier uko = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_OUT, higherBarrier); ResolvedFxSingleBarrierOption optionUko = ResolvedFxSingleBarrierOption.of(PUT, uko, REBATE); double priceUkoBlack = BLACK_PRICER.price(optionUko, RATE_PROVIDER_FLAT, VOLS_FLAT); double priceUko = PRICER_70.price(optionUko, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEqualsRelative(priceUko, priceUkoBlack, tol); SimpleConstantContinuousBarrier uki = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_IN, higherBarrier); ResolvedFxSingleBarrierOption optionUki = ResolvedFxSingleBarrierOption.of(PUT, uki, REBATE); double priceUkiBlack = BLACK_PRICER.price(optionUki, RATE_PROVIDER_FLAT, VOLS_FLAT); double priceUki = PRICER_70.price(optionUki, RATE_PROVIDER_FLAT, VOLS_FLAT, DATA_70_FLAT); assertEqualsRelative(priceUki, priceUkiBlack, tol); } } @Test public void test_monotonicity() { double priceDkoPrev = 100d; double priceDkiPrev = 0d; double priceUkoPrev = 0d; double priceUkiPrev = 100d; for (int i = 0; i < 50; ++i) { // up barrier double lowerBarrier = 1.1 + 0.006 * i; SimpleConstantContinuousBarrier dko = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_OUT, lowerBarrier); ResolvedFxSingleBarrierOption optionDko = ResolvedFxSingleBarrierOption.of(CALL, dko); double priceDko = PRICER_39.price(optionDko, RATE_PROVIDER, VOLS, DATA_39); SimpleConstantContinuousBarrier dki = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_IN, lowerBarrier); ResolvedFxSingleBarrierOption optionDki = ResolvedFxSingleBarrierOption.of(CALL, dki); double priceDki = PRICER_39.price(optionDki, RATE_PROVIDER, VOLS, DATA_39); // down barrier double higherBarrier = 1.4 + 0.006 * (i + 1); SimpleConstantContinuousBarrier uko = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_OUT, higherBarrier); ResolvedFxSingleBarrierOption optionUko = ResolvedFxSingleBarrierOption.of(CALL, uko); double priceUko = PRICER_39.price(optionUko, RATE_PROVIDER, VOLS, DATA_39); SimpleConstantContinuousBarrier uki = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_IN, higherBarrier); ResolvedFxSingleBarrierOption optionUki = ResolvedFxSingleBarrierOption.of(CALL, uki); double priceUki = PRICER_39.price(optionUki, RATE_PROVIDER, VOLS, DATA_39); assertTrue(priceDkoPrev > priceDko); assertTrue(priceDkiPrev < priceDki); assertTrue(priceUkoPrev < priceUko); assertTrue(priceUkiPrev > priceUki); priceDkoPrev = priceDko; priceDkiPrev = priceDki; priceUkoPrev = priceUko; priceUkiPrev = priceUki; } } @Test public void test_inOutParity() { double tol = 1.0e-2; double callPrice = VANILLA_PRICER.price(CALL, RATE_PROVIDER, VOLS); double putPrice = VANILLA_PRICER.price(PUT, RATE_PROVIDER, VOLS); for (int i = 0; i < 11; ++i) { // up barrier double lowerBarrier = 1.1 + 0.025 * i; SimpleConstantContinuousBarrier dko = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_OUT, lowerBarrier); ResolvedFxSingleBarrierOption callDko = ResolvedFxSingleBarrierOption.of(CALL, dko); double priceCallDko = PRICER_39.price(callDko, RATE_PROVIDER, VOLS, DATA_39); ResolvedFxSingleBarrierOption putDko = ResolvedFxSingleBarrierOption.of(PUT, dko); double pricePutDko = PRICER_39.price(putDko, RATE_PROVIDER, VOLS, DATA_39); SimpleConstantContinuousBarrier dki = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_IN, lowerBarrier); ResolvedFxSingleBarrierOption callDki = ResolvedFxSingleBarrierOption.of(CALL, dki); double priceCallDki = PRICER_39.price(callDki, RATE_PROVIDER, VOLS, DATA_39); ResolvedFxSingleBarrierOption putDki = ResolvedFxSingleBarrierOption.of(PUT, dki); double pricePutDki = PRICER_39.price(putDki, RATE_PROVIDER, VOLS, DATA_39); assertEqualsRelative(priceCallDko + priceCallDki, callPrice, tol); assertEqualsRelative(pricePutDko + pricePutDki, putPrice, tol); // down barrier double higherBarrier = 1.45 + 0.025 * i; SimpleConstantContinuousBarrier uko = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_OUT, higherBarrier); ResolvedFxSingleBarrierOption callUko = ResolvedFxSingleBarrierOption.of(CALL, uko); double priceCallUko = PRICER_39.price(callUko, RATE_PROVIDER, VOLS, DATA_39); ResolvedFxSingleBarrierOption putUko = ResolvedFxSingleBarrierOption.of(PUT, uko); double pricePutUko = PRICER_39.price(putUko, RATE_PROVIDER, VOLS, DATA_39); SimpleConstantContinuousBarrier uki = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_IN, higherBarrier); ResolvedFxSingleBarrierOption callUki = ResolvedFxSingleBarrierOption.of(CALL, uki); double priceCallUki = PRICER_39.price(callUki, RATE_PROVIDER, VOLS, DATA_39); ResolvedFxSingleBarrierOption putUki = ResolvedFxSingleBarrierOption.of(PUT, uki); double pricePutUki = PRICER_39.price(putUki, RATE_PROVIDER, VOLS, DATA_39); assertEqualsRelative(priceCallUko + priceCallUki, callPrice, tol); assertEqualsRelative(pricePutUko + pricePutUki, putPrice, tol); } } //------------------------------------------------------------------------- public void test_presentValueSensitivityRates() { ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer pricer = new ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer(21); CurrencyParameterSensitivities computed = pricer.presentValueSensitivityRates(CALL_UKI_C, RATE_PROVIDER, VOLS); RatesFiniteDifferenceSensitivityCalculator calc = new RatesFiniteDifferenceSensitivityCalculator(1.0e-5); CurrencyParameterSensitivities expected = calc.sensitivity(RATE_PROVIDER, p -> pricer.presentValue(CALL_UKI_C, p, VOLS)); assertTrue(computed.equalWithTolerance(expected, 1.0e-13)); } //------------------------------------------------------------------------- public void test_withData() { ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer pricer = new ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer(5); RecombiningTrinomialTreeData data = pricer.getCalibrator().calibrateTrinomialTree(CALL_DKO.getUnderlyingOption(), RATE_PROVIDER, VOLS); double price = pricer.price(CALL_UKI_C, RATE_PROVIDER, VOLS); double priceWithData = pricer.price(CALL_UKI_C, RATE_PROVIDER, VOLS, data); assertEquals(price, priceWithData); CurrencyAmount pv = pricer.presentValue(CALL_DKO, RATE_PROVIDER, VOLS); CurrencyAmount pvWithData = pricer.presentValue(CALL_DKO, RATE_PROVIDER, VOLS, data); assertEquals(pv, pvWithData); MultiCurrencyAmount ce = pricer.currencyExposure(CALL_UKI_C, RATE_PROVIDER, VOLS); MultiCurrencyAmount ceWithData = pricer.currencyExposure(CALL_UKI_C, RATE_PROVIDER, VOLS, data); assertEquals(ce, ceWithData); } public void test_expired_calibration() { assertThrowsIllegalArg(() -> PRICER_39.getCalibrator().calibrateTrinomialTree(CALL_DKO.getUnderlyingOption(), RATE_PROVIDER_AFTER, VOLS_AFTER)); // pricing also fails because trinomial data can not be obtained assertThrowsIllegalArg(() -> PRICER_39.price(CALL_DKO, RATE_PROVIDER_AFTER, VOLS_AFTER)); assertThrowsIllegalArg(() -> PRICER_39.presentValue(CALL_DKO, RATE_PROVIDER_AFTER, VOLS_AFTER)); assertThrowsIllegalArg(() -> PRICER_39.currencyExposure(CALL_DKO, RATE_PROVIDER_AFTER, VOLS_AFTER)); } public void test_dataMismatch() { assertThrowsIllegalArg(() -> PRICER_70.presentValueSensitivityRates( CALL_DKO, RATE_PROVIDER, VOLS, DATA_39)); } public void test_tradePricer() { for (int i = 0; i < 11; ++i) { // up barrier double lowerBarrier = 1.1 + 0.025 * i; SimpleConstantContinuousBarrier dko = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_OUT, lowerBarrier); ResolvedFxSingleBarrierOption callDko = ResolvedFxSingleBarrierOption.of(CALL, dko); ResolvedFxSingleBarrierOptionTrade callTrade = ResolvedFxSingleBarrierOptionTrade.builder() .product(callDko) .premium(Payment.of(EUR, 0, VAL_DATE)) .build(); CurrencyAmount pvProduct = PRICER_39.presentValue(callDko, RATE_PROVIDER, VOLS); MultiCurrencyAmount pvTrade = TRADE_PRICER_39.presentValue(callTrade, RATE_PROVIDER, VOLS); assertEquals(pvTrade.getAmount(USD), pvProduct); } } //------------------------------------------------------------------------- private void assertEqualsRelative(double computed, double expected, double relTol) { assertEquals(computed, expected, Math.max(1d, Math.abs(expected)) * relTol); } }