/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.interestrate; import static com.opengamma.analytics.financial.interestrate.InterestRateCurveSensitivityUtils.addSensitivity; import static com.opengamma.analytics.financial.interestrate.InterestRateCurveSensitivityUtils.multiplySensitivity; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.opengamma.analytics.financial.interestrate.annuity.derivative.Annuity; import com.opengamma.analytics.financial.interestrate.annuity.derivative.AnnuityCouponFixed; import com.opengamma.analytics.financial.interestrate.bond.definition.BondFixedSecurity; import com.opengamma.analytics.financial.interestrate.cash.derivative.Cash; import com.opengamma.analytics.financial.interestrate.cash.derivative.DepositZero; import com.opengamma.analytics.financial.interestrate.cash.method.DepositZeroDiscountingMethod; import com.opengamma.analytics.financial.interestrate.fra.derivative.ForwardRateAgreement; import com.opengamma.analytics.financial.interestrate.fra.method.ForwardRateAgreementDiscountingBundleMethod; import com.opengamma.analytics.financial.interestrate.future.derivative.InterestRateFutureSecurity; import com.opengamma.analytics.financial.interestrate.future.derivative.InterestRateFutureTransaction; import com.opengamma.analytics.financial.interestrate.future.method.InterestRateFutureSecurityDiscountingMethod; import com.opengamma.analytics.financial.interestrate.payments.ForexForward; import com.opengamma.analytics.financial.interestrate.payments.derivative.CapFloorIbor; import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponFixed; import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponIbor; import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponIborSpread; import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponON; import com.opengamma.analytics.financial.interestrate.payments.derivative.PaymentFixed; import com.opengamma.analytics.financial.interestrate.payments.method.CouponIborDiscountingMethod; import com.opengamma.analytics.financial.interestrate.payments.method.CouponONDiscountingMethod; import com.opengamma.analytics.financial.interestrate.swap.derivative.SwapFixedCoupon; import com.opengamma.analytics.financial.interestrate.swap.method.SwapFixedCouponDiscountingMethod; import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve; import com.opengamma.analytics.financial.provider.description.interestrate.ParameterProviderInterface; import com.opengamma.financial.convention.daycount.DayCount; import com.opengamma.util.CompareUtils; import com.opengamma.util.tuple.DoublesPair; /** * For an instrument, this calculates the sensitivity of the par rate (the exact meaning of par rate depends on the instrument - for swaps it is the par swap rate) to points on the yield * curve(s) (i.e. dPar/dR at every point the instrument has sensitivity). The return format is a map with curve names (String) as keys and List of DoublesPair as the values; each list holds * set of time (corresponding to point of the yield curve) and sensitivity pairs (i.e. dPar/dR at that time). * <b>Note:</b> The length of the list is instrument dependent and may have repeated times (with the understanding the sensitivities should be summed). * @deprecated Use the calculators that reference {@link ParameterProviderInterface} */ @Deprecated public final class ParRateCurveSensitivityCalculator extends InstrumentDerivativeVisitorAdapter<YieldCurveBundle, Map<String, List<DoublesPair>>> { /** * The method unique instance. */ private static final ParRateCurveSensitivityCalculator INSTANCE = new ParRateCurveSensitivityCalculator(); /** * Return the unique instance of the class. * @return The instance. */ public static ParRateCurveSensitivityCalculator getInstance() { return INSTANCE; } /** * Constructor. */ ParRateCurveSensitivityCalculator() { } /** * The methods and calculators. */ private static final PresentValueCalculator PV_CALCULATOR = PresentValueCalculator.getInstance(); private static final ParRateCalculator PRC_CALCULATOR = ParRateCalculator.getInstance(); private static final PresentValueCurveSensitivityCalculator PV_SENSITIVITY_CALCULATOR = PresentValueCurveSensitivityCalculator.getInstance(); private static final RateReplacingInterestRateDerivativeVisitor REPLACE_RATE = RateReplacingInterestRateDerivativeVisitor.getInstance(); private static final CouponONDiscountingMethod METHOD_OIS = CouponONDiscountingMethod.getInstance(); private static final CouponIborDiscountingMethod METHOD_IBOR = CouponIborDiscountingMethod.getInstance(); private static final DepositZeroDiscountingMethod METHOD_DEPOSIT_ZERO = DepositZeroDiscountingMethod.getInstance(); private static final InterestRateFutureSecurityDiscountingMethod METHOD_IRFUT_SECURITY = InterestRateFutureSecurityDiscountingMethod.getInstance(); private static final SwapFixedCouponDiscountingMethod METHOD_SWAP = SwapFixedCouponDiscountingMethod.getInstance(); @Override public Map<String, List<DoublesPair>> visitCash(final Cash cash, final YieldCurveBundle curves) { final String curveName = cash.getYieldCurveName(); final YieldAndDiscountCurve curve = curves.getCurve(curveName); final double ta = cash.getStartTime(); final double tb = cash.getEndTime(); final double yearFrac = cash.getAccrualFactor(); final Map<String, List<DoublesPair>> result = new HashMap<>(); final List<DoublesPair> temp = new ArrayList<>(); if (yearFrac == 0.0) { if (!CompareUtils.closeEquals(ta, tb, 1e-16)) { throw new IllegalArgumentException("year fraction is zero, but payment time not equal the trade time"); } temp.add(DoublesPair.of(ta, 1.0)); } else { final double ratio = curve.getDiscountFactor(ta) / curve.getDiscountFactor(tb) / yearFrac; temp.add(DoublesPair.of(ta, -ta * ratio)); temp.add(DoublesPair.of(tb, tb * ratio)); } result.put(curveName, temp); return result; } @Override public Map<String, List<DoublesPair>> visitDepositZero(final DepositZero deposit, final YieldCurveBundle curves) { return METHOD_DEPOSIT_ZERO.parRateCurveSensitivity(deposit, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitForwardRateAgreement(final ForwardRateAgreement fra, final YieldCurveBundle curves) { final ForwardRateAgreementDiscountingBundleMethod method = ForwardRateAgreementDiscountingBundleMethod.getInstance(); return method.parRateCurveSensitivity(fra, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitInterestRateFutureTransaction(final InterestRateFutureTransaction future, final YieldCurveBundle curves) { final String curveName = future.getUnderlyingSecurity().getForwardCurveName(); final YieldAndDiscountCurve curve = curves.getCurve(curveName); final double ta = future.getUnderlyingSecurity().getFixingPeriodStartTime(); final double tb = future.getUnderlyingSecurity().getFixingPeriodEndTime(); final double ratio = curve.getDiscountFactor(ta) / curve.getDiscountFactor(tb) / future.getUnderlyingSecurity().getFixingPeriodAccrualFactor(); final DoublesPair s1 = DoublesPair.of(ta, -ta * ratio); final DoublesPair s2 = DoublesPair.of(tb, tb * ratio); final List<DoublesPair> temp = new ArrayList<>(); temp.add(s1); temp.add(s2); final Map<String, List<DoublesPair>> result = new HashMap<>(); result.put(curveName, temp); return result; } @Override public Map<String, List<DoublesPair>> visitInterestRateFutureSecurity(final InterestRateFutureSecurity futures, final YieldCurveBundle curves) { return METHOD_IRFUT_SECURITY.parRateCurveSensitivity(futures, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitFixedCouponSwap(final SwapFixedCoupon<?> swap, final YieldCurveBundle curves) { final AnnuityCouponFixed unitCouponAnnuity = REPLACE_RATE.visitFixedCouponAnnuity(swap.getFixedLeg(), 1.0); final Annuity<?> floatingAnnuity = swap.getSecondLeg(); final double a = unitCouponAnnuity.accept(PV_CALCULATOR, curves); final double b = floatingAnnuity.accept(PV_CALCULATOR, curves); final double bOveraSq = b / a / a; final Map<String, List<DoublesPair>> senseA = unitCouponAnnuity.accept(PV_SENSITIVITY_CALCULATOR, curves); final Map<String, List<DoublesPair>> senseB = floatingAnnuity.accept(PV_SENSITIVITY_CALCULATOR, curves); return addSensitivity(multiplySensitivity(senseA, bOveraSq), multiplySensitivity(senseB, -1 / a)); } /** * Computes the sensitivity to the curve of swap convention-modified par rate for a fixed coupon swap with a PVBP externally provided. * <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 curves The curves. * @return The modified rate. */ public Map<String, List<DoublesPair>> visitFixedCouponSwap(final SwapFixedCoupon<?> swap, final DayCount dayCount, final YieldCurveBundle curves) { final double pvSecond = swap.getSecondLeg().accept(PV_CALCULATOR, curves) * Math.signum(swap.getSecondLeg().getNthPayment(0).getNotional()); final double pvbp = METHOD_SWAP.presentValueBasisPoint(swap, dayCount, curves); final InterestRateCurveSensitivity pvbpDr = METHOD_SWAP.presentValueBasisPointCurveSensitivity(swap, dayCount, curves); final InterestRateCurveSensitivity pvSecondDr = new InterestRateCurveSensitivity(swap.getSecondLeg().accept(PV_SENSITIVITY_CALCULATOR, curves)).multipliedBy(Math .signum(swap.getSecondLeg().getNthPayment(0).getNotional())); final InterestRateCurveSensitivity result = pvSecondDr.multipliedBy(1.0 / pvbp).plus(pvbpDr.multipliedBy(-pvSecond / (pvbp * pvbp))); return result.getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitForexForward(final ForexForward fx, final YieldCurveBundle curves) { final double fwdFX = fx.accept(PRC_CALCULATOR, curves); final double t = fx.getPaymentTime(); List<DoublesPair> temp = new ArrayList<>(); temp.add(DoublesPair.of(t, t * fwdFX)); final Map<String, List<DoublesPair>> senseD = new HashMap<>(); senseD.put(fx.getPaymentCurrency1().getFundingCurveName(), temp); temp = new ArrayList<>(); temp.add(DoublesPair.of(t, -t * fwdFX)); final Map<String, List<DoublesPair>> senseF = new HashMap<>(); senseF.put(fx.getPaymentCurrency2().getFundingCurveName(), temp); return addSensitivity(senseD, senseF); } @Override public Map<String, List<DoublesPair>> visitCouponIbor(final CouponIbor payment, final YieldCurveBundle data) { return METHOD_IBOR.parRateCurveSensitivity(payment, data).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitCouponIborSpread(final CouponIborSpread payment, final YieldCurveBundle data) { final String curveName = payment.getForwardCurveName(); final YieldAndDiscountCurve curve = data.getCurve(curveName); // final double ta = payment.getFixingTime(); final double ta = payment.getFixingPeriodStartTime(); final double tb = payment.getFixingPeriodEndTime(); final double delta = payment.getFixingAccrualFactor(); final double ratio = curve.getDiscountFactor(ta) / curve.getDiscountFactor(tb) / delta; final DoublesPair s1 = DoublesPair.of(ta, -ta * ratio); final DoublesPair s2 = DoublesPair.of(tb, tb * ratio); final List<DoublesPair> temp = new ArrayList<>(); temp.add(s1); temp.add(s2); final Map<String, List<DoublesPair>> result = new HashMap<>(); result.put(curveName, temp); return result; } @Override public Map<String, List<DoublesPair>> visitCouponOIS(final CouponON payment, final YieldCurveBundle data) { return METHOD_OIS.parRateCurveSensitivity(payment, data).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitCapFloorIbor(final CapFloorIbor payment, final YieldCurveBundle data) { return visitCouponIborSpread(payment.toCoupon(), data); } @Override public Map<String, List<DoublesPair>> visitBondFixedSecurity(final BondFixedSecurity bond, final YieldCurveBundle curves) { final Annuity<CouponFixed> coupons = bond.getCoupon(); final int n = coupons.getNumberOfPayments(); final CouponFixed[] unitCoupons = new CouponFixed[n]; for (int i = 0; i < n; i++) { unitCoupons[i] = coupons.getNthPayment(i).withUnitCoupon(); } final Annuity<CouponFixed> unitCouponAnnuity = new Annuity<>(unitCoupons); final double a = unitCouponAnnuity.accept(PV_CALCULATOR, curves); final Map<String, List<DoublesPair>> senseA = unitCouponAnnuity.accept(PV_SENSITIVITY_CALCULATOR, curves); final Map<String, List<DoublesPair>> result = new HashMap<>(); final PaymentFixed principlePayment = bond.getNominal().getNthPayment(0); final double df = principlePayment.accept(PV_CALCULATOR, curves); final double factor = -(1 - df) / a / a; for (final String name : curves.getAllNames()) { if (senseA.containsKey(name)) { final List<DoublesPair> temp = new ArrayList<>(); final List<DoublesPair> list = senseA.get(name); final int m = list.size(); for (int i = 0; i < (m - 1); i++) { final DoublesPair pair = list.get(i); temp.add(DoublesPair.of(pair.getFirstDouble(), factor * pair.getSecondDouble())); } final DoublesPair pair = list.get(m - 1); temp.add(DoublesPair.of(pair.getFirstDouble(), principlePayment.getPaymentTime() * df / a + factor * pair.getSecondDouble())); result.put(name, temp); } } return result; } }