CapFloorIborLMMDDMethod { public MultipleCurrencyAmount presentValue(final CapFloorIbor cap, final LiborMarketModelDisplacedDiffusionProviderInterface lmmData) { ArgumentChecker.notNull(cap, "The cap/floor shoud not be null"); ArgumentChecker.notNull(lmmData, "LMM provider"); Currency ccy = cap.getCurrency(); MulticurveProviderInterface multicurves = lmmData.getMulticurveProvider(); LiborMarketModelDisplacedDiffusionParameters parameters = lmmData.getLMMParameters(); int index = lmmData.getLMMParameters().getTimeIndex(cap.getFixingPeriodStartTime()); double volatility = 0; for (int loopfact = 0; loopfact < lmmData.getLMMParameters().getNbFactor(); loopfact++) { volatility += parameters.getVolatility()[index][loopfact] * parameters.getVolatility()[index][loopfact]; } volatility = Math.sqrt(volatility); double timeDependentFactor = Math.sqrt((Math.exp(2 * parameters.getMeanReversion() * cap.getFixingTime()) - 1.0) / (2.0 * parameters.getMeanReversion())); volatility *= timeDependentFactor; double displacement = parameters.getDisplacement()[index]; double forward = multicurves.getSimplyCompoundForwardRate(cap.getIndex(), cap.getFixingPeriodStartTime(), cap.getFixingPeriodEndTime(), cap.getFixingAccrualFactor()); double beta = (1.0 + cap.getFixingAccrualFactor() * forward) * multicurves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime()) / multicurves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime()); double strikeAdjusted = (cap.getStrike() - (beta - 1) / cap.getFixingAccrualFactor()) / beta; EuropeanVanillaOption option = new EuropeanVanillaOption(strikeAdjusted + displacement, 1.0, cap.isCap()); double forwardDsc = (multicurves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime()) / multicurves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime()) - 1.0) / cap.getFixingAccrualFactor(); final double df = multicurves.getDiscountFactor(ccy, cap.getPaymentTime()); final BlackFunctionData dataBlack = new BlackFunctionData(forwardDsc + displacement, df, volatility); final Function1D<BlackFunctionData, Double> func = BLACK_FUNCTION.getPriceFunction(option); final double price = beta * func.evaluate(dataBlack) * cap.getNotional() * cap.getPaymentYearFraction(); return MultipleCurrencyAmount.of(cap.getCurrency(), price); } private  CapFloorIborLMMDDMethod(); static CapFloorIborLMMDDMethod getInstance(); MultipleCurrencyAmount presentValue(final CapFloorIbor cap, final LiborMarketModelDisplacedDiffusionProviderInterface lmmData);  }
@Test public void presentValueExplicit() { final MultipleCurrencyAmount pvLastExplicit = METHOD_LMM_CAP.presentValue(CAP_LAST, LMM_MULTICURVES); final int index = PARAMETERS_LMM.getTimeIndex(CAP_LAST.getFixingPeriodStartTime()); double volatility = 0; for (int loopfact = 0; loopfact < PARAMETERS_LMM.getNbFactor(); loopfact++) { volatility += PARAMETERS_LMM.getVolatility()[index][loopfact] * PARAMETERS_LMM.getVolatility()[index][loopfact]; } volatility = Math.sqrt(volatility); final double timeDependentFactor = Math.sqrt((Math.exp(2 * PARAMETERS_LMM.getMeanReversion() * CAP_LAST.getFixingTime()) - 1.0) / (2.0 * PARAMETERS_LMM.getMeanReversion())); volatility *= timeDependentFactor; final double displacement = PARAMETERS_LMM.getDisplacement()[index]; final double forward = MULTICURVES.getSimplyCompoundForwardRate(CAP_LAST.getIndex(), CAP_LAST.getFixingPeriodStartTime(), CAP_LAST.getFixingPeriodEndTime(), CAP_LAST.getFixingAccrualFactor()); final double beta = (1.0 + CAP_LAST.getFixingAccrualFactor() * forward) * MULTICURVES.getDiscountFactor(EUR, CAP_LAST.getFixingPeriodEndTime()) / MULTICURVES.getDiscountFactor(EUR, CAP_LAST.getFixingPeriodStartTime()); final double strikeAdjusted = (STRIKE - (beta - 1) / CAP_LAST.getFixingAccrualFactor()) / beta; final EuropeanVanillaOption option = new EuropeanVanillaOption(strikeAdjusted + displacement, 1.0, CAP_LAST.isCap()); final double forwardDsc = (MULTICURVES.getDiscountFactor(EUR, CAP_LAST.getFixingPeriodStartTime()) / MULTICURVES.getDiscountFactor(EUR, CAP_LAST.getFixingPeriodEndTime()) - 1.0) / CAP_LAST.getFixingAccrualFactor(); final double df = MULTICURVES.getDiscountFactor(EUR, CAP_LAST.getPaymentTime()); final BlackFunctionData dataBlack = new BlackFunctionData(forwardDsc + displacement, df, volatility); final Function1D<BlackFunctionData, Double> func = BLACK_FUNCTION.getPriceFunction(option); final double pvLastExpected = beta * func.evaluate(dataBlack) * NOTIONAL * CAP_LAST.getPaymentYearFraction(); assertEquals("Cap/floor: LMM pricing by explicit formula - Multi-curves", pvLastExpected, pvLastExplicit.getAmount(EUR), TOLERANCE_PV); }
@Test public void presentValueLongShort() { final MultipleCurrencyAmount pvLastLong = METHOD_LMM_CAP.presentValue(CAP_LAST, LMM_MULTICURVES); final MultipleCurrencyAmount pvLastShort = METHOD_LMM_CAP.presentValue(CAP_LAST_SHORT, LMM_MULTICURVES); assertEquals("Cap/floor: LMM pricing by explicit formula", pvLastLong.getAmount(EUR), -pvLastShort.getAmount(EUR), TOLERANCE_PV); }
@Test public void presentValuePutCallParity() { final MultipleCurrencyAmount pvCapShort = METHOD_LMM_CAP.presentValue(CAP_LAST_SHORT, LMM_MULTICURVES); final MultipleCurrencyAmount pvFloorLong = METHOD_LMM_CAP.presentValue(FLOOR_LAST, LMM_MULTICURVES); final MultipleCurrencyAmount pvFixed = COUPON_FIXED_LAST.accept(PVDC, MULTICURVES); final MultipleCurrencyAmount pvIbor = COUPON_IBOR_LAST.accept(PVDC, MULTICURVES); assertEquals("Cap/floor: LMM pricing by explicit formula", -pvIbor.getAmount(EUR) - pvFixed.getAmount(EUR), pvCapShort.getAmount(EUR) + pvFloorLong.getAmount(EUR), TOLERANCE_PV); }
@Test(enabled = true) public void presentValueMCMultiCurves() { LiborMarketModelMonteCarloMethod methodLmmMc; methodLmmMc = new LiborMarketModelMonteCarloMethod(new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH); final MultipleCurrencyAmount pvLastMC = methodLmmMc.presentValue(CAP_LAST, EUR, LMM_MULTICURVES); final double pvLastPreviousRun = 45829.535; assertEquals("Cap/floor: LMM pricing by Monte Carlo", pvLastPreviousRun, pvLastMC.getAmount(EUR), TOLERANCE_PV); final MultipleCurrencyAmount pvLastExplicit = METHOD_LMM_CAP.presentValue(CAP_LAST, LMM_MULTICURVES); assertEquals("Cap/floor: LMM pricing by Monte Carlo", pvLastExplicit.getAmount(EUR), pvLastMC.getAmount(EUR), 2.5E+2); methodLmmMc = new LiborMarketModelMonteCarloMethod(new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH); final MultipleCurrencyAmount pv6MC = methodLmmMc.presentValue(CAP_6, EUR, LMM_MULTICURVES); final double pv6PreviousRun = 12081.062; assertEquals("Cap/floor: LMM pricing by Monte Carlo", pv6PreviousRun, pv6MC.getAmount(EUR), TOLERANCE_PV); final MultipleCurrencyAmount pv6Explicit = METHOD_LMM_CAP.presentValue(CAP_6, LMM_MULTICURVES); assertEquals("Cap/floor: LMM pricing by Monte Carlo", pv6Explicit.getAmount(EUR), pv6MC.getAmount(EUR), 1.0E+2); }
@Test public void longShortParity() { final MultipleCurrencyAmount pvLongExplicit = METHOD_LMM_CAP.presentValue(CAP_LAST, LMM_MULTICURVES); final MultipleCurrencyAmount pvShortExplicit = METHOD_LMM_CAP.presentValue(CAP_LAST_SHORT, LMM_MULTICURVES); assertEquals("Cap/floor - LMM - present value - long/short parity", pvLongExplicit.getAmount(EUR), -pvShortExplicit.getAmount(EUR), TOLERANCE_PV); LiborMarketModelMonteCarloMethod methodLmmMc; methodLmmMc = new LiborMarketModelMonteCarloMethod(new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH); final MultipleCurrencyAmount pvLongMC = methodLmmMc.presentValue(CAP_LAST, EUR, LMM_MULTICURVES); methodLmmMc = new LiborMarketModelMonteCarloMethod(new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH); final MultipleCurrencyAmount pvShortMC = methodLmmMc.presentValue(CAP_LAST_SHORT, EUR, LMM_MULTICURVES); assertEquals("Cap/floor - LMM - present value MC- long/short parity", pvLongMC.getAmount(EUR), -pvShortMC.getAmount(EUR), TOLERANCE_PV); }
@Test public void capFloorParity() { final MultipleCurrencyAmount pvCapExplicit = METHOD_LMM_CAP.presentValue(CAP_LAST, LMM_MULTICURVES); final MultipleCurrencyAmount pvFloorExplicit = METHOD_LMM_CAP.presentValue(FLOOR_LAST, LMM_MULTICURVES); final MultipleCurrencyAmount pvFixedExplicit = SWAP_PAYER.getFirstLeg().getNthPayment(NB_CPN_IBOR - 1).accept(PVDC, MULTICURVES); final MultipleCurrencyAmount pvIborExplicit = SWAP_PAYER.getSecondLeg().getNthPayment(NB_CPN_IBOR - 1).accept(PVDC, MULTICURVES); assertEquals("Cap/floor - LMM - present value Explcit- cap/floor/strike/Ibor parity", pvCapExplicit.getAmount(EUR) - pvFloorExplicit.getAmount(EUR) - pvFixedExplicit.getAmount(EUR), pvIborExplicit.getAmount(EUR), TOLERANCE_PV); LiborMarketModelMonteCarloMethod methodLmmMc; methodLmmMc = new LiborMarketModelMonteCarloMethod(new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH); final MultipleCurrencyAmount pvCapMC = methodLmmMc.presentValue(CAP_LAST, EUR, LMM_MULTICURVES); methodLmmMc = new LiborMarketModelMonteCarloMethod(new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH); final MultipleCurrencyAmount pvFloorMC = methodLmmMc.presentValue(FLOOR_LAST, EUR, LMM_MULTICURVES); assertEquals("Cap/floor - LMM - present value - cap/floor/strike/Ibor parity", pvCapMC.getAmount(EUR) - pvFloorMC.getAmount(EUR) - pvFixedExplicit.getAmount(EUR), pvIborExplicit.getAmount(EUR), 1.0E+3); }
@Test(enabled = false) public void performance() { long startTime, endTime; final int nbTest = 10; LiborMarketModelMonteCarloMethod methodLmmMc; methodLmmMc = new LiborMarketModelMonteCarloMethod(new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH); final double[] pvMC = new double[nbTest]; startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { pvMC[looptest] = methodLmmMc.presentValue(CAP_LAST, EUR, LMM_MULTICURVES).getAmount(EUR); } endTime = System.currentTimeMillis(); System.out.println(nbTest + " cap/floor LMM Monte Carlo method (" + NB_PATH + " paths): " + (endTime - startTime) + " ms"); }