CapFloorCMSSpreadSABRBinormalMethod { public MultipleCurrencyAmount presentValue(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 NormalFunctionData dataCap1 = new NormalFunctionData(cmsCoupon1Price / (discountFactorPayment * cmsCap1.getNotional() * cmsCap1.getPaymentYearFraction()), discountFactorPayment * cmsCap1.getNotional() * cmsCap1.getPaymentYearFraction(), 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) { } final NormalFunctionData dataCap2 = new NormalFunctionData(cmsCoupon2Price / (discountFactorPayment * cmsCap2.getNotional() * cmsCap2.getPaymentYearFraction()), discountFactorPayment * cmsCap2.getNotional() * cmsCap2.getPaymentYearFraction(), 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 cmsSpreadImpliedVolatility = Math.sqrt(cmsCap1ImpliedVolatility * cmsCap1ImpliedVolatility - 2 * _correlation.evaluate(cmsSpread.getStrike()) * cmsCap1ImpliedVolatility * cmsCap2ImpliedVolatility + cmsCap2ImpliedVolatility * cmsCap2ImpliedVolatility); final NormalFunctionData dataSpread = new NormalFunctionData( (cmsCoupon1Price - cmsCoupon2Price) / (discountFactorPayment * Math.abs(cmsSpread.getNotional()) * cmsSpread.getPaymentYearFraction()), discountFactorPayment * cmsSpread.getNotional() * cmsSpread.getPaymentYearFraction(), cmsSpreadImpliedVolatility); final EuropeanVanillaOption optionSpread = new EuropeanVanillaOption(cmsSpread.getStrike(), cmsSpread.getFixingTime(), cmsSpread.isCap()); final Function1D<NormalFunctionData, Double> normalFunction = NORMAL_PRICE.getPriceFunction(optionSpread); final double cmsSpreadPrice = normalFunction.evaluate(dataSpread); return MultipleCurrencyAmount.of(cmsSpread.getCurrency(), cmsSpreadPrice); } 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 presentValue() { final double correlation = 0.80; final DoubleFunction1D correlationFunction = new RealPolynomialFunction1D(new double[] {correlation}); final CapFloorCMSSpreadSABRBinormalMethod method = new CapFloorCMSSpreadSABRBinormalMethod(correlationFunction, METHOD_CMS_CAP, METHOD_CMS_COUPON); final double cmsSpreadPrice = method.presentValue(CMS_CAP_SPREAD, SABR_MULTICURVES).getAmount(EUR); final double discountFactorPayment = MULTICURVES.getDiscountFactor(EUR, PAYMENT_TIME); final CouponCMSSABRReplicationMethod methodCms = CouponCMSSABRReplicationMethod.getInstance(); final CapFloorCMSSABRReplicationMethod methodCmsCap = CapFloorCMSSABRReplicationMethod.getDefaultInstance(); final NormalImpliedVolatilityFormula impliedVolatility = new NormalImpliedVolatilityFormula(); final NormalPriceFunction normalPrice = new NormalPriceFunction(); final CouponCMS cmsCoupon1 = CouponCMS.from(CMS_CAP_SPREAD, SWAP_1, SETTLEMENT_TIME); final CouponCMS cmsCoupon2 = CouponCMS.from(CMS_CAP_SPREAD, SWAP_2, SETTLEMENT_TIME); final double cmsCoupon1Price = methodCms.presentValue(cmsCoupon1, SABR_MULTICURVES).getAmount(EUR); final double cmsCoupon2Price = methodCms.presentValue(cmsCoupon2, SABR_MULTICURVES).getAmount(EUR); final double expectedRate1 = cmsCoupon1Price / discountFactorPayment / cmsCoupon1.getNotional() / cmsCoupon1.getPaymentYearFraction(); final double expectedRate2 = cmsCoupon2Price / discountFactorPayment / cmsCoupon2.getNotional() / cmsCoupon2.getPaymentYearFraction(); final double forward1 = SWAP_1.accept(PRDC, MULTICURVES); final double forward2 = SWAP_2.accept(PRDC, MULTICURVES); final CapFloorCMS cmsCap1 = CapFloorCMS.from(cmsCoupon1, forward1, true); final CapFloorCMS cmsCap2 = CapFloorCMS.from(cmsCoupon2, forward2, true); final double cmsCap1Price = methodCmsCap.presentValue(cmsCap1, SABR_MULTICURVES).getAmount(EUR); final double cmsCap2Price = methodCmsCap.presentValue(cmsCap2, SABR_MULTICURVES).getAmount(EUR); final EuropeanVanillaOption optionCap1 = new EuropeanVanillaOption(forward1, FIXING_TIME, true); final NormalFunctionData dataCap1 = new NormalFunctionData(expectedRate1, 1.0, 0.0); final double cmsCap1IV = impliedVolatility.getImpliedVolatility(dataCap1, optionCap1, cmsCap1Price / discountFactorPayment / cmsCoupon1.getNotional() / cmsCoupon1.getPaymentYearFraction()); final EuropeanVanillaOption optionCap2 = new EuropeanVanillaOption(forward2, FIXING_TIME, true); final NormalFunctionData dataCap2 = new NormalFunctionData(expectedRate2, 1.0, 0.0); final double cmsCap2IV = impliedVolatility.getImpliedVolatility(dataCap2, optionCap2, cmsCap2Price / discountFactorPayment / cmsCoupon2.getNotional() / cmsCoupon2.getPaymentYearFraction()); double spreadVol = cmsCap1IV * cmsCap1IV - 2 * correlation * cmsCap1IV * cmsCap2IV + cmsCap2IV * cmsCap2IV; spreadVol = Math.sqrt(spreadVol); final EuropeanVanillaOption optionSpread = new EuropeanVanillaOption(STRIKE, FIXING_TIME, IS_CAP); final NormalFunctionData dataSpread = new NormalFunctionData(expectedRate1 - expectedRate2, 1.0, spreadVol); final Function1D<NormalFunctionData, Double> priceFunction = normalPrice.getPriceFunction(optionSpread); final double cmsSpreadPriceExpected = discountFactorPayment * priceFunction.evaluate(dataSpread) * CMS_CAP_SPREAD.getNotional() * CMS_CAP_SPREAD.getPaymentYearFraction(); assertEquals("CMS spread: price with constant correlation", cmsSpreadPriceExpected, cmsSpreadPrice, TOLERANCE_PV); }
@Test public void presentValueConstructor() { final CapFloorCMSSpreadSABRBinormalMethod methodDefault = new CapFloorCMSSpreadSABRBinormalMethod(CORRELATION_FUNCTION, METHOD_CMS_CAP, METHOD_CMS_COUPON); final MultipleCurrencyAmount pvDefault = methodDefault.presentValue(CMS_CAP_SPREAD, SABR_MULTICURVES); final CapFloorCMSSpreadSABRBinormalMethod methodNoExtrapolation = new CapFloorCMSSpreadSABRBinormalMethod(CORRELATION_FUNCTION, METHOD_CMS_CAP, METHOD_CMS_COUPON); final MultipleCurrencyAmount pvNoExtrapolation = methodNoExtrapolation.presentValue(CMS_CAP_SPREAD, SABR_MULTICURVES); assertEquals("CMS spread: price with constant correlation", pvDefault.getAmount(EUR), pvNoExtrapolation.getAmount(EUR), TOLERANCE_PV); }
@Test public void presentValueRightExtrapolation() { final MultipleCurrencyAmount pvExtrapolation = METHOD_CMS_SPREAD_EXTRAPOLATION.presentValue(CMS_CAP_SPREAD, SABR_MULTICURVES); final double pvHardCoded = 71760.169; assertEquals("CMS spread: price with constant correlation", pvHardCoded, pvExtrapolation.getAmount(EUR), TOLERANCE_PV); }
@Test public void presentValueLongShortParity() { 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); final MultipleCurrencyAmount pvCapLong = METHOD_CMS_SPREAD.presentValue(CMS_CAP_SPREAD, SABR_MULTICURVES); final MultipleCurrencyAmount pvCapShort = METHOD_CMS_SPREAD.presentValue(cmsCapSpreadShort, SABR_MULTICURVES); assertEquals("CMS spread: Long/Short parity", pvCapLong.getAmount(EUR), -pvCapShort.getAmount(EUR), TOLERANCE_PV); final MultipleCurrencyAmount pvCapLongExtra = METHOD_CMS_SPREAD_EXTRAPOLATION.presentValue(CMS_CAP_SPREAD, SABR_MULTICURVES); final MultipleCurrencyAmount pvCapShortExtra = METHOD_CMS_SPREAD_EXTRAPOLATION.presentValue(cmsCapSpreadShort, SABR_MULTICURVES); assertEquals("CMS spread: Long/Short parity", pvCapLongExtra.getAmount(EUR), -pvCapShortExtra.getAmount(EUR), TOLERANCE_PV); final CapFloorCMSSpread cmsFloorSpreadShort = 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 MultipleCurrencyAmount pvFloorLong = METHOD_CMS_SPREAD.presentValue(CMS_FLOOR_SPREAD, SABR_MULTICURVES); final MultipleCurrencyAmount pvFloorShort = METHOD_CMS_SPREAD.presentValue(cmsFloorSpreadShort, SABR_MULTICURVES); assertEquals("CMS spread: Long/Short parity", pvFloorLong.getAmount(EUR), -pvFloorShort.getAmount(EUR), TOLERANCE_PV); final MultipleCurrencyAmount pvFloorLongExtra = METHOD_CMS_SPREAD_EXTRAPOLATION.presentValue(CMS_FLOOR_SPREAD, SABR_MULTICURVES); final MultipleCurrencyAmount pvFloorShortExtra = METHOD_CMS_SPREAD_EXTRAPOLATION.presentValue(cmsFloorSpreadShort, SABR_MULTICURVES); assertEquals("CMS spread: Long/Short parity", pvFloorLongExtra.getAmount(EUR), -pvFloorShortExtra.getAmount(EUR), TOLERANCE_PV); }
@Test public void presentValueCapFloorParity() { 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); final MultipleCurrencyAmount pvCapLong = METHOD_CMS_SPREAD.presentValue(CMS_CAP_SPREAD, SABR_MULTICURVES); final MultipleCurrencyAmount pvFloorLong = METHOD_CMS_SPREAD.presentValue(CMS_FLOOR_SPREAD, SABR_MULTICURVES); final MultipleCurrencyAmount pvCMS1 = cms1.accept(PVSSC, SABR_MULTICURVES); final MultipleCurrencyAmount pvCMS2 = cms2.accept(PVSSC, SABR_MULTICURVES); final MultipleCurrencyAmount pvStrike = cpnStrike.accept(PVDC, MULTICURVES); assertEquals("CMS spread: Cap/Floor parity", pvCMS1.getAmount(EUR) - pvCMS2.getAmount(EUR) - pvStrike.getAmount(EUR), pvCapLong.getAmount(EUR) - pvFloorLong.getAmount(EUR), TOLERANCE_PV); final MultipleCurrencyAmount pvCapLongExtra = METHOD_CMS_SPREAD_EXTRAPOLATION.presentValue(CMS_CAP_SPREAD, SABR_MULTICURVES); final MultipleCurrencyAmount pvFloorLongExtra = METHOD_CMS_SPREAD_EXTRAPOLATION.presentValue(CMS_FLOOR_SPREAD, SABR_MULTICURVES); final MultipleCurrencyAmount pvCMS1Extra = cms1.accept(PVSSXC, SABR_MULTICURVES); final MultipleCurrencyAmount pvCMS2Extra = cms2.accept(PVSSXC, SABR_MULTICURVES); assertEquals("CMS spread: Cap/Floor parity", pvCMS1Extra.getAmount(EUR) - pvCMS2Extra.getAmount(EUR) - pvStrike.getAmount(EUR), pvCapLongExtra.getAmount(EUR) - pvFloorLongExtra.getAmount(EUR), TOLERANCE_PV); }
@Test public void presentValueMethodVsCalculator() { final MultipleCurrencyAmount pvMethod = METHOD_CMS_SPREAD.presentValue(CMS_CAP_SPREAD, SABR_MULTICURVES); final MultipleCurrencyAmount pvCalculator = CMS_CAP_SPREAD.accept(PVSSC, SABR_MULTICURVES); assertEquals("CMS spread: present value Method vs Calculator", pvMethod.getAmount(EUR), pvCalculator.getAmount(EUR), TOLERANCE_PV); final MultipleCurrencyAmount pvExtraMethod = METHOD_CMS_SPREAD_EXTRAPOLATION.presentValue(CMS_CAP_SPREAD, SABR_MULTICURVES); final MultipleCurrencyAmount pvExtraCalculator = CMS_CAP_SPREAD.accept(PVSSXC, SABR_MULTICURVES); assertEquals("CMS spread: present value Method vs Calculator", pvExtraMethod.getAmount(EUR), pvExtraCalculator.getAmount(EUR), TOLERANCE_PV); }