/** * 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 org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; import java.time.LocalDate; import java.time.Period; import java.util.Arrays; import org.testng.annotations.Test; import com.opengamma.strata.basics.date.HolidayCalendar; import com.opengamma.strata.basics.date.HolidayCalendars; import com.opengamma.strata.basics.schedule.StubConvention; import com.opengamma.strata.market.ShiftType; import com.opengamma.strata.math.impl.differentiation.FiniteDifferenceType; /** * Test. */ @Test public class SpreadSensitivityTest { private static final FiniteDifferenceSpreadSensitivityCalculator CDV01_CAL = new FiniteDifferenceSpreadSensitivityCalculator(); private static final HolidayCalendar DEFAULT_CALENDAR = HolidayCalendars.SAT_SUN; // common data private static final LocalDate TODAY = LocalDate.of(2013, 4, 21); private static final LocalDate EFFECTIVE_DATE = TODAY.plusDays(1); // AKA stepin date private static final LocalDate CASH_SETTLE_DATE = DEFAULT_CALENDAR.shift(TODAY, 3); // AKA valuation date private static final double RECOVERY_RATE = 0.4; private static final double NOTIONAL = 1e7; // valuation CDS private static final LocalDate PROTECTION_STATE_DATE = LocalDate.of(2013, 2, 3); // Seasoned CDS private static final LocalDate PROTECTION_END_DATE = LocalDate.of(2018, 3, 20); private static final double DEAL_SPREAD = 101; private static final CdsAnalytic CDS; // market CDSs private static final LocalDate[] PAR_SPD_DATES = new LocalDate[] {LocalDate.of(2013, 6, 20), LocalDate.of(2013, 9, 20), LocalDate.of(2014, 3, 20), LocalDate.of(2015, 3, 20), LocalDate.of(2016, 3, 20), LocalDate.of(2018, 3, 20), LocalDate.of(2023, 3, 20) }; private static final double[] PAR_SPREADS = new double[] {50, 70, 80, 95, 100, 95, 80 }; private static final int NUM_MARKET_CDS = PAR_SPD_DATES.length; private static final CdsAnalytic[] MARKET_CDS = new CdsAnalytic[NUM_MARKET_CDS]; // yield curve private static IsdaCompliantYieldCurve YIELD_CURVE; static { final double flatrate = 0.05; final double t = 20.0; YIELD_CURVE = new IsdaCompliantYieldCurve(new double[] {t }, new double[] {flatrate }); final boolean payAccOndefault = true; final Period tenor = Period.ofMonths(3); final StubConvention stubType = StubConvention.SHORT_INITIAL; final boolean protectionStart = true; CDS = new CdsAnalytic(TODAY, EFFECTIVE_DATE, CASH_SETTLE_DATE, PROTECTION_STATE_DATE, PROTECTION_END_DATE, payAccOndefault, tenor, stubType, protectionStart, RECOVERY_RATE); for (int i = 0; i < NUM_MARKET_CDS; i++) { MARKET_CDS[i] = new CdsAnalytic(TODAY, EFFECTIVE_DATE, CASH_SETTLE_DATE, TODAY, PAR_SPD_DATES[i], payAccOndefault, tenor, stubType, protectionStart, RECOVERY_RATE); } } public void parellelCreditDV01Test() { final double fromExcel = 4238.557409; final double dealSpread = DEAL_SPREAD / 10000; final double[] mrkSpreads = new double[NUM_MARKET_CDS]; for (int i = 0; i < NUM_MARKET_CDS; i++) { mrkSpreads[i] = PAR_SPREADS[i] / 10000; } final double cdv01 = NOTIONAL / 10000 * CDV01_CAL.parallelCS01FromParSpreads( CDS, dealSpread, YIELD_CURVE, MARKET_CDS, mrkSpreads, 1e-4, ShiftType.ABSOLUTE); assertEquals("", fromExcel, cdv01, 1e-13 * NOTIONAL); /* * Errors checked */ try { CDV01_CAL.parallelCS01FromParSpreads(CDS, dealSpread, YIELD_CURVE, MARKET_CDS, mrkSpreads, 1e-12, ShiftType.ABSOLUTE); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { final double[] mktSpShort = Arrays.copyOf(mrkSpreads, NUM_MARKET_CDS - 2); CDV01_CAL.parallelCS01FromParSpreads(CDS, dealSpread, YIELD_CURVE, MARKET_CDS, mktSpShort, 1e-4, ShiftType.ABSOLUTE); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } } /** * */ public void crossPrallelCS01test() { /* * Tol is not needed if exactly the same steps are taken */ final double tol = 1.e-13; final AccrualOnDefaultFormulae form = AccrualOnDefaultFormulae.MARKIT_FIX; final FiniteDifferenceSpreadSensitivityCalculator localCal = new FiniteDifferenceSpreadSensitivityCalculator(form); final MarketQuoteConverter conv = new MarketQuoteConverter(form); final IsdaCompliantCreditCurveBuilder cvBuild = new FastCreditCurveBuilder(form); final AnalyticCdsPricer pricer = new AnalyticCdsPricer(form); final double bump = 1.e-4; final double spread = 115. * bump; final double fixedCoupon = 100. * bump; final double puf = 0.1; final CdsQuoteConvention quotePS = new CdsParSpread(spread); final CdsQuoteConvention quoteQS = new CdsQuotedSpread(fixedCoupon, spread); final CdsQuoteConvention quotePU = new PointsUpFront(fixedCoupon, puf); final double pCS01PS = localCal.parallelCS01(CDS, quotePS, YIELD_CURVE, bump); final double pCS01QS = localCal.parallelCS01(CDS, quoteQS, YIELD_CURVE, bump); final double pCS01PU = localCal.parallelCS01(CDS, quotePU, YIELD_CURVE, bump); final double pCS01PSd = localCal.parallelCS01FromSpread(CDS, spread, YIELD_CURVE, spread, bump, ShiftType.ABSOLUTE); final double pCS01QSd = localCal.parallelCS01FromSpread(CDS, fixedCoupon, YIELD_CURVE, spread, bump, ShiftType.ABSOLUTE); final double pCS01PUd = localCal.parallelCS01FromPUF(CDS, fixedCoupon, YIELD_CURVE, puf, bump); assertEquals(pCS01PS, pCS01PSd, tol); assertEquals(pCS01QS, pCS01QSd, tol); assertEquals(pCS01PU, pCS01PUd, tol); final IsdaCompliantCreditCurve curvePSUp = cvBuild.calibrateCreditCurve(CDS, spread + bump, YIELD_CURVE); final IsdaCompliantCreditCurve curvePS = cvBuild.calibrateCreditCurve(CDS, spread, YIELD_CURVE); final double pufFromBumpedPSpread = pricer.pv(CDS, YIELD_CURVE, curvePSUp, spread, CdsPriceType.DIRTY); final double pufFromPSpread = pricer.pv(CDS, YIELD_CURVE, curvePS, spread, CdsPriceType.DIRTY); final double pCS01PSExp = (pufFromBumpedPSpread - pufFromPSpread) / bump; assertEquals(pCS01PSExp, pCS01PS, tol); final IsdaCompliantCreditCurve curveUp = cvBuild.calibrateCreditCurve(CDS, spread + bump, YIELD_CURVE); final IsdaCompliantCreditCurve curve = cvBuild.calibrateCreditCurve(CDS, spread, YIELD_CURVE); final double up = pricer.pv(CDS, YIELD_CURVE, curveUp, fixedCoupon, CdsPriceType.DIRTY); final double price = pricer.pv(CDS, YIELD_CURVE, curve, fixedCoupon, CdsPriceType.DIRTY); final double pCS01QSExp = (up - price) / bump; assertEquals(pCS01QSExp, pCS01QS, tol); final double bumpedQSpreadFromPUF = conv.pufToQuotedSpread(CDS, fixedCoupon, YIELD_CURVE, puf) + bump; final double pufFromBumpedSpread = conv.quotedSpreadToPUF(CDS, fixedCoupon, YIELD_CURVE, bumpedQSpreadFromPUF); final double pCS01PUExp = (pufFromBumpedSpread - puf) / bump; assertEquals(pCS01PUExp, pCS01PU, tol); final double pCS01Diff = localCal.parallelCS01FromQuotedSpread( CDS, fixedCoupon, YIELD_CURVE, MARKET_CDS[1], spread, bump, ShiftType.ABSOLUTE); final IsdaCompliantCreditCurve curveAnUp = cvBuild.calibrateCreditCurve(MARKET_CDS[1], spread + bump, YIELD_CURVE); final IsdaCompliantCreditCurve curveAn = cvBuild.calibrateCreditCurve(MARKET_CDS[1], spread, YIELD_CURVE); final double upAn = pricer.pv(CDS, YIELD_CURVE, curveAnUp, fixedCoupon, CdsPriceType.DIRTY); final double priceAn = pricer.pv(CDS, YIELD_CURVE, curveAn, fixedCoupon, CdsPriceType.DIRTY); final double pCS01DiffExp = (upAn - priceAn) / bump; assertEquals(pCS01DiffExp, pCS01Diff, tol); /* * Errors checked */ try { localCal.parallelCS01FromQuotedSpread( CDS, fixedCoupon, YIELD_CURVE, MARKET_CDS[1], spread, bump * bump * bump, ShiftType.ABSOLUTE); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } } /** * */ public void CS01PillarAndCreditTest() { /* * Tol is not needed if exactly the same steps are taken */ final double tol = 1.e-13; final AccrualOnDefaultFormulae form = AccrualOnDefaultFormulae.ORIGINAL_ISDA; final FiniteDifferenceSpreadSensitivityCalculator localCal = new FiniteDifferenceSpreadSensitivityCalculator(form); final IsdaCompliantCreditCurveBuilder cvBuild = new FastCreditCurveBuilder(form); final AnalyticCdsPricer pricer = new AnalyticCdsPricer(form); final MarketQuoteConverter conv = new MarketQuoteConverter(form); final double basisPt = 1.e-4; final double coupon = 125. * basisPt; final LocalDate startDate = ImmDateLogic.getPrevIMMDate(TODAY); final LocalDate nextIMM = ImmDateLogic.getNextIMMDate(TODAY); final double[] pillarSpreads = new double[] {107.81, 112.99, 115.26, 117.63, 120.8, 124.09, 127.81, 130.38, 136.82, 138.77, 141.3 }; final Period[] tenors = 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) }; final LocalDate[] pillarDates = ImmDateLogic.getIMMDateSet(nextIMM, tenors); pillarDates[2] = pillarDates[2].minusMonths(2); pillarDates[3] = pillarDates[3].plusWeeks(3); final int nPillars = pillarDates.length; final CdsAnalytic[] pillarCDSs = new CdsAnalytic[nPillars]; final CdsQuoteConvention[] pillar_quotes = new CdsQuoteConvention[nPillars]; final CdsQuoteConvention[] pillar_quotes_bumped = new CdsQuoteConvention[nPillars]; final double[] pillar_qSpreads = new double[nPillars]; pillarCDSs[0] = new CdsAnalytic(TODAY, EFFECTIVE_DATE, CASH_SETTLE_DATE, startDate, pillarDates[0], true, Period.ofMonths(3), StubConvention.SHORT_INITIAL, true, 0.4); pillar_qSpreads[0] = pillarSpreads[0] * basisPt; final double puf = conv.quotedSpreadToPUF(pillarCDSs[0], coupon, YIELD_CURVE, pillar_qSpreads[0]); final double pufBumped = conv.quotedSpreadToPUF(pillarCDSs[0], coupon, YIELD_CURVE, pillar_qSpreads[0] + basisPt); pillar_quotes[0] = new PointsUpFront(coupon, puf); pillar_quotes_bumped[0] = new PointsUpFront(coupon, pufBumped); for (int i = 1; i < nPillars; i++) { pillarCDSs[i] = new CdsAnalytic(TODAY, EFFECTIVE_DATE, CASH_SETTLE_DATE, startDate, pillarDates[i], true, Period.ofMonths(3), StubConvention.SHORT_INITIAL, true, 0.4); pillar_qSpreads[i] = pillarSpreads[i] * basisPt; if (ImmDateLogic.isIMMDate(pillarDates[i])) { pillar_quotes[i] = new CdsQuotedSpread(coupon, pillar_qSpreads[i]); pillar_quotes_bumped[i] = new CdsQuotedSpread(coupon, pillar_qSpreads[i] + basisPt); } else { pillar_quotes[i] = new CdsParSpread(pillar_qSpreads[i]); pillar_quotes_bumped[i] = new CdsParSpread(pillar_qSpreads[i] + basisPt); } } /* * Test parallelCS01FromPillarQuotes */ final double res1 = localCal.parallelCS01FromPillarQuotes(CDS, coupon, YIELD_CURVE, pillarCDSs, pillar_quotes, basisPt); final IsdaCompliantCreditCurve curve = cvBuild.calibrateCreditCurve(pillarCDSs, pillar_quotes, YIELD_CURVE); final double pv = pricer.pv(CDS, YIELD_CURVE, curve, coupon); final IsdaCompliantCreditCurve curveBumped = cvBuild.calibrateCreditCurve(pillarCDSs, pillar_quotes_bumped, YIELD_CURVE); final double pvBumped = pricer.pv(CDS, YIELD_CURVE, curveBumped, coupon); assertEquals((pvBumped - pv) / basisPt, res1, tol); /* * Test parallelCS01FromCreditCurve */ final double res2 = localCal.parallelCS01FromCreditCurve(CDS, coupon, pillarCDSs, YIELD_CURVE, curve, basisPt); final double[] impSpreads = new double[nPillars]; final double[] impSpreadsBumped = new double[nPillars]; for (int i = 0; i < nPillars; ++i) { impSpreads[i] = pricer.parSpread(pillarCDSs[i], YIELD_CURVE, curve); impSpreadsBumped[i] = impSpreads[i] + basisPt; } final IsdaCompliantCreditCurve curveFromImpliedSpreads = cvBuild.calibrateCreditCurve(pillarCDSs, impSpreads, YIELD_CURVE); final double pvBase = pricer.pv(CDS, YIELD_CURVE, curveFromImpliedSpreads, coupon); final IsdaCompliantCreditCurve curveFromImpliedSpreadsBumped = cvBuild.calibrateCreditCurve(pillarCDSs, impSpreadsBumped, YIELD_CURVE); final double pvBaseBumped = pricer.pv(CDS, YIELD_CURVE, curveFromImpliedSpreadsBumped, coupon); assertEquals((pvBaseBumped - pvBase) / basisPt, res2, tol); /* * Test bucketedCS01FromPillarQuotes */ final double[] bucketed1 = localCal.bucketedCS01FromPillarQuotes(CDS, coupon, YIELD_CURVE, pillarCDSs, pillar_quotes, basisPt); for (int i = 0; i < nPillars; ++i) { final double[] spreadsWithOneBump = Arrays.copyOf(pillar_qSpreads, nPillars); spreadsWithOneBump[i] += basisPt; final CdsQuoteConvention[] pillarQuotesLocal = new CdsQuoteConvention[nPillars]; for (int j = 0; j < nPillars; ++j) { if (ImmDateLogic.isIMMDate(pillarDates[j])) { pillarQuotesLocal[j] = new CdsQuotedSpread(coupon, spreadsWithOneBump[j]); } else { pillarQuotesLocal[j] = new CdsParSpread(spreadsWithOneBump[j]); } } final IsdaCompliantCreditCurve curveWithOneBump = cvBuild.calibrateCreditCurve(pillarCDSs, pillarQuotesLocal, YIELD_CURVE); final double pvWithOneBump = pricer.pv(CDS, YIELD_CURVE, curveWithOneBump, coupon); assertEquals((pvWithOneBump - pv) / basisPt, bucketed1[i], tol); } /* * Test bucketedCS01FromPillarQuotes */ final LocalDate[] pSpDates = new LocalDate[] {LocalDate.of(2013, 9, 20), LocalDate.of(2014, 6, 20), LocalDate.of(2016, 9, 20), LocalDate.of(2018, 6, 20), LocalDate.of(2023, 9, 20) }; final CdsAnalytic[] bucketCDSs = new CdsAnalytic[pSpDates.length]; for (int i = 0; i < pSpDates.length; i++) { bucketCDSs[i] = new CdsAnalytic(TODAY, EFFECTIVE_DATE, CASH_SETTLE_DATE, TODAY, pSpDates[i], true, Period.ofMonths(3), StubConvention.SHORT_INITIAL, true, RECOVERY_RATE); } final double[] bucketed2 = localCal.bucketedCS01FromParSpreads(CDS, coupon, bucketCDSs, YIELD_CURVE, pillarCDSs, pillar_qSpreads, basisPt); final double[] impSps = new double[pSpDates.length]; final IsdaCompliantCreditCurve curveFromSpreads = cvBuild.calibrateCreditCurve(pillarCDSs, pillar_qSpreads, YIELD_CURVE); for (int i = 0; i < pSpDates.length; ++i) { impSps[i] = pricer.parSpread(bucketCDSs[i], YIELD_CURVE, curveFromSpreads); } final IsdaCompliantCreditCurve curveBucket = cvBuild.calibrateCreditCurve(bucketCDSs, impSps, YIELD_CURVE); final double bvBase = pricer.pv(CDS, YIELD_CURVE, curveBucket, coupon); for (int i = 0; i < pSpDates.length; ++i) { final double[] impSpsBump = Arrays.copyOf(impSps, pSpDates.length); impSpsBump[i] += basisPt; final IsdaCompliantCreditCurve curveBucketBump = cvBuild.calibrateCreditCurve(bucketCDSs, impSpsBump, YIELD_CURVE); final double bvBaseBump = pricer.pv(CDS, YIELD_CURVE, curveBucketBump, coupon); assertEquals((bvBaseBump - bvBase) / basisPt, bucketed2[i], tol); } /* * Errors checked */ final CdsAnalytic[] shortCDSs = Arrays.copyOf(pillarCDSs, nPillars - 1); final double[] shortSpreads = Arrays.copyOf(pillarSpreads, pillarSpreads.length - 2); try { localCal.parallelCS01FromPillarQuotes(CDS, coupon, YIELD_CURVE, pillarCDSs, pillar_quotes, basisPt * 1.e-9); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { localCal.parallelCS01FromPillarQuotes(CDS, coupon, YIELD_CURVE, shortCDSs, pillar_quotes, basisPt); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { localCal.parallelCS01FromCreditCurve(CDS, coupon, pillarCDSs, YIELD_CURVE, curve, basisPt * 1.e-9); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { final CdsAnalytic[] unsortedCDSs = Arrays.copyOf(pillarCDSs, nPillars); final CdsAnalytic tmp = unsortedCDSs[2]; unsortedCDSs[2] = unsortedCDSs[1]; unsortedCDSs[1] = tmp; localCal.parallelCS01FromCreditCurve(CDS, coupon, unsortedCDSs, YIELD_CURVE, curve, basisPt); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { localCal.bucketedCS01FromPillarQuotes(CDS, coupon, YIELD_CURVE, pillarCDSs, pillar_quotes, basisPt * 1.e-9); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { localCal.bucketedCS01FromPillarQuotes(CDS, coupon, YIELD_CURVE, shortCDSs, pillar_quotes, basisPt); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { localCal.bucketedCS01FromCreditCurve(CDS, coupon, pillarCDSs, YIELD_CURVE, curve, basisPt * 1.e-7); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { pillarCDSs[2] = new CdsAnalytic(TODAY, EFFECTIVE_DATE, CASH_SETTLE_DATE, startDate, pillarDates[2].plusYears(10), true, Period.ofMonths(3), StubConvention.SHORT_INITIAL, true, 0.4); localCal.bucketedCS01FromCreditCurve(CDS, coupon, pillarCDSs, YIELD_CURVE, curve, basisPt); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { localCal.bucketedCS01FromQuotedSpreads( new CdsAnalytic[] {CDS}, coupon, YIELD_CURVE, pillarCDSs, pillarSpreads, basisPt * 1.e-7, ShiftType.ABSOLUTE); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { localCal.bucketedCS01FromQuotedSpreads( new CdsAnalytic[] {CDS}, coupon, YIELD_CURVE, pillarCDSs, shortSpreads, basisPt, ShiftType.ABSOLUTE); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { localCal.bucketedCS01FromParSpreads( CDS, coupon, YIELD_CURVE, pillarCDSs, pillarSpreads, basisPt * 1.e-7, ShiftType.ABSOLUTE); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { localCal.bucketedCS01FromParSpreads( CDS, coupon, YIELD_CURVE, pillarCDSs, shortSpreads, basisPt, ShiftType.ABSOLUTE); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { localCal.bucketedCS01FromQuotedSpreads( CDS, coupon, YIELD_CURVE, pillarCDSs, pillarSpreads, basisPt * 1.e-7, ShiftType.ABSOLUTE); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { localCal.bucketedCS01FromQuotedSpreads( CDS, coupon, YIELD_CURVE, pillarCDSs, shortSpreads, basisPt, ShiftType.ABSOLUTE); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } } /** * */ public void finiteDifferenceSpreadSensitivityTest() { /* * Tol is not needed if exactly the same steps are taken */ final double tol = 1.e-13; final AccrualOnDefaultFormulae form = AccrualOnDefaultFormulae.CORRECT; final FiniteDifferenceSpreadSensitivityCalculator localCal = new FiniteDifferenceSpreadSensitivityCalculator(form); final IsdaCompliantCreditCurveBuilder cvBuild = new FastCreditCurveBuilder(form); final AnalyticCdsPricer pricer = new AnalyticCdsPricer(form); final CdsPriceType pType = CdsPriceType.DIRTY; final double basisPt = 1.e-4; final double coupon = 125. * basisPt; final double[] spreads = new double[NUM_MARKET_CDS]; final double[] spreadBumps = new double[NUM_MARKET_CDS]; final double[] spreadBumpUp = new double[NUM_MARKET_CDS]; final double[] spreadBumpDw = new double[NUM_MARKET_CDS]; for (int i = 0; i < NUM_MARKET_CDS; ++i) { spreads[i] = PAR_SPREADS[i] * basisPt; spreadBumps[i] = spreads[i] * 1.e-2; spreadBumpUp[i] = spreads[i] + spreadBumps[i]; spreadBumpDw[i] = spreads[i] - spreadBumps[i]; } final double resCnt = localCal.finiteDifferenceSpreadSensitivity(CDS, coupon, pType, YIELD_CURVE, MARKET_CDS, spreads, spreadBumps, FiniteDifferenceType.CENTRAL); final double resFwd = localCal.finiteDifferenceSpreadSensitivity(CDS, coupon, pType, YIELD_CURVE, MARKET_CDS, spreads, spreadBumps, FiniteDifferenceType.FORWARD); final double resBck = localCal.finiteDifferenceSpreadSensitivity(CDS, coupon, pType, YIELD_CURVE, MARKET_CDS, spreads, spreadBumps, FiniteDifferenceType.BACKWARD); final IsdaCompliantCreditCurve curve = cvBuild.calibrateCreditCurve(MARKET_CDS, spreads, YIELD_CURVE); final IsdaCompliantCreditCurve curveUp = cvBuild.calibrateCreditCurve(MARKET_CDS, spreadBumpUp, YIELD_CURVE); final IsdaCompliantCreditCurve curveDw = cvBuild.calibrateCreditCurve(MARKET_CDS, spreadBumpDw, YIELD_CURVE); final double pv = pricer.pv(CDS, YIELD_CURVE, curve, coupon, pType); final double pvUp = pricer.pv(CDS, YIELD_CURVE, curveUp, coupon, pType); final double pvDw = pricer.pv(CDS, YIELD_CURVE, curveDw, coupon, pType); assertEquals(pvUp - pvDw, resCnt, tol); assertEquals(pvUp - pv, resFwd, tol); assertEquals(pv - pvDw, resBck, tol); /* * Errors checked */ try { final double[] shortSpreads = Arrays.copyOf(spreads, NUM_MARKET_CDS - 2); localCal.finiteDifferenceSpreadSensitivity(CDS, coupon, pType, YIELD_CURVE, MARKET_CDS, shortSpreads, spreadBumps, FiniteDifferenceType.CENTRAL); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { final double[] shortSpreadBumps = Arrays.copyOf(spreadBumps, NUM_MARKET_CDS - 3); localCal.finiteDifferenceSpreadSensitivity(CDS, coupon, pType, YIELD_CURVE, MARKET_CDS, spreads, shortSpreadBumps, FiniteDifferenceType.CENTRAL); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { final double[] negativeSpreads = Arrays.copyOf(spreads, NUM_MARKET_CDS); negativeSpreads[1] *= -1.; localCal.finiteDifferenceSpreadSensitivity(CDS, coupon, pType, YIELD_CURVE, MARKET_CDS, negativeSpreads, spreadBumps, FiniteDifferenceType.CENTRAL); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { final double[] negativeSpreadBumps = Arrays.copyOf(spreadBumps, NUM_MARKET_CDS); negativeSpreadBumps[3] *= -1.; localCal.finiteDifferenceSpreadSensitivity(CDS, coupon, pType, YIELD_CURVE, MARKET_CDS, spreads, negativeSpreadBumps, FiniteDifferenceType.CENTRAL); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } try { final double[] largeSpreadBumps = Arrays.copyOf(spreadBumps, NUM_MARKET_CDS); largeSpreadBumps[1] += 1.e2; localCal.finiteDifferenceSpreadSensitivity(CDS, coupon, pType, YIELD_CURVE, MARKET_CDS, spreads, largeSpreadBumps, FiniteDifferenceType.CENTRAL); throw new RuntimeException(); } catch (Exception e) { assertTrue(e instanceof IllegalArgumentException); } } }