/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.credit.isdastandardmodel.demo; import static com.opengamma.analytics.financial.credit.isdastandardmodel.IMMDateLogic.getIMMDateSet; import static com.opengamma.analytics.financial.credit.isdastandardmodel.IMMDateLogic.getNextIMMDate; import static com.opengamma.analytics.financial.credit.isdastandardmodel.IMMDateLogic.getPrevIMMDate; import static com.opengamma.financial.convention.businessday.BusinessDayDateUtils.addWorkDays; import java.util.Arrays; import org.testng.annotations.Test; import org.threeten.bp.LocalDate; import org.threeten.bp.Month; import org.threeten.bp.Period; import org.threeten.bp.format.DateTimeFormatter; import com.opengamma.analytics.financial.credit.isdastandardmodel.AnalyticSpreadSensitivityCalculator; import com.opengamma.analytics.financial.credit.isdastandardmodel.CDSAnalytic; import com.opengamma.analytics.financial.credit.isdastandardmodel.CDSAnalyticFactory; import com.opengamma.analytics.financial.credit.isdastandardmodel.FastCreditCurveBuilder; import com.opengamma.analytics.financial.credit.isdastandardmodel.FiniteDifferenceSpreadSensitivityCalculator; import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDABaseTest; import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantCreditCurve; import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantCreditCurveBuilder; import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantCreditCurveBuilder.ArbitrageHandling; import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantYieldCurve; import com.opengamma.analytics.financial.credit.isdastandardmodel.MarketQuoteConverter; import com.opengamma.analytics.financial.credit.isdastandardmodel.QuotedSpread; import com.opengamma.analytics.financial.model.BumpType; import com.opengamma.analytics.math.linearalgebra.LUDecompositionCommons; import com.opengamma.analytics.math.linearalgebra.LUDecompositionResult; import com.opengamma.analytics.math.matrix.DoubleMatrix1D; import com.opengamma.analytics.math.matrix.DoubleMatrix2D; import com.opengamma.analytics.math.matrix.MatrixAlgebra; import com.opengamma.analytics.math.matrix.OGMatrixAlgebra; import com.opengamma.util.ArgumentChecker; /** * This code generates the results in the paper <i>The Pricing and Risk Management of Credit Default Swaps, with a Focus * on the ISDA Model</i>. Tests either produce tables for Latex (directly using dumpLatexTable or via the Exce2LaTeX pluin) * or data sets used to produce graphs in Excel. */ public class CDSPaperExamples extends ISDABaseTest { private static final MatrixAlgebra MA = new OGMatrixAlgebra(); private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("dd-MMM-yy"); private static final MarketQuoteConverter PUF_CONVERTER = new MarketQuoteConverter(); private static final FiniteDifferenceSpreadSensitivityCalculator FD_SPREAD_SENSE_CAL = new FiniteDifferenceSpreadSensitivityCalculator(); private static final AnalyticSpreadSensitivityCalculator ANALYTIC_SPREAD_SENSE_CAL = new AnalyticSpreadSensitivityCalculator(); private static final CDSAnalyticFactory CDS_FACTORY = new CDSAnalyticFactory(0.4); private static final LocalDate TODAY = LocalDate.of(2011, Month.JUNE, 13); private static final LocalDate NEXT_IMM = getNextIMMDate(TODAY); private static final LocalDate TRADE_DATE = LocalDate.of(2011, Month.JUNE, 13); private static final LocalDate STEPIN = TRADE_DATE.plusDays(1); private static final LocalDate CASH_SETTLE_DATE = addWorkDays(TRADE_DATE, 3, DEFAULT_CALENDAR); // AKA valuation date private static final LocalDate STARTDATE = FOLLOWING.adjustDate(DEFAULT_CALENDAR, getPrevIMMDate(TRADE_DATE)); // LocalDate.of(2011, Month.MARCH, 21); private static final Period[] TENORS = new Period[] {Period.ofMonths(6), Period.ofYears(1), Period.ofYears(3), Period.ofYears(5), Period.ofYears(7), Period.ofYears(10) }; // private static final LocalDate NEXT_IMM = getNextIMMDate(EFFECTIVE_DATE); private static final LocalDate[] PILLAR_DATES = getIMMDateSet(NEXT_IMM, TENORS); private static final LocalDate[] IMM_DATES = getIMMDateSet(NEXT_IMM, 41); private static final LocalDate[] MATURITIES_6M_STEP; private static final LocalDate[] MATURITIES_1Y_STEP; // yield curve private static final LocalDate SPOT_DATE = LocalDate.of(2011, Month.JUNE, 15); private static final String[] YIELD_CURVE_POINTS = new String[] {"1M", "2M", "3M", "6M", "9M", "1Y", "2Y", "3Y", "4Y", "5Y", "6Y", "7Y", "8Y", "9Y", "10Y", "11Y", "12Y", "15Y", "20Y", "25Y", "30Y" }; private static final String[] YIELD_CURVE_INSTRUMENTS = new String[] {"M", "M", "M", "M", "M", "M", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S" }; private static final double[] YIELD_CURVE_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 }; private static final ISDACompliantYieldCurve YIELD_CURVE = makeYieldCurve(TRADE_DATE, SPOT_DATE, YIELD_CURVE_POINTS, YIELD_CURVE_INSTRUMENTS, YIELD_CURVE_RATES, ACT360, D30360, Period.ofYears(1)); private static final double COUPON = 0.01; private static final double[] SPREADS = new double[] {0.007926718, 0.007926718, 0.012239372, 0.016978579, 0.019270856, 0.02086048 }; private static final CDSAnalytic[] PILLAR_CDSS; private static final ISDACompliantCreditCurve CREDIT_CURVE; static { final ISDACompliantCreditCurveBuilder curveBuilder = new FastCreditCurveBuilder(MARKIT_FIX, ArbitrageHandling.ZeroHazardRate); final int nPillars = PILLAR_DATES.length; PILLAR_CDSS = new CDSAnalytic[nPillars]; for (int i = 0; i < nPillars; i++) { PILLAR_CDSS[i] = new CDSAnalytic(TRADE_DATE, STEPIN, CASH_SETTLE_DATE, STARTDATE, PILLAR_DATES[i], PAY_ACC_ON_DEFAULT, PAYMENT_INTERVAL, STUB, PROCTECTION_START, RECOVERY_RATE); } CREDIT_CURVE = curveBuilder.calibrateCreditCurve(PILLAR_CDSS, SPREADS, YIELD_CURVE); int n = IMM_DATES.length; LocalDate[] temp = new LocalDate[n]; int count = 0; for (int i = 0; i < n; i = i + 2) { temp[count++] = IMM_DATES[i]; } MATURITIES_6M_STEP = new LocalDate[count]; System.arraycopy(temp, 0, MATURITIES_6M_STEP, 0, count); count = 0; for (int i = 0; i < n; i = i + 4) { temp[count++] = IMM_DATES[i]; } MATURITIES_1Y_STEP = new LocalDate[count]; System.arraycopy(temp, 0, MATURITIES_1Y_STEP, 0, count); } /** * Print out the knots times (year fractions) and corresponding zero rates for the calibrated yield curve used in these * examples */ @Test(description = "Demo") public void yieldCurveDump() { int n = YIELD_CURVE.getNumberOfKnots(); System.out.println("Tenor\tRate\tYear Fraction\tZero Rate"); for (int i = 0; i < n; i++) { System.out.println(YIELD_CURVE_POINTS[i] + "\t" + YIELD_CURVE_RATES[i] + "\t" + YIELD_CURVE.getTimeAtIndex(i) + "\t" + YIELD_CURVE.getZeroRateAtIndex(i)); } } /** * Print on the credit curve pillar dates and their spreads, along with the year fractions and (calibrated) survival probabilities */ @Test(description = "Demo") public void creditCurveDump() { int n = PILLAR_DATES.length; System.out.println("Tenor\tMaturity\tSpread (bps)\tYear Fraction\tSurvival Probability"); for (int i = 0; i < n; i++) { double t = CREDIT_CURVE.getTimeAtIndex(i); System.out.println(TENORS[i].toString() + "\t" + PILLAR_DATES[i].toString(DATE_FORMAT) + "\t" + SPREADS[i] * TEN_THOUSAND + "\t" + t + "\t" + CREDIT_CURVE.getSurvivalProbability(t)); } } /** * Price a set of CDSs using standard ISDA model (1.8.2), OG's suggested fix and the (incorrect) Markit 'fit' */ @Test(description = "Demo") public void threeWayPriceTest() { double notional = 1e7; Period[] tenors = new Period[] {Period.ofMonths(3), Period.ofMonths(6), Period.ofYears(1), Period.ofYears(5), Period.ofYears(10) }; CDSAnalytic[] cds = CDS_FACTORY.makeIMMCDS(TRADE_DATE, tenors); int n = tenors.length; double[][] res = new double[3][n]; for (int i = 0; i < n; i++) { res[0][i] = notional * PRICER_OG_FIX.pv(cds[i], YIELD_CURVE, CREDIT_CURVE, 0.01); res[1][i] = notional * PRICER.pv(cds[i], YIELD_CURVE, CREDIT_CURVE, 0.01); res[2][i] = notional * PRICER_MARKIT_FIX.pv(cds[i], YIELD_CURVE, CREDIT_CURVE, 0.01); } System.out.println(new DoubleMatrix2D(res)); } /** * Plots price against hazard rate for various recovery rates */ @Test(description = "Demo") public void priceVsHazardRate() { double[] recoveryRates = new double[] {0, 0.25, 0.5, 0.75, 1.0 }; CDSAnalyticFactory factory = new CDSAnalyticFactory(); CDSAnalytic cds = factory.makeIMMCDS(TRADE_DATE, Period.ofYears(5)); int n = recoveryRates.length; System.out.print("Hazard rate"); for (int j = 0; j < n; j++) { System.out.print("\tRecovery " + (recoveryRates[j] * 100) + "%"); } System.out.print("\n"); for (int i = 0; i < 100; i++) { double lambda = 0.8 * i / 100.; System.out.print(lambda); ISDACompliantCreditCurve cc = new ISDACompliantCreditCurve(5.0, lambda); for (int j = 0; j < n; j++) { cds = cds.withRecoveryRate(recoveryRates[j]); double price = PRICER.pv(cds, YIELD_CURVE, cc, 0.05); System.out.print("\t" + price); } System.out.print("\n"); } } /** * Plots points-up-front (PUF) against quoted spread for coupons of 0bps, 100bps and 500bps */ @Test(description = "Demo") public void pufVsQuotedSpread() { CDSAnalyticFactory factory = new CDSAnalyticFactory(0.4); CDSAnalytic cds = factory.makeIMMCDS(TRADE_DATE, Period.ofYears(10)); for (int i = 0; i < 100; i++) { double qs = i * 10; double puf0 = PUF_CONVERTER.convert(cds, new QuotedSpread(0.0, qs * ONE_BP), YIELD_CURVE).getPointsUpFront(); double puf100 = PUF_CONVERTER.convert(cds, new QuotedSpread(0.01, qs * ONE_BP), YIELD_CURVE).getPointsUpFront(); double puf500 = PUF_CONVERTER.convert(cds, new QuotedSpread(0.05, qs * ONE_BP), YIELD_CURVE).getPointsUpFront(); System.out.println(qs + "\t" + puf0 + "\t" + puf100 + "\t" + puf500); } } /** * Print a table of the par rate sensitivity to the to zero hazard rates at the credit curve nodes for a set of CDSs with recovery rate 40\% */ @Test(description = "Demo") public void parRateSensitivityTest() { CDSAnalyticFactory factory = new CDSAnalyticFactory(); int nPillars = PILLAR_DATES.length; System.out.print("CDS Maturity"); for (int i = 0; i < nPillars; i++) { System.out.print("\t" + TENORS[i].toString()); } System.out.print("\n"); for (int i = 0; i < IMM_DATES.length; i = i + 2) { LocalDate mat = IMM_DATES[i]; System.out.print(mat.toString(DATE_FORMAT)); CDSAnalytic cds = factory.makeCDS(TRADE_DATE, STARTDATE, mat); for (int j = 0; j < nPillars; j++) { double sense = PRICER.parSpreadCreditSensitivity(cds, YIELD_CURVE, CREDIT_CURVE, j); System.out.print("\t" + sense); } System.out.print("\n"); } } /** * Print the present value sensitivity of CDSs with coupons of 100bps to the zero hazard rates at the credit curve nodes. * <b>Note:</b> This does not appear as a table in the paper. */ @Test(description = "Demo") public void pvSensitivityTest() { double coupon = 0.01; CDSAnalyticFactory factory = new CDSAnalyticFactory(0.4); int nPillars = PILLAR_DATES.length; System.out.print("CDS Maturity"); for (int i = 0; i < nPillars; i++) { System.out.print("\t" + TENORS[i].toString()); } System.out.print("\n"); for (int i = 0; i < nPillars; i++) { LocalDate mat = PILLAR_DATES[i]; System.out.print(mat.toString(DATE_FORMAT)); CDSAnalytic cds = factory.makeCDS(TRADE_DATE, STARTDATE, mat); for (int j = 0; j < nPillars; j++) { double sense = PRICER.pvCreditSensitivity(cds, YIELD_CURVE, CREDIT_CURVE, coupon, j); System.out.print("\t" + sense); } System.out.print("\n"); } } /** * For a set of CDSs with different maturities (every other IMM date) calculate the hedge ratios - the amount of the * standard (pillar) CDSs that will give the same first order PV sensitivity to the credit curve knots. When the * CDS in question IS a pillar CDS, the hedge ratio is of course exactly 1.0 for that pillar 9and zero everywhere else) * <b>Note:</b> This does not appear as a table in the paper, however it does provide hedge ratios for the hedgingPerformanceDemo. */ @Test(description = "Demo") public void pvHedgingDemo() { double coupon = 0.01; int nPillars = PILLAR_DATES.length; double[][] res = new double[nPillars][nPillars]; for (int i = 0; i < nPillars; i++) { LocalDate mat = PILLAR_DATES[i]; CDSAnalytic cds = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, mat); for (int j = 0; j < nPillars; j++) { double sense = PRICER.pvCreditSensitivity(cds, YIELD_CURVE, CREDIT_CURVE, coupon, j); res[j][i] = sense; } } DoubleMatrix2D jacT = new DoubleMatrix2D(res); // System.out.println(jacT.toString()); LUDecompositionCommons decomp = new LUDecompositionCommons(); LUDecompositionResult luRes = decomp.evaluate(jacT); System.out.print("CDS Maturity"); for (int i = 0; i < nPillars; i++) { System.out.print("\t" + TENORS[i].toString()); } System.out.print("\n"); for (int i = 0; i < IMM_DATES.length; i = i + 2) { LocalDate mat = IMM_DATES[i]; System.out.print(mat.toString(DATE_FORMAT)); CDSAnalytic cds = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, mat); double[] temp = new double[nPillars]; for (int j = 0; j < nPillars; j++) { double sense = PRICER.pvCreditSensitivity(cds, YIELD_CURVE, CREDIT_CURVE, coupon, j); temp[j] = sense; } DoubleMatrix1D vLambda = new DoubleMatrix1D(temp); DoubleMatrix1D w = luRes.solve(vLambda); for (int j = 0; j < nPillars; j++) { System.out.print("\t" + w.getEntry(j)); } System.out.print("\n"); } } /** * Take a hedged CDS portfolio (1.0 of June 20th 2015 and -0.47556 & -0.52474 of June 20th 2014 & June 20th 2016), * and compute its change in PV for both parallel shifts and tilts to the credit curve. The results are shown for a * notional of 10MM. */ @Test(description = "Demo") public void hedgingPerformanceDemo() { double coupon = 0.01; double notional = 1e7; LocalDate mat = LocalDate.of(2015, Month.JUNE, 20); LocalDate mat1 = LocalDate.of(2014, Month.JUNE, 20); LocalDate mat2 = LocalDate.of(2016, Month.JUNE, 20); double[] hedgeRatios = new double[] {1.0, -0.47556, -0.52474 }; CDSAnalytic[] cdsPort = new CDSAnalytic[3]; cdsPort[0] = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, mat); cdsPort[1] = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, mat1); cdsPort[2] = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, mat2); double basePVH = 0; for (int i = 0; i < 3; i++) { basePVH += notional* hedgeRatios[i] * PRICER.pv(cdsPort[i], YIELD_CURVE, CREDIT_CURVE, coupon); } System.out.println("Basis Points\tParallel\tTilt"); for (int k = 0; k < 101; k++) { double bump = -100 + 2.0 * k; ISDACompliantCreditCurve cc = bumpCurve(CREDIT_CURVE, bump * ONE_BP); ISDACompliantCreditCurve ccTilt = tiltCurve(CREDIT_CURVE, bump * ONE_BP); double pvH = 0; double pvTilt = 0; for (int i = 0; i < 3; i++) { pvH += notional* hedgeRatios[i] * PRICER .pv(cdsPort[i], YIELD_CURVE, cc, coupon); pvTilt += notional* hedgeRatios[i] * PRICER.pv(cdsPort[i], YIELD_CURVE, ccTilt, coupon); } System.out.println(bump + "\t" + (pvH - basePVH) + "\t" + (pvTilt - basePVH) ); } } /** * The sensitivity of the PV of a set of CDSs to the par spreads of the CDSs used to construct the credit curve. * The last column shows the sensitivity of all the spreads moving in parallel. The (priced) CDSs all have a coupon of 100bps. * All CDSs have a recovery rate of 40\% and the Trade date is 13-Jun-2011. <p> * This uses the method dumpLatexTable to format the output into a Latex table. */ @Test (description = "Demo") public void analyticCS01test() { int nMat = MATURITIES_6M_STEP.length; double[] coupons = new double[nMat]; Arrays.fill(coupons, COUPON); CDSAnalytic[] cds = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, MATURITIES_6M_STEP); double[][] analCS01 = ANALYTIC_SPREAD_SENSE_CAL.bucketedCS01FromCreditCurve(cds, coupons, PILLAR_CDSS, YIELD_CURVE, CREDIT_CURVE); int nPillars = PILLAR_DATES.length; String[] columnHeadings = new String[nPillars + 1]; for (int i = 0; i < nPillars; i++) { columnHeadings[i] = TENORS[i].toString(); } columnHeadings[nPillars] = "Total"; String[] rowHeadings = new String[nMat]; double[][] data = new double[nMat][nPillars + 1]; for (int i = 0; i < nMat; i++) { rowHeadings[i] = MATURITIES_6M_STEP[i].toString(DATE_FORMAT); System.arraycopy(analCS01[i], 0, data[i], 0, nPillars); double sum = 0; for (int j = 0; j < nPillars; j++) { sum += analCS01[i][j]; } data[i][nPillars] = sum; } System.out.println(dumpLatexTable("Tenors", "CDS Maturities", columnHeadings, rowHeadings, data, 4)); } /** * The sensitivity of the PV of 8Y CDSs to the par spreads of the CDSs used to construct the credit curve. The calculation * methods are analytic and forward finite difference (or bump and reprice). The bump in the forward difference is 1bps.<p> * This uses the method dumpLatexTable to format the output into a Latex table. */ @Test(description = "Demo") void analyticVFDCS01Test() { LocalDate mat = LocalDate.of(2019, Month.JUNE, 20); CDSAnalytic cds = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, mat); double[] analCS01 = ANALYTIC_SPREAD_SENSE_CAL.bucketedCS01FromCreditCurve(cds, COUPON, PILLAR_CDSS, YIELD_CURVE, CREDIT_CURVE); double pCS01 = FD_SPREAD_SENSE_CAL.parallelCS01FromParSpreads(cds, COUPON, YIELD_CURVE, PILLAR_CDSS, SPREADS, ONE_BP, BumpType.ADDITIVE); double[] bCS01 = FD_SPREAD_SENSE_CAL.bucketedCS01FromCreditCurve(cds, COUPON, PILLAR_CDSS, YIELD_CURVE, CREDIT_CURVE, ONE_BP); int nPillars = PILLAR_DATES.length; String[] columnHeadings = new String[nPillars + 2]; double[][] data = new double[2][nPillars + 2]; double sumA = 0; double sumFD = 0; for (int i = 0; i < nPillars; i++) { columnHeadings[i] = TENORS[i].toString(); data[0][i] = analCS01[i]; sumA += analCS01[i]; data[1][i] = bCS01[i]; sumFD += bCS01[i]; } data[0][nPillars] = sumA; data[0][nPillars + 1] = sumA; data[1][nPillars] = sumFD; data[1][nPillars + 1] = pCS01; columnHeadings[nPillars] = "Sum"; columnHeadings[nPillars + 1] = "Parallel"; String[] rowHeadings = new String[] {"Analytic", "Forward FD" }; System.out.println(dumpLatexTable("Tenors", "Calculation Method", columnHeadings, rowHeadings, data, 5)); } /** * This calculates hedge ratios from bucketed CS01. The main point this demonstrates is that this gives exactly (up to * numerical tolerances) as from pvHedgingDemo, but this involves a lot more work (i.e. calculating the CS01). <p> * <b>Note:</b> This does not appear as a table in the paper. */ @Test(description = "Demo") public void spreadHedgeDemo() { LUDecompositionCommons decomp = new LUDecompositionCommons(); int nPillars = PILLAR_CDSS.length; double[] coupons = new double[nPillars]; Arrays.fill(coupons, COUPON); double[][] temp = ANALYTIC_SPREAD_SENSE_CAL.bucketedCS01FromCreditCurve(PILLAR_CDSS, coupons, PILLAR_CDSS, YIELD_CURVE, CREDIT_CURVE); DoubleMatrix2D jacT = MA.getTranspose(new DoubleMatrix2D(temp)); // System.out.println(jac); LUDecompositionResult decRes = decomp.evaluate(jacT); int nMat = MATURITIES_6M_STEP.length; double[][] res = new double[nMat][]; CDSAnalytic[] cds = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, MATURITIES_6M_STEP); for (int i = 0; i < nMat; i++) { double[] vs = ANALYTIC_SPREAD_SENSE_CAL.bucketedCS01FromCreditCurve(cds[i], COUPON, PILLAR_CDSS, YIELD_CURVE, CREDIT_CURVE); res[i] = decRes.solve(vs); } DoubleMatrix2D hedge = new DoubleMatrix2D(res); System.out.println(hedge); } /** * This demonstrates that a constant (flat) hazard rate does not correspond to the same par spread for all maturities - * in this example the spread varies between 59.3 and 59.4bps */ @Test(description = "Demo") public void flatHazardTest() { ISDACompliantCreditCurve flat = new ISDACompliantCreditCurve(1.0, 0.01); int nMat = IMM_DATES.length; CDSAnalytic[] cds = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, IMM_DATES); System.out.println("Year fraction\tSpread (bps)"); for (int i = 0; i < nMat; i++) { double t = ACT365F.getDayCountFraction(TRADE_DATE, IMM_DATES[i]); double s = PRICER_OG_FIX.parSpread(cds[i], YIELD_CURVE, flat); System.out.println(t + "\t" + s * TEN_THOUSAND); } } /** * Compute bucketed and parallel CS01 by bumping 'flat spreads' by 1bps. That, is the spread at each pillar is set * to a constant value, a credit curve is bootstrapped and the CDS prices; the spread and each pillar is then bumped * up by 1bps an the calculation repeated. The difference from the base is the (bucketed) CS01 */ @Test(description = "Demo") public void bucketedCS01FromFlatSpreadDemo() { MarketQuoteConverter puf_con = new MarketQuoteConverter(); int nMat = MATURITIES_1Y_STEP.length; int nPillars = PILLAR_CDSS.length; CDSAnalytic[] cds = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, MATURITIES_1Y_STEP); System.out.print("CDS maturities"); for (int j = 0; j < nPillars; j++) { System.out.print("\t" + TENORS[j]); } System.out.print("\tSum\tParallel\n"); for (int i = 0; i < nMat; i++) { double puf = PRICER.pv(cds[i], YIELD_CURVE, CREDIT_CURVE, COUPON); double qs = puf_con.pufToQuotedSpread(cds[i], COUPON, YIELD_CURVE, puf); double[] spreads = new double[nPillars]; Arrays.fill(spreads, qs); double[] bCS01 = FD_SPREAD_SENSE_CAL.bucketedCS01FromParSpreads(cds[i], COUPON, YIELD_CURVE, PILLAR_CDSS, spreads, ONE_BP, BumpType.ADDITIVE); double pCS01 = FD_SPREAD_SENSE_CAL.parallelCS01FromParSpreads(cds[i], COUPON, YIELD_CURVE, PILLAR_CDSS, spreads, ONE_BP, BumpType.ADDITIVE); System.out.print(MATURITIES_1Y_STEP[i].toString(DATE_FORMAT)); double sum = 0; for (int j = 0; j < nPillars; j++) { sum += bCS01[j]; System.out.print("\t" + bCS01[j]); } System.out.print("\t" + sum + "\t" + pCS01); System.out.print("\n"); } } /** * Compute bucketed and parallel CS01 by bumping 'quoted' by 1bps - see paper for details */ @Test(description = "Demo") public void bucketedCS01FromQuotedSpreadDemo() { MarketQuoteConverter puf_con = new MarketQuoteConverter(); int nMat = MATURITIES_1Y_STEP.length; int nPillars = PILLAR_CDSS.length; CDSAnalytic[] cds = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, MATURITIES_1Y_STEP); System.out.print("CDS maturities"); for (int j = 0; j < nPillars; j++) { System.out.print("\t" + TENORS[j]); } System.out.print("\tSum\tParallel\n"); for (int i = 0; i < nMat; i++) { double puf = PRICER.pv(cds[i], YIELD_CURVE, CREDIT_CURVE, COUPON); double qs = puf_con.pufToQuotedSpread(cds[i], COUPON, YIELD_CURVE, puf); double[] spreads = new double[nPillars]; Arrays.fill(spreads, qs); double[] bCS01 = FD_SPREAD_SENSE_CAL.bucketedCS01FromQuotedSpreads(cds[i], COUPON, YIELD_CURVE, PILLAR_CDSS, SPREADS, ONE_BP, BumpType.ADDITIVE); double pCS01 = FD_SPREAD_SENSE_CAL.parallelCS01FromQuotedSpread(cds[i], COUPON, YIELD_CURVE, cds[i], qs, ONE_BP, BumpType.ADDITIVE); System.out.print(MATURITIES_1Y_STEP[i].toString(DATE_FORMAT)); double sum = 0; for (int j = 0; j < nPillars; j++) { sum += bCS01[j]; System.out.print("\t" + bCS01[j]); } System.out.print("\t" + sum + "\t" + pCS01); System.out.print("\n"); } } /** * The PV sensitivity to zero rates at the yield curve nodes for a set of standard CDSs with a coupon of 100bps and a * recovery rate 40%. The trade date is 13-Jun-2011. */ @Test(description = "Demo") public void yieldSenseTest() { String[] ycPoints = new String[] {"1M", "3M", "6M", "1Y", "3Y", "5Y", "7Y", "10Y", "11Y", "12Y", "15Y", "20Y", "25Y", "30Y" }; String[] instuments = new String[] {"M", "M", "M", "M", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S" }; 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 }; ISDACompliantYieldCurve yc = makeYieldCurve(TRADE_DATE, SPOT_DATE, ycPoints, instuments, rates, ACT360, D30360, Period.ofYears(1)); int nMat = MATURITIES_1Y_STEP.length; int nYCPoints = ycPoints.length; CDSAnalytic[] cds = CDS_FACTORY.makeCDS(TRADE_DATE, STARTDATE, MATURITIES_1Y_STEP); for (int j = 0; j < nYCPoints; j++) { System.out.print("\t" + ycPoints[j]); } System.out.print("\n"); for (int i = 0; i < nMat; i++) { System.out.print(MATURITIES_1Y_STEP[i].toString(DATE_FORMAT)); for (int j = 0; j < nYCPoints; j++) { double sense = PRICER_MARKIT_FIX.pvYieldSensitivity(cds[i], yc, CREDIT_CURVE, COUPON, j); System.out.print("\t" + sense); } System.out.print("\n"); } } /* * Better tables can be produced using the Exce2LaTeX plugin */ private String dumpLatexTable(String heading1, String heading2, String[] columnHeadings, String[] rowHeadings, double[][] data, int dp) { ArgumentChecker.noNulls(columnHeadings, "columnHeadings"); ArgumentChecker.noNulls(rowHeadings, "rowHeadings"); ArgumentChecker.noNulls(data, "data"); int nColumns = columnHeadings.length; int nRows = rowHeadings.length; ArgumentChecker.isTrue(nColumns == data[0].length, nColumns + "column headings, but data has " + data[0].length + " columns"); ArgumentChecker.isTrue(nRows == data.length, nRows + "row headings, but data has " + data.length + " rows"); String format = "& %." + dp + "f"; StringBuilder out = new StringBuilder(); out.append("\\begin{tabular}{"); for (int i = 0; i < nColumns + 1; i++) { out.append("c|"); } out.append("}\n"); out.append("\\cline{2-" + (nColumns + 1) + "}\n"); out.append("& \\multicolumn{" + nColumns + "}{c|}{" + heading1 + "}\\\\\n"); out.append("\\hline\n"); out.append("\\multicolumn{1}{|c|}{" + heading2 + "}"); for (int i = 0; i < nColumns; i++) { out.append("& " + columnHeadings[i]); } out.append("\\\\\n"); out.append("\\hline\n"); for (int i = 0; i < nRows; i++) { out.append("\\multicolumn{1}{|c|}{" + rowHeadings[i] + "}"); for (int j = 0; j < nColumns; j++) { out.append(String.format(format, data[i][j])); } out.append("\\\\\n"); } out.append("\\hline\n"); out.append("\\end{tabular}\n"); return out.toString(); } private ISDACompliantCreditCurve bumpCurve(ISDACompliantCreditCurve curve, double amount) { double[] r = curve.getKnotZeroRates(); int n = r.length; for (int i = 0; i < n; i++) { r[i] += amount; } return curve.withRates(r); } private ISDACompliantCreditCurve tiltCurve(ISDACompliantCreditCurve curve, double amount) { double[] r = curve.getKnotZeroRates(); int n = r.length; for (int i = 0; i < n; i++) { r[i] += +(amount / (n / 2)) * (i - n / 2); } return curve.withRates(r); } }