/**
* 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.method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivative;
import com.opengamma.analytics.financial.interestrate.InterestRateCurveSensitivity;
import com.opengamma.analytics.financial.interestrate.ParRateCalculator;
import com.opengamma.analytics.financial.interestrate.ParRateCurveSensitivityCalculator;
import com.opengamma.analytics.financial.interestrate.PresentValueSABRSensitivityDataBundle;
import com.opengamma.analytics.financial.interestrate.YieldCurveBundle;
import com.opengamma.analytics.financial.interestrate.method.PricingMethod;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CapFloorCMS;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CapFloorCMSSpread;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponCMS;
import com.opengamma.analytics.financial.model.option.definition.SABRInterestRateDataBundle;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.NormalFunctionData;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.NormalPriceFunction;
import com.opengamma.analytics.financial.model.volatility.NormalImpliedVolatilityFormula;
import com.opengamma.analytics.math.function.DoubleFunction1D;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.function.RealPolynomialFunction1D;
import com.opengamma.analytics.math.rootfinding.BrentSingleRootFinder;
import com.opengamma.util.money.CurrencyAmount;
import com.opengamma.util.tuple.DoublesPair;
/**
* Class used to compute the price of a CMS spread cap/floor with the bi-normal approach with correlation by strike.
* OpenGamma implementation note: Bi-normal with correlation by strike approach to CMS spread pricing, version 1.1, June 2011.
* @deprecated {@link SABRInterestRateDataBundle} is deprecated
*/
@Deprecated
public class CapFloorCMSSpreadSABRBinormalMethod implements PricingMethod {
/**
* The par rate calculator.
*/
private static final ParRateCalculator PRC = ParRateCalculator.getInstance();
private static final ParRateCurveSensitivityCalculator PRCSC = ParRateCurveSensitivityCalculator.getInstance();
/**
* The formula used to compute the implied volatility.
*/
private static final NormalImpliedVolatilityFormula NORMAL_IMPLIED_VOLATILITY = new NormalImpliedVolatilityFormula();
/**
* The formula used to compute the implied volatility.
*/
private static final NormalPriceFunction NORMAL_PRICE = new NormalPriceFunction();
/**
* The method to compute the price of CMS cap/floors.
*/
private final CapFloorCMSSABRReplicationAbstractMethod _methodCmsCap;
/**
* The method to compute the price o CMS coupons.
*/
private final CouponCMSSABRReplicationGenericMethod _methodCmsCoupon;
/**
* The correlation as function of the strike.
*/
private final DoubleFunction1D _correlation;
/**
* Constructor of the CMS spread cap/floor method with the CMS cap and coupon methods.
* @param correlation The rates correlation.
* @param methodCmsCap The pricing method for the CMS cap/floor.
* @param methodCmsCoupon The pricing method for the CMS coupons.
*/
public CapFloorCMSSpreadSABRBinormalMethod(final DoubleFunction1D correlation, final CapFloorCMSSABRReplicationAbstractMethod methodCmsCap,
final CouponCMSSABRReplicationGenericMethod methodCmsCoupon) {
Validate.notNull(correlation, "Correlation");
_correlation = correlation;
_methodCmsCap = methodCmsCap;
_methodCmsCoupon = methodCmsCoupon;
}
/**
* Gets the correlation (rho) as function of the strike.
* @return The correlation
*/
public DoubleFunction1D getCorrelation() {
return _correlation;
}
/**
* Compute the present value of a CMS spread cap/floor in the binormal approach.
* @param cmsSpread The CMS spread cap/floor.
* @param sabrData The SABR data bundle.
* @return The present value.
*/
public CurrencyAmount presentValue(final CapFloorCMSSpread cmsSpread, final SABRInterestRateDataBundle sabrData) {
final double forward1 = cmsSpread.getUnderlyingSwap1().accept(PRC, sabrData);
final double forward2 = cmsSpread.getUnderlyingSwap2().accept(PRC, sabrData);
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();
final double cmsCoupon2Price = _methodCmsCoupon.presentValue(cmsCoupon2, sabrData).getAmount();
final double cmsCap1Price = _methodCmsCap.presentValue(cmsCap1, sabrData).getAmount();
final double cmsCap2Price = _methodCmsCap.presentValue(cmsCap2, sabrData).getAmount();
final double discountFactorPayment = sabrData.getCurve(cmsSpread.getFundingCurveName()).getDiscountFactor(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) {
//TODO
}
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) {
//TODO
}
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 CurrencyAmount.of(cmsSpread.getCurrency(), cmsSpreadPrice);
}
@Override
public CurrencyAmount presentValue(final InstrumentDerivative instrument, final YieldCurveBundle curves) {
Validate.isTrue(instrument instanceof CapFloorCMSSpread, "CMS spread cap/floor");
Validate.isTrue(curves instanceof SABRInterestRateDataBundle, "Bundle should contain SABR data");
return presentValue((CapFloorCMSSpread) instrument, (SABRInterestRateDataBundle) curves);
}
/**
* Compute the implied correlation for a specific CMS spread cap/floor from the given price. The model correlation structure is not used.
* @param cmsSpread The CMS spread cap/floor.
* @param sabrData The SABR data bundle.
* @param price The CMS spread price.
* @return The implied correlation.
*/
public double impliedCorrelation(final CapFloorCMSSpread cmsSpread, final SABRInterestRateDataBundle sabrData, final double price) {
final SolveCorrelation function = new SolveCorrelation(cmsSpread, sabrData, price);
final BrentSingleRootFinder finder = new BrentSingleRootFinder();
final double correlation = finder.getRoot(function, -0.999, 0.999);
return correlation;
}
/**
* Computes the present value curves sensitivity of a CMS spread cap/floor in the bi-normal approach.
* For the CMS cap/floor volatility calibration, ATM forward strikes are used.
* @param cmsSpread The CMS spread cap/floor.
* @param sabrData The SABR data bundle.
* @return The present value curve sensitivity.
*/
public InterestRateCurveSensitivity presentValueCurveSensitivity(final CapFloorCMSSpread cmsSpread, final SABRInterestRateDataBundle sabrData) {
// Forward sweep
final double strike1 = cmsSpread.getUnderlyingSwap1().accept(PRC, sabrData);
final double strike2 = cmsSpread.getUnderlyingSwap2().accept(PRC, sabrData);
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, strike1, true); // ATM forward cap CMS
final CapFloorCMS cmsCap2 = CapFloorCMS.from(cmsCoupon2, strike2, true); // ATM forward cap CMS
final double cmsCoupon1Pv = _methodCmsCoupon.presentValue(cmsCoupon1, sabrData).getAmount();
final double cmsCoupon2Pv = _methodCmsCoupon.presentValue(cmsCoupon2, sabrData).getAmount();
final double cmsCap1Pv = _methodCmsCap.presentValue(cmsCap1, sabrData).getAmount();
final double cmsCap2Pv = _methodCmsCap.presentValue(cmsCap2, sabrData).getAmount();
final double discountFactorPayment = sabrData.getCurve(cmsSpread.getFundingCurveName()).getDiscountFactor(cmsSpread.getPaymentTime());
final double factor = discountFactorPayment * cmsCap1.getNotional() * cmsCap1.getPaymentYearFraction();
final double expectation1 = cmsCoupon1Pv / factor;
final double expectation2 = cmsCoupon2Pv / factor;
NormalFunctionData dataCap1 = new NormalFunctionData(expectation1, factor, 0.0);
final EuropeanVanillaOption optionCap1 = new EuropeanVanillaOption(strike1, cmsSpread.getFixingTime(), true);
double cmsCap1ImpliedVolatility = 0;
try {
cmsCap1ImpliedVolatility = NORMAL_IMPLIED_VOLATILITY.getImpliedVolatility(dataCap1, optionCap1, cmsCap1Pv);
} catch (final Exception e) {
//TODO
}
NormalFunctionData dataCap2 = new NormalFunctionData(expectation2, factor, cmsCap1ImpliedVolatility);
final EuropeanVanillaOption optionCap2 = new EuropeanVanillaOption(strike2, cmsSpread.getFixingTime(), true);
double cmsCap2ImpliedVolatility = 0;
try {
cmsCap2ImpliedVolatility = NORMAL_IMPLIED_VOLATILITY.getImpliedVolatility(dataCap2, optionCap2, cmsCap2Pv);
} catch (final Exception e) {
//TODO
}
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[] cmsSpreadPvDerivative = new double[3];
final double cmsSpreadPv = NORMAL_PRICE.getPriceAdjoint(optionSpread, dataSpread, cmsSpreadPvDerivative);
// Backward sweep
final double cmsSpreadPvBar = 1.0;
final double cmsSpreadImpliedVolatilityBar = cmsSpreadPvDerivative[1] * cmsSpreadPvBar;
final double cmsCap2ImpliedVolatilityBar = (cmsCap2ImpliedVolatility - rho * cmsCap1ImpliedVolatility) / cmsSpreadImpliedVolatility * cmsSpreadImpliedVolatilityBar; // OK
final double cmsCap1ImpliedVolatilityBar = (cmsCap1ImpliedVolatility - rho * cmsCap2ImpliedVolatility) / cmsSpreadImpliedVolatility * cmsSpreadImpliedVolatilityBar; // OK
dataCap2 = new NormalFunctionData(expectation2, factor, cmsCap2ImpliedVolatility);
final double[] cmsCap2PriceNormalDerivative = new double[3];
NORMAL_PRICE.getPriceAdjoint(optionCap2, dataCap2, cmsCap2PriceNormalDerivative);
final double expectation2Bar = -cmsSpreadPvDerivative[0] * cmsSpreadPvBar + -cmsCap2PriceNormalDerivative[0] / cmsCap2PriceNormalDerivative[1] * cmsCap2ImpliedVolatilityBar; // OK
dataCap1 = new NormalFunctionData(expectation1, factor, cmsCap1ImpliedVolatility);
final double[] cmsCap1PriceNormalDerivative = new double[3];
NORMAL_PRICE.getPriceAdjoint(optionCap1, dataCap1, cmsCap1PriceNormalDerivative);
final double expectation1Bar = cmsSpreadPvDerivative[0] * cmsSpreadPvBar + -cmsCap1PriceNormalDerivative[0] / cmsCap1PriceNormalDerivative[1] * cmsCap1ImpliedVolatilityBar; // OK
final double factorBar = -cmsCoupon1Pv / (factor * factor) * expectation1Bar + -cmsCoupon2Pv / (factor * factor) * expectation2Bar - cmsCap2Pv / factor / cmsCap2PriceNormalDerivative[1]
* cmsCap2ImpliedVolatilityBar - cmsCap1Pv / factor / cmsCap1PriceNormalDerivative[1] * cmsCap1ImpliedVolatilityBar; // OK
final double discountFactorPaymentBar = cmsCap1.getNotional() * cmsCap1.getPaymentYearFraction() * factorBar + cmsSpreadPv / discountFactorPayment * cmsSpreadPvBar;
final double cmsCap2PvBar = 1.0 / cmsCap2PriceNormalDerivative[1] * cmsCap2ImpliedVolatilityBar; // OK
final double cmsCap1PvBar = 1.0 / cmsCap1PriceNormalDerivative[1] * cmsCap1ImpliedVolatilityBar; // OK
final double cmsCoupon2PvBar = expectation2Bar / factor; // OK
final double cmsCoupon1PvBar = expectation1Bar / factor; // OK
//Calibration strike dependency -- START
double strike1Bar = -cmsCap1PriceNormalDerivative[2] / cmsCap1PriceNormalDerivative[1] * cmsCap1ImpliedVolatilityBar;
double strike2Bar = -cmsCap2PriceNormalDerivative[2] / cmsCap2PriceNormalDerivative[1] * cmsCap2ImpliedVolatilityBar;
strike1Bar += _methodCmsCap.presentValueStrikeSensitivity(cmsCap1, sabrData) * cmsCap1PvBar;
strike2Bar += _methodCmsCap.presentValueStrikeSensitivity(cmsCap2, sabrData) * cmsCap2PvBar;
final InterestRateCurveSensitivity forward1CurveSensitivity = new InterestRateCurveSensitivity(cmsSpread.getUnderlyingSwap1().accept(PRCSC, sabrData));
final InterestRateCurveSensitivity forward2CurveSensitivity = new InterestRateCurveSensitivity(cmsSpread.getUnderlyingSwap2().accept(PRCSC, sabrData));
//Calibration strike dependency -- END
final InterestRateCurveSensitivity cmsCoupon1CurveSensitivity = _methodCmsCoupon.presentValueCurveSensitivity(cmsCoupon1, sabrData);
final InterestRateCurveSensitivity cmsCoupon2CurveSensitivity = _methodCmsCoupon.presentValueCurveSensitivity(cmsCoupon2, sabrData);
final InterestRateCurveSensitivity cmsCap1CurveSensitivity = _methodCmsCap.presentValueCurveSensitivity(cmsCap1, sabrData);
final InterestRateCurveSensitivity cmsCap2CurveSensitivity = _methodCmsCap.presentValueCurveSensitivity(cmsCap2, sabrData);
final List<DoublesPair> list = new ArrayList<>();
list.add(new DoublesPair(cmsSpread.getPaymentTime(), -cmsSpread.getPaymentTime() * discountFactorPayment));
final Map<String, List<DoublesPair>> resultMap = new HashMap<>();
resultMap.put(cmsSpread.getFundingCurveName(), list);
final InterestRateCurveSensitivity dfCurveSensitivity = new InterestRateCurveSensitivity(resultMap);
InterestRateCurveSensitivity result;
result = dfCurveSensitivity.multipliedBy(discountFactorPaymentBar);
result = result.plus(cmsCoupon1CurveSensitivity.multipliedBy(cmsCoupon1PvBar));
result = result.plus(cmsCoupon2CurveSensitivity.multipliedBy(cmsCoupon2PvBar));
result = result.plus(cmsCap1CurveSensitivity.multipliedBy(cmsCap1PvBar));
result = result.plus(cmsCap2CurveSensitivity.multipliedBy(cmsCap2PvBar));
//Calibration strike dependency -- START
result = result.plus(forward1CurveSensitivity.multipliedBy(strike1Bar));
result = result.plus(forward2CurveSensitivity.multipliedBy(strike2Bar));
//Calibration strike dependency -- END
return result;
}
/**
* Computes the present value sensitivity to the SABR parameters of a CMS spread cap/floor in the SABR framework.
* @param cmsSpread The CMS spread cap/floor.
* @param sabrData The SABR data bundle.
* @return The present value SABR sensitivity.
*/
public PresentValueSABRSensitivityDataBundle presentValueSABRSensitivity(final CapFloorCMSSpread cmsSpread, final SABRInterestRateDataBundle sabrData) {
// Forward sweep
final double forward1 = cmsSpread.getUnderlyingSwap1().accept(PRC, sabrData);
final double forward2 = cmsSpread.getUnderlyingSwap2().accept(PRC, sabrData);
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();
final double cmsCoupon2Price = _methodCmsCoupon.presentValue(cmsCoupon2, sabrData).getAmount();
final double cmsCap1Price = _methodCmsCap.presentValue(cmsCap1, sabrData).getAmount();
final double cmsCap2Price = _methodCmsCap.presentValue(cmsCap2, sabrData).getAmount();
final double discountFactorPayment = sabrData.getCurve(cmsSpread.getFundingCurveName()).getDiscountFactor(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) {
//TODO
}
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) {
//TODO
}
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);
// Backward sweep
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;
}
/**
* Inner class to solve for the implied correlation.
*/
class SolveCorrelation extends DoubleFunction1D {
/**
* The CMS spread cap/floor.
*/
private final CapFloorCMSSpread _cmsSpread;
/**
* The SABR data bundle.
*/
private final SABRInterestRateDataBundle _sabrData;
/**
* The CMS spread price.
*/
private final double _price;
/**
* Constructor of the difference function.
* @param cmsSpread The CMS spread cap/floor.
* @param sabrData The SABR data bundle.
* @param price The CMS spread price.
*/
public SolveCorrelation(final CapFloorCMSSpread cmsSpread, final SABRInterestRateDataBundle sabrData, final double price) {
this._cmsSpread = cmsSpread;
this._sabrData = sabrData;
this._price = price;
}
@Override
public Double evaluate(final Double x) {
@SuppressWarnings("synthetic-access")
final CapFloorCMSSpreadSABRBinormalMethod method = new CapFloorCMSSpreadSABRBinormalMethod(new RealPolynomialFunction1D(new double[] {x }), _methodCmsCap, _methodCmsCoupon);
return method.presentValue(_cmsSpread, _sabrData).getAmount() - _price;
}
}
}