FastCreditCurveBuilder extends ISDACompliantCreditCurveBuilder { @Override public ISDACompliantCreditCurve calibrateCreditCurve(final CDSAnalytic[] cds, final double[] premiums, final ISDACompliantYieldCurve yieldCurve, final double[] pointsUpfront) { ArgumentChecker.noNulls(cds, "null CDSs"); ArgumentChecker.notEmpty(premiums, "empty fractionalSpreads"); ArgumentChecker.notEmpty(pointsUpfront, "empty pointsUpfront"); ArgumentChecker.notNull(yieldCurve, "null yieldCurve"); final int n = cds.length; ArgumentChecker.isTrue(n == premiums.length, "Number of CDSs does not match number of spreads"); ArgumentChecker.isTrue(n == pointsUpfront.length, "Number of CDSs does not match number of pointsUpfront"); final double proStart = cds[0].getEffectiveProtectionStart(); for (int i = 1; i < n; i++) { ArgumentChecker.isTrue(proStart == cds[i].getEffectiveProtectionStart(), "all CDSs must has same protection start"); ArgumentChecker.isTrue(cds[i].getProtectionEnd() > cds[i - 1].getProtectionEnd(), "protection end must be ascending"); } final double[] guess = new double[n]; final double[] t = new double[n]; for (int i = 0; i < n; i++) { t[i] = cds[i].getProtectionEnd(); guess[i] = (premiums[i] + pointsUpfront[i] / t[i]) / cds[i].getLGD(); } ISDACompliantCreditCurve creditCurve = new ISDACompliantCreditCurve(t, guess); for (int i = 0; i < n; i++) { final Pricer pricer = new Pricer(cds[i], yieldCurve, t, premiums[i], pointsUpfront[i]); final Function1D<Double, Double> func = pricer.getPointFunction(i, creditCurve); switch (getArbHanding()) { case Ignore: { try { double[] bracket = BRACKER.getBracketedPoints(func, 0.8 * guess[i], 1.25 * guess[i], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY); double zeroRate = bracket[0] > bracket[1] ? ROOTFINDER.getRoot(func, bracket[1], bracket[0]) : ROOTFINDER.getRoot(func, bracket[0], bracket[1]); creditCurve = creditCurve.withRate(zeroRate, i); } catch (final MathException e) { if (Math.abs(func.evaluate(creditCurve.getZeroRateAtIndex(i - 1))) < 1.e-12) { creditCurve = creditCurve.withRate(creditCurve.getZeroRateAtIndex(i - 1), i); } else { throw new MathException(e); } } break; } case Fail: { final double minValue = i == 0 ? 0.0 : creditCurve.getRTAtIndex(i - 1) / creditCurve.getTimeAtIndex(i); if (i > 0 && func.evaluate(minValue) > 0.0) { final StringBuilder msg = new StringBuilder(); if (pointsUpfront[i] == 0.0) { msg.append("The par spread of " + premiums[i] + " at index " + i); } else { msg.append("The premium of " + premiums[i] + "and points up-front of " + pointsUpfront[i] + " at index " + i); } msg.append(" is an arbitrage; cannot fit a curve with positive forward hazard rate. "); throw new IllegalArgumentException(msg.toString()); } guess[i] = Math.max(minValue, guess[i]); final double[] bracket = BRACKER.getBracketedPoints(func, guess[i], 1.2 * guess[i], minValue, Double.POSITIVE_INFINITY); final double zeroRate = ROOTFINDER.getRoot(func, bracket[0], bracket[1]); creditCurve = creditCurve.withRate(zeroRate, i); break; } case ZeroHazardRate: { final double minValue = i == 0 ? 0.0 : creditCurve.getRTAtIndex(i - 1) / creditCurve.getTimeAtIndex(i); if (i > 0 && func.evaluate(minValue) > 0.0) { creditCurve = creditCurve.withRate(minValue, i); } else { guess[i] = Math.max(minValue, guess[i]); final double[] bracket = BRACKER.getBracketedPoints(func, guess[i], 1.2 * guess[i], minValue, Double.POSITIVE_INFINITY); final double zeroRate = ROOTFINDER.getRoot(func, bracket[0], bracket[1]); creditCurve = creditCurve.withRate(zeroRate, i); } break; } default: throw new IllegalArgumentException("unknow case " + getArbHanding()); } } return creditCurve; } FastCreditCurveBuilder();  FastCreditCurveBuilder(final AccrualOnDefaultFormulae formula);  FastCreditCurveBuilder(final AccrualOnDefaultFormulae formula, final ArbitrageHandling arbHandling); @Override ISDACompliantCreditCurve calibrateCreditCurve(final CDSAnalytic[] cds, final double[] premiums, final ISDACompliantYieldCurve yieldCurve, final double[] pointsUpfront);  }
@SuppressWarnings("deprecation") @Test public void noAccOnDefaultTest() { final FastCreditCurveBuilder fastOg = new FastCreditCurveBuilder(OG_FIX, ArbitrageHandling.Ignore); final SimpleCreditCurveBuilder simpleISDA = new SimpleCreditCurveBuilder(ORIGINAL_ISDA); final SimpleCreditCurveBuilder simpleFix = new SimpleCreditCurveBuilder(MARKIT_FIX); final SimpleCreditCurveBuilder simpleOg = new SimpleCreditCurveBuilder(OG_FIX); final LocalDate tradeDate = LocalDate.of(2013, Month.APRIL, 25); final CDSAnalyticFactory baseFactory = new CDSAnalyticFactory(); final CDSAnalyticFactory noAccFactory = baseFactory.withPayAccOnDefault(false); final Period[] tenors = new Period[] {Period.ofMonths(6), Period.ofYears(1), Period.ofYears(3), Period.ofYears(5), Period.ofYears(7), Period.ofYears(10) }; final CDSAnalytic[] pillar = noAccFactory.makeIMMCDS(tradeDate, tenors); final double[] spreads = new double[] {0.027, 0.017, 0.012, 0.009, 0.008, 0.005 }; final LocalDate spotDate = addWorkDays(tradeDate.minusDays(1), 3, DEFAULT_CALENDAR); final String[] yieldCurvePoints = new String[] {"1M", "2M", "3M", "6M", "9M", "1Y", "2Y", "3Y", "4Y", "5Y", "6Y", "7Y", "8Y", "9Y", "10Y", "11Y", "12Y", "15Y", "20Y", "25Y", "30Y" }; final String[] yieldCurveInstruments = new String[] {"M", "M", "M", "M", "M", "M", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S" }; final double[] rates = new double[] {0.00445, 0.009488, 0.012337, 0.017762, 0.01935, 0.020838, 0.01652, 0.02018, 0.023033, 0.02525, 0.02696, 0.02825, 0.02931, 0.03017, 0.03092, 0.0316, 0.03231, 0.03367, 0.03419, 0.03411, 0.03412 }; final ISDACompliantYieldCurve yc = makeYieldCurve(tradeDate, spotDate, yieldCurvePoints, yieldCurveInstruments, rates, ACT360, D30360, Period.ofYears(1)); final ISDACompliantCreditCurve curveFastISDA = BUILDER_ISDA.calibrateCreditCurve(pillar, spreads, yc); final ISDACompliantCreditCurve curveFastFix = BUILDER_MARKIT.calibrateCreditCurve(pillar, spreads, yc); final ISDACompliantCreditCurve curveFastOriginal = fastOg.calibrateCreditCurve(pillar, spreads, yc); final ISDACompliantCreditCurve curveSimpleISDA = simpleISDA.calibrateCreditCurve(pillar, spreads, yc); final ISDACompliantCreditCurve curveSimpleFix = simpleFix.calibrateCreditCurve(pillar, spreads, yc); final ISDACompliantCreditCurve curveSimpleOriginal = simpleOg.calibrateCreditCurve(pillar, spreads, yc); final double[] sampleTime = new double[] {30 / 365., 90 / 365., 180. / 365., 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; final int num = sampleTime.length; for (int i = 0; i < num; ++i) { assertEquals(curveSimpleISDA.getHazardRate(sampleTime[i]), curveFastISDA.getHazardRate(sampleTime[i]), 1.e-6); assertEquals(curveSimpleFix.getHazardRate(sampleTime[i]), curveFastFix.getHazardRate(sampleTime[i]), 1.e-6); assertEquals(curveSimpleOriginal.getHazardRate(sampleTime[i]), curveFastOriginal.getHazardRate(sampleTime[i]), 1.e-6); } final double coupon = 0.025; final MarketQuoteConverter conv = new MarketQuoteConverter(); final double[] pufs = conv.parSpreadsToPUF(new CDSAnalytic[] {pillar[3] }, coupon, yc, new double[] {spreads[3] }); final double[] qsps = conv.quotedSpreadToParSpreads(new CDSAnalytic[] {pillar[3] }, coupon, yc, new double[] {spreads[3] }); final PointsUpFront puf = new PointsUpFront(coupon, pufs[0]); final QuotedSpread qsp = new QuotedSpread(coupon, qsps[0]); final ParSpread psp = new ParSpread(spreads[3]); final ISDACompliantCreditCurve curveFastPuf = BUILDER_ISDA.calibrateCreditCurve(pillar[3], puf, yc); final ISDACompliantCreditCurve curveFastQsp = BUILDER_ISDA.calibrateCreditCurve(pillar[3], qsp, yc); final ISDACompliantCreditCurve curveFastPsp = BUILDER_ISDA.calibrateCreditCurve(pillar[3], psp, yc); final ISDACompliantCreditCurve curveSimplePuf = simpleISDA.calibrateCreditCurve(pillar[3], puf, yc); final LocalDate stepinDate = tradeDate.plusDays(1); final LocalDate valueDate = BusinessDayDateUtils.addWorkDays(tradeDate, 3, DEFAULT_CALENDAR); final LocalDate startDate = IMMDateLogic.getPrevIMMDate(tradeDate); final LocalDate endDate = IMMDateLogic.getNextIMMDate(tradeDate.plus(tenors[3])); final ISDACompliantCreditCurve curveFastElem = BUILDER_ISDA.calibrateCreditCurve(tradeDate, stepinDate, valueDate, startDate, endDate, spreads[3], false, Period.ofMonths(3), StubType.FRONTSHORT, true, yc, 0.4); assertEquals(1, curveFastPuf.getNumberOfKnots()); assertEquals(1, curveFastQsp.getNumberOfKnots()); assertEquals(1, curveFastPsp.getNumberOfKnots()); for (int i = 0; i < num; ++i) { assertEquals(curveFastPuf.getForwardRate(sampleTime[i]), curveFastQsp.getForwardRate(sampleTime[i]), 1.e-12); assertEquals(curveFastPuf.getForwardRate(sampleTime[i]), curveFastPsp.getForwardRate(sampleTime[i]), 1.e-12); assertEquals(curveFastPuf.getForwardRate(sampleTime[i]), curveFastElem.getForwardRate(sampleTime[i]), 1.e-12); assertEquals(curveSimplePuf.getForwardRate(sampleTime[i]), curveFastPuf.getForwardRate(sampleTime[i]), 1.e-6); } final FastCreditCurveBuilder fastOriginalFail = new FastCreditCurveBuilder(AccrualOnDefaultFormulae.OrignalISDA, ArbitrageHandling.Fail); try { fastOriginalFail.calibrateCreditCurve(pillar, spreads, yc); throw new RuntimeException(); } catch (final Exception e) { assertTrue(e instanceof IllegalArgumentException); } final int nSpreads = spreads.length; final PointsUpFront[] pufsFail = new PointsUpFront[nSpreads]; final double[] pufValues = conv.parSpreadsToPUF(pillar, coupon, yc, spreads); for (int i = 0; i < nSpreads; ++i) { pufsFail[i] = new PointsUpFront(coupon, pufValues[i]); } try { fastOriginalFail.calibrateCreditCurve(pillar, pufsFail, yc); throw new RuntimeException(); } catch (final Exception e) { assertTrue(e instanceof IllegalArgumentException); } final double[] prems = new double[nSpreads]; Arrays.fill(prems, coupon); final double[] shortPufs = Arrays.copyOf(pufValues, nSpreads - 1); try { fastOriginalFail.calibrateCreditCurve(pillar, prems, yc, shortPufs); throw new RuntimeException(); } catch (final Exception e) { assertTrue(e instanceof IllegalArgumentException); } final double[] shortPrems = Arrays.copyOf(prems, nSpreads - 1); try { fastOriginalFail.calibrateCreditCurve(pillar, shortPrems, yc, pufValues); throw new RuntimeException(); } catch (final Exception e) { assertTrue(e instanceof IllegalArgumentException); } final CDSAnalytic[] pillarCopy = Arrays.copyOf(pillar, nSpreads); pillarCopy[2] = pillarCopy[2].withOffset(0.5); try { fastOriginalFail.calibrateCreditCurve(pillarCopy, prems, yc, pufValues); throw new RuntimeException(); } catch (final Exception e) { assertTrue(e instanceof IllegalArgumentException); } pillarCopy[2] = pillar[3]; pillarCopy[3] = pillar[2]; try { fastOriginalFail.calibrateCreditCurve(pillarCopy, prems, yc, pufValues); throw new RuntimeException(); } catch (final Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { BUILDER_ISDA.calibrateCreditCurve(tradeDate, stepinDate, valueDate, startDate, new LocalDate[] {endDate }, spreads, false, Period.ofMonths(3), StubType.FRONTSHORT, true, yc, 0.4); throw new RuntimeException(); } catch (final Exception e) { assertTrue(e instanceof IllegalArgumentException); } }