/**
* 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.e2e;
import static com.opengamma.strata.pricer.impl.credit.isda.ImmDateLogic.getIMMDateSet;
import static com.opengamma.strata.pricer.impl.credit.isda.ImmDateLogic.getNextIMMDate;
import static com.opengamma.strata.pricer.impl.credit.isda.ImmDateLogic.getPrevIMMDate;
import java.time.LocalDate;
import java.time.Month;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Locale;
import org.testng.annotations.Test;
import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.collect.array.DoubleMatrix;
import com.opengamma.strata.market.ShiftType;
import com.opengamma.strata.math.impl.linearalgebra.LUDecompositionCommons;
import com.opengamma.strata.math.impl.linearalgebra.LUDecompositionResult;
import com.opengamma.strata.math.impl.matrix.MatrixAlgebra;
import com.opengamma.strata.math.impl.matrix.OGMatrixAlgebra;
import com.opengamma.strata.pricer.impl.credit.isda.AnalyticSpreadSensitivityCalculator;
import com.opengamma.strata.pricer.impl.credit.isda.CdsAnalytic;
import com.opengamma.strata.pricer.impl.credit.isda.CdsAnalyticFactory;
import com.opengamma.strata.pricer.impl.credit.isda.CdsQuotedSpread;
import com.opengamma.strata.pricer.impl.credit.isda.FastCreditCurveBuilder;
import com.opengamma.strata.pricer.impl.credit.isda.FiniteDifferenceSpreadSensitivityCalculator;
import com.opengamma.strata.pricer.impl.credit.isda.IsdaBaseTest;
import com.opengamma.strata.pricer.impl.credit.isda.IsdaCompliantCreditCurve;
import com.opengamma.strata.pricer.impl.credit.isda.IsdaCompliantCreditCurveBuilder;
import com.opengamma.strata.pricer.impl.credit.isda.IsdaCompliantCreditCurveBuilder.ArbitrageHandling;
import com.opengamma.strata.pricer.impl.credit.isda.IsdaCompliantYieldCurve;
import com.opengamma.strata.pricer.impl.credit.isda.MarketQuoteConverter;
/**
* 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.
*/
@Test(enabled = false)
public class CdsPaperExamples extends IsdaBaseTest {
private static final MatrixAlgebra MA = new OGMatrixAlgebra();
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("dd-MMM-uu", Locale.ENGLISH);
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 = DEFAULT_CALENDAR.shift(TRADE_DATE, 3); // AKA valuation date
private static final LocalDate STARTDATE = FOLLOWING.adjust(getPrevIMMDate(TRADE_DATE), DEFAULT_CALENDAR); // 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[] 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", enabled = false)
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", enabled = false)
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].format(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", enabled = false)
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(DoubleMatrix.copyOf(res));
}
/**
* Plots price against hazard rate for various recovery rates
*/
@Test(description = "Demo", enabled = false)
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", enabled = false)
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 CdsQuotedSpread(0.0, qs * ONE_BP), YIELD_CURVE).getPointsUpFront();
double puf100 = PUF_CONVERTER.convert(cds, new CdsQuotedSpread(0.01, qs * ONE_BP), YIELD_CURVE).getPointsUpFront();
double puf500 = PUF_CONVERTER.convert(cds, new CdsQuotedSpread(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", enabled = false)
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.format(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", enabled = false)
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.format(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", enabled = false)
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;
}
}
DoubleMatrix jacT = DoubleMatrix.copyOf(res);
LUDecompositionCommons decomp = new LUDecompositionCommons();
LUDecompositionResult luRes = decomp.apply(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.format(DATE_FORMAT));
CdsAnalytic cds = CDS_FACTORY.makeCds(TRADE_DATE, STARTDATE, mat);
DoubleArray vLambda = DoubleArray.of(
nPillars,
j -> PRICER.pvCreditSensitivity(cds, YIELD_CURVE, CREDIT_CURVE, coupon, j));
DoubleArray w = luRes.solve(vLambda);
for (int j = 0; j < nPillars; j++) {
System.out.print("\t" + w.get(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", enabled = false)
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", enabled = false)
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].format(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", enabled = false)
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, ShiftType.ABSOLUTE);
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", enabled = false)
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);
DoubleMatrix jacT = MA.getTranspose(DoubleMatrix.copyOf(temp));
LUDecompositionResult decRes = decomp.apply(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);
}
DoubleMatrix hedge = DoubleMatrix.copyOf(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", enabled = false)
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.yearFraction(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", enabled = false)
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, ShiftType.ABSOLUTE);
double pCS01 = FD_SPREAD_SENSE_CAL.parallelCS01FromParSpreads(
cds[i], COUPON, YIELD_CURVE, PILLAR_CDSS, spreads, ONE_BP, ShiftType.ABSOLUTE);
System.out.print(MATURITIES_1Y_STEP[i].format(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", enabled = false)
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, ShiftType.ABSOLUTE);
double pCS01 = FD_SPREAD_SENSE_CAL.parallelCS01FromQuotedSpread(
cds[i], COUPON, YIELD_CURVE, cds[i], qs, ONE_BP, ShiftType.ABSOLUTE);
System.out.print(MATURITIES_1Y_STEP[i].format(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", enabled = false)
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].format(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) {
ArgChecker.noNulls(columnHeadings, "columnHeadings");
ArgChecker.noNulls(rowHeadings, "rowHeadings");
ArgChecker.noNulls(data, "data");
int nColumns = columnHeadings.length;
int nRows = rowHeadings.length;
ArgChecker.isTrue(nColumns == data[0].length, nColumns + "column headings, but data has " + data[0].length + " columns");
ArgChecker.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(Locale.ENGLISH, 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);
}
}