/**
* Copyright (C) 2015 - 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 com.opengamma.strata.product.common.LongShort.LONG;
import static com.opengamma.strata.product.common.LongShort.SHORT;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.time.LocalDate;
import java.time.LocalTime;
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.CurrencyPair;
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.datasets.RatesProviderDataSets;
import com.opengamma.strata.pricer.fx.RatesProviderFxDataSets;
import com.opengamma.strata.pricer.impl.option.BlackFormulaRepository;
import com.opengamma.strata.pricer.rate.RatesProvider;
import com.opengamma.strata.pricer.sensitivity.RatesFiniteDifferenceSensitivityCalculator;
import com.opengamma.strata.product.fx.ResolvedFxSingle;
import com.opengamma.strata.product.fxopt.ResolvedFxVanillaOption;
/**
* Test {@link BlackFxVanillaOptionProductPricer}.
*/
@Test
public class BlackFxVanillaOptionProductPricerTest {
private static final ZoneId ZONE = ZoneId.of("Z");
private static final ZonedDateTime EXPIRY = ZonedDateTime.of(2014, 5, 9, 13, 10, 0, 0, ZONE);
private static final LocalDate VAL_DATE = RatesProviderDataSets.VAL_DATE_2014_01_22;
private static final ZonedDateTime VAL_DATETIME_AFTER = EXPIRY.plusDays(1);
private static final LocalDate VAL_DATE_AFTER = VAL_DATETIME_AFTER.toLocalDate();
private static final LocalTime VAL_TIME = LocalTime.of(13, 45);
private static final ZonedDateTime VAL_DATETIME = VAL_DATE.atTime(VAL_TIME).atZone(ZONE);
private static final RatesProvider RATES_PROVIDER = RatesProviderFxDataSets.createProviderEURUSD(VAL_DATE);
private static final RatesProvider RATES_PROVIDER_EXPIRY =
RatesProviderFxDataSets.createProviderEURUSD(EXPIRY.toLocalDate());
private static final RatesProvider RATES_PROVIDER_AFTER =
RatesProviderFxDataSets.createProviderEURUSD(VAL_DATE_AFTER);
private static final BlackFxOptionSmileVolatilities VOLS =
FxVolatilitySmileDataSet.createVolatilitySmileProvider6(VAL_DATETIME);
private static final BlackFxOptionSmileVolatilities VOLS_EXPIRY =
FxVolatilitySmileDataSet.createVolatilitySmileProvider6(EXPIRY);
private static final BlackFxOptionSmileVolatilities VOLS_AFTER =
FxVolatilitySmileDataSet.createVolatilitySmileProvider6(VAL_DATETIME_AFTER);
private static final InterpolatedStrikeSmileDeltaTermStructure SMILE_TERM =
FxVolatilitySmileDataSet.getSmileDeltaTermStructure6();
private static final CurrencyPair CURRENCY_PAIR = CurrencyPair.of(EUR, USD);
private static final double NOTIONAL = 1.0e6;
private static final LocalDate PAYMENT_DATE = LocalDate.of(2014, 5, 13);
private static final double STRIKE_RATE_HIGH = 1.44;
private static final double STRIKE_RATE_LOW = 1.36;
private static final CurrencyAmount EUR_AMOUNT = CurrencyAmount.of(EUR, NOTIONAL);
private static final CurrencyAmount USD_AMOUNT_HIGH = CurrencyAmount.of(USD, -NOTIONAL * STRIKE_RATE_HIGH);
private static final CurrencyAmount USD_AMOUNT_LOW = CurrencyAmount.of(USD, -NOTIONAL * STRIKE_RATE_LOW);
private static final ResolvedFxSingle FX_PRODUCT_HIGH = ResolvedFxSingle.of(EUR_AMOUNT, USD_AMOUNT_HIGH, PAYMENT_DATE);
private static final ResolvedFxSingle FX_PRODUCT_LOW = ResolvedFxSingle.of(EUR_AMOUNT, USD_AMOUNT_LOW, PAYMENT_DATE);
private static final ResolvedFxVanillaOption CALL_OTM = ResolvedFxVanillaOption.builder()
.longShort(SHORT)
.expiry(EXPIRY)
.underlying(FX_PRODUCT_HIGH)
.build();
private static final ResolvedFxVanillaOption CALL_ITM = ResolvedFxVanillaOption.builder()
.longShort(LONG)
.expiry(EXPIRY)
.underlying(FX_PRODUCT_LOW)
.build();
private static final ResolvedFxVanillaOption PUT_OTM = ResolvedFxVanillaOption.builder()
.longShort(SHORT)
.expiry(EXPIRY)
.underlying(FX_PRODUCT_LOW.inverse())
.build();
private static final ResolvedFxVanillaOption PUT_ITM = ResolvedFxVanillaOption.builder()
.longShort(LONG)
.expiry(EXPIRY)
.underlying(FX_PRODUCT_HIGH.inverse())
.build();
private static final BlackFxVanillaOptionProductPricer PRICER = BlackFxVanillaOptionProductPricer.DEFAULT;
private static final double TOL = 1.0e-13;
private static final double FD_EPS = 1.0e-7;
private static final RatesFiniteDifferenceSensitivityCalculator FD_CAL =
new RatesFiniteDifferenceSensitivityCalculator(FD_EPS);
//-------------------------------------------------------------------------
public void test_price_presentValue() {
double priceCallOtm = PRICER.price(CALL_OTM, RATES_PROVIDER, VOLS);
CurrencyAmount pvCallOtm = PRICER.presentValue(CALL_OTM, RATES_PROVIDER, VOLS);
double pricePutOtm = PRICER.price(PUT_OTM, RATES_PROVIDER, VOLS);
CurrencyAmount pvPutOtm = PRICER.presentValue(PUT_OTM, RATES_PROVIDER, VOLS);
double timeToExpiry = VOLS.relativeTime(EXPIRY);
double df = RATES_PROVIDER.discountFactor(USD, PAYMENT_DATE);
double forward = PRICER.getDiscountingFxSingleProductPricer()
.forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER).fxRate(CURRENCY_PAIR);
double volHigh = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_HIGH, forward);
double volLow = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_LOW, forward);
double expectedPriceCallOtm =
df * BlackFormulaRepository.price(forward, STRIKE_RATE_HIGH, timeToExpiry, volHigh, true);
double expectedPricePutOtm =
df * BlackFormulaRepository.price(forward, STRIKE_RATE_LOW, timeToExpiry, volLow, false);
double expectedPvCallOtm = -NOTIONAL * df *
BlackFormulaRepository.price(forward, STRIKE_RATE_HIGH, timeToExpiry, volHigh, true);
double expectedPvPutOtm = -NOTIONAL * df *
BlackFormulaRepository.price(forward, STRIKE_RATE_LOW, timeToExpiry, volLow, false);
assertEquals(priceCallOtm, expectedPriceCallOtm, TOL);
assertEquals(pvCallOtm.getCurrency(), USD);
assertEquals(pvCallOtm.getAmount(), expectedPvCallOtm, NOTIONAL * TOL);
assertEquals(pricePutOtm, expectedPricePutOtm, TOL);
assertEquals(pvPutOtm.getCurrency(), USD);
assertEquals(pvPutOtm.getAmount(), expectedPvPutOtm, NOTIONAL * TOL);
}
public void test_price_presentValue_atExpiry() {
double df = RATES_PROVIDER_EXPIRY.discountFactor(USD, PAYMENT_DATE);
double forward = PRICER.getDiscountingFxSingleProductPricer()
.forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER_EXPIRY).fxRate(CURRENCY_PAIR);
double priceCallOtm = PRICER.price(CALL_OTM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyAmount pvCallOtm = PRICER.presentValue(CALL_OTM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(priceCallOtm, 0d, TOL);
assertEquals(pvCallOtm.getAmount(), 0d, NOTIONAL * TOL);
double priceCallItm = PRICER.price(CALL_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyAmount pvCallItm = PRICER.presentValue(CALL_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(priceCallItm, df * (forward - STRIKE_RATE_LOW), TOL);
assertEquals(pvCallItm.getAmount(), df * (forward - STRIKE_RATE_LOW) * NOTIONAL, NOTIONAL * TOL);
double pricePutOtm = PRICER.price(PUT_OTM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyAmount pvPutOtm = PRICER.presentValue(PUT_OTM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(pricePutOtm, 0d, TOL);
assertEquals(pvPutOtm.getAmount(), 0d, NOTIONAL * TOL);
double pricePutItm = PRICER.price(PUT_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyAmount pvPutItm = PRICER.presentValue(PUT_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(pricePutItm, df * (STRIKE_RATE_HIGH - forward), TOL);
assertEquals(pvPutItm.getAmount(), df * (STRIKE_RATE_HIGH - forward) * NOTIONAL, NOTIONAL * TOL);
}
public void test_price_presentValue_afterExpiry() {
double price = PRICER.price(CALL_OTM, RATES_PROVIDER_AFTER, VOLS_AFTER);
CurrencyAmount pv = PRICER.presentValue(CALL_OTM, RATES_PROVIDER_AFTER, VOLS_AFTER);
assertEquals(price, 0d, NOTIONAL * TOL);
assertEquals(pv.getAmount(), 0d, NOTIONAL * TOL);
}
public void test_price_presentValue_parity() {
double df = RATES_PROVIDER.discountFactor(USD, PAYMENT_DATE);
double forward = PRICER.getDiscountingFxSingleProductPricer()
.forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER).fxRate(CURRENCY_PAIR);
double priceCallOtm = PRICER.price(CALL_OTM, RATES_PROVIDER, VOLS);
CurrencyAmount pvCallOtm = PRICER.presentValue(CALL_OTM, RATES_PROVIDER, VOLS);
double pricePutItm = PRICER.price(PUT_ITM, RATES_PROVIDER, VOLS);
CurrencyAmount pvPutItm = PRICER.presentValue(PUT_ITM, RATES_PROVIDER, VOLS);
assertEquals(priceCallOtm - pricePutItm, df * (forward - STRIKE_RATE_HIGH), TOL);
assertEquals(-pvCallOtm.getAmount() - pvPutItm.getAmount(),
df * (forward - STRIKE_RATE_HIGH) * NOTIONAL, NOTIONAL * TOL);
}
//-------------------------------------------------------------------------
public void test_delta_presentValueDelta() {
double deltaCall = PRICER.delta(CALL_OTM, RATES_PROVIDER, VOLS);
CurrencyAmount pvDeltaCall = PRICER.presentValueDelta(CALL_OTM, RATES_PROVIDER, VOLS);
double deltaPut = PRICER.delta(PUT_ITM, RATES_PROVIDER, VOLS);
CurrencyAmount pvDeltaPut = PRICER.presentValueDelta(PUT_ITM, RATES_PROVIDER, VOLS);
double timeToExpiry = VOLS.relativeTime(EXPIRY);
double dfFor = RATES_PROVIDER.discountFactor(EUR, PAYMENT_DATE);
double forward = PRICER.getDiscountingFxSingleProductPricer().forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER)
.fxRate(CURRENCY_PAIR);
double vol = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_HIGH, forward);
double expectedDeltaCall = dfFor * BlackFormulaRepository.delta(forward, STRIKE_RATE_HIGH, timeToExpiry, vol, true);
double expectedDeltaPut = dfFor * BlackFormulaRepository.delta(forward, STRIKE_RATE_HIGH, timeToExpiry, vol, false);
double expectedPvDeltaCall = -NOTIONAL * dfFor
* BlackFormulaRepository.delta(forward, STRIKE_RATE_HIGH, timeToExpiry, vol, true);
double expectedPvDeltaPut = NOTIONAL * dfFor
* BlackFormulaRepository.delta(forward, STRIKE_RATE_HIGH, timeToExpiry, vol, false);
assertEquals(deltaCall, expectedDeltaCall, TOL);
assertEquals(pvDeltaCall.getCurrency(), USD);
assertEquals(pvDeltaCall.getAmount(), expectedPvDeltaCall, NOTIONAL * TOL);
assertEquals(deltaPut, expectedDeltaPut, TOL);
assertEquals(pvDeltaPut.getCurrency(), USD);
assertEquals(pvDeltaPut.getAmount(), expectedPvDeltaPut, NOTIONAL * TOL);
}
public void test_delta_presentValueDelta_atExpiry() {
double dfFor = RATES_PROVIDER_EXPIRY.discountFactor(EUR, PAYMENT_DATE);
double deltaCallOtm = PRICER.delta(CALL_OTM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyAmount pvDeltaCallOtm = PRICER.presentValueDelta(CALL_OTM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(deltaCallOtm, 0d, TOL);
assertEquals(pvDeltaCallOtm.getAmount(), 0d, NOTIONAL * TOL);
double deltaCallItm = PRICER.delta(CALL_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyAmount pvDeltaCallItm = PRICER.presentValueDelta(CALL_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(deltaCallItm, dfFor, TOL);
assertEquals(pvDeltaCallItm.getAmount(), NOTIONAL * dfFor, NOTIONAL * TOL);
double deltaPutItm = PRICER.delta(PUT_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyAmount pvDeltaPutItm = PRICER.presentValueDelta(PUT_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(deltaPutItm, -dfFor, TOL);
assertEquals(pvDeltaPutItm.getAmount(), -NOTIONAL * dfFor, NOTIONAL * TOL);
double deltaPutOtm = PRICER.delta(PUT_OTM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyAmount pvDeltaPutOtm = PRICER.presentValueDelta(PUT_OTM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(deltaPutOtm, 0d, TOL);
assertEquals(pvDeltaPutOtm.getAmount(), 0d, NOTIONAL * TOL);
}
public void test_delta_presentValueDelta_afterExpiry() {
double delta = PRICER.delta(CALL_OTM, RATES_PROVIDER_AFTER, VOLS_AFTER);
CurrencyAmount pvDelta = PRICER.presentValueDelta(CALL_OTM, RATES_PROVIDER_AFTER, VOLS_AFTER);
assertEquals(delta, 0d, TOL);
assertEquals(pvDelta.getAmount(), 0d, NOTIONAL * TOL);
}
//-------------------------------------------------------------------------
public void test_presentValueSensitivity() {
// call
PointSensitivities pointCall = PRICER.presentValueSensitivityRatesStickyStrike(CALL_OTM, RATES_PROVIDER, VOLS);
CurrencyParameterSensitivities computedCall = RATES_PROVIDER.parameterSensitivity(pointCall);
CurrencyParameterSensitivities expectedCall = FD_CAL.sensitivity(
RATES_PROVIDER, (p) -> PRICER.presentValue(CALL_OTM, (p), VOLS));
// contribution via implied volatility, to be subtracted.
CurrencyAmount pvVegaCall = PRICER.presentValueVega(CALL_OTM, RATES_PROVIDER, VOLS);
CurrencyParameterSensitivities impliedVolSenseCall =
FD_CAL.sensitivity(RATES_PROVIDER,
(p) -> CurrencyAmount.of(USD, PRICER.impliedVolatility(CALL_OTM, (p), VOLS)))
.multipliedBy(-pvVegaCall.getAmount());
assertTrue(computedCall.equalWithTolerance(expectedCall.combinedWith(impliedVolSenseCall), NOTIONAL * FD_EPS));
// put
PointSensitivities pointPut = PRICER.presentValueSensitivityRatesStickyStrike(PUT_OTM, RATES_PROVIDER, VOLS);
CurrencyParameterSensitivities computedPut = RATES_PROVIDER.parameterSensitivity(pointPut);
CurrencyParameterSensitivities expectedPut = FD_CAL.sensitivity(
RATES_PROVIDER, (p) -> PRICER.presentValue(PUT_OTM, (p), VOLS));
// contribution via implied volatility, to be subtracted.
CurrencyAmount pvVegaPut = PRICER.presentValueVega(PUT_OTM, RATES_PROVIDER, VOLS);
CurrencyParameterSensitivities impliedVolSensePut = FD_CAL.sensitivity(
RATES_PROVIDER, (p) -> CurrencyAmount.of(USD, PRICER.impliedVolatility(PUT_OTM, (p), VOLS)))
.multipliedBy(-pvVegaPut.getAmount());
assertTrue(computedPut.equalWithTolerance(expectedPut.combinedWith(impliedVolSensePut), NOTIONAL * FD_EPS));
}
public void test_presentValueSensitivity_atExpiry() {
// call
PointSensitivities pointCall = PRICER.presentValueSensitivityRatesStickyStrike(CALL_OTM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyParameterSensitivities computedCall = RATES_PROVIDER_EXPIRY.parameterSensitivity(pointCall);
CurrencyParameterSensitivities expectedCall = FD_CAL.sensitivity(
RATES_PROVIDER_EXPIRY, (p) -> PRICER.presentValue(CALL_OTM, (p), VOLS_EXPIRY));
assertTrue(computedCall.equalWithTolerance(expectedCall, NOTIONAL * FD_EPS));
// put
PointSensitivities pointPut = PRICER.presentValueSensitivityRatesStickyStrike(PUT_OTM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyParameterSensitivities computedPut = RATES_PROVIDER_EXPIRY.parameterSensitivity(pointPut);
CurrencyParameterSensitivities expectedPut = FD_CAL.sensitivity(
RATES_PROVIDER_EXPIRY, (p) -> PRICER.presentValue(PUT_OTM, (p), VOLS_EXPIRY));
assertTrue(computedPut.equalWithTolerance(expectedPut, NOTIONAL * FD_EPS));
}
public void test_presentValueSensitivity_afterExpiry() {
PointSensitivities point = PRICER.presentValueSensitivityRatesStickyStrike(CALL_ITM, RATES_PROVIDER_AFTER, VOLS_AFTER);
assertEquals(point, PointSensitivities.empty());
}
//-------------------------------------------------------------------------
public void test_gamma_presentValueGamma() {
double gammaCall = PRICER.gamma(CALL_OTM, RATES_PROVIDER, VOLS);
CurrencyAmount pvGammaCall = PRICER.presentValueGamma(CALL_OTM, RATES_PROVIDER, VOLS);
double gammaPut = PRICER.gamma(PUT_ITM, RATES_PROVIDER, VOLS);
CurrencyAmount pvGammaPut = PRICER.presentValueGamma(PUT_ITM, RATES_PROVIDER, VOLS);
double timeToExpiry = VOLS.relativeTime(EXPIRY);
double dfDom = RATES_PROVIDER.discountFactor(USD, PAYMENT_DATE);
double dfFor = RATES_PROVIDER.discountFactor(EUR, PAYMENT_DATE);
double forward = PRICER.getDiscountingFxSingleProductPricer().forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER)
.fxRate(CURRENCY_PAIR);
double vol = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_HIGH, forward);
double expectedGamma = dfFor * dfFor / dfDom *
BlackFormulaRepository.gamma(forward, STRIKE_RATE_HIGH, timeToExpiry, vol);
double expectedPvGamma = -NOTIONAL * dfFor * dfFor / dfDom *
BlackFormulaRepository.gamma(forward, STRIKE_RATE_HIGH, timeToExpiry, vol);
assertEquals(gammaCall, expectedGamma, TOL);
assertEquals(pvGammaCall.getCurrency(), USD);
assertEquals(pvGammaCall.getAmount(), expectedPvGamma, NOTIONAL * TOL);
assertEquals(gammaPut, expectedGamma, TOL);
assertEquals(pvGammaPut.getCurrency(), USD);
assertEquals(pvGammaPut.getAmount(), -expectedPvGamma, NOTIONAL * TOL);
}
public void test_gamma_presentValueGamma_atExpiry() {
double gamma = PRICER.gamma(PUT_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyAmount pvGamma = PRICER.presentValueGamma(PUT_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(gamma, 0d, TOL);
assertEquals(pvGamma.getAmount(), 0d, NOTIONAL * TOL);
}
public void test_gamma_presentValueGamma_afterExpiry() {
double gamma = PRICER.gamma(CALL_ITM, RATES_PROVIDER_AFTER, VOLS_AFTER);
CurrencyAmount pvGamma = PRICER.presentValueGamma(CALL_ITM, RATES_PROVIDER_AFTER, VOLS_AFTER);
assertEquals(gamma, 0d, TOL);
assertEquals(pvGamma.getAmount(), 0d, NOTIONAL * TOL);
}
//-------------------------------------------------------------------------
public void test_vega_presentValueVega() {
double vegaCall = PRICER.vega(CALL_OTM, RATES_PROVIDER, VOLS);
CurrencyAmount pvVegaCall = PRICER.presentValueVega(CALL_OTM, RATES_PROVIDER, VOLS);
double vegaPut = PRICER.vega(PUT_ITM, RATES_PROVIDER, VOLS);
CurrencyAmount pvVegaPut = PRICER.presentValueVega(PUT_ITM, RATES_PROVIDER, VOLS);
double timeToExpiry = VOLS.relativeTime(EXPIRY);
double dfDom = RATES_PROVIDER.discountFactor(USD, PAYMENT_DATE);
double forward = PRICER.getDiscountingFxSingleProductPricer().forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER)
.fxRate(CURRENCY_PAIR);
double vol = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_HIGH, forward);
double expectedVega = dfDom * BlackFormulaRepository.vega(forward, STRIKE_RATE_HIGH, timeToExpiry, vol);
double expectedPvVega = -NOTIONAL * dfDom *
BlackFormulaRepository.vega(forward, STRIKE_RATE_HIGH, timeToExpiry, vol);
assertEquals(vegaCall, expectedVega, TOL);
assertEquals(pvVegaCall.getCurrency(), USD);
assertEquals(pvVegaCall.getAmount(), expectedPvVega, NOTIONAL * TOL);
assertEquals(vegaPut, expectedVega, TOL);
assertEquals(pvVegaPut.getCurrency(), USD);
assertEquals(pvVegaPut.getAmount(), -expectedPvVega, NOTIONAL * TOL);
}
public void test_vega_presentValueVega_atExpiry() {
double vega = PRICER.vega(PUT_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyAmount pvVega = PRICER.presentValueVega(PUT_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(vega, 0d, TOL);
assertEquals(pvVega.getAmount(), 0d, NOTIONAL * TOL);
}
public void test_vega_presentValueVega_afterExpiry() {
double vega = PRICER.vega(CALL_ITM, RATES_PROVIDER_AFTER, VOLS_AFTER);
CurrencyAmount pvVega = PRICER.presentValueVega(CALL_ITM, RATES_PROVIDER_AFTER, VOLS_AFTER);
assertEquals(vega, 0d, TOL);
assertEquals(pvVega.getAmount(), 0d, NOTIONAL * TOL);
}
//-------------------------------------------------------------------------
public void test_presentValueSensitivityBlackVolatility() {
FxOptionSensitivity computedCall = (FxOptionSensitivity)
PRICER.presentValueSensitivityModelParamsVolatility(CALL_OTM, RATES_PROVIDER, VOLS);
FxOptionSensitivity computedPut = (FxOptionSensitivity)
PRICER.presentValueSensitivityModelParamsVolatility(PUT_ITM, RATES_PROVIDER, VOLS);
double timeToExpiry = VOLS.relativeTime(EXPIRY);
double df = RATES_PROVIDER.discountFactor(USD, PAYMENT_DATE);
double forward = PRICER.getDiscountingFxSingleProductPricer().forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER)
.fxRate(CURRENCY_PAIR);
double vol = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_HIGH, forward);
FxOptionSensitivity expected = FxOptionSensitivity.of(
VOLS.getName(), CURRENCY_PAIR, timeToExpiry, STRIKE_RATE_HIGH, forward, USD,
-NOTIONAL * df * BlackFormulaRepository.vega(forward, STRIKE_RATE_HIGH, timeToExpiry, vol));
assertTrue(computedCall.build().equalWithTolerance(expected.build(), NOTIONAL * TOL));
assertTrue(computedPut.build().equalWithTolerance(expected.build().multipliedBy(-1d), NOTIONAL * TOL));
}
public void test_presentValueSensitivityBlackVolatility_atExpiry() {
PointSensitivityBuilder point =
PRICER.presentValueSensitivityModelParamsVolatility(PUT_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(point, PointSensitivityBuilder.none());
}
public void test_presentValueSensitivityBlackVolatility_afterExpiry() {
PointSensitivityBuilder point =
PRICER.presentValueSensitivityModelParamsVolatility(CALL_ITM, RATES_PROVIDER_AFTER, VOLS_AFTER);
assertEquals(point, PointSensitivityBuilder.none());
}
//-------------------------------------------------------------------------
public void test_theta_presentValueTheta() {
double theta = PRICER.theta(CALL_OTM, RATES_PROVIDER, VOLS);
CurrencyAmount pvTheta = PRICER.presentValueTheta(CALL_OTM, RATES_PROVIDER, VOLS);
double timeToExpiry = VOLS.relativeTime(EXPIRY);
double dfDom = RATES_PROVIDER.discountFactor(USD, PAYMENT_DATE);
double forward = PRICER.getDiscountingFxSingleProductPricer().forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER)
.fxRate(CURRENCY_PAIR);
double vol = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_HIGH, forward);
double expectedTheta = dfDom * BlackFormulaRepository.driftlessTheta(forward, STRIKE_RATE_HIGH, timeToExpiry, vol);
assertEquals(theta, expectedTheta, TOL);
double expectedPvTheta = -NOTIONAL * dfDom *
BlackFormulaRepository.driftlessTheta(forward, STRIKE_RATE_HIGH, timeToExpiry, vol);
assertEquals(pvTheta.getCurrency(), USD);
assertEquals(pvTheta.getAmount(), expectedPvTheta, NOTIONAL * TOL);
}
public void test_theta_presentValueTheta_atExpiry() {
double theta = PRICER.theta(PUT_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
CurrencyAmount pvTheta = PRICER.presentValueTheta(PUT_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY);
assertEquals(theta, 0d, TOL);
assertEquals(pvTheta.getAmount(), 0d, NOTIONAL * TOL);
}
public void test_theta_presentValueTheta_afterExpiry() {
double theta = PRICER.theta(CALL_ITM, RATES_PROVIDER_AFTER, VOLS_AFTER);
CurrencyAmount pvTheta = PRICER.presentValueTheta(CALL_ITM, RATES_PROVIDER_AFTER, VOLS_AFTER);
assertEquals(theta, 0d, TOL);
assertEquals(pvTheta.getAmount(), 0d, NOTIONAL * TOL);
}
//-------------------------------------------------------------------------
public void test_impliedVolatility() {
double computedCall = PRICER.impliedVolatility(CALL_OTM, RATES_PROVIDER, VOLS);
double computedPut = PRICER.impliedVolatility(PUT_ITM, RATES_PROVIDER, VOLS);
double timeToExpiry = VOLS.relativeTime(EXPIRY);
double forward = PRICER.getDiscountingFxSingleProductPricer().forwardFxRate(FX_PRODUCT_HIGH, RATES_PROVIDER)
.fxRate(CURRENCY_PAIR);
double expected = SMILE_TERM.volatility(timeToExpiry, STRIKE_RATE_HIGH, forward);
assertEquals(computedCall, expected);
assertEquals(computedPut, expected);
}
public void test_impliedVolatility_atExpiry() {
assertThrowsIllegalArg(() -> PRICER.impliedVolatility(CALL_ITM, RATES_PROVIDER_EXPIRY, VOLS_EXPIRY));
}
public void test_impliedVolatility_afterExpiry() {
assertThrowsIllegalArg(() -> PRICER.impliedVolatility(CALL_ITM, RATES_PROVIDER_AFTER, VOLS_AFTER));
}
//-------------------------------------------------------------------------
public void test_currencyExposure() {
MultiCurrencyAmount computedPricer = PRICER.currencyExposure(CALL_OTM, RATES_PROVIDER, VOLS);
CurrencyAmount pv = PRICER.presentValue(CALL_OTM, RATES_PROVIDER, VOLS);
PointSensitivities point = PRICER.presentValueSensitivityRatesStickyStrike(CALL_OTM, RATES_PROVIDER, VOLS);
MultiCurrencyAmount computedPoint = RATES_PROVIDER.currencyExposure(point).plus(pv);
assertEquals(computedPricer.getAmount(EUR).getAmount(), computedPoint.getAmount(EUR).getAmount(), NOTIONAL * TOL);
assertEquals(computedPricer.getAmount(USD).getAmount(), computedPoint.getAmount(USD).getAmount(), NOTIONAL * TOL);
}
}