/** * For an instrument, this calculates the sensitivity of the present value (PV) to points on the * yield curve(s) (i.e. dPV/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. dPV/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). */ public class PresentValueCurveSensitivityCalculator extends AbstractInstrumentDerivativeVisitor<YieldCurveBundle, Map<String, List<DoublesPair>>> { // TODO: Change the output format from Map to InterestRateCurveSensitivity, which wraps the map // and adds common functionality. /** The method unique instance. */ private static final PresentValueCurveSensitivityCalculator INSTANCE = new PresentValueCurveSensitivityCalculator(); /** * Return the unique instance of the class. * * @return The instance. */ public static PresentValueCurveSensitivityCalculator getInstance() { return INSTANCE; } /** Constructor. */ PresentValueCurveSensitivityCalculator() {} /** The method used for OIS coupons. */ private static final CouponOISDiscountingMethod METHOD_OIS = CouponOISDiscountingMethod.getInstance(); private static final CouponIborDiscountingMethod METHOD_IBOR = CouponIborDiscountingMethod.getInstance(); private static final CouponIborGearingDiscountingMethod METHOD_IBOR_GEARING = CouponIborGearingDiscountingMethod.getInstance(); private static final CashDiscountingMethod METHOD_DEPOSIT = CashDiscountingMethod.getInstance(); private static final DepositZeroDiscountingMethod METHOD_DEPOSIT_ZERO = DepositZeroDiscountingMethod.getInstance(); private static final BillSecurityDiscountingMethod METHOD_BILL_SECURITY = BillSecurityDiscountingMethod.getInstance(); private static final BillTransactionDiscountingMethod METHOD_BILL_TRANSACTION = BillTransactionDiscountingMethod.getInstance(); @Override public Map<String, List<DoublesPair>> visit( final InstrumentDerivative instrument, final YieldCurveBundle curves) { return instrument.accept(this, curves); } @Override public Map<String, List<DoublesPair>> visitCash(final Cash cash, final YieldCurveBundle curves) { return METHOD_DEPOSIT.presentValueCurveSensitivity(cash, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitDepositZero( final DepositZero deposit, final YieldCurveBundle curves) { return METHOD_DEPOSIT_ZERO.presentValueCurveSensitivity(deposit, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitForwardRateAgreement( final ForwardRateAgreement fra, final YieldCurveBundle curves) { final ForwardRateAgreementDiscountingMethod method = ForwardRateAgreementDiscountingMethod.getInstance(); return method.presentValueCurveSensitivity(fra, curves).getSensitivities(); } /** {@inheritDoc} Future transaction pricing without convexity adjustment. */ @Override public Map<String, List<DoublesPair>> visitInterestRateFuture( final InterestRateFuture future, final YieldCurveBundle curves) { final InterestRateFutureDiscountingMethod method = InterestRateFutureDiscountingMethod.getInstance(); return method.presentValueCurveSensitivity(future, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitBondFixedSecurity( final BondFixedSecurity bond, final YieldCurveBundle curves) { final BondSecurityDiscountingMethod method = BondSecurityDiscountingMethod.getInstance(); return method.presentValueCurveSensitivity(bond, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitBondFixedTransaction( final BondFixedTransaction bond, final YieldCurveBundle curves) { final BondTransactionDiscountingMethod method = BondTransactionDiscountingMethod.getInstance(); return method.presentValueSensitivity(bond, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitBondIborTransaction( final BondIborTransaction bond, final YieldCurveBundle curves) { final BondTransactionDiscountingMethod method = BondTransactionDiscountingMethod.getInstance(); return method.presentValueSensitivity(bond, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitBillSecurity( final BillSecurity bill, final YieldCurveBundle curves) { return METHOD_BILL_SECURITY.presentValueCurveSensitivity(bill, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitBillTransaction( final BillTransaction bill, final YieldCurveBundle curves) { return METHOD_BILL_TRANSACTION.presentValueCurveSensitivity(bill, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitBondFuture( final BondFuture bondFuture, final YieldCurveBundle curves) { Validate.notNull(curves); Validate.notNull(bondFuture); final BondFutureDiscountingMethod method = BondFutureDiscountingMethod.getInstance(); return method.presentValueCurveSensitivity(bondFuture, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitSwap( final Swap<?, ?> swap, final YieldCurveBundle curves) { final Map<String, List<DoublesPair>> senseR = visit(swap.getSecondLeg(), curves); final Map<String, List<DoublesPair>> senseP = visit(swap.getFirstLeg(), curves); return addSensitivity(senseR, senseP); } @Override public Map<String, List<DoublesPair>> visitFixedCouponSwap( final SwapFixedCoupon<?> swap, final YieldCurveBundle curves) { return visitSwap(swap, curves); } @Override public Map<String, List<DoublesPair>> visitTenorSwap( final TenorSwap<? extends Payment> swap, final YieldCurveBundle curves) { return visitSwap(swap, curves); } @Override public Map<String, List<DoublesPair>> visitFloatingRateNote( final FloatingRateNote frn, final YieldCurveBundle curves) { return visitSwap(frn, curves); } @Override public Map<String, List<DoublesPair>> visitCrossCurrencySwap( final CrossCurrencySwap ccs, final YieldCurveBundle curves) { final Map<String, List<DoublesPair>> senseD = visit(ccs.getDomesticLeg(), curves); final Map<String, List<DoublesPair>> senseF = visit(ccs.getForeignLeg(), curves); // Note the sensitivities subtract rather than add here because the CCS is set up as domestic // FRN minus a foreign FRN return addSensitivity(senseD, multiplySensitivity(senseF, -ccs.getSpotFX())); } @Override public Map<String, List<DoublesPair>> visitForexForward( final ForexForward fx, final YieldCurveBundle curves) { final Map<String, List<DoublesPair>> senseP1 = visit(fx.getPaymentCurrency1(), curves); final Map<String, List<DoublesPair>> senseP2 = visit(fx.getPaymentCurrency2(), curves); // Note the sensitivities add rather than subtract here because the FX Forward is set up as a // notional in one currency PLUS a notional in another with the opposite sign return InterestRateCurveSensitivityUtils.addSensitivity( senseP1, multiplySensitivity(senseP2, fx.getSpotForexRate())); } @Override public Map<String, List<DoublesPair>> visitGenericAnnuity( final Annuity<? extends Payment> annuity, final YieldCurveBundle data) { final Map<String, List<DoublesPair>> map = new HashMap<String, List<DoublesPair>>(); for (final Payment p : annuity.getPayments()) { final Map<String, List<DoublesPair>> tempMap = visit(p, data); for (final String name : tempMap.keySet()) { if (!map.containsKey(name)) { map.put(name, tempMap.get(name)); } else { final List<DoublesPair> tempList = map.get(name); tempList.addAll(tempMap.get(name)); map.put(name, tempList); } } } return map; } @Override public Map<String, List<DoublesPair>> visitFixedPayment( final PaymentFixed payment, final YieldCurveBundle data) { final String curveName = payment.getFundingCurveName(); final YieldAndDiscountCurve curve = data.getCurve(curveName); final double t = payment.getPaymentTime(); final DoublesPair s = new DoublesPair(t, -t * payment.getAmount() * curve.getDiscountFactor(t)); final List<DoublesPair> list = new ArrayList<DoublesPair>(); list.add(s); final Map<String, List<DoublesPair>> result = new HashMap<String, List<DoublesPair>>(); result.put(curveName, list); return result; } @Override public Map<String, List<DoublesPair>> visitCouponIborSpread( final CouponIborSpread payment, final YieldCurveBundle data) { final String fundingCurveName = payment.getFundingCurveName(); final String liborCurveName = payment.getForwardCurveName(); final YieldAndDiscountCurve fundCurve = data.getCurve(fundingCurveName); final YieldAndDiscountCurve liborCurve = data.getCurve(liborCurveName); final double tPay = payment.getPaymentTime(); final double tStart = payment.getFixingPeriodStartTime(); final double tEnd = payment.getFixingPeriodEndTime(); final double dfPay = fundCurve.getDiscountFactor(tPay); final double dfStart = liborCurve.getDiscountFactor(tStart); final double dfEnd = liborCurve.getDiscountFactor(tEnd); final double forward = (dfStart / dfEnd - 1) / payment.getFixingYearFraction(); final double notional = payment.getNotional(); final Map<String, List<DoublesPair>> result = new HashMap<String, List<DoublesPair>>(); List<DoublesPair> temp = new ArrayList<DoublesPair>(); DoublesPair s; s = new DoublesPair( tPay, -tPay * dfPay * notional * (forward + payment.getSpread()) * payment.getPaymentYearFraction()); temp.add(s); if (!liborCurveName.equals(fundingCurveName)) { result.put(fundingCurveName, temp); temp = new ArrayList<DoublesPair>(); } final double ratio = notional * dfPay * dfStart / dfEnd * payment.getPaymentYearFraction() / payment.getFixingYearFraction(); s = new DoublesPair(tStart, -tStart * ratio); temp.add(s); s = new DoublesPair(tEnd, tEnd * ratio); temp.add(s); result.put(liborCurveName, temp); return result; } @Override public Map<String, List<DoublesPair>> visitCouponOIS( final CouponOIS payment, final YieldCurveBundle data) { final Map<String, List<DoublesPair>> result = METHOD_OIS.presentValueCurveSensitivity(payment, data).getSensitivities(); return result; } @Override public Map<String, List<DoublesPair>> visitFixedCouponAnnuity( final AnnuityCouponFixed annuity, final YieldCurveBundle data) { return visitGenericAnnuity(annuity, data); } @Override public Map<String, List<DoublesPair>> visitCouponFixed( final CouponFixed payment, final YieldCurveBundle data) { return visitFixedPayment(payment.toPaymentFixed(), data); } @Override public Map<String, List<DoublesPair>> visitForwardLiborAnnuity( final AnnuityCouponIbor annuity, final YieldCurveBundle data) { return visitGenericAnnuity(annuity, data); } @Override public Map<String, List<DoublesPair>> visitFixedFloatSwap( final FixedFloatSwap swap, final YieldCurveBundle data) { return visitFixedCouponSwap(swap, data); } @Override public Map<String, List<DoublesPair>> visitCouponCMS( final CouponCMS payment, final YieldCurveBundle data) { final CouponCMSDiscountingMethod method = CouponCMSDiscountingMethod.getInstance(); return method.presentValueSensitivity(payment, data).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitCouponIbor( final CouponIbor coupon, final YieldCurveBundle curves) { return METHOD_IBOR.presentValueCurveSensitivity(coupon, curves).getSensitivities(); } @Override public Map<String, List<DoublesPair>> visitCouponIborGearing( final CouponIborGearing coupon, final YieldCurveBundle curves) { return METHOD_IBOR_GEARING.presentValueCurveSensitivity(coupon, curves).getSensitivities(); } /** * Compute the sensitivity of the discount factor at a given time. * * @param curveName The curve name associated to the discount factor. * @param curve The curve from which the discount factor should be computed. * @param time The time * @return The sensitivity. */ public static Map<String, List<DoublesPair>> discountFactorSensitivity( final String curveName, final YieldAndDiscountCurve curve, final double time) { final DoublesPair s = new DoublesPair(time, -time * curve.getDiscountFactor(time)); final List<DoublesPair> list = new ArrayList<DoublesPair>(); list.add(s); final Map<String, List<DoublesPair>> result = new HashMap<String, List<DoublesPair>>(); result.put(curveName, list); return result; } }
@Override public Map<String, List<DoublesPair>> visitBillSecurity( final BillSecurity bill, final YieldCurveBundle curves) { return METHOD_BILL_SECURITY.presentValueCurveSensitivity(bill, curves).getSensitivities(); }