/**
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.capfloor;
import static com.opengamma.strata.basics.currency.Currency.EUR;
import static com.opengamma.strata.basics.date.DayCounts.ACT_ACT_ISDA;
import static com.opengamma.strata.basics.index.IborIndices.EUR_EURIBOR_3M;
import static com.opengamma.strata.collect.TestHelper.coverBeanEquals;
import static com.opengamma.strata.collect.TestHelper.coverImmutableBean;
import static com.opengamma.strata.collect.TestHelper.dateUtc;
import static com.opengamma.strata.market.model.SabrParameterType.ALPHA;
import static com.opengamma.strata.market.model.SabrParameterType.BETA;
import static com.opengamma.strata.market.model.SabrParameterType.NU;
import static com.opengamma.strata.market.model.SabrParameterType.RHO;
import static com.opengamma.strata.market.model.SabrParameterType.SHIFT;
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 java.util.Optional;
import org.testng.annotations.Test;
import com.opengamma.strata.basics.index.IborIndices;
import com.opengamma.strata.basics.value.ValueDerivatives;
import com.opengamma.strata.collect.DoubleArrayMath;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.market.param.CurrencyParameterSensitivities;
import com.opengamma.strata.market.param.CurrencyParameterSensitivity;
import com.opengamma.strata.market.param.UnitParameterSensitivity;
import com.opengamma.strata.market.sensitivity.PointSensitivities;
import com.opengamma.strata.market.surface.SurfaceName;
import com.opengamma.strata.pricer.model.SabrParameters;
/**
* Test {@link SabrParametersIborCapletFloorletVolatilities}.
*/
@Test
public class SabrParametersIborCapletFloorletVolatilitiesTest {
private static final LocalDate DATE = LocalDate.of(2014, 1, 3);
private static final LocalTime TIME = LocalTime.of(10, 0);
private static final ZoneId ZONE = ZoneId.of("Europe/London");
private static final ZonedDateTime DATE_TIME = DATE.atTime(TIME).atZone(ZONE);
private static final SabrParameters PARAM = IborCapletFloorletSabrRateVolatilityDataSet.SABR_PARAM;
private static final ZonedDateTime[] TEST_OPTION_EXPIRY = new ZonedDateTime[] {
dateUtc(2014, 1, 3), dateUtc(2015, 1, 3), dateUtc(2016, 4, 21), dateUtc(2017, 1, 3)};
private static final int NB_TEST = TEST_OPTION_EXPIRY.length;
private static final double TEST_FORWARD = 0.025;
private static final double[] TEST_STRIKE = new double[] {0.02, 0.025, 0.03};
private static final int NB_STRIKE = TEST_STRIKE.length;
static final IborCapletFloorletVolatilitiesName NAME = IborCapletFloorletSabrRateVolatilityDataSet.NAME;
static final IborCapletFloorletVolatilitiesName NAME2 = IborCapletFloorletVolatilitiesName.of("Test-SABR2");
private static final double TOLERANCE_VOL = 1.0E-10;
public void test_of() {
SabrParametersIborCapletFloorletVolatilities test =
SabrParametersIborCapletFloorletVolatilities.of(NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM);
assertEquals(test.getIndex(), EUR_EURIBOR_3M);
assertEquals(test.getDayCount(), ACT_ACT_ISDA);
assertEquals(test.getParameters(), PARAM);
assertEquals(test.getValuationDateTime(), DATE_TIME);
assertEquals(test.getParameterCount(), PARAM.getParameterCount());
int nParams = PARAM.getParameterCount();
double newValue = 152d;
for (int i = 0; i < nParams; ++i) {
assertEquals(test.getParameter(i), PARAM.getParameter(i));
assertEquals(test.getParameterMetadata(i), PARAM.getParameterMetadata(i));
assertEquals(test.withParameter(i, newValue), SabrParametersIborCapletFloorletVolatilities.of(
NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM.withParameter(i, newValue)));
assertEquals(test.withPerturbation((n, v, m) -> 2d * v), SabrParametersIborCapletFloorletVolatilities.of(
NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM.withPerturbation((n, v, m) -> 2d * v)));
}
}
public void test_findData() {
SabrParametersIborCapletFloorletVolatilities test =
SabrParametersIborCapletFloorletVolatilities.of(NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM);
assertEquals(test.findData(PARAM.getAlphaCurve().getName()), Optional.of(PARAM.getAlphaCurve()));
assertEquals(test.findData(PARAM.getBetaCurve().getName()), Optional.of(PARAM.getBetaCurve()));
assertEquals(test.findData(PARAM.getRhoCurve().getName()), Optional.of(PARAM.getRhoCurve()));
assertEquals(test.findData(PARAM.getNuCurve().getName()), Optional.of(PARAM.getNuCurve()));
assertEquals(test.findData(PARAM.getShiftCurve().getName()), Optional.of(PARAM.getShiftCurve()));
assertEquals(test.findData(SurfaceName.of("Rubbish")), Optional.empty());
}
public void test_calc() {
SabrParametersIborCapletFloorletVolatilities test =
SabrParametersIborCapletFloorletVolatilities.of(NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM);
assertEquals(test.alpha(1.56), PARAM.alpha(1.56));
assertEquals(test.beta(1.56), PARAM.beta(1.56));
assertEquals(test.rho(1.56), PARAM.rho(1.56));
assertEquals(test.nu(1.56), PARAM.nu(1.56));
assertEquals(test.shift(1.56), PARAM.shift(1.56));
}
public void test_relativeTime() {
SabrParametersIborCapletFloorletVolatilities prov =
SabrParametersIborCapletFloorletVolatilities.of(NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM);
double test1 = prov.relativeTime(DATE_TIME);
assertEquals(test1, 0d);
double test2 = prov.relativeTime(DATE_TIME.plusYears(2));
double test3 = prov.relativeTime(DATE_TIME.minusYears(2));
assertEquals(test2, -test3, 1e-2);
}
public void test_volatility() {
SabrParametersIborCapletFloorletVolatilities prov =
SabrParametersIborCapletFloorletVolatilities.of(NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM);
for (int i = 0; i < NB_TEST; i++) {
for (int j = 0; j < NB_STRIKE; ++j) {
double expiryTime = prov.relativeTime(TEST_OPTION_EXPIRY[i]);
double volExpected = PARAM.volatility(expiryTime, TEST_STRIKE[j], TEST_FORWARD);
double volComputed = prov.volatility(TEST_OPTION_EXPIRY[i], TEST_STRIKE[j], TEST_FORWARD);
assertEquals(volComputed, volExpected, TOLERANCE_VOL);
ValueDerivatives volAdjExpected = PARAM.volatilityAdjoint(expiryTime, TEST_STRIKE[j], TEST_FORWARD);
ValueDerivatives volAdjComputed = prov.volatilityAdjoint(expiryTime, TEST_STRIKE[j], TEST_FORWARD);
assertEquals(volAdjComputed.getValue(), volExpected, TOLERANCE_VOL);
assertTrue(DoubleArrayMath.fuzzyEquals(
volAdjComputed.getDerivatives().toArray(), volAdjExpected.getDerivatives().toArray(), TOLERANCE_VOL));
}
}
}
public void test_parameterSensitivity() {
double alphaSensi = 2.24, betaSensi = 3.45, rhoSensi = -2.12, nuSensi = -0.56, shiftSensi = 2.5;
SabrParametersIborCapletFloorletVolatilities prov =
SabrParametersIborCapletFloorletVolatilities.of(NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM);
for (int i = 0; i < NB_TEST; i++) {
double expiryTime = prov.relativeTime(TEST_OPTION_EXPIRY[i]);
PointSensitivities point = PointSensitivities.of(
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime, ALPHA, EUR, alphaSensi),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime, BETA, EUR, betaSensi),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime, RHO, EUR, rhoSensi),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime, NU, EUR, nuSensi),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime, SHIFT, EUR, shiftSensi));
CurrencyParameterSensitivities sensiComputed = prov.parameterSensitivity(point);
UnitParameterSensitivity alphaSensitivities = prov.getParameters().getAlphaCurve()
.yValueParameterSensitivity(expiryTime);
UnitParameterSensitivity betaSensitivities = prov.getParameters().getBetaCurve()
.yValueParameterSensitivity(expiryTime);
UnitParameterSensitivity rhoSensitivities = prov.getParameters().getRhoCurve()
.yValueParameterSensitivity(expiryTime);
UnitParameterSensitivity nuSensitivities = prov.getParameters().getNuCurve()
.yValueParameterSensitivity(expiryTime);
UnitParameterSensitivity shiftSensitivities = prov.getParameters().getShiftCurve()
.yValueParameterSensitivity(expiryTime);
CurrencyParameterSensitivity alphaSensiObj = sensiComputed.getSensitivity(
IborCapletFloorletSabrRateVolatilityDataSet.META_ALPHA.getCurveName(), EUR);
CurrencyParameterSensitivity betaSensiObj = sensiComputed.getSensitivity(
IborCapletFloorletSabrRateVolatilityDataSet.META_BETA.getCurveName(), EUR);
CurrencyParameterSensitivity rhoSensiObj = sensiComputed.getSensitivity(
IborCapletFloorletSabrRateVolatilityDataSet.META_RHO.getCurveName(), EUR);
CurrencyParameterSensitivity nuSensiObj = sensiComputed.getSensitivity(
IborCapletFloorletSabrRateVolatilityDataSet.META_NU.getCurveName(), EUR);
CurrencyParameterSensitivity shiftSensiObj = sensiComputed.getSensitivity(
IborCapletFloorletSabrRateVolatilityDataSet.META_SHIFT.getCurveName(), EUR);
DoubleArray alphaNodeSensiComputed = alphaSensiObj.getSensitivity();
DoubleArray betaNodeSensiComputed = betaSensiObj.getSensitivity();
DoubleArray rhoNodeSensiComputed = rhoSensiObj.getSensitivity();
DoubleArray nuNodeSensiComputed = nuSensiObj.getSensitivity();
DoubleArray shiftNodeSensiComputed = shiftSensiObj.getSensitivity();
assertEquals(alphaSensitivities.getSensitivity().size(), alphaNodeSensiComputed.size());
assertEquals(betaSensitivities.getSensitivity().size(), betaNodeSensiComputed.size());
assertEquals(rhoSensitivities.getSensitivity().size(), rhoNodeSensiComputed.size());
assertEquals(nuSensitivities.getSensitivity().size(), nuNodeSensiComputed.size());
assertEquals(shiftSensitivities.getSensitivity().size(), shiftNodeSensiComputed.size());
for (int k = 0; k < alphaNodeSensiComputed.size(); ++k) {
assertEquals(alphaNodeSensiComputed.get(k), alphaSensitivities.getSensitivity().get(k) * alphaSensi, TOLERANCE_VOL);
}
for (int k = 0; k < betaNodeSensiComputed.size(); ++k) {
assertEquals(betaNodeSensiComputed.get(k), betaSensitivities.getSensitivity().get(k) * betaSensi, TOLERANCE_VOL);
}
for (int k = 0; k < rhoNodeSensiComputed.size(); ++k) {
assertEquals(rhoNodeSensiComputed.get(k), rhoSensitivities.getSensitivity().get(k) * rhoSensi, TOLERANCE_VOL);
}
for (int k = 0; k < nuNodeSensiComputed.size(); ++k) {
assertEquals(nuNodeSensiComputed.get(k), nuSensitivities.getSensitivity().get(k) * nuSensi, TOLERANCE_VOL);
}
for (int k = 0; k < shiftNodeSensiComputed.size(); ++k) {
assertEquals(shiftNodeSensiComputed.get(k), shiftSensitivities.getSensitivity().get(k) * shiftSensi, TOLERANCE_VOL);
}
}
}
public void test_parameterSensitivity_multi() {
double[] points1 = new double[] {2.24, 3.45, -2.12, -0.56};
double[] points2 = new double[] {-0.145, 1.01, -5.0, -11.0};
double[] points3 = new double[] {1.3, -4.32, 2.1, -7.18};
SabrParametersIborCapletFloorletVolatilities prov =
SabrParametersIborCapletFloorletVolatilities.of(NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM);
double expiryTime0 = prov.relativeTime(TEST_OPTION_EXPIRY[0]);
double expiryTime3 = prov.relativeTime(TEST_OPTION_EXPIRY[3]);
for (int i = 0; i < NB_TEST; i++) {
PointSensitivities sensi1 = PointSensitivities.of(
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime0, ALPHA, EUR, points1[0]),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime0, BETA, EUR, points1[1]),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime0, RHO, EUR, points1[2]),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime0, NU, EUR, points1[3]));
PointSensitivities sensi2 = PointSensitivities.of(
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime0, ALPHA, EUR, points2[0]),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime0, BETA, EUR, points2[1]),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime0, RHO, EUR, points2[2]),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime0, NU, EUR, points2[3]));
PointSensitivities sensi3 = PointSensitivities.of(
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime3, ALPHA, EUR, points3[0]),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime3, BETA, EUR, points3[1]),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime3, RHO, EUR, points3[2]),
IborCapletFloorletSabrSensitivity.of(NAME, expiryTime3, NU, EUR, points3[3]));
PointSensitivities sensis = sensi1.combinedWith(sensi2).combinedWith(sensi3).normalized();
CurrencyParameterSensitivities computed = prov.parameterSensitivity(sensis);
CurrencyParameterSensitivities expected = prov.parameterSensitivity(sensi1)
.combinedWith(prov.parameterSensitivity(sensi2))
.combinedWith(prov.parameterSensitivity(sensi3));
DoubleArrayMath.fuzzyEquals(
computed.getSensitivity(PARAM.getAlphaCurve().getName(), EUR).getSensitivity().toArray(),
expected.getSensitivity(PARAM.getAlphaCurve().getName(), EUR).getSensitivity().toArray(),
TOLERANCE_VOL);
DoubleArrayMath.fuzzyEquals(
computed.getSensitivity(PARAM.getBetaCurve().getName(), EUR).getSensitivity().toArray(),
expected.getSensitivity(PARAM.getBetaCurve().getName(), EUR).getSensitivity().toArray(),
TOLERANCE_VOL);
DoubleArrayMath.fuzzyEquals(
computed.getSensitivity(PARAM.getRhoCurve().getName(), EUR).getSensitivity().toArray(),
expected.getSensitivity(PARAM.getRhoCurve().getName(), EUR).getSensitivity().toArray(),
TOLERANCE_VOL);
DoubleArrayMath.fuzzyEquals(
computed.getSensitivity(PARAM.getNuCurve().getName(), EUR).getSensitivity().toArray(),
expected.getSensitivity(PARAM.getNuCurve().getName(), EUR).getSensitivity().toArray(),
TOLERANCE_VOL);
}
}
public void coverage() {
SabrParametersIborCapletFloorletVolatilities test1 =
SabrParametersIborCapletFloorletVolatilities.of(NAME, EUR_EURIBOR_3M, DATE_TIME, PARAM);
coverImmutableBean(test1);
SabrParametersIborCapletFloorletVolatilities test2 = SabrParametersIborCapletFloorletVolatilities.of(
NAME2, IborIndices.EUR_LIBOR_3M, DATE_TIME.plusDays(1), IborCapletFloorletSabrRateVolatilityDataSet.SABR_PARAM_FLAT);
coverBeanEquals(test1, test2);
}
}