CapFloorCMSSpreadSABRBinormalMethod { public PresentValueSABRSensitivityDataBundle presentValueSABRSensitivity(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 forward1 = cmsSpread.getUnderlyingSwap1().accept(PRDC, multicurves); final double forward2 = 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, forward1, true); final CapFloorCMS cmsCap2 = CapFloorCMS.from(cmsCoupon2, forward2, true); final double cmsCoupon1Price = _methodCmsCoupon.presentValue(cmsCoupon1, sabrData).getAmount(ccy); final double cmsCoupon2Price = _methodCmsCoupon.presentValue(cmsCoupon2, sabrData).getAmount(ccy); final double cmsCap1Price = _methodCmsCap.presentValue(cmsCap1, sabrData).getAmount(ccy); final double cmsCap2Price = _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 = cmsCoupon1Price / factor; final double expectation2 = cmsCoupon2Price / factor; NormalFunctionData dataCap1 = new NormalFunctionData(expectation1, factor, 0.0); final EuropeanVanillaOption optionCap1 = new EuropeanVanillaOption(forward1, cmsSpread.getFixingTime(), true); double cmsCap1ImpliedVolatility = 0; try { cmsCap1ImpliedVolatility = NORMAL_IMPLIED_VOLATILITY.getImpliedVolatility(dataCap1, optionCap1, cmsCap1Price); } catch (final Exception e) { } NormalFunctionData dataCap2 = new NormalFunctionData(expectation2, factor, cmsCap1ImpliedVolatility); final EuropeanVanillaOption optionCap2 = new EuropeanVanillaOption(forward2, cmsSpread.getFixingTime(), true); double cmsCap2ImpliedVolatility = 0; try { cmsCap2ImpliedVolatility = NORMAL_IMPLIED_VOLATILITY.getImpliedVolatility(dataCap2, optionCap2, cmsCap2Price); } 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[] cmsSpreadPriceDerivative = new double[3]; NORMAL_PRICE.getPriceAdjoint(optionSpread, dataSpread, cmsSpreadPriceDerivative); final double cmsSpreadPriceBar = 1.0; final double cmsSpreadImpliedVolatilityBar = cmsSpreadPriceDerivative[1] * cmsSpreadPriceBar; 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 = -cmsSpreadPriceDerivative[0] * cmsSpreadPriceBar + -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 = cmsSpreadPriceDerivative[0] * cmsSpreadPriceBar + -cmsCap1PriceNormalDerivative[0] / cmsCap1PriceNormalDerivative[1] * cmsCap1ImpliedVolatilityBar; final double cmsCap2PriceBar = 1.0 / cmsCap2PriceNormalDerivative[1] * cmsCap2ImpliedVolatilityBar; final double cmsCap1PriceBar = 1.0 / cmsCap1PriceNormalDerivative[1] * cmsCap1ImpliedVolatilityBar; final double cmsCoupon2PriceBar = expectation2Bar / factor; final double cmsCoupon1PriceBar = expectation1Bar / factor; PresentValueSABRSensitivityDataBundle cmsCoupon1SABRSensitivity = _methodCmsCoupon.presentValueSABRSensitivity(cmsCoupon1, sabrData); PresentValueSABRSensitivityDataBundle cmsCoupon2SABRSensitivity = _methodCmsCoupon.presentValueSABRSensitivity(cmsCoupon2, sabrData); PresentValueSABRSensitivityDataBundle cmsCap1SABRSensitivity = _methodCmsCap.presentValueSABRSensitivity(cmsCap1, sabrData); PresentValueSABRSensitivityDataBundle cmsCap2SABRSensitivity = _methodCmsCap.presentValueSABRSensitivity(cmsCap2, sabrData); cmsCoupon1SABRSensitivity = cmsCoupon1SABRSensitivity.multiplyBy(cmsCoupon1PriceBar); cmsCoupon2SABRSensitivity = cmsCoupon2SABRSensitivity.multiplyBy(cmsCoupon2PriceBar); cmsCap1SABRSensitivity = cmsCap1SABRSensitivity.multiplyBy(cmsCap1PriceBar); cmsCap2SABRSensitivity = cmsCap2SABRSensitivity.multiplyBy(cmsCap2PriceBar); PresentValueSABRSensitivityDataBundle result = cmsCoupon1SABRSensitivity; result = result.plus(cmsCoupon2SABRSensitivity); result = result.plus(cmsCap1SABRSensitivity); result = result.plus(cmsCap2SABRSensitivity); 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 presentValueSABRSensitivity() { final double pv = METHOD_CMS_SPREAD.presentValue(CMS_CAP_SPREAD, SABR_MULTICURVES).getAmount(EUR); final PresentValueSABRSensitivityDataBundle pvsCapLong = METHOD_CMS_SPREAD.presentValueSABRSensitivity(CMS_CAP_SPREAD, SABR_MULTICURVES); final double shift = 0.0001; final double shiftAlpha = 0.00001; final double maturity1 = CMS_CAP_SPREAD.getUnderlyingSwap1().getFixedLeg().getNthPayment(CMS_CAP_SPREAD.getUnderlyingSwap1().getFixedLeg().getNumberOfPayments() - 1).getPaymentTime() - CMS_CAP_SPREAD.getSettlementTime(); final DoublesPair expectedExpiryTenor1 = DoublesPair.of(CMS_CAP_SPREAD.getFixingTime(), maturity1); final double maturity2 = CMS_CAP_SPREAD.getUnderlyingSwap2().getFixedLeg().getNthPayment(CMS_CAP_SPREAD.getUnderlyingSwap2().getFixedLeg().getNumberOfPayments() - 1).getPaymentTime() - CMS_CAP_SPREAD.getSettlementTime(); final DoublesPair expectedExpiryTenor2 = DoublesPair.of(CMS_CAP_SPREAD.getFixingTime(), maturity2); final SABRInterestRateParameters sabrParameterAlphaBumped = SABRDataSets.createSABR1AlphaBumped(shiftAlpha); final SABRSwaptionProviderDiscount sabrBundleAlphaBumped = new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterAlphaBumped, EUR1YEURIBOR6M); final double pvLongPayerAlphaBumped = METHOD_CMS_SPREAD.presentValue(CMS_CAP_SPREAD, sabrBundleAlphaBumped).getAmount(EUR); final double expectedAlphaSensi = (pvLongPayerAlphaBumped - pv) / shiftAlpha; assertEquals("Number of alpha sensitivity", pvsCapLong.getAlpha().getMap().keySet().size(), 2); assertEquals("Alpha sensitivity expiry/tenor", pvsCapLong.getAlpha().getMap().keySet().contains(expectedExpiryTenor1), true); assertEquals("Alpha sensitivity expiry/tenor", pvsCapLong.getAlpha().getMap().keySet().contains(expectedExpiryTenor2), true); assertEquals("Alpha sensitivity value", expectedAlphaSensi, pvsCapLong.getAlpha().getMap().get(expectedExpiryTenor1) + pvsCapLong.getAlpha().getMap().get(expectedExpiryTenor2), 5.0E+3); final SABRInterestRateParameters sabrParameterRhoBumped = SABRDataSets.createSABR1RhoBumped(); final SABRSwaptionProviderDiscount sabrBundleRhoBumped = new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterRhoBumped, EUR1YEURIBOR6M); final double pvLongPayerRhoBumped = METHOD_CMS_SPREAD.presentValue(CMS_CAP_SPREAD, sabrBundleRhoBumped).getAmount(EUR); final double expectedRhoSensi = (pvLongPayerRhoBumped - pv) / shift; assertEquals("Number of rho sensitivity", pvsCapLong.getRho().getMap().keySet().size(), 2); assertEquals("Rho sensitivity expiry/tenor", pvsCapLong.getRho().getMap().keySet().contains(expectedExpiryTenor1), true); assertEquals("Rho sensitivity expiry/tenor", pvsCapLong.getRho().getMap().keySet().contains(expectedExpiryTenor2), true); assertEquals("Rho sensitivity value", expectedRhoSensi, pvsCapLong.getRho().getMap().get(expectedExpiryTenor1) + pvsCapLong.getRho().getMap().get(expectedExpiryTenor2), 5.0E+1); final SABRInterestRateParameters sabrParameterNuBumped = SABRDataSets.createSABR1NuBumped(); final SABRSwaptionProviderDiscount sabrBundleNuBumped = new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterNuBumped, EUR1YEURIBOR6M); final double pvLongPayerNuBumped = METHOD_CMS_SPREAD.presentValue(CMS_CAP_SPREAD, sabrBundleNuBumped).getAmount(EUR); final double expectedNuSensi = (pvLongPayerNuBumped - pv) / shift; assertEquals("Number of nu sensitivity", pvsCapLong.getNu().getMap().keySet().size(), 2); assertTrue("Nu sensitivity expiry/tenor", pvsCapLong.getNu().getMap().keySet().contains(expectedExpiryTenor1)); assertTrue("Nu sensitivity expiry/tenor", pvsCapLong.getNu().getMap().keySet().contains(expectedExpiryTenor2)); assertEquals("Nu sensitivity value", expectedNuSensi, pvsCapLong.getNu().getMap().get(expectedExpiryTenor1) + pvsCapLong.getNu().getMap().get(expectedExpiryTenor2), 2.0E+2); }
@Test public void presentValueSABRSensitivityMethodVsCalculator() { final PresentValueSABRSensitivityDataBundle pvcsMethod = METHOD_CMS_SPREAD.presentValueSABRSensitivity(CMS_CAP_SPREAD, SABR_MULTICURVES); final PresentValueSABRSensitivityDataBundle pvcsCalculator = CMS_CAP_SPREAD.accept(PVSSSSC, SABR_MULTICURVES); assertEquals("CMS spread: SABR sensitivity Method vs Calculator", pvcsMethod, pvcsCalculator); final PresentValueSABRSensitivityDataBundle pvcsMethodExtra = METHOD_CMS_SPREAD_EXTRAPOLATION.presentValueSABRSensitivity(CMS_CAP_SPREAD, SABR_MULTICURVES); final PresentValueSABRSensitivityDataBundle pvcsCalculatorExtra = CMS_CAP_SPREAD.accept(PVSSSSXC, SABR_MULTICURVES); assertEquals("CMS spread: SABR sensitivity Method vs Calculator", pvcsMethodExtra, pvcsCalculatorExtra); }
@Test public void presentValueSABRSensitivityLongShortParity() { final CapFloorCMSSpread cmsSpreadShort = 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); final PresentValueSABRSensitivityDataBundle pvssLong = METHOD_CMS_SPREAD.presentValueSABRSensitivity(CMS_CAP_SPREAD, SABR_MULTICURVES); PresentValueSABRSensitivityDataBundle pvssShort = METHOD_CMS_SPREAD.presentValueSABRSensitivity(cmsSpreadShort, SABR_MULTICURVES); pvssShort = pvssShort.multiplyBy(-1); assertEquals("CMS spread: Long/Short parity", pvssLong, pvssShort); }