/**
* 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_ACT_ISDA;
import static com.opengamma.strata.basics.index.IborIndices.USD_LIBOR_3M;
import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.List;
import org.testng.annotations.Test;
import com.opengamma.strata.collect.array.DoubleMatrix;
import com.opengamma.strata.collect.tuple.Pair;
import com.opengamma.strata.market.ValueType;
import com.opengamma.strata.market.curve.interpolator.CurveExtrapolators;
import com.opengamma.strata.market.curve.interpolator.CurveInterpolators;
import com.opengamma.strata.market.surface.ConstantSurface;
import com.opengamma.strata.market.surface.Surfaces;
import com.opengamma.strata.pricer.impl.volatility.smile.SabrHaganVolatilityFunctionProvider;
import com.opengamma.strata.pricer.option.RawOptionData;
import com.opengamma.strata.product.capfloor.ResolvedIborCapFloorLeg;
/**
* Test {@link SabrIborCapletFloorletVolatilityBootstrapper}.
*/
@Test
public class SabrIborCapletFloorletVolatilityBootstrapperTest extends CapletStrippingSetup {
private static final SabrIborCapletFloorletVolatilityBootstrapper CALIBRATOR =
SabrIborCapletFloorletVolatilityBootstrapper.DEFAULT;
private static final BlackIborCapFloorLegPricer LEG_PRICER_BLACK = BlackIborCapFloorLegPricer.DEFAULT;
private static final NormalIborCapFloorLegPricer LEG_PRICER_NORMAL = NormalIborCapFloorLegPricer.DEFAULT;
private static final SabrIborCapFloorLegPricer LEG_PRICER_SABR = SabrIborCapFloorLegPricer.DEFAULT;
private static final double TOL = 1.0e-3;
public void test_recovery_black() {
SabrIborCapletFloorletVolatilityBootstrapDefinition definition =
SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
IborCapletFloorletVolatilitiesName.of("test"),
USD_LIBOR_3M,
ACT_ACT_ISDA,
0.85,
CurveInterpolators.STEP_UPPER,
CurveExtrapolators.FLAT,
CurveExtrapolators.FLAT,
SabrHaganVolatilityFunctionProvider.DEFAULT);
DoubleMatrix volData = createFullBlackDataMatrix();
double errorValue = 1.0e-3;
DoubleMatrix error = DoubleMatrix.filled(volData.rowCount(), volData.columnCount(), errorValue);
RawOptionData data = RawOptionData.of(
createBlackMaturities(), createBlackStrikes(), ValueType.STRIKE, volData, error, ValueType.BLACK_VOLATILITY);
IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER);
SabrParametersIborCapletFloorletVolatilities resVols = (SabrParametersIborCapletFloorletVolatilities) res.getVolatilities();
double expSq = 0d;
for (int i = 0; i < NUM_BLACK_STRIKES; ++i) {
Pair<List<ResolvedIborCapFloorLeg>, List<Double>> capsAndVols = getCapsBlackVols(i);
List<ResolvedIborCapFloorLeg> caps = capsAndVols.getFirst();
List<Double> vols = capsAndVols.getSecond();
int nCaps = caps.size();
for (int j = 0; j < nCaps; ++j) {
ConstantSurface volSurface = ConstantSurface.of(
Surfaces.blackVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols.get(j));
BlackIborCapletFloorletExpiryStrikeVolatilities constVol = BlackIborCapletFloorletExpiryStrikeVolatilities.of(
USD_LIBOR_3M, CALIBRATION_TIME, volSurface);
double priceOrg = LEG_PRICER_BLACK.presentValue(caps.get(j), RATES_PROVIDER, constVol).getAmount();
double priceCalib = LEG_PRICER_SABR.presentValue(caps.get(j), RATES_PROVIDER, resVols).getAmount();
expSq += Math.pow((priceOrg - priceCalib) / priceOrg / errorValue, 2);
assertEquals(priceOrg, priceCalib, Math.max(priceOrg, 1d) * TOL * 3d);
}
}
assertEquals(res.getChiSquare(), expSq, expSq * 1.0e-14);
assertEquals(resVols.getIndex(), USD_LIBOR_3M);
assertEquals(resVols.getName(), definition.getName());
assertEquals(resVols.getValuationDateTime(), CALIBRATION_TIME);
assertEquals(resVols.getParameters().getShiftCurve(), definition.getShiftCurve());
assertEquals(resVols.getParameters().getBetaCurve(), definition.getBetaCurve().get());
}
public void test_recovery_black_fixedRho() {
SabrIborCapletFloorletVolatilityBootstrapDefinition definition =
SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedRho(
IborCapletFloorletVolatilitiesName.of("test"),
USD_LIBOR_3M,
ACT_ACT_ISDA,
0.0,
CurveInterpolators.STEP_UPPER,
CurveExtrapolators.FLAT,
CurveExtrapolators.FLAT,
SabrHaganVolatilityFunctionProvider.DEFAULT);
DoubleMatrix volData = createFullBlackDataMatrix();
double errorValue = 1.0e-3;
DoubleMatrix error = DoubleMatrix.filled(volData.rowCount(), volData.columnCount(), errorValue);
RawOptionData data = RawOptionData.of(
createBlackMaturities(), createBlackStrikes(), ValueType.STRIKE, volData, error, ValueType.BLACK_VOLATILITY);
IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER);
SabrParametersIborCapletFloorletVolatilities resVols = (SabrParametersIborCapletFloorletVolatilities) res.getVolatilities();
double expSq = 0d;
for (int i = 0; i < NUM_BLACK_STRIKES; ++i) {
Pair<List<ResolvedIborCapFloorLeg>, List<Double>> capsAndVols = getCapsBlackVols(i);
List<ResolvedIborCapFloorLeg> caps = capsAndVols.getFirst();
List<Double> vols = capsAndVols.getSecond();
int nCaps = caps.size();
for (int j = 0; j < nCaps; ++j) {
ConstantSurface volSurface = ConstantSurface.of(
Surfaces.blackVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols.get(j));
BlackIborCapletFloorletExpiryStrikeVolatilities constVol = BlackIborCapletFloorletExpiryStrikeVolatilities.of(
USD_LIBOR_3M, CALIBRATION_TIME, volSurface);
double priceOrg = LEG_PRICER_BLACK.presentValue(caps.get(j), RATES_PROVIDER, constVol).getAmount();
double priceCalib = LEG_PRICER_SABR.presentValue(caps.get(j), RATES_PROVIDER, resVols).getAmount();
expSq += Math.pow((priceOrg - priceCalib) / priceOrg / errorValue, 2);
assertEquals(priceOrg, priceCalib, Math.max(priceOrg, 1d) * TOL * 3d);
}
}
assertEquals(res.getChiSquare(), expSq, expSq * 1.0e-14);
assertEquals(resVols.getIndex(), USD_LIBOR_3M);
assertEquals(resVols.getName(), definition.getName());
assertEquals(resVols.getValuationDateTime(), CALIBRATION_TIME);
assertEquals(resVols.getParameters().getShiftCurve(), definition.getShiftCurve());
assertEquals(resVols.getParameters().getRhoCurve(), definition.getRhoCurve().get());
}
public void test_invalid_data() {
SabrIborCapletFloorletVolatilityBootstrapDefinition definition =
SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
IborCapletFloorletVolatilitiesName.of("test"),
USD_LIBOR_3M,
ACT_ACT_ISDA,
0.85,
CurveInterpolators.LINEAR,
CurveExtrapolators.FLAT,
CurveExtrapolators.FLAT,
SabrHaganVolatilityFunctionProvider.DEFAULT);
RawOptionData data = RawOptionData.of(createBlackMaturities(), createBlackStrikes(), ValueType.STRIKE,
createFullBlackDataMatrixInvalid(), ValueType.BLACK_VOLATILITY);
assertThrowsIllegalArg(() -> CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER));
}
public void test_recovery_black_shift() {
SabrIborCapletFloorletVolatilityBootstrapDefinition definition =
SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
IborCapletFloorletVolatilitiesName.of("test"),
USD_LIBOR_3M,
ACT_ACT_ISDA,
0.95,
0.02,
CurveInterpolators.LINEAR,
CurveExtrapolators.FLAT,
CurveExtrapolators.FLAT,
SabrHaganVolatilityFunctionProvider.DEFAULT);
DoubleMatrix volData = createFullBlackDataMatrix();
double errorValue = 1.0e-3;
DoubleMatrix error = DoubleMatrix.filled(volData.rowCount(), volData.columnCount(), errorValue);
RawOptionData data = RawOptionData.of(
createBlackMaturities(), createBlackStrikes(), ValueType.STRIKE, volData, error, ValueType.BLACK_VOLATILITY);
IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER);
SabrParametersIborCapletFloorletVolatilities resVols = (SabrParametersIborCapletFloorletVolatilities) res.getVolatilities();
double expSq = 0d;
for (int i = 0; i < NUM_BLACK_STRIKES; ++i) {
Pair<List<ResolvedIborCapFloorLeg>, List<Double>> capsAndVols = getCapsBlackVols(i);
List<ResolvedIborCapFloorLeg> caps = capsAndVols.getFirst();
List<Double> vols = capsAndVols.getSecond();
int nCaps = caps.size();
for (int j = 0; j < nCaps; ++j) {
ConstantSurface volSurface = ConstantSurface.of(
Surfaces.blackVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols.get(j));
BlackIborCapletFloorletExpiryStrikeVolatilities constVol = BlackIborCapletFloorletExpiryStrikeVolatilities.of(
USD_LIBOR_3M, CALIBRATION_TIME, volSurface);
double priceOrg = LEG_PRICER_BLACK.presentValue(caps.get(j), RATES_PROVIDER, constVol).getAmount();
double priceCalib = LEG_PRICER_SABR.presentValue(caps.get(j), RATES_PROVIDER, resVols).getAmount();
expSq += Math.pow((priceOrg - priceCalib) / priceOrg / errorValue, 2);
assertEquals(priceOrg, priceCalib, Math.max(priceOrg, 1d) * TOL * 10d);
}
}
assertEquals(res.getChiSquare(), expSq, expSq * 1.0e-14);
assertEquals(resVols.getIndex(), USD_LIBOR_3M);
assertEquals(resVols.getName(), definition.getName());
assertEquals(resVols.getValuationDateTime(), CALIBRATION_TIME);
assertEquals(resVols.getParameters().getShiftCurve(), definition.getShiftCurve());
assertEquals(resVols.getParameters().getBetaCurve(), definition.getBetaCurve().get());
}
public void test_recovery_normal() {
SabrIborCapletFloorletVolatilityBootstrapDefinition definition =
SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
IborCapletFloorletVolatilitiesName.of("test"),
USD_LIBOR_3M,
ACT_ACT_ISDA,
0.85,
CurveInterpolators.LINEAR,
CurveExtrapolators.FLAT,
CurveExtrapolators.FLAT,
SabrHaganVolatilityFunctionProvider.DEFAULT);
RawOptionData data = RawOptionData.of(
createNormalEquivMaturities(),
createNormalEquivStrikes(),
ValueType.STRIKE,
createFullNormalEquivDataMatrix(),
ValueType.NORMAL_VOLATILITY);
IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER);
SabrParametersIborCapletFloorletVolatilities resVols = (SabrParametersIborCapletFloorletVolatilities) res.getVolatilities();
for (int i = 1; i < NUM_BLACK_STRIKES; ++i) {
Pair<List<ResolvedIborCapFloorLeg>, List<Double>> capsAndVols = getCapsNormalEquivVols(i);
List<ResolvedIborCapFloorLeg> caps = capsAndVols.getFirst();
List<Double> vols = capsAndVols.getSecond();
int nCaps = caps.size();
for (int j = 0; j < nCaps; ++j) {
ConstantSurface volSurface = ConstantSurface.of(
Surfaces.normalVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols.get(j));
NormalIborCapletFloorletExpiryStrikeVolatilities constVol = NormalIborCapletFloorletExpiryStrikeVolatilities.of(
USD_LIBOR_3M, CALIBRATION_TIME, volSurface);
double priceOrg = LEG_PRICER_NORMAL.presentValue(caps.get(j), RATES_PROVIDER, constVol).getAmount();
double priceCalib = LEG_PRICER_SABR.presentValue(caps.get(j), RATES_PROVIDER, resVols).getAmount();
assertEquals(priceOrg, priceCalib, Math.max(priceOrg, 1d) * TOL * 3d);
}
}
assertTrue(res.getChiSquare() > 0d);
assertEquals(resVols.getIndex(), USD_LIBOR_3M);
assertEquals(resVols.getName(), definition.getName());
assertEquals(resVols.getValuationDateTime(), CALIBRATION_TIME);
}
public void test_recovery_normal_fixedRho() {
SabrIborCapletFloorletVolatilityBootstrapDefinition definition =
SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedRho(
IborCapletFloorletVolatilitiesName.of("test"),
USD_LIBOR_3M,
ACT_ACT_ISDA,
0.0,
CurveInterpolators.LINEAR,
CurveExtrapolators.FLAT,
CurveExtrapolators.FLAT,
SabrHaganVolatilityFunctionProvider.DEFAULT);
RawOptionData data = RawOptionData.of(
createNormalEquivMaturities(),
createNormalEquivStrikes(),
ValueType.STRIKE,
createFullNormalEquivDataMatrix(),
ValueType.NORMAL_VOLATILITY);
IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER);
SabrParametersIborCapletFloorletVolatilities resVols = (SabrParametersIborCapletFloorletVolatilities) res.getVolatilities();
for (int i = 1; i < NUM_BLACK_STRIKES; ++i) {
Pair<List<ResolvedIborCapFloorLeg>, List<Double>> capsAndVols = getCapsNormalEquivVols(i);
List<ResolvedIborCapFloorLeg> caps = capsAndVols.getFirst();
List<Double> vols = capsAndVols.getSecond();
int nCaps = caps.size();
for (int j = 0; j < nCaps; ++j) {
ConstantSurface volSurface = ConstantSurface.of(
Surfaces.normalVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols.get(j));
NormalIborCapletFloorletExpiryStrikeVolatilities constVol = NormalIborCapletFloorletExpiryStrikeVolatilities.of(
USD_LIBOR_3M, CALIBRATION_TIME, volSurface);
double priceOrg = LEG_PRICER_NORMAL.presentValue(caps.get(j), RATES_PROVIDER, constVol).getAmount();
double priceCalib = LEG_PRICER_SABR.presentValue(caps.get(j), RATES_PROVIDER, resVols).getAmount();
assertEquals(priceOrg, priceCalib, Math.max(priceOrg, 1d) * TOL * 3d);
}
}
assertTrue(res.getChiSquare() > 0d);
assertEquals(resVols.getIndex(), USD_LIBOR_3M);
assertEquals(resVols.getName(), definition.getName());
assertEquals(resVols.getValuationDateTime(), CALIBRATION_TIME);
}
public void test_recovery_flatVol() {
double beta = 0.8;
SabrIborCapletFloorletVolatilityBootstrapDefinition definition =
SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(
IborCapletFloorletVolatilitiesName.of("test"),
USD_LIBOR_3M,
ACT_ACT_ISDA,
beta,
CurveInterpolators.STEP_UPPER,
CurveExtrapolators.FLAT,
CurveExtrapolators.FLAT,
SabrHaganVolatilityFunctionProvider.DEFAULT);
RawOptionData data = RawOptionData.of(
createBlackMaturities(),
createBlackStrikes(),
ValueType.STRIKE,
createFullFlatBlackDataMatrix(),
ValueType.BLACK_VOLATILITY);
IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER);
SabrParametersIborCapletFloorletVolatilities resVols = (SabrParametersIborCapletFloorletVolatilities) res.getVolatilities();
for (int i = 0; i < NUM_BLACK_STRIKES; ++i) {
Pair<List<ResolvedIborCapFloorLeg>, List<Double>> capsAndVols = getCapsFlatBlackVols(i);
List<ResolvedIborCapFloorLeg> caps = capsAndVols.getFirst();
List<Double> vols = capsAndVols.getSecond();
int nCaps = caps.size();
for (int j = 0; j < nCaps; ++j) {
ConstantSurface volSurface = ConstantSurface.of(
Surfaces.blackVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols.get(j));
BlackIborCapletFloorletExpiryStrikeVolatilities constVol = BlackIborCapletFloorletExpiryStrikeVolatilities.of(
USD_LIBOR_3M, CALIBRATION_TIME, volSurface);
double priceOrg = LEG_PRICER_BLACK.presentValue(caps.get(j), RATES_PROVIDER, constVol).getAmount();
double priceCalib = LEG_PRICER_SABR.presentValue(caps.get(j), RATES_PROVIDER, resVols).getAmount();
assertEquals(priceOrg, priceCalib, Math.max(priceOrg, 1d) * TOL);
}
}
}
}