/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.provider.calculator.discounting;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitorAdapter;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponIbor;
import com.opengamma.analytics.financial.interestrate.payments.provider.CouponIborDiscountingMethod;
import com.opengamma.analytics.financial.interestrate.swap.derivative.SwapFixedCoupon;
import com.opengamma.analytics.financial.interestrate.swap.provider.SwapFixedCouponDiscountingMethod;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderInterface;
import com.opengamma.analytics.financial.provider.description.interestrate.ParameterProviderInterface;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MulticurveSensitivity;
import com.opengamma.financial.convention.daycount.DayCount;
import com.opengamma.util.money.Currency;
/**
* Get the single fixed rate that makes the PV of the instrument zero.
*/
public final class ParRateCurveSensitivityDiscountingCalculator
extends InstrumentDerivativeVisitorAdapter<ParameterProviderInterface, MulticurveSensitivity> {
/**
* The unique instance of the calculator.
*/
private static final ParRateCurveSensitivityDiscountingCalculator INSTANCE = new ParRateCurveSensitivityDiscountingCalculator();
/**
* Gets the calculator instance.
* @return The calculator.
*/
public static ParRateCurveSensitivityDiscountingCalculator getInstance() {
return INSTANCE;
}
/**
* Constructor.
*/
private ParRateCurveSensitivityDiscountingCalculator() {
}
/**
* The methods and calculators.
*/
private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance();
private static final PresentValueCurveSensitivityDiscountingCalculator PVCSDC = PresentValueCurveSensitivityDiscountingCalculator.getInstance();
private static final SwapFixedCouponDiscountingMethod METHOD_SWAP = SwapFixedCouponDiscountingMethod.getInstance();
/**
* Computes the par rate of a swap with one fixed leg.
* @param swap The Fixed coupon swap.
* @param multicurves The multi-curves provider.
* @return The par swap rate. If the fixed leg has been set up with some fixed payments these are ignored for the purposes of finding the swap rate
*/
@Override
public MulticurveSensitivity visitFixedCouponSwap(final SwapFixedCoupon<?> swap, final ParameterProviderInterface multicurves) {
final Currency ccy = swap.getSecondLeg().getCurrency();
final double pvSecond = swap.getSecondLeg().accept(PVDC, multicurves).getAmount(ccy) * Math.signum(swap.getSecondLeg().getNthPayment(0).getNotional());
final double pvbp = METHOD_SWAP.presentValueBasisPoint(swap, multicurves.getMulticurveProvider());
final double pvbpBar = -pvSecond / (pvbp * pvbp);
final double pvSecondBar = 1.0 / pvbp;
final MulticurveSensitivity pvbpDr = METHOD_SWAP.presentValueBasisPointCurveSensitivity(swap, multicurves.getMulticurveProvider());
final MulticurveSensitivity pvSecondDr = swap.getSecondLeg().accept(PVCSDC, multicurves).getSensitivity(ccy).multipliedBy(Math.signum(swap.getSecondLeg().getNthPayment(0).getNotional()));
final MulticurveSensitivity result = pvSecondDr.multipliedBy(pvSecondBar).plus(pvbpDr.multipliedBy(pvbpBar));
return result;
}
/**
* Computes the swap convention-modified par rate for a fixed coupon swap.
* <P>Reference: Swaption pricing - v 1.3, OpenGamma Quantitative Research, June 2012.
* @param swap The swap.
* @param dayCount The day count convention to modify the swap rate.
* @param multicurves The multi-curves provider.
* @return The modified rate.
*/
public MulticurveSensitivity visitFixedCouponSwap(final SwapFixedCoupon<?> swap, final DayCount dayCount, final MulticurveProviderInterface multicurves) {
final Currency ccy = swap.getSecondLeg().getCurrency();
final double pvSecond = swap.getSecondLeg().accept(PVDC, multicurves).getAmount(ccy) * Math.signum(swap.getSecondLeg().getNthPayment(0).getNotional());
final double pvbp = METHOD_SWAP.presentValueBasisPoint(swap, dayCount, multicurves);
final double pvbpBar = -pvSecond / (pvbp * pvbp);
final double pvSecondBar = 1.0 / pvbp;
final MulticurveSensitivity pvbpDr = METHOD_SWAP.presentValueBasisPointCurveSensitivity(swap, dayCount, multicurves);
final MulticurveSensitivity pvSecondDr = swap.getSecondLeg().accept(PVCSDC, multicurves).getSensitivity(ccy).multipliedBy(Math.signum(swap.getSecondLeg().getNthPayment(0).getNotional()));
final MulticurveSensitivity result = pvSecondDr.multipliedBy(pvSecondBar).plus(pvbpDr.multipliedBy(pvbpBar));
return result;
}
/**
* Computes the swap convention-modified par rate curve sensitivity for a fixed coupon swap.
* <P>Reference: Swaption pricing - v 1.3, OpenGamma Quantitative Research, June 2012.
* @param swap The swap.
* @param dayCount The day count convention to modify the swap rate.
* @param multicurves The multi-curves provider.
* @return The modified rate curve sensitivity.
*/
public MulticurveSensitivity visitFixedCouponSwapDerivative(final SwapFixedCoupon<?> swap, final DayCount dayCount, final MulticurveProviderInterface multicurves) {
final Currency ccy = swap.getSecondLeg().getCurrency();
final double pvSecond = swap.getSecondLeg().accept(PVDC, multicurves).getAmount(ccy) * Math.signum(swap.getSecondLeg().getNthPayment(0).getNotional());
final double pvbp = METHOD_SWAP.presentValueBasisPoint(swap, dayCount, multicurves);
final double pvCoeff = 1. / pvbp;
final double crossCoeff = -1.0 / pvbp / pvbp;
final double pvbpCoeff = 2.0 * pvSecond / pvbp / pvbp;
final MulticurveSensitivity pvbpDr = METHOD_SWAP.presentValueBasisPointCurveSensitivity(swap, dayCount, multicurves);
final MulticurveSensitivity pvSecondDr = swap.getSecondLeg().accept(PVCSDC, multicurves).getSensitivity(ccy)
.multipliedBy(Math.signum(swap.getSecondLeg().getNthPayment(0).getNotional()));
final MulticurveSensitivity pvbpDr2 = METHOD_SWAP.presentValueBasisPointSecondOrderCurveSensitivity(swap, dayCount, multicurves);
final int len = swap.getSecondLeg().getNumberOfPayments();
CouponIbor couponInitial = (CouponIbor) swap.getSecondLeg().getPayments()[0];
MulticurveSensitivity pvSecondDr2 = CouponIborDiscountingMethod.getInstance().presentValueSecondOrderCurveSensitivity(couponInitial, multicurves).getSensitivity(ccy);
for (int i = 1; i < len; ++i) {
CouponIbor coupon = (CouponIbor) swap.getSecondLeg().getPayments()[i];
pvSecondDr2.plus(CouponIborDiscountingMethod.getInstance().presentValueSecondOrderCurveSensitivity(coupon, multicurves).getSensitivity(ccy));
}
final MulticurveSensitivity result = pvSecondDr2.multipliedBy(pvCoeff).plus(pvbpDr2.multipliedBy(pvbpCoeff)).plus(pvSecondDr.productOf(pvbpDr.multipliedBy(crossCoeff)))
.multipliedBy(Math.signum(swap.getSecondLeg().getNthPayment(0).getNotional()));
return result;
}
}