/** * 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 java.time.LocalDate; import java.time.Period; import org.testng.annotations.Test; import com.opengamma.strata.basics.schedule.StubConvention; import com.opengamma.strata.market.ShiftType; /** * Test. */ @Test public class AnalyticSpreadSensitivityTest extends IsdaBaseTest { private static final AnalyticSpreadSensitivityCalculator ANAL_CS01_CAL = new AnalyticSpreadSensitivityCalculator(); // 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 // 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); } } @Test public void Test() { final double dealSpread = DEAL_SPREAD * ONE_BP; final double[] mrkSpreads = new double[NUM_MARKET_CDS]; for (int i = 0; i < NUM_MARKET_CDS; i++) { mrkSpreads[i] = PAR_SPREADS[i] * ONE_BP; } // compare with bump and reprice final double[] an_CS01 = ANAL_CS01_CAL.bucketedCS01FromParSpreads(CDS, dealSpread, YIELD_CURVE, MARKET_CDS, mrkSpreads); final double[] fd_CS01 = CS01_CAL.bucketedCS01FromParSpreads( CDS, dealSpread, YIELD_CURVE, MARKET_CDS, mrkSpreads, 1e-7, ShiftType.ABSOLUTE); final int n = fd_CS01.length; for (int i = 0; i < n; i++) { assertEquals(fd_CS01[i], an_CS01[i], 1e-6); // the fd is only forward difference - so accuracy is not great } } /** * */ @Test public void ParallelCS01FiniteDifferenceComparisonTest() { final AccrualOnDefaultFormulae form = AccrualOnDefaultFormulae.CORRECT; final AnalyticSpreadSensitivityCalculator aCal = new AnalyticSpreadSensitivityCalculator(form); final FiniteDifferenceSpreadSensitivityCalculator fCal = new FiniteDifferenceSpreadSensitivityCalculator(form); final double eps = 1.e-6; final double coupon = 100. * 1.e-4; final double quotedSpread = 104. * 1.e-4; final CdsQuoteConvention qSp = new CdsQuotedSpread(coupon, quotedSpread); final double puf = 0.3; final double pCS01 = aCal.parallelCS01(CDS, qSp, YIELD_CURVE); final double pCS01Fin = fCal.parallelCS01(CDS, qSp, YIELD_CURVE, eps); assertEquals(pCS01Fin, pCS01, Math.abs(pCS01Fin) * eps * 10.); final double pCS01FromPuf = aCal.parallelCS01FromPUF(CDS, coupon, YIELD_CURVE, puf); final double pCS01FromPufFin = fCal.parallelCS01FromPUF(CDS, coupon, YIELD_CURVE, puf, eps); assertEquals(pCS01FromPufFin, pCS01FromPuf, Math.abs(pCS01FromPufFin) * eps * 10.); final double pCS01FromSpread = aCal.parallelCS01FromSpread(CDS, coupon, YIELD_CURVE, quotedSpread); final double pCS01FromSpreadFin = fCal.parallelCS01FromSpread( CDS, coupon, YIELD_CURVE, quotedSpread, eps, ShiftType.ABSOLUTE); assertEquals(pCS01FromSpreadFin, pCS01FromSpread, Math.abs(pCS01FromSpreadFin) * eps * 10.); final double pCS01FromEqSpread = aCal.parallelCS01FromSpread(CDS, coupon, YIELD_CURVE, coupon); final double pCS01FromEqSpreadFin = fCal.parallelCS01FromSpread( CDS, coupon, YIELD_CURVE, coupon, eps, ShiftType.ABSOLUTE); assertEquals(pCS01FromEqSpreadFin, pCS01FromEqSpread, Math.abs(pCS01FromEqSpreadFin) * eps * 10.); } /** * */ @Test(enabled = false) public void BucketedCS01FiniteDifferenceComparisonTest() { //TODO Tests should be added (PLAT-5931) once PLAT-5971 is fixed final AccrualOnDefaultFormulae form = AccrualOnDefaultFormulae.CORRECT; final AnalyticSpreadSensitivityCalculator aCal = new AnalyticSpreadSensitivityCalculator(form); final FiniteDifferenceSpreadSensitivityCalculator fCal = new FiniteDifferenceSpreadSensitivityCalculator(form); final IsdaCompliantCreditCurveBuilder builder = new FastCreditCurveBuilder(form); final double eps = 1.e-6; final double coupon = 100. * 1.e-4; final double quotedSpread = 104. * 1.e-4; final double[] bCS01FromSpread = aCal.bucketedCS01FromSpread(CDS, coupon, YIELD_CURVE, quotedSpread, MARKET_CDS); final IsdaCompliantCreditCurve curve = builder.calibrateCreditCurve(CDS, quotedSpread, YIELD_CURVE); final double[] bCS01FromSpreadFin = fCal.bucketedCS01FromCreditCurve(CDS, coupon, MARKET_CDS, YIELD_CURVE, curve, eps); for (int i = 0; i < NUM_MARKET_CDS; ++i) { assertEquals(bCS01FromSpreadFin[i], bCS01FromSpread[i], Math.abs(bCS01FromSpreadFin[i]) * eps * 10.); } } }