ProtectionLegElement { public double[] pvAndSense(final ISDACompliantCreditCurve creditCurve) { double t = _knots[0]; double[] htAndSense = creditCurve.getRTandSensitivity(t, _creditCurveKnot); double ht0 = htAndSense[0]; double rt0 = _rt[0]; double q0 = Math.exp(-ht0); double dqdh0 = -htAndSense[1] * q0; double p0 = _p[0]; double b0 = p0 * q0; double pv = 0.0; double pvSense = 0.0; for (int i = 1; i < _n; ++i) { t = _knots[i]; htAndSense = creditCurve.getRTandSensitivity(t, _creditCurveKnot); final double ht1 = htAndSense[0]; final double rt1 = _rt[i]; final double q1 = Math.exp(-ht1); final double p1 = _p[i]; final double b1 = p1 * q1; final double dqdh1 = -htAndSense[1] * q1; final double dht = ht1 - ht0; final double drt = rt1 - rt0; final double dhrt = dht + drt; double dPV; double dPVSense; if (Math.abs(dhrt) < 1e-5) { final double e = epsilon(-dhrt); final double eP = epsilonP(-dhrt); dPV = dht * b0 * e; final double dPVdq0 = p0 * ((1 + dht) * e - dht * eP); final double dPVdq1 = -p0 * q0 / q1 * (e - dht * eP); dPVSense = dPVdq0 * dqdh0 + dPVdq1 * dqdh1; } else { final double w1 = (b0 - b1) / dhrt; dPV = dht * w1; final double w = drt * w1; dPVSense = ((w / q0 + dht * p0) / dhrt) * dqdh0 - ((w / q1 + dht * p1) / dhrt) * dqdh1; } pv += dPV; pvSense += dPVSense; ht0 = ht1; dqdh0 = dqdh1; rt0 = rt1; p0 = p1; q0 = q1; b0 = b1; } return new double[] {pv, pvSense }; } ProtectionLegElement(final double start, final double end, final ISDACompliantYieldCurve yieldCurve, final int creditCurveKnot, final double[] knots); double[] pvAndSense(final ISDACompliantCreditCurve creditCurve); @Override int hashCode(); @Override boolean equals(final Object obj);  }
@Test public void test() { final LocalDate tradeDate = LocalDate.of(2013, Month.SEPTEMBER, 5); final LocalDate spotDate = addWorkDays(tradeDate.minusDays(1), 1, DEFAULT_CALENDAR); final String[] yieldCurvePoints = new String[] {"1M", "2M", "3M", "6M", "1Y", "2Y", "3Y", "4Y", "5Y", "6Y", "7Y", "8Y", "9Y", "10Y", "12Y", "15Y", "20Y", "25Y", "30Y" }; final String[] yieldCurveInstruments = new String[] {"M", "M", "M", "M", "M", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S" }; final double[] rates = new double[] {0.004919, 0.005006, 0.00515, 0.005906, 0.008813, 0.0088, 0.01195, 0.01534, 0.01836, 0.02096, 0.02322, 0.02514, 0.02673, 0.02802, 0.02997, 0.0318, 0.03331, 0.03383, 0.034 }; final ISDACompliantYieldCurve yieldCurve = makeYieldCurve(tradeDate, spotDate, yieldCurvePoints, yieldCurveInstruments, rates, ACT_ACT_ISDA, ACT_ACT_ISDA, Period.ofMonths(6)); final double[] ccKnots = new double[] {0.5, 1, 2, 3, 5, 10 }; final double[] h = new double[] {0.01, 0.012, 0.015, 0.015, 0.013, 0.012 }; final double[] knots = getIntegrationsPoints(0, 10, yieldCurve.getKnotTimes(), ccKnots); final ISDACompliantCreditCurve creditCurve = new ISDACompliantCreditCurve(ccKnots, h); final ProtectionLegElement protElem = new ProtectionLegElement(2., 5., yieldCurve, 4, knots); double[] pv = protElem.pvAndSense(creditCurve); final double eps = 1e-6; final ISDACompliantCreditCurve ccUp = creditCurve.withRate(h[4] + eps, 4); final ISDACompliantCreditCurve ccDown = creditCurve.withRate(h[4] - eps, 4); double pvUp = protElem.pvAndSense(ccUp)[0]; double pvDown = protElem.pvAndSense(ccDown)[0]; double fdSense = (pvUp - pvDown) / 2 / eps; assertEquals(fdSense, pv[1], 1e-10); final CDSAnalyticFactory factory = new CDSAnalyticFactory(); final CDSAnalytic cds = factory.makeIMMCDS(tradeDate, Period.ofYears(5)); final CDSCoupon coupon = cds.getCoupon(cds.getNumPayments() - 1); PremiumLegElement premElem = new PremiumLegElement(0, coupon, yieldCurve, 4, knots, AccrualOnDefaultFormulae.OrignalISDA); pv = premElem.pvAndSense(creditCurve); pvUp = premElem.pvAndSense(ccUp)[0]; pvDown = premElem.pvAndSense(ccDown)[0]; fdSense = (pvUp - pvDown) / 2 / eps; assertEquals(fdSense, pv[1], 1e-10); premElem = new PremiumLegElement(0, coupon, yieldCurve, 4, knots, AccrualOnDefaultFormulae.MarkitFix); pv = premElem.pvAndSense(creditCurve); pvUp = premElem.pvAndSense(ccUp)[0]; pvDown = premElem.pvAndSense(ccDown)[0]; fdSense = (pvUp - pvDown) / 2 / eps; assertEquals(fdSense, pv[1], 1e-10); }