CapFloorCMSSABRExtrapolationRightReplicationMethod extends CapFloorCMSSABRReplicationAbstractMethod { @Override public MultipleCurrencyAmount presentValue(final CapFloorCMS cmsCapFloor, final SABRSwaptionProviderInterface sabrData) { ArgumentChecker.notNull(cmsCapFloor, "CMA cap/floor"); ArgumentChecker.notNull(sabrData, "SABR swaption provider"); final Currency ccy = cmsCapFloor.getCurrency(); final SABRInterestRateParameters sabrParameter = sabrData.getSABRParameter(); final SwapFixedCoupon<? extends Payment> underlyingSwap = cmsCapFloor.getUnderlyingSwap(); final double forward = underlyingSwap.accept(PRDC, sabrData.getMulticurveProvider()); final double discountFactorTp = sabrData.getMulticurveProvider().getDiscountFactor(ccy, cmsCapFloor.getPaymentTime()); final double maturity = underlyingSwap.getFixedLeg().getNthPayment(underlyingSwap.getFixedLeg().getNumberOfPayments() - 1).getPaymentTime() - cmsCapFloor.getSettlementTime(); final DoublesPair expiryMaturity = DoublesPair.of(cmsCapFloor.getFixingTime(), maturity); final double alpha = sabrParameter.getAlpha(expiryMaturity); final double beta = sabrParameter.getBeta(expiryMaturity); final double rho = sabrParameter.getRho(expiryMaturity); final double nu = sabrParameter.getNu(expiryMaturity); final SABRFormulaData sabrPoint = new SABRFormulaData(alpha, beta, rho, nu); final CMSIntegrant integrant = new CMSIntegrant(cmsCapFloor, sabrPoint, forward, _cutOffStrike, _mu); final double strike = cmsCapFloor.getStrike(); final double factor = discountFactorTp / integrant.h(forward) * integrant.g(forward); final double strikePart = factor * integrant.k(strike) * integrant.bs(strike); final double absoluteTolerance = 1.0 / (factor * Math.abs(cmsCapFloor.getNotional()) * cmsCapFloor.getPaymentYearFraction()); final double relativeTolerance = 1E-10; final RungeKuttaIntegrator1D integrator = new RungeKuttaIntegrator1D(absoluteTolerance, relativeTolerance, getNbIteration()); double integralPart; try { if (cmsCapFloor.isCap()) { integralPart = discountFactorTp * integrator.integrate(integrant, strike, strike + getIntegrationInterval()); } else { integralPart = discountFactorTp * integrator.integrate(integrant, 0.0, strike); } } catch (final Exception e) { throw new MathException(e); } final double priceCMS = (strikePart + integralPart) * cmsCapFloor.getNotional() * cmsCapFloor.getPaymentYearFraction(); return MultipleCurrencyAmount.of(cmsCapFloor.getCurrency(), priceCMS); } CapFloorCMSSABRExtrapolationRightReplicationMethod(final double cutOffStrike, final double mu);  CapFloorCMSSABRExtrapolationRightReplicationMethod(final double cutOffStrike, final double mu, final double integrationInterval); @Override MultipleCurrencyAmount presentValue(final CapFloorCMS cmsCapFloor, final SABRSwaptionProviderInterface sabrData); @Override MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final CapFloorCMS cmsCapFloor, final SABRSwaptionProviderInterface sabrData); @Override PresentValueSABRSensitivityDataBundle presentValueSABRSensitivity(final CapFloorCMS cmsCapFloor, final SABRSwaptionProviderInterface sabrData); @Override double presentValueStrikeSensitivity(final CapFloorCMS cmsCapFloor, final SABRSwaptionProviderInterface sabrData);  }
@Test public void presentValue() { final double priceCouponStd = METHOD_STANDARD_CPN.presentValue(CMS_COUPON, SABR_MULTICURVES).getAmount(EUR); final double rateCouponStd = priceCouponStd / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); final double priceCouponExtra = METHOD_EXTRAPOLATION_CPN.presentValue(CMS_COUPON, SABR_MULTICURVES).getAmount(EUR); final double rateCouponExtra = priceCouponExtra / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); final double priceCouponNoAdj = METHOD_DSC_CPN.presentValue(CMS_COUPON, MULTICURVES).getAmount(EUR); final double rateCouponNoAdj = priceCouponNoAdj / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); assertEquals("Extrapolation: comparison with standard method", rateCouponStd > rateCouponExtra, true); assertEquals("Extrapolation: comparison with no convexity adjustment", rateCouponExtra > rateCouponNoAdj, true); final double rateCouponExtraExpected = 0.0189864; assertEquals("Extrapolation: hard-coded value", rateCouponExtraExpected, rateCouponExtra, 1E-6); final double priceCap0Extra = METHOD_EXTRAPOLATION_CAP.presentValue(CMS_CAP_0, SABR_MULTICURVES).getAmount(EUR); assertEquals("Extrapolation: CMS coupon vs Cap 0", priceCouponExtra, priceCap0Extra, TOLERANCE_PV); }
@Test public void presentValueMethodVsCalculator() { final double pvMethod = METHOD_EXTRAPOLATION_CAP.presentValue(CMS_CAP_LONG, SABR_MULTICURVES).getAmount(EUR); final double pvCalculator = CMS_CAP_LONG.accept(PVSSXC, SABR_MULTICURVES).getAmount(EUR); assertEquals("CMS cap/floor SABR: Present value : method vs calculator", pvMethod, pvCalculator, TOLERANCE_PV); }
@Test public void presentValueReplicationCap() { final double priceCapLongStd = METHOD_STANDARD_CAP.presentValue(CMS_CAP_LONG, SABR_MULTICURVES).getAmount(EUR); final double priceCapLongExtra = METHOD_EXTRAPOLATION_CAP.presentValue(CMS_CAP_LONG, SABR_MULTICURVES).getAmount(EUR); final double priceCapShortExtra = METHOD_EXTRAPOLATION_CAP.presentValue(CMS_CAP_SHORT, SABR_MULTICURVES).getAmount(EUR); assertEquals("CMS cap by replication - Extrapolation: comparison with standard method", priceCapLongStd > priceCapLongExtra, true); final double priceCapExtraExpected = 30696.572; assertEquals("CMS cap by replication - Extrapolation: hard-coded value", priceCapExtraExpected, priceCapLongExtra, TOLERANCE_PV); assertEquals("CMS cap by replication - Extrapolation: long/short parity", -priceCapShortExtra, priceCapLongExtra, TOLERANCE_PV); }
@Test(enabled = true) public void testPriceMultiMu() { final double[] mu = new double[] {1.10, 1.30, 1.55, 2.25, 3.50, 6.00, 15.0}; final int nbMu = mu.length; final double priceCouponStd = METHOD_STANDARD_CPN.presentValue(CMS_COUPON, SABR_MULTICURVES).getAmount(EUR); @SuppressWarnings("unused") final double rateCouponStd = priceCouponStd / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); final double[] priceCouponExtra = new double[nbMu]; final double[] rateCouponExtra = new double[nbMu]; for (int loopmu = 0; loopmu < nbMu; loopmu++) { final CouponCMSSABRExtrapolationRightReplicationMethod methodExtrapolation = new CouponCMSSABRExtrapolationRightReplicationMethod(CUT_OFF_STRIKE, mu[loopmu]); priceCouponExtra[loopmu] = methodExtrapolation.presentValue(CMS_COUPON, SABR_MULTICURVES).getAmount(EUR); rateCouponExtra[loopmu] = priceCouponExtra[loopmu] / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); } final double priceCouponNoAdj = METHOD_DSC_CPN.presentValue(CMS_COUPON, MULTICURVES).getAmount(EUR); final double rateCouponNoAdj = priceCouponNoAdj / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); for (int loopmu = 1; loopmu < nbMu; loopmu++) { assertTrue("Extrapolation: comparison with standard method", rateCouponExtra[loopmu - 1] > rateCouponExtra[loopmu]); } assertTrue("Extrapolation: comparison with standard method", rateCouponExtra[nbMu - 1] > rateCouponNoAdj); }