/**
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.index;
import static com.opengamma.strata.basics.date.DayCounts.ACT_365F;
import static com.opengamma.strata.basics.index.IborIndices.GBP_LIBOR_2M;
import static com.opengamma.strata.collect.TestHelper.date;
import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.LINEAR;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
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 org.testng.annotations.Test;
import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.market.model.MoneynessType;
import com.opengamma.strata.market.sensitivity.PointSensitivities;
import com.opengamma.strata.market.surface.InterpolatedNodalSurface;
import com.opengamma.strata.market.surface.Surfaces;
import com.opengamma.strata.market.surface.interpolator.GridSurfaceInterpolator;
import com.opengamma.strata.market.surface.interpolator.SurfaceInterpolator;
import com.opengamma.strata.pricer.impl.option.EuropeanVanillaOption;
import com.opengamma.strata.pricer.impl.option.NormalFunctionData;
import com.opengamma.strata.pricer.impl.option.NormalPriceFunction;
import com.opengamma.strata.pricer.rate.IborIndexRates;
import com.opengamma.strata.pricer.rate.SimpleRatesProvider;
import com.opengamma.strata.product.index.ResolvedIborFutureOption;
/**
* Tests {@link NormalIborFutureOptionMarginedProductPricer}
*/
@Test
public class NormalIborFutureOptionMarginedProductPricerTest {
private static final ReferenceData REF_DATA = ReferenceData.standard();
private static final SurfaceInterpolator INTERPOLATOR_2D = GridSurfaceInterpolator.of(LINEAR, LINEAR);
private static final DoubleArray TIMES =
DoubleArray.of(0.25, 0.25, 0.25, 0.25, 0.50, 0.50, 0.50, 0.50, 1.00, 1.00, 1.00, 1.00);
private static final DoubleArray MONEYNESS_PRICES =
DoubleArray.of(-0.02, -0.01, 0.00, 0.01, -0.02, -0.01, 0.00, 0.01, -0.02, -0.01, 0.00, 0.01);
private static final DoubleArray NORMAL_VOL = DoubleArray.of(
0.01, 0.011, 0.012, 0.010,
0.011, 0.012, 0.013, 0.012,
0.012, 0.013, 0.014, 0.014);
private static final InterpolatedNodalSurface PARAMETERS_PRICE = InterpolatedNodalSurface.of(
Surfaces.normalVolatilityByExpirySimpleMoneyness("Test", ACT_365F, MoneynessType.PRICE),
TIMES,
MONEYNESS_PRICES,
NORMAL_VOL,
INTERPOLATOR_2D);
private static final LocalDate VAL_DATE = date(2015, 2, 17);
private static final LocalTime VAL_TIME = LocalTime.of(13, 45);
private static final ZoneId LONDON_ZONE = ZoneId.of("Europe/London");
private static final NormalIborFutureOptionVolatilities VOL_SIMPLE_MONEY_PRICE =
NormalIborFutureOptionExpirySimpleMoneynessVolatilities.of(
GBP_LIBOR_2M, VAL_DATE.atTime(VAL_TIME).atZone(LONDON_ZONE), PARAMETERS_PRICE);
private static final ResolvedIborFutureOption OPTION = IborFutureDummyData.IBOR_FUTURE_OPTION_2.resolve(REF_DATA);
private static final double RATE = 0.015;
private static final NormalPriceFunction NORMAL_FUNCTION = new NormalPriceFunction();
private static final DiscountingIborFutureProductPricer FUTURE_PRICER = DiscountingIborFutureProductPricer.DEFAULT;
private static final NormalIborFutureOptionMarginedProductPricer OPTION_PRICER =
new NormalIborFutureOptionMarginedProductPricer(FUTURE_PRICER);
private static final double TOLERANCE_PRICE = 1.0E-10;
private static final double TOLERANCE_PRICE_DELTA = 1.0E-8;
// ---------- price ----------
public void price_from_future_price() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
double futurePrice = 0.9875;
double strike = OPTION.getStrikePrice();
double timeToExpiry = ACT_365F.relativeYearFraction(VAL_DATE, OPTION.getExpiryDate());
double priceSimpleMoneyness = strike - futurePrice;
double normalVol = PARAMETERS_PRICE.zValue(timeToExpiry, priceSimpleMoneyness);
EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, timeToExpiry, OPTION.getPutCall());
NormalFunctionData normalPoint = NormalFunctionData.of(futurePrice, 1.0, normalVol);
double optionPriceExpected = NORMAL_FUNCTION.getPriceFunction(option).apply(normalPoint);
double optionPriceComputed = OPTION_PRICER.price(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice);
assertEquals(optionPriceComputed, optionPriceExpected, TOLERANCE_PRICE);
}
public void price_from_env() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
double futurePrice = 1.0 - RATE;
double optionPriceExpected = OPTION_PRICER.price(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice);
double optionPriceComputed = OPTION_PRICER.price(OPTION, prov, VOL_SIMPLE_MONEY_PRICE);
assertEquals(optionPriceComputed, optionPriceExpected, TOLERANCE_PRICE);
}
// ---------- delta ----------
public void delta_from_future_price() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
double futurePrice = 0.9875;
double strike = OPTION.getStrikePrice();
double timeToExpiry = ACT_365F.relativeYearFraction(VAL_DATE, OPTION.getExpiryDate());
double priceSimpleMoneyness = strike - futurePrice;
double normalVol = PARAMETERS_PRICE.zValue(timeToExpiry, priceSimpleMoneyness);
EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, timeToExpiry, OPTION.getPutCall());
NormalFunctionData normalPoint = NormalFunctionData.of(futurePrice, 1.0, normalVol);
double optionDeltaExpected = NORMAL_FUNCTION.getDelta(option, normalPoint);
double optionDeltaComputed =
OPTION_PRICER.deltaStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice);
assertEquals(optionDeltaComputed, optionDeltaExpected, TOLERANCE_PRICE);
}
public void delta_from_env() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
double futurePrice = 1.0 - RATE;
double optionDeltaExpected =
OPTION_PRICER.deltaStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice);
double optionDeltaComputed = OPTION_PRICER.deltaStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE);
assertEquals(optionDeltaComputed, optionDeltaExpected, TOLERANCE_PRICE);
}
// ---------- priceSensitivity ----------
public void priceSensitivityStickyStrike_from_future_price() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
double futurePrice = 0.9875;
PointSensitivities futurePriceSensitivity =
FUTURE_PRICER.priceSensitivity(OPTION.getUnderlyingFuture(), prov);
double delta = OPTION_PRICER.deltaStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice);
PointSensitivities optionPriceSensitivityExpected = futurePriceSensitivity.multipliedBy(delta);
PointSensitivities optionPriceSensitivityComputed =
OPTION_PRICER.priceSensitivityRatesStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice);
assertTrue(optionPriceSensitivityExpected.equalWithTolerance(optionPriceSensitivityComputed, TOLERANCE_PRICE_DELTA));
}
public void priceSensitivityStickyStrike_from_env() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
PointSensitivities futurePriceSensitivity = OPTION_PRICER.getFuturePricer()
.priceSensitivity(OPTION.getUnderlyingFuture(), prov);
double delta = OPTION_PRICER.deltaStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE);
PointSensitivities optionPriceSensitivityExpected = futurePriceSensitivity.multipliedBy(delta);
PointSensitivities optionPriceSensitivityComputed =
OPTION_PRICER.priceSensitivityRatesStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE);
assertTrue(optionPriceSensitivityExpected.equalWithTolerance(optionPriceSensitivityComputed, TOLERANCE_PRICE_DELTA));
}
// ---------- priceSensitivityNormalVolatility ----------
public void priceSensitivityNormalVolatility_from_future_price() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
double futurePrice = 0.9875;
double strike = OPTION.getStrikePrice();
double timeToExpiry = ACT_365F.relativeYearFraction(VAL_DATE, OPTION.getExpiryDate());
double priceSimpleMoneyness = strike - futurePrice;
double normalVol = PARAMETERS_PRICE.zValue(timeToExpiry, priceSimpleMoneyness);
EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, timeToExpiry, OPTION.getPutCall());
NormalFunctionData normalPoint = NormalFunctionData.of(futurePrice, 1.0, normalVol);
double optionVegaExpected = NORMAL_FUNCTION.getVega(option, normalPoint);
IborFutureOptionSensitivity optionVegaComputed = OPTION_PRICER.priceSensitivityModelParamsVolatility(
OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice);
assertEquals(optionVegaComputed.getSensitivity(), optionVegaExpected, TOLERANCE_PRICE);
assertEquals(optionVegaComputed.getExpiry(), timeToExpiry);
assertEquals(optionVegaComputed.getFixingDate(), OPTION.getUnderlyingFuture().getIborRate().getObservation().getFixingDate());
assertEquals(optionVegaComputed.getStrikePrice(), OPTION.getStrikePrice());
assertEquals(optionVegaComputed.getFuturePrice(), futurePrice);
}
public void priceSensitivityNormalVolatility_from_env() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
double futurePrice = 1.0 - RATE;
IborFutureOptionSensitivity optionVegaExpected = OPTION_PRICER.priceSensitivityModelParamsVolatility(
OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice);
IborFutureOptionSensitivity optionVegaComputed = OPTION_PRICER.priceSensitivityModelParamsVolatility(
OPTION, prov, VOL_SIMPLE_MONEY_PRICE);
assertTrue(optionVegaExpected.compareKey(optionVegaComputed) == 0);
assertEquals(optionVegaComputed.getSensitivity(), optionVegaExpected.getSensitivity(), TOLERANCE_PRICE_DELTA);
}
}