@Test
/**
* Test the present value rate sensitivity for a CMS cap with pricing by replication in the SABR with extrapolation framework.
*/
public void presentValueCurveSensitivity() {
final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
final SABRInterestRateParameters sabrParameter = TestsDataSetsSABR.createSABR1();
final SABRInterestRateDataBundle sabrBundle = new SABRInterestRateDataBundle(sabrParameter, curves);
// Swaption sensitivity
InterestRateCurveSensitivity pvsCapLong = METHOD_EXTRAPOLATION_CAP.presentValueCurveSensitivity(CMS_CAP_LONG, sabrBundle);
InterestRateCurveSensitivity pvsCapLongStd = METHOD_STANDARD_CAP.presentValueCurveSensitivity(CMS_CAP_LONG, sabrBundle);
final InterestRateCurveSensitivity pvsCapShort = METHOD_EXTRAPOLATION_CAP.presentValueCurveSensitivity(CMS_CAP_SHORT, sabrBundle);
// Long/short parity
final InterestRateCurveSensitivity pvsCapShort_1 = pvsCapShort.multipliedBy(-1);
assertEquals(pvsCapLong.getSensitivities(), pvsCapShort_1.getSensitivities());
// Present value sensitivity comparison with finite difference.
pvsCapLong = pvsCapLong.cleaned();
pvsCapLongStd = pvsCapLongStd.cleaned();
final double deltaTolerance = 4.0E+2;
//Testing note: Sensitivity is for a movement of 1. 1E+2 = 1 cent for a 1 bp move. Tolerance increased to cope with numerical imprecision of finite difference.
final double deltaShift = 1.0E-5;
pvsCapLong = pvsCapLong.cleaned();
final double pv = METHOD_EXTRAPOLATION_CAP.presentValue(CMS_CAP_LONG, sabrBundle).getAmount();
// 1. Forward curve sensitivity
final String bumpedCurveName = "Bumped Curve";
final String[] bumpedCurvesForwardName = {FUNDING_CURVE_NAME, bumpedCurveName };
final CapFloorCMS capBumpedForward = (CapFloorCMS) CMS_CAP_LONG_DEFINITION.toDerivative(REFERENCE_DATE, bumpedCurvesForwardName);
final YieldAndDiscountCurve curveForward = curves.getCurve(FORWARD_CURVE_NAME);
final Set<Double> timeForwardSet = new TreeSet<>();
for (final Payment pay : CMS_CAP_LONG.getUnderlyingSwap().getSecondLeg().getPayments()) {
final CouponIbor coupon = (CouponIbor) pay;
timeForwardSet.add(coupon.getFixingPeriodStartTime());
timeForwardSet.add(coupon.getFixingPeriodEndTime());
}
final int nbForwardDate = timeForwardSet.size();
final List<Double> timeForwardList = new ArrayList<>(timeForwardSet);
Double[] timeForwardArray = new Double[nbForwardDate];
timeForwardArray = timeForwardList.toArray(timeForwardArray);
final double[] yieldsForward = new double[nbForwardDate + 1];
final double[] nodeTimesForward = new double[nbForwardDate + 1];
yieldsForward[0] = curveForward.getInterestRate(0.0);
for (int i = 0; i < nbForwardDate; i++) {
nodeTimesForward[i + 1] = timeForwardArray[i];
yieldsForward[i + 1] = curveForward.getInterestRate(nodeTimesForward[i + 1]);
}
final YieldAndDiscountCurve tempCurveForward = YieldCurve.from(InterpolatedDoublesCurve.fromSorted(nodeTimesForward, yieldsForward, new LinearInterpolator1D()));
final List<DoublesPair> tempForward = pvsCapLong.getSensitivities().get(FORWARD_CURVE_NAME);
final double[] resFwd = new double[nbForwardDate];
for (int i = 0; i < nbForwardDate; i++) {
final YieldAndDiscountCurve bumpedCurveForward = tempCurveForward.withSingleShift(nodeTimesForward[i + 1], deltaShift);
final YieldCurveBundle curvesBumpedForward = new YieldCurveBundle();
curvesBumpedForward.addAll(curves);
curvesBumpedForward.setCurve("Bumped Curve", bumpedCurveForward);
final SABRInterestRateDataBundle sabrBundleBumped = new SABRInterestRateDataBundle(sabrParameter, curvesBumpedForward);
final double bumpedpv = METHOD_EXTRAPOLATION_CAP.presentValue(capBumpedForward, sabrBundleBumped).getAmount();
resFwd[i] = (bumpedpv - pv) / deltaShift;
final DoublesPair pair = tempForward.get(i);
assertEquals("Sensitivity to forward curve: Node " + i, nodeTimesForward[i + 1], pair.getFirst(), 1E-8);
assertEquals("Sensitivity to forward curve: Node " + i, resFwd[i], pair.getSecond(), deltaTolerance);
}
// 2. Funding curve sensitivity
final String[] bumpedCurvesFundingName = {bumpedCurveName, FORWARD_CURVE_NAME };
final CapFloorCMS capBumpedFunding = (CapFloorCMS) CMS_CAP_LONG_DEFINITION.toDerivative(REFERENCE_DATE, bumpedCurvesFundingName);
final int nbPayDate = CMS_CAP_LONG_DEFINITION.getUnderlyingSwap().getIborLeg().getPayments().length;
final YieldAndDiscountCurve curveFunding = curves.getCurve(FUNDING_CURVE_NAME);
final double[] yieldsFunding = new double[nbPayDate + 1];
final double[] nodeTimesFunding = new double[nbPayDate + 1];
yieldsFunding[0] = curveFunding.getInterestRate(0.0);
for (int i = 0; i < nbPayDate; i++) {
nodeTimesFunding[i + 1] = CMS_CAP_LONG.getUnderlyingSwap().getSecondLeg().getNthPayment(i).getPaymentTime();
yieldsFunding[i + 1] = curveFunding.getInterestRate(nodeTimesFunding[i + 1]);
}
final YieldAndDiscountCurve tempCurveFunding = YieldCurve.from(InterpolatedDoublesCurve.fromSorted(nodeTimesFunding, yieldsFunding, new LinearInterpolator1D()));
final List<DoublesPair> tempFunding = pvsCapLong.getSensitivities().get(FUNDING_CURVE_NAME);
final double[] resDsc = new double[nbPayDate];
for (int i = 0; i < nbPayDate; i++) {
final YieldAndDiscountCurve bumpedCurve = tempCurveFunding.withSingleShift(nodeTimesFunding[i + 1], deltaShift);
final YieldCurveBundle curvesBumped = new YieldCurveBundle();
curvesBumped.addAll(curves);
curvesBumped.setCurve("Bumped Curve", bumpedCurve);
final SABRInterestRateDataBundle sabrBundleBumped = new SABRInterestRateDataBundle(sabrParameter, curvesBumped);
final double bumpedpv = METHOD_EXTRAPOLATION_CAP.presentValue(capBumpedFunding, sabrBundleBumped).getAmount();
resDsc[i] = (bumpedpv - pv) / deltaShift;
final DoublesPair pair = tempFunding.get(i);
assertEquals("Sensitivity to discounting curve: Node " + i, nodeTimesFunding[i + 1], pair.getFirst(), 1E-8);