/**
* 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.basics.currency.CurrencyAmount;
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.rate.IborIndexRates;
import com.opengamma.strata.pricer.rate.SimpleRatesProvider;
import com.opengamma.strata.product.TradeInfo;
import com.opengamma.strata.product.index.ResolvedIborFutureOption;
import com.opengamma.strata.product.index.ResolvedIborFutureOptionTrade;
/**
* Tests {@link NormalIborFutureOptionMarginedTradePricer}
*/
@Test
public class NormalIborFutureOptionMarginedTradePricerTest {
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.5, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0);
private static final DoubleArray MONEYNESS_PRICES =
DoubleArray.of(-0.02, -0.01, 0.0, 0.01, -0.02, -0.01, 0.0, 0.01, -0.02, -0.01, 0.0, 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 LocalDate TRADE_DATE = date(2015, 2, 16);
private static final long OPTION_QUANTITY = 12345;
private static final double TRADE_PRICE = 0.0100;
private static final ResolvedIborFutureOptionTrade FUTURE_OPTION_TRADE_TD = ResolvedIborFutureOptionTrade.builder()
.info(TradeInfo.builder()
.tradeDate(VAL_DATE)
.build())
.product(OPTION)
.quantity(OPTION_QUANTITY)
.price(TRADE_PRICE)
.build();
private static final ResolvedIborFutureOptionTrade FUTURE_OPTION_TRADE = ResolvedIborFutureOptionTrade.builder()
.info(TradeInfo.builder()
.tradeDate(TRADE_DATE)
.build())
.product(OPTION)
.quantity(OPTION_QUANTITY)
.price(TRADE_PRICE)
.build();
private static final double RATE = 0.015;
private static final DiscountingIborFutureProductPricer FUTURE_PRICER = DiscountingIborFutureProductPricer.DEFAULT;
private static final NormalIborFutureOptionMarginedProductPricer OPTION_PRODUCT_PRICER =
new NormalIborFutureOptionMarginedProductPricer(FUTURE_PRICER);
private static final NormalIborFutureOptionMarginedTradePricer OPTION_TRADE_PRICER =
new NormalIborFutureOptionMarginedTradePricer(OPTION_PRODUCT_PRICER);
private static final double TOLERANCE_PV = 1.0E-2;
private static final double TOLERANCE_PV_DELTA = 1.0E-1;
// ---------- present value ----------
public void presentValue_from_option_price_trade_date() {
double optionPrice = 0.0125;
double lastClosingPrice = 0.0150;
CurrencyAmount pvComputed = OPTION_TRADE_PRICER
.presentValue(FUTURE_OPTION_TRADE_TD, VAL_DATE, optionPrice, lastClosingPrice);
double pvExpected = (OPTION_PRODUCT_PRICER.marginIndex(OPTION, optionPrice) -
OPTION_PRODUCT_PRICER.marginIndex(OPTION, TRADE_PRICE)) * OPTION_QUANTITY;
assertEquals(pvComputed.getAmount(), pvExpected, TOLERANCE_PV);
}
public void presentValue_from_future_price() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider(VAL_DATE);
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
double futurePrice = 0.9875;
double lastClosingPrice = 0.0150;
CurrencyAmount pvComputed = OPTION_TRADE_PRICER
.presentValue(FUTURE_OPTION_TRADE, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice, lastClosingPrice);
double optionPrice =
OPTION_PRODUCT_PRICER.price(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice);
double pvExpected = (OPTION_PRODUCT_PRICER.marginIndex(OPTION, optionPrice) -
OPTION_PRODUCT_PRICER.marginIndex(OPTION, lastClosingPrice)) * OPTION_QUANTITY;
assertEquals(pvComputed.getAmount(), pvExpected, TOLERANCE_PV);
}
public void presentValue_from_env() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider(VAL_DATE);
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
double lastClosingPrice = 0.0150;
CurrencyAmount pvComputed = OPTION_TRADE_PRICER
.presentValue(FUTURE_OPTION_TRADE, prov, VOL_SIMPLE_MONEY_PRICE, lastClosingPrice);
double optionPrice =
OPTION_PRODUCT_PRICER.price(OPTION, prov, VOL_SIMPLE_MONEY_PRICE);
double pvExpected = (OPTION_PRODUCT_PRICER.marginIndex(OPTION, optionPrice) -
OPTION_PRODUCT_PRICER.marginIndex(OPTION, lastClosingPrice)) * OPTION_QUANTITY;
assertEquals(pvComputed.getAmount(), pvExpected, TOLERANCE_PV);
}
// ---------- present value sensitivity ----------
public void presentValueSensitivity_from_env() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
PointSensitivities psProduct =
OPTION_PRODUCT_PRICER.priceSensitivityRatesStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE);
PointSensitivities psExpected = psProduct
.multipliedBy(OPTION_PRODUCT_PRICER.marginIndex(OPTION, 1) * OPTION_QUANTITY);
PointSensitivities psComputed = OPTION_TRADE_PRICER
.presentValueSensitivityRates(FUTURE_OPTION_TRADE, prov, VOL_SIMPLE_MONEY_PRICE);
assertTrue(psComputed.equalWithTolerance(psExpected, TOLERANCE_PV_DELTA));
}
// ---------- present value normal vol sensitivity ----------
public void presentvalue_normalVolSensitivity_from_env() {
IborIndexRates mockIbor = mock(IborIndexRates.class);
SimpleRatesProvider prov = new SimpleRatesProvider();
prov.setIborRates(mockIbor);
when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE);
IborFutureOptionSensitivity psProduct =
OPTION_PRODUCT_PRICER.priceSensitivityModelParamsVolatility(OPTION, prov, VOL_SIMPLE_MONEY_PRICE);
IborFutureOptionSensitivity psExpected = psProduct.withSensitivity(
psProduct.getSensitivity() * OPTION_PRODUCT_PRICER.marginIndex(OPTION, 1) * OPTION_QUANTITY);
IborFutureOptionSensitivity psComputed = OPTION_TRADE_PRICER
.presentValueSensitivityModelParamsVolatility(FUTURE_OPTION_TRADE, prov, VOL_SIMPLE_MONEY_PRICE);
assertTrue(psExpected.compareKey(psComputed) == 0);
assertEquals(psComputed.getSensitivity(), psExpected.getSensitivity(), TOLERANCE_PV_DELTA);
}
}