/**
* 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 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 static com.opengamma.strata.pricer.impl.credit.isda.ImmDateLogic.isIMMDate;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import java.time.LocalDate;
import java.time.Month;
import java.time.Period;
import java.util.Arrays;
import org.testng.annotations.Test;
import com.opengamma.strata.basics.date.Tenor;
/**
* Test.
*/
@Test
public class MultiAnalyticPricerTest extends IsdaBaseTest {
private static final MultiAnalyticCdsPricer MULTI_PRICER_ISDA = new MultiAnalyticCdsPricer();
private static final MultiAnalyticCdsPricer MULTI_PRICER_MARKIT_FIX = new MultiAnalyticCdsPricer(MARKIT_FIX);
private static final CdsAnalyticFactory FACTORY = new CdsAnalyticFactory();
private static final IsdaCompliantYieldCurve YIELD_CURVE;
private static final IsdaCompliantCreditCurve CREDIT_CURVE;
static {
final double[] yieldCurveNodes = new double[] {1 / 365., 1 / 52., 1 / 12., 1 / 4., 1 / 2., 1., 2., 3., 4., 5., 7., 10, 15, 20, 30 };
final double[] zeroRates = new double[] {0.01, 0.011, 0.013, 0.015, 0.02, 0.03, 0.035, 0.04, 0.04, 0.06, 0.06, 0.057, 0.055, 0.05, 0.05 };
YIELD_CURVE = new IsdaCompliantYieldCurve(yieldCurveNodes, zeroRates);
final double[] creditCurveNodes = new double[] {1 / 2., 1, 2, 3, 5, 7, 10 };
final double[] zeroHazardRates = new double[] {0.0015, 0.002, 0.0023, 0.0025, 0.0024, 0.0023, 0.002 };
CREDIT_CURVE = new IsdaCompliantCreditCurve(creditCurveNodes, zeroHazardRates);
}
public void singleCDSTest() {
final LocalDate tradeDate = LocalDate.of(2013, Month.AUGUST, 30);
final LocalDate effectiveDate = FOLLOWING.adjust(getPrevIMMDate(tradeDate), DEFAULT_CALENDAR);
final LocalDate stepinDate = tradeDate.plusDays(1);
final LocalDate valueDate = DEFAULT_CALENDAR.shift(tradeDate, 3);
final LocalDate nextIMM = getNextIMMDate(tradeDate);
final int matIndex = 4;
LocalDate temp = nextIMM;
for (int i = 0; i < matIndex; i++) {
temp = temp.plus(PAYMENT_INTERVAL);
}
final LocalDate maturity = temp;
final Tenor paymentInt = Tenor.of(PAYMENT_INTERVAL);
final CdsAnalytic cdsS = FACTORY.makeCds(tradeDate, effectiveDate, maturity);
final MultiCdsAnalytic cdsM = new MultiCdsAnalytic(tradeDate, stepinDate, valueDate, effectiveDate, nextIMM, new int[] {matIndex }, PAY_ACC_ON_DEFAULT, paymentInt, STUB, PROCTECTION_START,
RECOVERY_RATE, FOLLOWING, DEFAULT_CALENDAR, ACT360, ACT365F);
final double proLegS = PRICER.protectionLeg(cdsS, YIELD_CURVE, CREDIT_CURVE);
final double proLegM = MULTI_PRICER_ISDA.protectionLeg(cdsM, YIELD_CURVE, CREDIT_CURVE)[0];
final double rpv01S = PRICER.annuity(cdsS, YIELD_CURVE, CREDIT_CURVE, CdsPriceType.CLEAN);
final double rpv01M = MULTI_PRICER_ISDA.pvPremiumLegPerUnitSpread(cdsM, YIELD_CURVE, CREDIT_CURVE, CdsPriceType.CLEAN)[0];
//These are identical calculations, so the match should be exact
assertEquals("proLeg", proLegS, proLegM, 0);
assertEquals("RPV01", rpv01S, rpv01M, 0);
}
public void multiCDSTest() {
final LocalDate tradeDate = LocalDate.of(2013, Month.AUGUST, 30);
final LocalDate effectiveDate = FOLLOWING.adjust(getPrevIMMDate(tradeDate), DEFAULT_CALENDAR);
final LocalDate stepinDate = tradeDate.plusDays(1);
final LocalDate valueDate = DEFAULT_CALENDAR.shift(tradeDate, 3);
final LocalDate nextIMM = getNextIMMDate(tradeDate);
final int[] matIndex = new int[] {1, 2, 4, 8, 12, 20, 28 };
final int nMat = matIndex.length;
final LocalDate[] maturities = new LocalDate[nMat];
LocalDate tMat = nextIMM;
for (int i = 0; i < nMat; i++) {
final int steps = i == 0 ? matIndex[0] : matIndex[i] - matIndex[i - 1];
for (int j = 0; j < steps; j++) {
tMat = tMat.plus(PAYMENT_INTERVAL);
}
maturities[i] = tMat;
}
final double[] coupons = new double[] {0.0075, 0.008, 0.01, 0.01, 0.011, 0.01, 0.009 };
final Tenor paymentInt = Tenor.of(PAYMENT_INTERVAL);
final CdsAnalytic[] cdsS = FACTORY.makeCds(tradeDate, effectiveDate, maturities);
final MultiCdsAnalytic cdsM = new MultiCdsAnalytic(tradeDate, stepinDate, valueDate, effectiveDate, nextIMM, matIndex, PAY_ACC_ON_DEFAULT, paymentInt, STUB, PROCTECTION_START, RECOVERY_RATE,
FOLLOWING, DEFAULT_CALENDAR, ACT360, ACT365F);
final double[] pvM = MULTI_PRICER_ISDA.pv(cdsM, YIELD_CURVE, CREDIT_CURVE, coupons);
final double[] pvS = new double[nMat];
for (int i = 0; i < nMat; i++) {
pvS[i] = PRICER.pv(cdsS[i], YIELD_CURVE, CREDIT_CURVE, coupons[i]);
}
//These take different paths, so the match will not be exact
for (int i = 0; i < nMat; i++) {
assertEquals("pv " + i, pvS[i], pvM[i], 1e-16);
}
//check to correct integral prices
final double[] pvMC = MULTI_PRICER_MARKIT_FIX.pv(cdsM, YIELD_CURVE, CREDIT_CURVE, coupons);
final double[] pvSC = new double[nMat];
for (int i = 0; i < nMat; i++) {
pvSC[i] = PRICER_MARKIT_FIX.pv(cdsS[i], YIELD_CURVE, CREDIT_CURVE, coupons[i]);
}
//These take different paths, so the match will not be exact
for (int i = 0; i < nMat; i++) {
assertEquals("pv (fixed)" + i, pvSC[i], pvMC[i], 1e-16);
}
}
public void multiCDSTest3() {
final int nValDates = 41;
final LocalDate tradeDate = LocalDate.of(2011, 6, 13);
final LocalDate nextIMM = getNextIMMDate(tradeDate);
final LocalDate accStartDate = FOLLOWING.adjust(getPrevIMMDate(tradeDate), DEFAULT_CALENDAR);
final LocalDate[] maturityDates = getIMMDateSet(nextIMM, nValDates); //maturity dates don't change (it is the same CDSs on each day of the scenario)
final double[] coupons = new double[nValDates];
Arrays.fill(coupons, ONE_PC);
final CdsAnalytic[] cds = FACTORY.makeCds(tradeDate, accStartDate, maturityDates);
final MultiCdsAnalytic multiCDS = FACTORY.makeMultiImmCds(tradeDate, 0, 40);
final MultiAnalyticCdsPricer mPricer = new MultiAnalyticCdsPricer(MARKIT_FIX);
final double[] mRPV01 = mPricer.pvPremiumLegPerUnitSpread(multiCDS, YIELD_CURVE, CREDIT_CURVE, CdsPriceType.CLEAN);
for (int i = 0; i < nValDates; i++) {
final double rpv01 = PRICER_MARKIT_FIX.annuity(cds[i], YIELD_CURVE, CREDIT_CURVE, CdsPriceType.CLEAN);
assertEquals(rpv01, mRPV01[i], 1e-15 * rpv01);
}
}
public void multiCDSTest2() {
//numbers from ISDA model excel (with fix)
final double[] expectedProtLeg = new double[] {2.45394099651068E-05, 0.00227491490938686, 0.00448142313178339, 0.00666745010334752, 0.00885603585574933, 0.012691978781156, 0.0164500855081327,
0.0201318759141635, 0.0238598226827485, 0.0275443376519455, 0.0311399510498073, 0.0346489017007175, 0.0381880070431471, 0.0434702839464633, 0.0486021197153017, 0.0535881757494423,
0.0585947781482861, 0.0635100334228483, 0.0682822757875156, 0.0729670602447138, 0.0776160534847412, 0.0818931345586326, 0.0860467169145431, 0.0900806892461579, 0.0941296532623397,
0.0981042087895352, 0.101963461190518, 0.105711060988118, 0.109472064842192, 0.113288927289599, 0.116993122936688, 0.120588291169969, 0.124194442553579, 0.127732056036848, 0.131164913796168,
0.13453307768769, 0.137873733063254, 0.141150384026368, 0.144329371544781, 0.147413885672373, 0.150506909958133 };
final double[] expectedRPV01 = new double[] {0.255551477261065, 0.256632130692319, 0.505623806773112, 0.75227939608251, 0.999196556679805, 1.24414240013293, 1.48412997820174, 1.71924769187078,
1.95722450070843, 2.19205173432063, 2.42120515404789, 2.64484382580866, 2.87031426005254, 3.0921437216807, 3.30771077822955, 3.51719921532105, 3.7273400042775, 3.93373063819273,
4.13412825531985, 4.33085331038569, 4.52597943738742, 4.71755423579183, 4.9036063521181, 5.08430937903227, 5.26557601138535, 5.44360502471132, 5.61646068630761, 5.78432376573634,
5.95268616377267, 6.11796359393172, 6.27837179689681, 6.43406633865226, 6.59017164733675, 6.74336671903601, 6.89201730114158, 7.03786649101056, 7.18241173055505, 7.3242766448501,
7.46192022533206, 7.5954663571564, 7.72932665473152 };
final LocalDate spotDate = LocalDate.of(2011, Month.JUNE, 15);
final String[] yieldCurvePoints = new String[] {"1M", "2M", "3M", "6M", "9M", "1Y", "2Y", "3Y", "4Y", "5Y", "6Y", "7Y", "8Y", "9Y", "10Y", "11Y", "12Y", "15Y", "20Y", "25Y", "30Y" };
final String[] yieldCurveInstruments = new String[] {"M", "M", "M", "M", "M", "M", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S", "S" };
final 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, 0.03092, 0.0316, 0.03231,
0.03367, 0.03419, 0.03411, 0.03412 };
final LocalDate tradeDate = LocalDate.of(2011, Month.JUNE, 19);
final IsdaCompliantYieldCurve yieldCurve = makeYieldCurve(tradeDate, spotDate, yieldCurvePoints, yieldCurveInstruments, rates, ACT360, D30360, Period.ofYears(1));
final FastCreditCurveBuilder ccBuilder = new FastCreditCurveBuilder(MARKIT_FIX);
final double[] spreads = new double[] {0.00886315689995649, 0.00886315689995649, 0.0133044689825873, 0.0171490070952563, 0.0183903639181293, 0.0194721890639724 };
final Period[] tenors = new Period[] {Period.ofMonths(6), Period.ofYears(1), Period.ofYears(3), Period.ofYears(5), Period.ofYears(7), Period.ofYears(10) };
final CdsAnalytic[] pillarCDS = FACTORY.makeImmCds(tradeDate, tenors);
final IsdaCompliantCreditCurve creditCurve = ccBuilder.calibrateCreditCurve(pillarCDS, spreads, yieldCurve);
final int nVals = 41;
final LocalDate accStart = FOLLOWING.adjust(getPrevIMMDate(tradeDate), DEFAULT_CALENDAR);
final LocalDate nextIMM = isIMMDate(tradeDate) ? tradeDate : getNextIMMDate(tradeDate);
final LocalDate[] maturities = getIMMDateSet(nextIMM, nVals);
final CdsAnalytic[] cdsArray = FACTORY.makeCds(tradeDate, accStart, maturities);
final MultiCdsAnalytic multiCDS = FACTORY.makeMultiImmCds(tradeDate, 0, nVals - 1);
final double[] proLeg1 = new double[nVals];
final double[] premLeg1 = new double[nVals];
final double[] proLeg2 = MULTI_PRICER_MARKIT_FIX.protectionLeg(multiCDS, yieldCurve, creditCurve);
final double[] premLeg2 = MULTI_PRICER_MARKIT_FIX.pvPremiumLegPerUnitSpread(multiCDS, yieldCurve, creditCurve, CdsPriceType.DIRTY);
for (int i = 0; i < nVals; i++) {
proLeg1[i] = PRICER_MARKIT_FIX.protectionLeg(cdsArray[i], yieldCurve, creditCurve);
premLeg1[i] = PRICER_MARKIT_FIX.annuity(cdsArray[i], yieldCurve, creditCurve, CdsPriceType.DIRTY);
assertEquals(expectedProtLeg[i], proLeg1[i], 1e-15);
assertEquals(expectedRPV01[i], premLeg1[i], 1e-14);
assertEquals(proLeg1[i], proLeg2[i], 1e-15);
assertEquals(premLeg1[i], premLeg2[i], 1e-14);
}
}
/**
*
*/
public void pvTest() {
/*
* This is not needed if we follow exactly the same procedure.
*/
final double tol = 1.e-13;
final AccrualOnDefaultFormulae form = AccrualOnDefaultFormulae.ORIGINAL_ISDA;
final MultiAnalyticCdsPricer mPricer = new MultiAnalyticCdsPricer(form);
final AnalyticCdsPricer sPricer = new AnalyticCdsPricer(form);
final double premium = 250. * 1.e-4;
final LocalDate tradeDate = LocalDate.of(2013, Month.AUGUST, 30);
final LocalDate effectiveDate = FOLLOWING.adjust(getPrevIMMDate(tradeDate), DEFAULT_CALENDAR);
final LocalDate stepinDate = tradeDate.plusDays(1);
final LocalDate valueDate = DEFAULT_CALENDAR.shift(tradeDate, 3);
final LocalDate nextIMM = getNextIMMDate(tradeDate);
final int matIndex0 = 4;
final int matIndex1 = 8;
LocalDate temp = nextIMM;
for (int i = 0; i < matIndex0; i++) {
temp = temp.plus(PAYMENT_INTERVAL);
}
final LocalDate maturity0 = temp;
temp = nextIMM;
for (int i = 0; i < matIndex1; i++) {
temp = temp.plus(PAYMENT_INTERVAL);
}
final LocalDate maturity1 = temp;
final Tenor paymentInt = Tenor.of(PAYMENT_INTERVAL);
final boolean accOnDefault = false;
final MultiCdsAnalytic cdsM = new MultiCdsAnalytic(tradeDate, stepinDate, valueDate, effectiveDate, nextIMM, new int[] {matIndex0, matIndex1 }, accOnDefault, paymentInt, STUB,
PROCTECTION_START, RECOVERY_RATE, FOLLOWING, DEFAULT_CALENDAR, ACT360, ACT365F);
final CdsAnalytic cds0 = new CdsAnalytic(tradeDate, stepinDate, valueDate, effectiveDate, maturity0, accOnDefault, PAYMENT_INTERVAL, STUB,
PROCTECTION_START, RECOVERY_RATE, FOLLOWING, DEFAULT_CALENDAR, ACT360, ACT365F);
final CdsAnalytic cds1 = new CdsAnalytic(tradeDate, stepinDate, valueDate, effectiveDate, maturity1, accOnDefault, PAYMENT_INTERVAL, STUB,
PROCTECTION_START, RECOVERY_RATE, FOLLOWING, DEFAULT_CALENDAR, ACT360, ACT365F);
final double[] prices = mPricer.pv(cdsM, YIELD_CURVE, CREDIT_CURVE, premium, CdsPriceType.CLEAN);
final double price0 = sPricer.pv(cds0, YIELD_CURVE, CREDIT_CURVE, premium, CdsPriceType.CLEAN);
final double price1 = sPricer.pv(cds1, YIELD_CURVE, CREDIT_CURVE, premium, CdsPriceType.CLEAN);
assertEquals(price0, prices[0], tol);
assertEquals(price1, prices[1], tol);
final double[] pricesClean = mPricer.pv(cdsM, YIELD_CURVE, CREDIT_CURVE, premium);
assertEquals(pricesClean[0], prices[0], tol);
assertEquals(pricesClean[1], prices[1], tol);
/*
* Error tested
*/
try {
mPricer.pv(cdsM, YIELD_CURVE, CREDIT_CURVE, new double[] {premium }, CdsPriceType.CLEAN);
throw new RuntimeException();
} catch (Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
}
/**
*
*/
public void flatFactorTest() {
/*
* This is not needed if we follow exactly the same procedure.
*/
final double tol = 1.e-13;
final AccrualOnDefaultFormulae form1 = AccrualOnDefaultFormulae.ORIGINAL_ISDA;
final AccrualOnDefaultFormulae form2 = AccrualOnDefaultFormulae.MARKIT_FIX;
final MultiAnalyticCdsPricer mPricerOrig = new MultiAnalyticCdsPricer(form1);
final MultiAnalyticCdsPricer mPricerFix = new MultiAnalyticCdsPricer(form2);
final AnalyticCdsPricer sPricerOrig = new AnalyticCdsPricer(form1);
final AnalyticCdsPricer sPricerFix = new AnalyticCdsPricer(form2);
final LocalDate tradeDate = LocalDate.of(2013, Month.JANUARY, 31);
final LocalDate effectiveDate = FOLLOWING.adjust(getPrevIMMDate(tradeDate), DEFAULT_CALENDAR);
final LocalDate stepinDate = tradeDate.plusDays(1);
final LocalDate valueDate = DEFAULT_CALENDAR.shift(tradeDate, 3);
final LocalDate nextIMM = getNextIMMDate(tradeDate);
final int matIndex0 = 4;
final int matIndex1 = 6;
LocalDate temp = nextIMM;
for (int i = 0; i < matIndex0; i++) {
temp = temp.plus(PAYMENT_INTERVAL);
}
final LocalDate maturity0 = temp;
temp = nextIMM;
for (int i = 0; i < matIndex1; i++) {
temp = temp.plus(PAYMENT_INTERVAL);
}
final LocalDate maturity1 = temp;
final Tenor paymentInt = Tenor.of(PAYMENT_INTERVAL);
final MultiCdsAnalytic cdsM = new MultiCdsAnalytic(tradeDate, stepinDate, valueDate, effectiveDate, nextIMM, new int[] {matIndex0, matIndex1 }, PAY_ACC_ON_DEFAULT, paymentInt, STUB,
PROCTECTION_START, RECOVERY_RATE, FOLLOWING, DEFAULT_CALENDAR, ACT360, ACT365F);
final CdsAnalytic cds0 = new CdsAnalytic(tradeDate, stepinDate, valueDate, effectiveDate, maturity0, PAY_ACC_ON_DEFAULT, PAYMENT_INTERVAL, STUB,
PROCTECTION_START, RECOVERY_RATE, FOLLOWING, DEFAULT_CALENDAR, ACT360, ACT365F);
final CdsAnalytic cds1 = new CdsAnalytic(tradeDate, stepinDate, valueDate, effectiveDate, maturity1, PAY_ACC_ON_DEFAULT, PAYMENT_INTERVAL, STUB,
PROCTECTION_START, RECOVERY_RATE, FOLLOWING, DEFAULT_CALENDAR, ACT360, ACT365F);
final double[] yieldCurveNodes = new double[] {1 / 365., 1 / 52., 1 / 12., 1 / 4., 1 / 2., 1., 2., 3., 4., 5., 7., 10, 15, 20, 30 };
final double[] zeroRates = new double[] {0.01, 0.011, 0.013, 0.015, 0.02, 0.072, 0.036, 0.024, 0.018, 0.06, 0.06, 0.057, 0.055, 0.05, 0.05 };
final IsdaCompliantYieldCurve yCurve = new IsdaCompliantYieldCurve(yieldCurveNodes, zeroRates);
final double[] creditCurveNodes = new double[] {1 / 2., 1, 2, 3, 5, 7, 10 };
final double[] zeroHazardRates = new double[] {0.0015, 0.0048, 0.0024, 0.0016, 0.00096, 0.0023, 0.002 };
final IsdaCompliantCreditCurve cCurve = new IsdaCompliantCreditCurve(creditCurveNodes, zeroHazardRates);
final double[] spreads = mPricerOrig.parSpread(cdsM, yCurve, cCurve);
final double spread0 = sPricerOrig.parSpread(cds0, yCurve, cCurve);
final double spread1 = sPricerOrig.parSpread(cds1, yCurve, cCurve);
assertEquals(spread0, spreads[0], tol);
assertEquals(spread1, spreads[1], tol);
final double[] spreadsFix = mPricerFix.parSpread(cdsM, yCurve, cCurve);
final double spread0Fix = sPricerFix.parSpread(cds0, yCurve, cCurve);
final double spread1Fix = sPricerFix.parSpread(cds1, yCurve, cCurve);
assertEquals(spread0Fix, spreadsFix[0], tol);
assertEquals(spread1Fix, spreadsFix[1], tol);
}
}