/**
* 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.date.DayCounts.ACT_365F;
import static com.opengamma.strata.basics.date.DayCounts.ACT_ACT_ISDA;
import static com.opengamma.strata.basics.index.IborIndices.GBP_LIBOR_3M;
import static com.opengamma.strata.basics.index.IborIndices.USD_LIBOR_3M;
import static com.opengamma.strata.collect.TestHelper.assertSerialization;
import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg;
import static com.opengamma.strata.collect.TestHelper.coverBeanEquals;
import static com.opengamma.strata.collect.TestHelper.coverImmutableBean;
import static com.opengamma.strata.market.ValueType.SABR_ALPHA;
import static com.opengamma.strata.market.ValueType.SABR_BETA;
import static com.opengamma.strata.market.ValueType.SABR_NU;
import static com.opengamma.strata.market.ValueType.SABR_RHO;
import static com.opengamma.strata.market.curve.interpolator.CurveExtrapolators.FLAT;
import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.DOUBLE_QUADRATIC;
import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.LINEAR;
import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.STEP_UPPER;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import java.time.LocalDate;
import java.time.Period;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.opengamma.strata.basics.date.BusinessDayAdjustment;
import com.opengamma.strata.basics.date.BusinessDayConventions;
import com.opengamma.strata.basics.date.DaysAdjustment;
import com.opengamma.strata.basics.schedule.Frequency;
import com.opengamma.strata.basics.schedule.PeriodicSchedule;
import com.opengamma.strata.basics.schedule.RollConventions;
import com.opengamma.strata.basics.schedule.StubConvention;
import com.opengamma.strata.basics.value.ValueSchedule;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.collect.array.DoubleMatrix;
import com.opengamma.strata.market.ValueType;
import com.opengamma.strata.market.curve.ConstantCurve;
import com.opengamma.strata.market.curve.Curve;
import com.opengamma.strata.market.curve.CurveMetadata;
import com.opengamma.strata.market.curve.Curves;
import com.opengamma.strata.market.curve.interpolator.CurveExtrapolators;
import com.opengamma.strata.market.surface.SurfaceMetadata;
import com.opengamma.strata.market.surface.Surfaces;
import com.opengamma.strata.pricer.model.SabrVolatilityFormula;
import com.opengamma.strata.pricer.option.RawOptionData;
import com.opengamma.strata.product.capfloor.IborCapFloorLeg;
import com.opengamma.strata.product.common.PayReceive;
import com.opengamma.strata.product.swap.IborRateCalculation;
/**
* Test {@link SabrIborCapletFloorletVolatilityBootstrapDefinition}.
*/
@Test
public class SabrIborCapletFloorletVolatilityBootstrapDefinitionTest {
private static final IborCapletFloorletVolatilitiesName NAME = IborCapletFloorletVolatilitiesName.of("TestName");
public void test_ofFixedBeta() {
SabrIborCapletFloorletVolatilityBootstrapDefinition test = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan());
assertEquals(test.getDayCount(), ACT_ACT_ISDA);
assertEquals(test.getIndex(), USD_LIBOR_3M);
assertEquals(test.getInterpolator(), LINEAR);
assertEquals(test.getExtrapolatorLeft(), FLAT);
assertEquals(test.getExtrapolatorRight(), FLAT);
assertEquals(test.getName(), NAME);
assertEquals(test.getBetaCurve().get(),
ConstantCurve.of(Curves.sabrParameterByExpiry(NAME.getName() + "-Beta", ACT_ACT_ISDA, SABR_BETA), 0.5));
assertFalse(test.getRhoCurve().isPresent());
assertEquals(test.getSabrVolatilityFormula(), SabrVolatilityFormula.hagan());
assertEquals(test.getShiftCurve(), ConstantCurve.of("Zero shift", 0d));
}
public void test_ofFixedBeta_shift() {
SabrIborCapletFloorletVolatilityBootstrapDefinition test = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, 0.01, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan());
assertEquals(test.getDayCount(), ACT_ACT_ISDA);
assertEquals(test.getIndex(), USD_LIBOR_3M);
assertEquals(test.getInterpolator(), LINEAR);
assertEquals(test.getExtrapolatorLeft(), FLAT);
assertEquals(test.getExtrapolatorRight(), FLAT);
assertEquals(test.getName(), NAME);
assertEquals(test.getBetaCurve().get(),
ConstantCurve.of(Curves.sabrParameterByExpiry(NAME.getName() + "-Beta", ACT_ACT_ISDA, SABR_BETA), 0.5));
assertFalse(test.getRhoCurve().isPresent());
assertEquals(test.getSabrVolatilityFormula(), SabrVolatilityFormula.hagan());
assertEquals(test.getShiftCurve(), ConstantCurve.of("Shift curve", 0.01));
}
public void test_ofFixedRho() {
SabrIborCapletFloorletVolatilityBootstrapDefinition test = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedRho(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan());
assertEquals(test.getDayCount(), ACT_ACT_ISDA);
assertEquals(test.getIndex(), USD_LIBOR_3M);
assertEquals(test.getInterpolator(), LINEAR);
assertEquals(test.getExtrapolatorLeft(), FLAT);
assertEquals(test.getExtrapolatorRight(), FLAT);
assertEquals(test.getName(), NAME);
assertEquals(test.getRhoCurve().get(),
ConstantCurve.of(Curves.sabrParameterByExpiry(NAME.getName() + "-Rho", ACT_ACT_ISDA, SABR_RHO), 0.5));
assertFalse(test.getBetaCurve().isPresent());
assertEquals(test.getSabrVolatilityFormula(), SabrVolatilityFormula.hagan());
assertEquals(test.getShiftCurve(), ConstantCurve.of("Zero shift", 0d));
}
public void test_ofFixedRho_shift() {
SabrIborCapletFloorletVolatilityBootstrapDefinition test = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedRho(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, 0.01, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan());
assertEquals(test.getDayCount(), ACT_ACT_ISDA);
assertEquals(test.getIndex(), USD_LIBOR_3M);
assertEquals(test.getInterpolator(), LINEAR);
assertEquals(test.getExtrapolatorLeft(), FLAT);
assertEquals(test.getExtrapolatorRight(), FLAT);
assertEquals(test.getName(), NAME);
assertEquals(test.getRhoCurve().get(),
ConstantCurve.of(Curves.sabrParameterByExpiry(NAME.getName() + "-Rho", ACT_ACT_ISDA, SABR_RHO), 0.5));
assertFalse(test.getBetaCurve().isPresent());
assertEquals(test.getSabrVolatilityFormula(), SabrVolatilityFormula.hagan());
assertEquals(test.getShiftCurve(), ConstantCurve.of("Shift curve", 0.01));
}
public void test_builder() {
Curve betaCurve = ConstantCurve.of(Curves.sabrParameterByExpiry(NAME.getName() + "-Beta", ACT_ACT_ISDA, SABR_BETA), 0.65);
SabrIborCapletFloorletVolatilityBootstrapDefinition test = SabrIborCapletFloorletVolatilityBootstrapDefinition.builder()
.index(USD_LIBOR_3M)
.name(NAME)
.interpolator(LINEAR)
.extrapolatorLeft(FLAT)
.extrapolatorRight(CurveExtrapolators.LINEAR)
.dayCount(ACT_ACT_ISDA)
.sabrVolatilityFormula(SabrVolatilityFormula.hagan())
.betaCurve(betaCurve)
.build();
assertEquals(test.getDayCount(), ACT_ACT_ISDA);
assertEquals(test.getIndex(), USD_LIBOR_3M);
assertEquals(test.getInterpolator(), LINEAR);
assertEquals(test.getExtrapolatorLeft(), FLAT);
assertEquals(test.getExtrapolatorRight(), CurveExtrapolators.LINEAR);
assertEquals(test.getName(), NAME);
assertEquals(test.getBetaCurve().get(), betaCurve);
assertFalse(test.getRhoCurve().isPresent());
assertEquals(test.getSabrVolatilityFormula(), SabrVolatilityFormula.hagan());
assertEquals(test.getShiftCurve(), ConstantCurve.of("Zero shift", 0d));
}
public void test_createCap() {
SabrIborCapletFloorletVolatilityBootstrapDefinition base = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, STEP_UPPER, FLAT, FLAT, SabrVolatilityFormula.hagan());
LocalDate startDate = LocalDate.of(2012, 4, 20);
LocalDate endDate = LocalDate.of(2017, 4, 20);
double strike = 0.01;
IborCapFloorLeg expected = IborCapFloorLeg.builder()
.calculation(IborRateCalculation.of(USD_LIBOR_3M))
.capSchedule(ValueSchedule.of(strike))
.currency(USD_LIBOR_3M.getCurrency())
.notional(ValueSchedule.ALWAYS_1)
.paymentDateOffset(DaysAdjustment.NONE)
.paymentSchedule(
PeriodicSchedule.of(
startDate,
endDate,
Frequency.of(USD_LIBOR_3M.getTenor().getPeriod()),
BusinessDayAdjustment.of(BusinessDayConventions.MODIFIED_FOLLOWING, USD_LIBOR_3M.getFixingCalendar()),
StubConvention.NONE,
RollConventions.NONE))
.payReceive(PayReceive.RECEIVE)
.build();
IborCapFloorLeg computed = base.createCap(startDate, endDate, strike);
assertEquals(computed, expected);
}
public void test_createSabrParameterMetadata() {
SabrIborCapletFloorletVolatilityBootstrapDefinition base = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan());
ImmutableList<CurveMetadata> expected = ImmutableList.of(
Curves.sabrParameterByExpiry(NAME.getName() + "-Alpha", ACT_ACT_ISDA, SABR_ALPHA),
Curves.sabrParameterByExpiry(NAME.getName() + "-Beta", ACT_ACT_ISDA, SABR_BETA),
Curves.sabrParameterByExpiry(NAME.getName() + "-Rho", ACT_ACT_ISDA, SABR_RHO),
Curves.sabrParameterByExpiry(NAME.getName() + "-Nu", ACT_ACT_ISDA, SABR_NU));
ImmutableList<CurveMetadata> computed = base.createSabrParameterMetadata();
assertEquals(computed, expected);
}
public void test_createMetadata_normal() {
SabrIborCapletFloorletVolatilityBootstrapDefinition base = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan());
RawOptionData capData = RawOptionData.of(
ImmutableList.of(Period.ofYears(1), Period.ofYears(5)),
DoubleArray.of(0.005, 0.01, 0.015),
ValueType.STRIKE,
DoubleMatrix.copyOf(new double[][] {{0.15, 0.12, 0.13}, {0.1, Double.NaN, 0.09}}),
ValueType.NORMAL_VOLATILITY);
SurfaceMetadata expected = Surfaces.normalVolatilityByExpiryStrike(NAME.getName(), ACT_ACT_ISDA);
SurfaceMetadata computed = base.createMetadata(capData);
assertEquals(computed, expected);
}
public void test_createMetadata_black() {
SabrIborCapletFloorletVolatilityBootstrapDefinition base = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan());
RawOptionData capData = RawOptionData.of(
ImmutableList.of(Period.ofYears(1), Period.ofYears(5)),
DoubleArray.of(0.005, 0.01, 0.015),
ValueType.STRIKE,
DoubleMatrix.copyOf(new double[][] {{0.15, 0.12, 0.13}, {0.1, 0.08, 0.09}}),
ValueType.BLACK_VOLATILITY);
SurfaceMetadata expected = Surfaces.blackVolatilityByExpiryStrike(NAME.getName(), ACT_ACT_ISDA);
SurfaceMetadata computed = base.createMetadata(capData);
assertEquals(computed, expected);
}
//-------------------------------------------------------------------------
public void test_of_wrongInterpolator() {
assertThrowsIllegalArg(() -> SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, DOUBLE_QUADRATIC, FLAT, FLAT, SabrVolatilityFormula.hagan()));
}
public void test_createMetadata_wrongValueType() {
SabrIborCapletFloorletVolatilityBootstrapDefinition base = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan());
RawOptionData capData = RawOptionData.of(
ImmutableList.of(Period.ofYears(1), Period.ofYears(5)),
DoubleArray.of(0.005, 0.01, 0.015),
ValueType.STRIKE,
DoubleMatrix.copyOf(new double[][] {{0.15, 0.12, 0.13}, {0.1, 0.08, 0.09}}),
ValueType.PRICE);
assertThrowsIllegalArg(() -> base.createMetadata(capData));
}
//-------------------------------------------------------------------------
public void coverage() {
SabrIborCapletFloorletVolatilityBootstrapDefinition test1 = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan());
coverImmutableBean(test1);
SabrIborCapletFloorletVolatilityBootstrapDefinition test2 = SabrIborCapletFloorletVolatilityBootstrapDefinition.builder()
.index(GBP_LIBOR_3M)
.name(IborCapletFloorletVolatilitiesName.of("other"))
.interpolator(STEP_UPPER)
.extrapolatorLeft(FLAT)
.extrapolatorRight(CurveExtrapolators.LINEAR)
.rhoCurve(ConstantCurve.of("rho", 0.1d))
.shiftCurve(ConstantCurve.of("shift", 0.01d))
.dayCount(ACT_365F)
.sabrVolatilityFormula(SabrVolatilityFormula.hagan())
.build();
coverBeanEquals(test1, test2);
}
public void test_serialization() {
SabrIborCapletFloorletVolatilityBootstrapDefinition test = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan());
assertSerialization(test);
}
}