/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.interestrate.payments.provider; import com.opengamma.analytics.financial.interestrate.payments.derivative.CapFloorIbor; import com.opengamma.analytics.financial.model.interestrate.definition.LiborMarketModelDisplacedDiffusionParameters; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackFunctionData; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackPriceFunction; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption; import com.opengamma.analytics.financial.provider.description.interestrate.LiborMarketModelDisplacedDiffusionProviderInterface; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderInterface; import com.opengamma.analytics.math.function.Function1D; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.money.Currency; import com.opengamma.util.money.MultipleCurrencyAmount; /** * Class used to compute the price a Ibor cap/floor with LMM. * No convexity adjustment is done for payment at non-standard dates. */ public final class CapFloorIborLMMDDMethod { /** * The method unique instance. */ private static final CapFloorIborLMMDDMethod INSTANCE = new CapFloorIborLMMDDMethod(); /** * Private constructor. */ private CapFloorIborLMMDDMethod() { } /** * Return the unique instance of the class. * @return The instance. */ public static CapFloorIborLMMDDMethod getInstance() { return INSTANCE; } /** * The Black function used in the pricing. */ private static final BlackPriceFunction BLACK_FUNCTION = new BlackPriceFunction(); /** * Computes the present value of the cap/floor in the LMM. It is computed using a Black formula (on the shifted rate). The volatility is the LMM volatilities for the * relevant period multiplied by the time dependent factor square mean. * The method is used mainly for calibration purposes. * @param cap The cap. Should have the same underlying index as the model (same payment frequency). * @param lmmData The LMM and multi-curves provider. * @return The present value. */ 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()); // Time is in timeDependentFactor 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); } }