CapFloorCMSSpreadSABRBinormalMethod { public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final CapFloorCMSSpread cmsSpread, final SABRSwaptionProviderInterface sabrData) { ArgumentChecker.notNull(cmsSpread, "CMA cap/floor"); ArgumentChecker.notNull(sabrData, "SABR swaption provider"); final Currency ccy = cmsSpread.getCurrency(); final MulticurveProviderInterface multicurves = sabrData.getMulticurveProvider(); final double strike1 = cmsSpread.getUnderlyingSwap1().accept(PRDC, multicurves); final double strike2 = cmsSpread.getUnderlyingSwap2().accept(PRDC, multicurves); CouponCMS cmsCoupon1 = CouponCMS.from(cmsSpread, cmsSpread.getUnderlyingSwap1(), cmsSpread.getSettlementTime()); cmsCoupon1 = cmsCoupon1.withNotional(Math.abs(cmsCoupon1.getNotional())); CouponCMS cmsCoupon2 = CouponCMS.from(cmsSpread, cmsSpread.getUnderlyingSwap2(), cmsSpread.getSettlementTime()); cmsCoupon2 = cmsCoupon2.withNotional(Math.abs(cmsCoupon2.getNotional())); final CapFloorCMS cmsCap1 = CapFloorCMS.from(cmsCoupon1, strike1, true); final CapFloorCMS cmsCap2 = CapFloorCMS.from(cmsCoupon2, strike2, true); final double cmsCoupon1Pv = _methodCmsCoupon.presentValue(cmsCoupon1, sabrData).getAmount(ccy); final double cmsCoupon2Pv = _methodCmsCoupon.presentValue(cmsCoupon2, sabrData).getAmount(ccy); final double cmsCap1Pv = _methodCmsCap.presentValue(cmsCap1, sabrData).getAmount(ccy); final double cmsCap2Pv = _methodCmsCap.presentValue(cmsCap2, sabrData).getAmount(ccy); final double discountFactorPayment = multicurves.getDiscountFactor(ccy, cmsSpread.getPaymentTime()); final double factor = discountFactorPayment * cmsCap1.getNotional() * cmsCap1.getPaymentYearFraction(); final double expectation1 = cmsCoupon1Pv / factor; final double expectation2 = cmsCoupon2Pv / factor; NormalFunctionData dataCap1 = new NormalFunctionData(expectation1, factor, 0.0); final EuropeanVanillaOption optionCap1 = new EuropeanVanillaOption(strike1, cmsSpread.getFixingTime(), true); double cmsCap1ImpliedVolatility = 0; try { cmsCap1ImpliedVolatility = NORMAL_IMPLIED_VOLATILITY.getImpliedVolatility(dataCap1, optionCap1, cmsCap1Pv); } catch (final Exception e) { } NormalFunctionData dataCap2 = new NormalFunctionData(expectation2, factor, cmsCap1ImpliedVolatility); final EuropeanVanillaOption optionCap2 = new EuropeanVanillaOption(strike2, cmsSpread.getFixingTime(), true); double cmsCap2ImpliedVolatility = 0; try { cmsCap2ImpliedVolatility = NORMAL_IMPLIED_VOLATILITY.getImpliedVolatility(dataCap2, optionCap2, cmsCap2Pv); } catch (final Exception e) { } final double rho = _correlation.evaluate(cmsSpread.getStrike()); final double cmsSpreadImpliedVolatility = Math.sqrt(cmsCap1ImpliedVolatility * cmsCap1ImpliedVolatility - 2 * rho * cmsCap1ImpliedVolatility * cmsCap2ImpliedVolatility + cmsCap2ImpliedVolatility * cmsCap2ImpliedVolatility); final NormalFunctionData dataSpread = new NormalFunctionData(expectation1 - expectation2, discountFactorPayment * cmsSpread.getNotional() * cmsSpread.getPaymentYearFraction(), cmsSpreadImpliedVolatility); final EuropeanVanillaOption optionSpread = new EuropeanVanillaOption(cmsSpread.getStrike(), cmsSpread.getFixingTime(), cmsSpread.isCap()); final double[] cmsSpreadPvDerivative = new double[3]; final double cmsSpreadPv = NORMAL_PRICE.getPriceAdjoint(optionSpread, dataSpread, cmsSpreadPvDerivative); final double cmsSpreadPvBar = 1.0; final double cmsSpreadImpliedVolatilityBar = cmsSpreadPvDerivative[1] * cmsSpreadPvBar; final double cmsCap2ImpliedVolatilityBar = (cmsCap2ImpliedVolatility - rho * cmsCap1ImpliedVolatility) / cmsSpreadImpliedVolatility * cmsSpreadImpliedVolatilityBar; final double cmsCap1ImpliedVolatilityBar = (cmsCap1ImpliedVolatility - rho * cmsCap2ImpliedVolatility) / cmsSpreadImpliedVolatility * cmsSpreadImpliedVolatilityBar; dataCap2 = new NormalFunctionData(expectation2, factor, cmsCap2ImpliedVolatility); final double[] cmsCap2PriceNormalDerivative = new double[3]; NORMAL_PRICE.getPriceAdjoint(optionCap2, dataCap2, cmsCap2PriceNormalDerivative); final double expectation2Bar = -cmsSpreadPvDerivative[0] * cmsSpreadPvBar + -cmsCap2PriceNormalDerivative[0] / cmsCap2PriceNormalDerivative[1] * cmsCap2ImpliedVolatilityBar; dataCap1 = new NormalFunctionData(expectation1, factor, cmsCap1ImpliedVolatility); final double[] cmsCap1PriceNormalDerivative = new double[3]; NORMAL_PRICE.getPriceAdjoint(optionCap1, dataCap1, cmsCap1PriceNormalDerivative); final double expectation1Bar = cmsSpreadPvDerivative[0] * cmsSpreadPvBar + -cmsCap1PriceNormalDerivative[0] / cmsCap1PriceNormalDerivative[1] * cmsCap1ImpliedVolatilityBar; final double factorBar = -cmsCoupon1Pv / (factor * factor) * expectation1Bar + -cmsCoupon2Pv / (factor * factor) * expectation2Bar - cmsCap2Pv / factor / cmsCap2PriceNormalDerivative[1] * cmsCap2ImpliedVolatilityBar - cmsCap1Pv / factor / cmsCap1PriceNormalDerivative[1] * cmsCap1ImpliedVolatilityBar; final double discountFactorPaymentBar = cmsCap1.getNotional() * cmsCap1.getPaymentYearFraction() * factorBar + cmsSpreadPv / discountFactorPayment * cmsSpreadPvBar; final double cmsCap2PvBar = 1.0 / cmsCap2PriceNormalDerivative[1] * cmsCap2ImpliedVolatilityBar; final double cmsCap1PvBar = 1.0 / cmsCap1PriceNormalDerivative[1] * cmsCap1ImpliedVolatilityBar; final double cmsCoupon2PvBar = expectation2Bar / factor; final double cmsCoupon1PvBar = expectation1Bar / factor; double strike1Bar = -cmsCap1PriceNormalDerivative[2] / cmsCap1PriceNormalDerivative[1] * cmsCap1ImpliedVolatilityBar; double strike2Bar = -cmsCap2PriceNormalDerivative[2] / cmsCap2PriceNormalDerivative[1] * cmsCap2ImpliedVolatilityBar; strike1Bar += _methodCmsCap.presentValueStrikeSensitivity(cmsCap1, sabrData) * cmsCap1PvBar; strike2Bar += _methodCmsCap.presentValueStrikeSensitivity(cmsCap2, sabrData) * cmsCap2PvBar; final MulticurveSensitivity forward1CurveSensitivity = cmsSpread.getUnderlyingSwap1().accept(PRCSDC, multicurves); final MulticurveSensitivity forward2CurveSensitivity = cmsSpread.getUnderlyingSwap2().accept(PRCSDC, multicurves); final MultipleCurrencyMulticurveSensitivity cmsCoupon1CurveSensitivity = _methodCmsCoupon.presentValueCurveSensitivity(cmsCoupon1, sabrData); final MultipleCurrencyMulticurveSensitivity cmsCoupon2CurveSensitivity = _methodCmsCoupon.presentValueCurveSensitivity(cmsCoupon2, sabrData); final MultipleCurrencyMulticurveSensitivity cmsCap1CurveSensitivity = _methodCmsCap.presentValueCurveSensitivity(cmsCap1, sabrData); final MultipleCurrencyMulticurveSensitivity cmsCap2CurveSensitivity = _methodCmsCap.presentValueCurveSensitivity(cmsCap2, sabrData); final List<DoublesPair> list = new ArrayList<>(); list.add(DoublesPair.of(cmsSpread.getPaymentTime(), -cmsSpread.getPaymentTime() * discountFactorPayment)); final Map<String, List<DoublesPair>> resultMap = new HashMap<>(); resultMap.put(multicurves.getName(ccy), list); final MulticurveSensitivity dfCurveSensitivity = MulticurveSensitivity.ofYieldDiscounting(resultMap); MultipleCurrencyMulticurveSensitivity result = MultipleCurrencyMulticurveSensitivity.of(ccy, dfCurveSensitivity.multipliedBy(discountFactorPaymentBar)); result = result.plus(cmsCoupon1CurveSensitivity.multipliedBy(cmsCoupon1PvBar)); result = result.plus(cmsCoupon2CurveSensitivity.multipliedBy(cmsCoupon2PvBar)); result = result.plus(cmsCap1CurveSensitivity.multipliedBy(cmsCap1PvBar)); result = result.plus(cmsCap2CurveSensitivity.multipliedBy(cmsCap2PvBar)); result = result.plus(ccy, forward1CurveSensitivity.multipliedBy(strike1Bar)); result = result.plus(ccy, forward2CurveSensitivity.multipliedBy(strike2Bar)); return result; } CapFloorCMSSpreadSABRBinormalMethod(final DoubleFunction1D correlation, final CapFloorCMSSABRReplicationAbstractMethod methodCmsCap,
      final CouponCMSSABRReplicationGenericMethod methodCmsCoupon); DoubleFunction1D getCorrelation(); MultipleCurrencyAmount presentValue(final CapFloorCMSSpread cmsSpread, final SABRSwaptionProviderInterface sabrData); double impliedCorrelation(final CapFloorCMSSpread cmsSpread, final SABRSwaptionProviderInterface sabrData, final double price); MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final CapFloorCMSSpread cmsSpread, final SABRSwaptionProviderInterface sabrData); PresentValueSABRSensitivityDataBundle presentValueSABRSensitivity(final CapFloorCMSSpread cmsSpread, final SABRSwaptionProviderInterface sabrData);  }
@Test public void presentValueCurveSensitivityMethodVsCalculator() { final MultipleCurrencyMulticurveSensitivity pvcsMethod = METHOD_CMS_SPREAD.presentValueCurveSensitivity(CMS_CAP_SPREAD, SABR_MULTICURVES); final MultipleCurrencyMulticurveSensitivity pvcsCalculator = CMS_CAP_SPREAD.accept(PVCSSSC, SABR_MULTICURVES); AssertSensitivityObjects.assertEquals("CMS spread: curve sensitivity Method vs Calculator", pvcsMethod, pvcsCalculator, TOLERANCE_PV_DELTA); final MultipleCurrencyMulticurveSensitivity pvcsMethodExtra = METHOD_CMS_SPREAD_EXTRAPOLATION.presentValueCurveSensitivity(CMS_CAP_SPREAD, SABR_MULTICURVES); final MultipleCurrencyMulticurveSensitivity pvcsCalculatorExtra = CMS_CAP_SPREAD.accept(PVCSSSXC, SABR_MULTICURVES); AssertSensitivityObjects.assertEquals("CMS spread: curve sensitivity Method vs Calculator", pvcsMethodExtra, pvcsCalculatorExtra, TOLERANCE_PV_DELTA); }
@Test public void presentValueCurveSensitivityCapLongShortParity() { final CapFloorCMSSpread cmsCapSpreadShort = new CapFloorCMSSpread(EUR, PAYMENT_TIME, PAYMENT_ACCRUAL_FACTOR, -NOTIONAL, FIXING_TIME, SWAP_1, CMS_INDEX_1, SWAP_2, CMS_INDEX_2, SETTLEMENT_TIME, STRIKE, IS_CAP); MultipleCurrencyMulticurveSensitivity pvcsLong = METHOD_CMS_SPREAD.presentValueCurveSensitivity(CMS_CAP_SPREAD, SABR_MULTICURVES); pvcsLong = pvcsLong.cleaned(); MultipleCurrencyMulticurveSensitivity pvcsShort = METHOD_CMS_SPREAD.presentValueCurveSensitivity(cmsCapSpreadShort, SABR_MULTICURVES); pvcsShort = pvcsShort.multipliedBy(-1); pvcsShort = pvcsShort.cleaned(); AssertSensitivityObjects.assertEquals("CMS cap spread: Long/Short parity", pvcsLong, pvcsShort, TOLERANCE_PV); }
@Test public void presentValueCurveSensitivityFloorLongShortParity() { final CapFloorCMSSpread cmsCapSpreadShort = new CapFloorCMSSpread(EUR, PAYMENT_TIME, PAYMENT_ACCRUAL_FACTOR, -NOTIONAL, FIXING_TIME, SWAP_1, CMS_INDEX_1, SWAP_2, CMS_INDEX_2, SETTLEMENT_TIME, STRIKE, !IS_CAP); MultipleCurrencyMulticurveSensitivity pvcsLong = METHOD_CMS_SPREAD.presentValueCurveSensitivity(CMS_FLOOR_SPREAD, SABR_MULTICURVES); pvcsLong = pvcsLong.cleaned(); MultipleCurrencyMulticurveSensitivity pvcsShort = METHOD_CMS_SPREAD.presentValueCurveSensitivity(cmsCapSpreadShort, SABR_MULTICURVES); pvcsShort = pvcsShort.multipliedBy(-1); pvcsShort = pvcsShort.cleaned(); AssertSensitivityObjects.assertEquals("CMS floor spread: Long/Short parity", pvcsLong, pvcsShort, TOLERANCE_PV); }
@Test public void presentValueCurveSensitivityCapFloorParity() { MultipleCurrencyMulticurveSensitivity pvcsCapLong = METHOD_CMS_SPREAD.presentValueCurveSensitivity(CMS_CAP_SPREAD, SABR_MULTICURVES); pvcsCapLong = pvcsCapLong.cleaned(); MultipleCurrencyMulticurveSensitivity pvcsFloorLong = METHOD_CMS_SPREAD.presentValueCurveSensitivity(CMS_FLOOR_SPREAD, SABR_MULTICURVES); pvcsFloorLong = pvcsFloorLong.cleaned(); final CouponCMS cms1 = new CouponCMS(EUR, PAYMENT_TIME, PAYMENT_ACCRUAL_FACTOR, NOTIONAL, FIXING_TIME, SWAP_1, SETTLEMENT_TIME); final CouponCMS cms2 = new CouponCMS(EUR, PAYMENT_TIME, PAYMENT_ACCRUAL_FACTOR, NOTIONAL, FIXING_TIME, SWAP_2, SETTLEMENT_TIME); final CouponFixed cpnStrike = new CouponFixed(EUR, PAYMENT_TIME, PAYMENT_ACCRUAL_FACTOR, NOTIONAL, STRIKE); MultipleCurrencyMulticurveSensitivity pvcsCMS1 = METHOD_CMS_COUPON.presentValueCurveSensitivity(cms1, SABR_MULTICURVES); pvcsCMS1 = pvcsCMS1.cleaned(); MultipleCurrencyMulticurveSensitivity pvcsCMS2 = METHOD_CMS_COUPON.presentValueCurveSensitivity(cms2, SABR_MULTICURVES); pvcsCMS2 = pvcsCMS2.cleaned(); final MultipleCurrencyMulticurveSensitivity pvcsStrike = METHOD_CPN_FIXED.presentValueCurveSensitivity(cpnStrike, MULTICURVES); MultipleCurrencyMulticurveSensitivity pvcsParity1 = pvcsCMS1.plus(pvcsCMS2.plus(pvcsStrike).multipliedBy(-1)); pvcsParity1 = pvcsParity1.cleaned(); MultipleCurrencyMulticurveSensitivity pvcsParity2 = pvcsCapLong.plus(pvcsFloorLong.multipliedBy(-1)); pvcsParity2 = pvcsParity2.cleaned(); AssertSensitivityObjects.assertEquals("CMS spread: curve sensitivity - Cap/Floor parity", pvcsParity1, pvcsParity2, TOLERANCE_PV); }