/** * 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.Month; import java.time.Period; import org.testng.annotations.Test; import com.opengamma.strata.basics.schedule.StubConvention; /** * Test. */ @Test public class AnalyticCdsPricerTest extends IsdaBaseTest { public void creditCurveSensitivityTest() { final double[] ccTimes = new double[] {0.25, 0.5, 1.001, 2.0, 3.0, 5.0, 7.2, 10.0, 20.0 }; final double[] ccNormalRates = new double[] {0.05, 0.06, 0.07, 0.08, 0.09, 0.09, 0.07, 0.065, 0.06 }; final double[] ccLowRates = new double[] {0.00, 0.00, 1e-6, 2e-4, 5e-4, 0.001, 0.0015, 0.002, 0.0015 }; final double[] ycTimes = new double[] {1 / 52., 1 / 12., 1 / 4., 1 / 2., 3 / 4., 1.0, 2.1, 5.0, 11.0, 30.0 }; final double[] ycNormalRates = new double[] {0.004, 0.006, 0.007, 0.01, 0.01, 0.015, 0.02, 0.03, 0.04, 0.05 }; final double[] ycLowRates = new double[] {0.00, 0.00, 0.00, 0.0, 0.00, 0.0005, 0.001, 0.0015, 0.002, 0.0015 }; final IsdaCompliantCreditCurve creditCurveLow = new IsdaCompliantCreditCurve(ccTimes, ccLowRates); final IsdaCompliantCreditCurve creditCurveNorm = new IsdaCompliantCreditCurve(ccTimes, ccNormalRates); final IsdaCompliantYieldCurve yieldCurveLow = new IsdaCompliantYieldCurve(ycTimes, ycLowRates); final IsdaCompliantYieldCurve yieldCurveNorm = new IsdaCompliantYieldCurve(ycTimes, ycNormalRates); final LocalDate today = LocalDate.of(2013, 7, 2); // Tuesday final LocalDate stepin = today.plusDays(1); // this is usually 1 final LocalDate valueDate = today.plusDays(3); // Friday final LocalDate startDate = today; // protection starts now final LocalDate endDate = LocalDate.of(2017, 9, 20); final boolean payAccOnDefault = true; final CdsAnalytic cds = new CdsAnalytic(today, stepin, valueDate, startDate, endDate, payAccOnDefault, Period.ofMonths(3), StubConvention.SHORT_INITIAL, false, 0.4); for (int count = 0; count < 2; count++) { final AnalyticCdsPricer pricer = count == 0 ? PRICER : PRICER_MARKIT_FIX; creditCurveSenseTest(pricer, cds, yieldCurveLow, creditCurveLow); creditCurveSenseTest(pricer, cds, yieldCurveLow, creditCurveNorm); creditCurveSenseTest(pricer, cds, yieldCurveNorm, creditCurveLow); creditCurveSenseTest(pricer, cds, yieldCurveNorm, creditCurveNorm); } } public void yieldCurveSenseTest() { final double coupon = 0.01; final double[] ccTimes = new double[] {0.25, 0.5, 1.001, 2.0, 3.0, 5.0, 7.2, 10.0, 20.0 }; final double[] ccNormalRates = new double[] {0.05, 0.06, 0.07, 0.08, 0.09, 0.09, 0.07, 0.065, 0.06 }; final double[] ycTimes = new double[] {1 / 52., 1 / 12., 1 / 4., 1 / 2., 3 / 4., 1.0, 2.1, 5.0, 11.0, 30.0 }; final double[] ycNormalRates = new double[] {0.004, 0.006, 0.007, 0.01, 0.01, 0.015, 0.02, 0.03, 0.04, 0.05 }; final IsdaCompliantCreditCurve creditCurveNorm = new IsdaCompliantCreditCurve(ccTimes, ccNormalRates); final IsdaCompliantYieldCurve yieldCurveNorm = new IsdaCompliantYieldCurve(ycTimes, ycNormalRates); final CdsAnalyticFactory factory = new CdsAnalyticFactory(); final CdsAnalytic cds = factory.makeImmCds(LocalDate.of(2013, Month.SEPTEMBER, 10), Period.ofYears(5)); final int n = ycTimes.length; for (int i = 0; i < n; i++) { double fd = fdProtectionLegYieldSense(PRICER_MARKIT_FIX, cds, yieldCurveNorm, creditCurveNorm, i); double anal = PRICER_MARKIT_FIX.protectionLegYieldSensitivity(cds, yieldCurveNorm, creditCurveNorm, i); assertEquals(fd, anal, 1e-10); fd = fdPremiumLegYieldSense(PRICER_MARKIT_FIX, cds, yieldCurveNorm, creditCurveNorm, i); anal = PRICER_MARKIT_FIX.pvPremiumLegYieldSensitivity(cds, yieldCurveNorm, creditCurveNorm, i); assertEquals(fd, anal, 1e-9); fd = fdPVYieldSense(PRICER_MARKIT_FIX, cds, yieldCurveNorm, creditCurveNorm, coupon, i); anal = PRICER_MARKIT_FIX.pvYieldSensitivity(cds, yieldCurveNorm, creditCurveNorm, coupon, i); assertEquals(fd, anal, 1e-10); } } private void creditCurveSenseTest(final AnalyticCdsPricer pricer, final CdsAnalytic cds, final IsdaCompliantYieldCurve yieldCurve, final IsdaCompliantCreditCurve creditCurve) { final int n = creditCurve.getNumberOfKnots(); for (int i = 0; i < n; i++) { final double fdProSense = fdProtectionLegSense(cds, yieldCurve, creditCurve, i); final double analProSense = pricer.protectionLegCreditSensitivity(cds, yieldCurve, creditCurve, i); final double fdRPV01Sense = fdRPV01Sense(cds, yieldCurve, creditCurve, i, pricer); final double analRPV01Sense = pricer.pvPremiumLegCreditSensitivity(cds, yieldCurve, creditCurve, i); assertEquals("ProSense " + i, fdProSense, analProSense, 1e-9); assertEquals("RPV01Sense " + i, fdRPV01Sense, analRPV01Sense, 5e-8); } } public void sensitivityParallelShiftTest() { final double[] ccTimes = new double[] {0.25, 0.5, 1.00000001, 2.0, 3.0, 5.0, 7.2, 10.0, 20.0 }; final double[] ccRates = new double[] {0.05, 0.06, 0.07, 0.05, 0.09, 0.09, 0.07, 0.065, 0.06 }; final double[] ycTimes = new double[] {1 / 52., 1 / 12., 1 / 4., 1 / 2., 3 / 4., 1.0, 2.1, 5.2, 11.0, 30.0 }; final double[] ycRates = new double[] {0.005, 0.006, 0.007, 0.01, 0.01, 0.015, 0.02, 0.03, 0.04, 0.05 }; final IsdaCompliantCreditCurve creditCurve = new IsdaCompliantCreditCurve(ccTimes, ccRates); final IsdaCompliantYieldCurve yieldCurve = new IsdaCompliantYieldCurve(ycTimes, ycRates); final LocalDate today = LocalDate.of(2013, 7, 2); // Tuesday final LocalDate stepin = today.plusDays(2); // this is usually 1 final LocalDate valueDate = today.plusDays(3); // Friday final LocalDate startDate = today.plusMonths(1); // protection starts in a month final LocalDate endDate = LocalDate.of(2023, 6, 20); final CdsAnalytic cds = new CdsAnalytic(today, stepin, valueDate, startDate, endDate, true, Period.ofMonths(3), StubConvention.SHORT_INITIAL, false, 0.4); final double fd = fdProtectionLegSense(cds, yieldCurve, creditCurve); final int n = creditCurve.getNumberOfKnots(); double anal = 0.0; for (int i = 0; i < n; i++) { anal += PRICER.protectionLegCreditSensitivity(cds, yieldCurve, creditCurve, i); } assertEquals(fd, anal, 1e-8); } private double fdRPV01Sense(final CdsAnalytic cds, final IsdaCompliantYieldCurve yieldCurve, final IsdaCompliantCreditCurve creditCurve, final int creditCurveNode, final AnalyticCdsPricer pricer) { final double h = creditCurve.getZeroRateAtIndex(creditCurveNode); final double eps = 1e-3 * Math.max(1e-3, h); final IsdaCompliantCreditCurve ccUp = creditCurve.withRate(h + eps, creditCurveNode); final IsdaCompliantCreditCurve ccDown = creditCurve.withRate(h - eps, creditCurveNode); final double up = pricer.annuity(cds, yieldCurve, ccUp, CdsPriceType.DIRTY); // clean or dirty has no effect on sensitivity final double down = pricer.annuity(cds, yieldCurve, ccDown, CdsPriceType.DIRTY); return (up - down) / 2 / eps; } private double fdProtectionLegSense(final CdsAnalytic cds, final IsdaCompliantYieldCurve yieldCurve, final IsdaCompliantCreditCurve creditCurve) { final int n = creditCurve.getNumberOfKnots(); final double h = 0.5 * (creditCurve.getZeroRateAtIndex(0) + creditCurve.getZeroRateAtIndex(n - 1)); final double eps = 1e-4 * h; final double[] rUp = creditCurve.getKnotZeroRates(); final double[] rDown = creditCurve.getKnotZeroRates(); for (int i = 0; i < n; i++) { rUp[i] += eps; rDown[i] -= eps; } final double up = PRICER.protectionLeg(cds, yieldCurve, creditCurve.withRates(rUp)); final double down = PRICER.protectionLeg(cds, yieldCurve, creditCurve.withRates(rDown)); return (up - down) / 2 / eps; } private double fdProtectionLegSense(final CdsAnalytic cds, final IsdaCompliantYieldCurve yieldCurve, final IsdaCompliantCreditCurve creditCurve, final int creditCurveNode) { final double h = creditCurve.getZeroRateAtIndex(creditCurveNode); final double eps = 1e-4 * Math.max(1e-3, h); final IsdaCompliantCreditCurve ccUp = creditCurve.withRate(h + eps, creditCurveNode); final IsdaCompliantCreditCurve ccDown = creditCurve.withRate(h - eps, creditCurveNode); final double up = PRICER.protectionLeg(cds, yieldCurve, ccUp); final double down = PRICER.protectionLeg(cds, yieldCurve, ccDown); return (up - down) / 2 / eps; } private double fdProtectionLegYieldSense(final AnalyticCdsPricer pricer, final CdsAnalytic cds, final IsdaCompliantYieldCurve yieldCurve, final IsdaCompliantCreditCurve creditCurve, final int yieldCurveNode) { final double r = yieldCurve.getZeroRateAtIndex(yieldCurveNode); final double eps = 1e-4 * Math.max(1e-3, r); final IsdaCompliantYieldCurve yUp = yieldCurve.withRate(r + eps, yieldCurveNode); final IsdaCompliantYieldCurve yDown = yieldCurve.withRate(r - eps, yieldCurveNode); final double up = pricer.protectionLeg(cds, yUp, creditCurve); final double down = pricer.protectionLeg(cds, yDown, creditCurve); return (up - down) / 2 / eps; } private double fdPremiumLegYieldSense(final AnalyticCdsPricer pricer, final CdsAnalytic cds, final IsdaCompliantYieldCurve yieldCurve, final IsdaCompliantCreditCurve creditCurve, final int yieldCurveNode) { final double r = yieldCurve.getZeroRateAtIndex(yieldCurveNode); final double eps = 1e-4 * Math.max(1e-3, r); final IsdaCompliantYieldCurve yUp = yieldCurve.withRate(r + eps, yieldCurveNode); final IsdaCompliantYieldCurve yDown = yieldCurve.withRate(r - eps, yieldCurveNode); final double up = pricer.annuity(cds, yUp, creditCurve, CdsPriceType.CLEAN); final double down = pricer.annuity(cds, yDown, creditCurve, CdsPriceType.CLEAN); return (up - down) / 2 / eps; } private double fdPVYieldSense(final AnalyticCdsPricer pricer, final CdsAnalytic cds, final IsdaCompliantYieldCurve yieldCurve, final IsdaCompliantCreditCurve creditCurve, final double coupon, final int yieldCurveNode) { final double r = yieldCurve.getZeroRateAtIndex(yieldCurveNode); final double eps = 1e-4 * Math.max(1e-3, r); final IsdaCompliantYieldCurve yUp = yieldCurve.withRate(r + eps, yieldCurveNode); final IsdaCompliantYieldCurve yDown = yieldCurve.withRate(r - eps, yieldCurveNode); final double up = pricer.pv(cds, yUp, creditCurve, coupon, CdsPriceType.DIRTY); final double down = pricer.pv(cds, yDown, creditCurve, coupon, CdsPriceType.DIRTY); return (up - down) / 2 / eps; } }