/**
* 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.currency.Currency.EUR;
import static com.opengamma.strata.basics.date.DayCounts.ACT_365F;
import static com.opengamma.strata.basics.index.IborIndices.EUR_EURIBOR_3M;
import static com.opengamma.strata.basics.index.IborIndices.EUR_EURIBOR_6M;
import static com.opengamma.strata.collect.TestHelper.coverBeanEquals;
import static com.opengamma.strata.collect.TestHelper.coverImmutableBean;
import static com.opengamma.strata.collect.TestHelper.date;
import static com.opengamma.strata.collect.TestHelper.dateUtc;
import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.LINEAR;
import static org.testng.Assert.assertEquals;
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.collect.array.DoubleArray;
import com.opengamma.strata.market.model.MoneynessType;
import com.opengamma.strata.market.param.CurrencyParameterSensitivities;
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;
/**
* Tests {@link NormalIborFutureOptionExpirySimpleMoneynessVolatilities}
*/
@Test
public class NormalIborFutureOptionExpirySimpleMoneynessVolatilitiesTest {
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, 1, 1, 1);
private static final DoubleArray MONEYNESS_PRICES =
DoubleArray.of(-0.02, -0.01, 0, 0.01, -0.02, -0.01, 0, 0.01, -0.02, -0.01, 0, 0.01);
private static final DoubleArray NORMAL_VOL_PRICES =
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 DoubleArray MONEYNESS_RATES =
DoubleArray.of(-0.01, 0, 0.01, 0.02, -0.01, 0, 0.01, 0.02, -0.01, 0, 0.01, 0.02);
private static final DoubleArray NORMAL_VOL_RATES =
DoubleArray.of(0.010, 0.012, 0.011, 0.01, 0.012, 0.013, 0.012, 0.011, 0.014, 0.014, 0.013, 0.012);
private static final InterpolatedNodalSurface PARAMETERS_PRICE = InterpolatedNodalSurface.of(
Surfaces.normalVolatilityByExpirySimpleMoneyness("Price", ACT_365F, MoneynessType.PRICE),
TIMES,
MONEYNESS_PRICES,
NORMAL_VOL_PRICES,
INTERPOLATOR_2D);
private static final InterpolatedNodalSurface PARAMETERS_RATE = InterpolatedNodalSurface.of(
Surfaces.normalVolatilityByExpirySimpleMoneyness("Rate", ACT_365F, MoneynessType.RATES),
TIMES,
MONEYNESS_RATES,
NORMAL_VOL_RATES,
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 ZonedDateTime VAL_DATE_TIME = VAL_DATE.atTime(VAL_TIME).atZone(LONDON_ZONE);
private static final NormalIborFutureOptionExpirySimpleMoneynessVolatilities VOL_SIMPLE_MONEY_PRICE =
NormalIborFutureOptionExpirySimpleMoneynessVolatilities.of(EUR_EURIBOR_3M, VAL_DATE_TIME, PARAMETERS_PRICE);
private static final NormalIborFutureOptionExpirySimpleMoneynessVolatilities VOL_SIMPLE_MONEY_RATE =
NormalIborFutureOptionExpirySimpleMoneynessVolatilities.of(EUR_EURIBOR_3M, VAL_DATE_TIME, PARAMETERS_RATE);
private static final ZonedDateTime[] TEST_EXPIRY = new ZonedDateTime[] {
dateUtc(2015, 2, 17), dateUtc(2015, 5, 17), dateUtc(2015, 6, 17), dateUtc(2017, 2, 17)};
private static final int NB_TEST = TEST_EXPIRY.length;
private static final LocalDate[] TEST_FIXING =
new LocalDate[] {date(2015, 2, 17), date(2015, 5, 17), date(2015, 5, 17), date(2015, 5, 17)};
private static final double[] TEST_STRIKE_PRICE = {0.985, 0.985, 0.985, 0.985};
private static final double[] TEST_FUTURE_PRICE = {0.98, 0.985, 1.00, 1.01};
private static final double TOLERANCE_VOL = 1.0E-10;
private static final double TOLERANCE_DELTA = 1.0E-2;
//-------------------------------------------------------------------------
public void test_basics() {
assertEquals(VOL_SIMPLE_MONEY_PRICE.getValuationDate(), VAL_DATE_TIME.toLocalDate());
assertEquals(VOL_SIMPLE_MONEY_PRICE.getValuationDateTime(), VAL_DATE_TIME);
assertEquals(VOL_SIMPLE_MONEY_PRICE.getIndex(), EUR_EURIBOR_3M);
assertEquals(VOL_SIMPLE_MONEY_PRICE.getName(), IborFutureOptionVolatilitiesName.of("Price"));
}
public void test_volatility_price() {
for (int i = 0; i < NB_TEST; i++) {
double timeToExpiry = VOL_SIMPLE_MONEY_RATE.relativeTime(TEST_EXPIRY[i]);
double volExpected = PARAMETERS_PRICE.zValue(timeToExpiry, TEST_STRIKE_PRICE[i] - TEST_FUTURE_PRICE[i]);
double volComputed = VOL_SIMPLE_MONEY_PRICE.volatility(
TEST_EXPIRY[i], TEST_FIXING[i], TEST_STRIKE_PRICE[i], TEST_FUTURE_PRICE[i]);
assertEquals(volComputed, volExpected, TOLERANCE_VOL);
}
}
public void test_volatility_rate() {
for (int i = 0; i < NB_TEST; i++) {
double timeToExpiry = VOL_SIMPLE_MONEY_RATE.relativeTime(TEST_EXPIRY[i]);
double volExpected = PARAMETERS_RATE.zValue(timeToExpiry, TEST_FUTURE_PRICE[i] - TEST_STRIKE_PRICE[i]);
double volComputed = VOL_SIMPLE_MONEY_RATE.volatility(
TEST_EXPIRY[i], TEST_FIXING[i], TEST_STRIKE_PRICE[i], TEST_FUTURE_PRICE[i]);
assertEquals(volComputed, volExpected, TOLERANCE_VOL);
}
}
//-------------------------------------------------------------------------
public void test_parameterSensitivity() {
double expiry = ACT_365F.relativeYearFraction(VAL_DATE, LocalDate.of(2015, 8, 14));
LocalDate fixing = LocalDate.of(2016, 9, 14);
double strikePrice = 1.0025;
double futurePrice = 0.9975;
double sensitivity = 123456;
IborFutureOptionSensitivity point = IborFutureOptionSensitivity.of(
VOL_SIMPLE_MONEY_RATE.getName(), expiry, fixing, strikePrice, futurePrice, EUR, sensitivity);
CurrencyParameterSensitivities ps = VOL_SIMPLE_MONEY_RATE.parameterSensitivity(point);
double shift = 1.0E-6;
double v0 = VOL_SIMPLE_MONEY_RATE.volatility(expiry, fixing, strikePrice, futurePrice);
for (int i = 0; i < NORMAL_VOL_RATES.size(); i++) {
DoubleArray v = NORMAL_VOL_RATES.with(i, NORMAL_VOL_RATES.get(i) + shift);
InterpolatedNodalSurface param = InterpolatedNodalSurface.of(
Surfaces.normalVolatilityByExpirySimpleMoneyness("Rate", ACT_365F, MoneynessType.RATES),
TIMES,
MONEYNESS_RATES,
v,
INTERPOLATOR_2D);
NormalIborFutureOptionExpirySimpleMoneynessVolatilities vol =
NormalIborFutureOptionExpirySimpleMoneynessVolatilities.of(EUR_EURIBOR_3M, VAL_DATE_TIME, param);
double vP = vol.volatility(expiry, fixing, strikePrice, futurePrice);
double s = ps.getSensitivity(PARAMETERS_RATE.getName(), EUR).getSensitivity().get(i);
assertEquals(s, (vP - v0) / shift * sensitivity, TOLERANCE_DELTA);
}
}
//-------------------------------------------------------------------------
public void coverage() {
NormalIborFutureOptionExpirySimpleMoneynessVolatilities test =
NormalIborFutureOptionExpirySimpleMoneynessVolatilities.of(EUR_EURIBOR_3M, VAL_DATE_TIME, PARAMETERS_RATE);
coverImmutableBean(test);
NormalIborFutureOptionExpirySimpleMoneynessVolatilities test2 =
NormalIborFutureOptionExpirySimpleMoneynessVolatilities.of(
EUR_EURIBOR_6M, VAL_DATE_TIME.plusDays(1), PARAMETERS_PRICE);
coverBeanEquals(test, test2);
}
}