/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.credit.index;
import static com.opengamma.analytics.financial.credit.options.CDSIndexPrvider.CDX_NA_HY_20140213_RECOVERY_RATES;
import static com.opengamma.analytics.financial.credit.options.CDSIndexPrvider.getCDX_NA_HY_20140213_CreditCurves;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import java.util.Arrays;
import java.util.BitSet;
import org.testng.annotations.Test;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDABaseTest;
import com.opengamma.analytics.financial.credit.isdastandardmodel.ISDACompliantCreditCurve;
import com.opengamma.util.test.TestGroup;
/**
*
*/
@Test(groups = TestGroup.UNIT)
public class IntrinsicIndexDataBundleTest extends ISDABaseTest {
private static final ISDACompliantCreditCurve[] CREDIT_CURVES = getCDX_NA_HY_20140213_CreditCurves();
private static final double[] RECOVERY_RATES = CDX_NA_HY_20140213_RECOVERY_RATES;
/**
*
*/
@SuppressWarnings("unused")
@Test
public void defaultedNamesTest() {
final int[] defaultedIndex = new int[] {5, 14, 22, 45 };
final int indexSize = CREDIT_CURVES.length;
BitSet defaulted = new BitSet(indexSize);
IntrinsicIndexDataBundle intrinsicData = new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES);
final IntrinsicIndexDataBundle intrinsicDataNoDefault = new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, defaulted);
assertTrue(checkEqual(intrinsicData, intrinsicDataNoDefault, 1.e-15));
final double[] rrCp = Arrays.copyOf(RECOVERY_RATES, indexSize);
rrCp[33] = -0.4;
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, rrCp);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("recovery rate must be between 0 and 1.Value of " + rrCp[33] + " given at index " + 33, e.getMessage());
}
rrCp[33] = 1.4;
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, rrCp);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("recovery rate must be between 0 and 1.Value of " + rrCp[33] + " given at index " + 33, e.getMessage());
}
IntrinsicIndexDataBundle intrinsicDataRec = new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES);
intrinsicData = intrinsicData.withDefault(defaultedIndex);
final ISDACompliantCreditCurve[] creditCurveDefaulted = Arrays.copyOf(CREDIT_CURVES, indexSize);
for (int i = 0; i < defaultedIndex.length; ++i) {
defaulted.set(defaultedIndex[i]);
creditCurveDefaulted[defaultedIndex[i]] = null;
intrinsicDataRec = intrinsicDataRec.withDefault(defaultedIndex[i]);
}
final IntrinsicIndexDataBundle intrinsicDataDefaulted = new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, defaulted);
assertTrue(checkEqual(intrinsicData, intrinsicDataDefaulted, 1.e-13));
assertEquals(intrinsicData.getCreditCurves(), intrinsicDataDefaulted.getCreditCurves());
assertTrue(checkEqual(intrinsicData, intrinsicDataRec, 1.e-13));
assertEquals(intrinsicData.getCreditCurves(), intrinsicDataRec.getCreditCurves());
final IntrinsicIndexDataBundle intrinsicDataWithCurves = intrinsicDataDefaulted.withCreditCurves(creditCurveDefaulted);
assertTrue(checkEqual(intrinsicData, intrinsicDataWithCurves, 1.e-13));
/*
* throw exception
*/
BitSet longSet = new BitSet(indexSize + 10);
longSet.set(indexSize + 3);
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, longSet);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Length of defaulted (" + (indexSize + 3 + 1) + ") is greater than index size (" + indexSize + ")", e.getMessage());
}
final double[] shortRR = Arrays.copyOf(RECOVERY_RATES, indexSize - 1);
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, shortRR);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Length of recoveryRates (" + (indexSize - 1) + ") does not match index size (" + indexSize + ")", e.getMessage());
}
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, shortRR, defaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Length of recoveryRates (" + (indexSize - 1) + ") does not match index size (" + indexSize + ")", e.getMessage());
}
creditCurveDefaulted[12] = null;
try {
intrinsicData.withCreditCurves(creditCurveDefaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("null curve at index 12, but this is not listed as defaulted", e.getMessage());
}
try {
new IntrinsicIndexDataBundle(creditCurveDefaulted, RECOVERY_RATES, defaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Null credit curve, but not set as defaulted in alive list. Index is " + 12, e.getMessage());
}
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, rrCp, defaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("recovery rate must be between 0 and 1.Value of " + rrCp[33] + " given at index " + 33, e.getMessage());
}
rrCp[33] = -2.4;
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, rrCp, defaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("recovery rate must be between 0 and 1.Value of " + rrCp[33] + " given at index " + 33, e.getMessage());
}
try {
intrinsicData.withDefault(14);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Index " + 14 + " is already defaulted", e.getMessage());
}
try {
intrinsicData.withDefault(new int[] {11, 15, 22 });
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Index " + 22 + " is already defaulted", e.getMessage());
}
final ISDACompliantCreditCurve[] shortCC = Arrays.copyOf(CREDIT_CURVES, indexSize - 2);
try {
intrinsicDataNoDefault.withCreditCurves(shortCC);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("wrong number of curves. Require " + indexSize + ", but " + (indexSize - 2) + " given", e.getMessage());
}
try {
intrinsicDataNoDefault.withDefault(indexSize);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("index (" + indexSize + ") should be smaller than index size (" + indexSize + ")", e.getMessage());
}
try {
intrinsicDataNoDefault.withDefault(1, 4, indexSize + 2);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("index (" + (indexSize + 2) + ") should be smaller than index size (" + indexSize + ")", e.getMessage());
}
}
/**
*
*/
@SuppressWarnings("unused")
@Test
public void differentWeightTest() {
final int indexSize = CREDIT_CURVES.length;
final double[] weights = new double[indexSize];
Arrays.fill(weights, 1.0 / indexSize);
final double[] diff = new double[] {weights[0] * 0.1, weights[0] * 0.2, weights[0] * 0.3, weights[0] * 0.4, weights[0] * 0.5 };
weights[2] += diff[0];
weights[5] -= diff[0];
weights[13] += diff[1];
weights[22] -= diff[1];
weights[42] += diff[2];
weights[55] -= diff[2];
weights[58] += diff[3];
weights[78] -= diff[3];
weights[79] += diff[4];
weights[82] -= diff[4];
final IntrinsicIndexDataBundle bundle = new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, weights);
for (int i = 0; i < indexSize; ++i) {
assertEquals(weights[i], bundle.getWeight(i));
}
final int[] defaultedIndex = new int[] {15, 34, 22, 65 };
final IntrinsicIndexDataBundle bundleDefaulted = bundle.withDefault(defaultedIndex);
IntrinsicIndexDataBundle bundleToDefaulted = new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, weights);
BitSet defaulted = new BitSet(indexSize);
final IntrinsicIndexDataBundle bundleNoDefault = new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, weights, defaulted);
assertTrue(checkEqual(bundle, bundleNoDefault, 1.e-13));
final ISDACompliantCreditCurve[] ccCopy = Arrays.copyOf(CREDIT_CURVES, indexSize);
ccCopy[defaultedIndex[1]] = null;//null is allowed if defaulted
for (int i = 0; i < defaultedIndex.length; ++i) {
defaulted.set(defaultedIndex[i]);
bundleToDefaulted = bundleToDefaulted.withDefault(defaultedIndex[i]);
}
final IntrinsicIndexDataBundle bundleWithBitSet = new IntrinsicIndexDataBundle(ccCopy, RECOVERY_RATES, weights, defaulted);
assertTrue(checkEqual(bundleWithBitSet, bundleDefaulted, 1.e-13));
assertTrue(checkEqual(bundleWithBitSet, bundleToDefaulted, 1.e-13));
/*
* throw exception
*/
BitSet longSet = new BitSet(indexSize + 10);
longSet.set(indexSize + 4);
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, weights, longSet);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Length of defaulted (" + (indexSize + 4 + 1) + ") is greater than index size (" + indexSize + ")", e.getMessage());
}
final double[] shortRR = Arrays.copyOf(RECOVERY_RATES, indexSize - 1);
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, shortRR, weights, defaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Length of recoveryRates (" + (indexSize - 1) + ") does not match index size (" + indexSize + ")", e.getMessage());
}
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, shortRR, weights);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Length of recoveryRates (" + (indexSize - 1) + ") does not match index size (" + indexSize + ")", e.getMessage());
}
final double[] longWeights = new double[indexSize + 1];
Arrays.fill(longWeights, 1. / (indexSize + 1.));
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, longWeights);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Length of weights (" + (indexSize + 1) + ") does not match index size (" + indexSize + ")", e.getMessage());
}
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, longWeights, defaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Length of weights (" + (indexSize + 1) + ") does not match index size (" + indexSize + ")", e.getMessage());
}
weights[14] *= -1.;
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, weights);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("weights must be positive. Value of " + weights[14] + " given at index " + 14, e.getMessage());
}
weights[14] *= -1.;
weights[14] *= 10.;
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, weights);
throw new RuntimeException();
} catch (final Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
weights[14] *= 0.1;
final double[] rrCp = Arrays.copyOf(RECOVERY_RATES, indexSize);
rrCp[24] *= -1.;
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, rrCp, weights);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("recovery rate must be between 0 and 1.Value of " + rrCp[24] + " given at index " + 24, e.getMessage());
}
rrCp[24] = 3.;
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, rrCp, weights);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("recovery rate must be between 0 and 1.Value of " + rrCp[24] + " given at index " + 24, e.getMessage());
}
final ISDACompliantCreditCurve[] cc = Arrays.copyOf(CREDIT_CURVES, indexSize);
cc[23] = null;
try {
new IntrinsicIndexDataBundle(cc, RECOVERY_RATES, weights, defaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("Null credit curve, but not set as defaulted in alive list. Index is " + 23, e.getMessage());
}
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, rrCp, weights, defaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("recovery rate must be between 0 and 1.Value of " + rrCp[24] + " given at index " + 24, e.getMessage());
}
rrCp[24] = -3.;
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, rrCp, weights, defaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("recovery rate must be between 0 and 1.Value of " + rrCp[24] + " given at index " + 24, e.getMessage());
}
weights[56] *= -1.;
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, weights, defaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertEquals("weights must be positive. Value of " + weights[56] + " given at index " + 56, e.getMessage());
}
weights[56] = 5.1;
try {
new IntrinsicIndexDataBundle(CREDIT_CURVES, RECOVERY_RATES, weights, defaulted);
throw new RuntimeException();
} catch (final Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
}
@Test
private boolean checkEqual(final IntrinsicIndexDataBundle bundle1, final IntrinsicIndexDataBundle bundle2, final double tol) {
if (bundle1.getIndexSize() != bundle2.getIndexSize()) {
return false;
}
if (bundle1.getNumOfDefaults() != bundle2.getNumOfDefaults()) {
return false;
}
if (Math.abs(bundle1.getIndexFactor() - bundle2.getIndexFactor()) > tol) {
return false;
}
final int size = bundle1.getIndexSize();
for (int i = 0; i < size; ++i) {
if (Math.abs(bundle1.getWeight(i) - bundle2.getWeight(i)) > tol) {
return false;
}
if (Math.abs(bundle1.getLGD(i) - bundle2.getLGD(i)) > tol) {
return false;
}
if (bundle1.isDefaulted(i) != bundle2.isDefaulted(i)) {
return false;
}
/*
* Null is allowed if defaulted
*/
if (!bundle1.isDefaulted(i)) {
if (!(bundle1.getCreditCurve(i).equals(bundle2.getCreditCurve(i)))) {
return false;
}
}
}
return true;
}
}