/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.pricer.impl.credit.isda; import static com.opengamma.strata.pricer.impl.credit.isda.ImmDateLogic.getPrevIMMDate; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; import java.time.LocalDate; import java.time.Month; import java.time.Period; import java.util.Arrays; import org.testng.annotations.Test; import com.opengamma.strata.basics.schedule.StubConvention; import com.opengamma.strata.pricer.impl.credit.isda.IsdaCompliantCreditCurveBuilder.ArbitrageHandling; /** * Test. */ @SuppressWarnings("deprecation") @Test public class FastCreditCurveBuilderTest extends CreditCurveCalibrationTest { private static final FastCreditCurveBuilder BUILDER_ISDA = new FastCreditCurveBuilder(); private static final FastCreditCurveBuilder BUILDER_MARKIT = new FastCreditCurveBuilder(MARKIT_FIX); @Test public void test() { testCalibrationAgainstISDA(BUILDER_ISDA, 1e-14); testCalibrationAgainstISDA(BUILDER_MARKIT, 1e-14); } /** * */ @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 = DEFAULT_CALENDAR.shift(tradeDate.minusDays(1), 3); 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); } /* * Flat hazard rate case */ 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 CdsQuotedSpread qsp = new CdsQuotedSpread(coupon, qsps[0]); final CdsParSpread psp = new CdsParSpread(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 = DEFAULT_CALENDAR.shift(tradeDate, 3); 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), StubConvention.SHORT_INITIAL, 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); } /* * Consistency */ final FastCreditCurveBuilder fastOriginalFail = new FastCreditCurveBuilder(AccrualOnDefaultFormulae.ORIGINAL_ISDA, ArbitrageHandling.Fail); /* * Fail with zero pufs */ try { fastOriginalFail.calibrateCreditCurve(pillar, spreads, yc); throw new RuntimeException(); } catch (final Exception e) { assertTrue(e instanceof IllegalArgumentException); } /* * Fail with nonzero pufs */ 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), StubConvention.SHORT_INITIAL, true, yc, 0.4); throw new RuntimeException(); } catch (final Exception e) { assertTrue(e instanceof IllegalArgumentException); } } /** * */ public void viaConverterTest() { LocalDate tradeDate = LocalDate.of(2014, 5, 22); double recovery = 0.25; CdsAnalyticFactory immCDSFact = new CdsAnalyticFactory(recovery); LocalDate spotDate = LocalDate.of(2014, 5, 27); String[] yieldCurvePoints = new String[] {"1M", "2M", "3M", "6M", "1Y", "2Y", "3Y", "4Y", "5Y", "6Y", "7Y", "8Y", "9Y", "10Y", "12Y", "15Y", "20Y", "25Y", "30Y" }; String[] yieldCurveInstruments = new String[] {"M", "M", "M", "M", "M", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S" }; double[] rates = new double[] {0.001, 0.002, 0.0025, 0.003, 0.0052, 0.0053, 0.00851, 0.0125, 0.016, 0.02, 0.02, 0.022, 0.024, 0.025, 0.02, 0.031, 0.030, 0.031, 0.0323 }; IsdaCompliantYieldCurve yieldCurve = makeYieldCurve(tradeDate, spotDate, yieldCurvePoints, yieldCurveInstruments, rates, ACT360, D30360, Period.ofMonths(6)); LocalDate end = LocalDate.of(2014, 6, 20); double spF = 6.726 * 1.e-4; double spS = 6.727 * 1.e-4; CdsAnalytic cds = immCDSFact.makeCds(tradeDate, getPrevIMMDate(tradeDate), end); double coupon = 500. * 1.e-4; MarketQuoteConverter conv = new MarketQuoteConverter(); double[] resS = conv.parSpreadsToQuotedSpreads(new CdsAnalytic[] {cds }, coupon, yieldCurve, new double[] {spS }); double[] resF = conv.parSpreadsToQuotedSpreads(new CdsAnalytic[] {cds }, coupon, yieldCurve, new double[] {spF }); assertEquals(resS[0], resF[0], 1.e-5); } /** * */ public void viaImpliedSpreadTest() { LocalDate tradeDate = LocalDate.of(2014, 5, 16); double recoveryF = 0.248; double recoveryS = 0.247; CdsAnalyticFactory nonImmCDSFactS = new CdsAnalyticFactory(recoveryS, Period.ofMonths(6)); CdsAnalyticFactory nonImmCDSFactF = new CdsAnalyticFactory(recoveryF, Period.ofMonths(6)); LocalDate spotDate = LocalDate.of(2014, Month.MAY, 20); String[] yieldCurvePoints = new String[] {"1M", "2M", "3M", "6M", "1Y", "2Y", "3Y", "4Y", "5Y", "6Y", "7Y", "8Y", "9Y", "10Y", "12Y", "15Y", "20Y", "25Y", "30Y" }; String[] yieldCurveInstruments = new String[] {"M", "M", "M", "M", "M", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S" }; double[] rates = new double[] {0.00151, 0.0018, 0.0026, 0.0031, 0.0052, 0.0053, 0.00851, 0.0125, 0.016, 0.02, 0.02, 0.022, 0.024, 0.025, 0.02, 0.031, 0.030, 0.031, 0.0323 }; IsdaCompliantYieldCurve yieldCurve = makeYieldCurve(tradeDate, spotDate, yieldCurvePoints, yieldCurveInstruments, rates, ACT360, D30360, Period.ofMonths(6)); LocalDate end = LocalDate.of(2014, 5, 20); double puf = 1.101e-2; double coupon = 500.0 * 1.0e-4; Period[] buckets = new Period[] {Period.ofMonths(6), Period.ofYears(1), Period.ofYears(2), Period.ofYears(3), Period.ofYears(4), Period.ofYears(5), Period.ofYears(6), Period.ofYears(7), Period.ofYears(8), Period.ofYears(9), Period.ofYears(10), Period.ofYears(12), Period.ofYears(15), Period.ofYears(20), Period.ofYears(25), Period.ofYears(30) }; CdsAnalytic cdsS = nonImmCDSFactS.makeCds(tradeDate, getPrevIMMDate(tradeDate), end); CdsAnalytic[] bucketCDSS = nonImmCDSFactS.makeImmCds(tradeDate, buckets); CdsAnalytic cdsF = nonImmCDSFactF.makeCds(tradeDate, getPrevIMMDate(tradeDate), end); CdsAnalytic[] bucketCDSF = nonImmCDSFactF.makeImmCds(tradeDate, buckets); double bump = 1.e-4; FiniteDifferenceSpreadSensitivityCalculator cs01Cal = new FiniteDifferenceSpreadSensitivityCalculator(); PointsUpFront pufC = new PointsUpFront(coupon, puf); double[] resS = cs01Cal.bucketedCS01FromPUF(cdsS, pufC, yieldCurve, bucketCDSS, bump); double[] resF = cs01Cal.bucketedCS01FromPUF(cdsF, pufC, yieldCurve, bucketCDSF, bump); for (int i = 0; i < resS.length; ++i) { assertEquals(resS[i], resF[i], 1.e-5); } } }