PortfolioSwapAdjustment { public IntrinsicIndexDataBundle adjustCurves(final double indexPUF, final CDSAnalytic indexCDS, final double indexCoupon, final ISDACompliantYieldCurve yieldCurve, final IntrinsicIndexDataBundle intrinsicData) { ArgumentChecker.isTrue(indexPUF <= 1.0, "indexPUF must be given as a fraction. Value of {} is too high.", indexPUF); ArgumentChecker.notNull(indexCDS, "indexCDS"); ArgumentChecker.isTrue(indexCoupon >= 0, "indexCoupon cannot be negative"); ArgumentChecker.isTrue(indexCoupon < 10, "indexCoupon should be a fraction. The value of {} would be a coupon of {}", indexCoupon, indexCoupon * 1e4); ArgumentChecker.notNull(yieldCurve, "yieldCurve"); ArgumentChecker.notNull(intrinsicData, "intrinsicData"); final Function1D<Double, Double> func = getHazardRateAdjFunction(indexPUF, indexCDS, indexCoupon, yieldCurve, intrinsicData); final double x = ROOTFINDER.getRoot(func, 1.0); final ISDACompliantCreditCurve[] adjCC = adjustCurves(intrinsicData.getCreditCurves(), x); return intrinsicData.withCreditCurves(adjCC); } PortfolioSwapAdjustment(); IntrinsicIndexDataBundle adjustCurves(final double indexPUF, final CDSAnalytic indexCDS, final double indexCoupon, final ISDACompliantYieldCurve yieldCurve,
      final IntrinsicIndexDataBundle intrinsicData); IntrinsicIndexDataBundle adjustCurves(final double[] indexPUF, final CDSAnalytic[] indexCDS, final double indexCoupon, final ISDACompliantYieldCurve yieldCurve,
      final IntrinsicIndexDataBundle intrinsicData);  }
@Test public void singleTermAdjustmentTest() { final CDSAnalytic[] cdx = FACTORY.makeCDX(TRADE_DATE, INDEX_PILLARS); final int n = cdx.length; for (int i = 0; i < n; i++) { final double puf = 1 - PRICES[i]; final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(puf, cdx[i], INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA); final double puf2 = INDEX_CAL.indexPUF(cdx[i], INDEX_COUPON, YIELD_CURVE, adjCurves); assertEquals(puf, puf2, 1e-14); } }
@Test public void singleTermAdjustmentWithDefaultsTest() { final CDSAnalytic[] cdx = FACTORY.makeCDX(TRADE_DATE, INDEX_PILLARS); final int n = cdx.length; final IntrinsicIndexDataBundle data = INTRINSIC_DATA.withDefault(7); for (int i = 0; i < n; i++) { final double puf = 1 - PRICES[i]; final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(puf, cdx[i], INDEX_COUPON, YIELD_CURVE, data); final double puf2 = INDEX_CAL.indexPUF(cdx[i], INDEX_COUPON, YIELD_CURVE, adjCurves); assertEquals(puf, puf2, 1e-14); } final double largePuf = 1.2; try { PSA.adjustCurves(largePuf, cdx[1], INDEX_COUPON, YIELD_CURVE, data); throw new RuntimeException(); } catch (final Exception e) { assertEquals("indexPUF must be given as a fraction. Value of " + largePuf + " is too high.", e.getMessage()); } final double negativeCoupon = -100. * 1.e-4; try { PSA.adjustCurves(0.6, cdx[1], negativeCoupon, YIELD_CURVE, data); throw new RuntimeException(); } catch (final Exception e) { assertEquals("indexCoupon cannot be negative", e.getMessage()); } final double largeCoupon = 250.; try { PSA.adjustCurves(0.6, cdx[1], largeCoupon, YIELD_CURVE, data); throw new RuntimeException(); } catch (final Exception e) { assertEquals("indexCoupon should be a fraction. The value of " + largeCoupon + " would be a coupon of " + largeCoupon * 1.e4, e.getMessage()); } final int[] defaulted = new int[] {1, 33, 45, 89 }; BitSet bitset = new BitSet(INTRINSIC_DATA.getIndexSize()); final ISDACompliantCreditCurve[] ccs = INTRINSIC_DATA.getCreditCurves().clone(); final double[] rrs = new double[INTRINSIC_DATA.getIndexSize()]; for (int i = 0; i < defaulted.length; ++i) { bitset.set(defaulted[i]); ccs[defaulted[i]] = null; } for (int i = 0; i < INTRINSIC_DATA.getIndexSize(); ++i) { rrs[i] = 1. - INTRINSIC_DATA.getLGD(i); } final IntrinsicIndexDataBundle dataWithDefault = new IntrinsicIndexDataBundle(ccs, rrs, bitset); for (int i = 0; i < n; i++) { final double puf = 1 - PRICES[i]; final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(puf, cdx[i], INDEX_COUPON, YIELD_CURVE, dataWithDefault); final double puf2 = INDEX_CAL.indexPUF(cdx[i], INDEX_COUPON, YIELD_CURVE, adjCurves); assertEquals(puf, puf2, 1e-14); } }
@Test public void multiTermAdjustmentTest() { final CDSAnalytic[] cdx = FACTORY.makeCDX(TRADE_DATE, INDEX_PILLARS); final int n = cdx.length; final double[] puf = new double[n]; for (int i = 0; i < n; i++) { puf[i] = 1 - PRICES[i]; } final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(puf, cdx, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA); for (int i = 0; i < n; i++) { final double puf2 = INDEX_CAL.indexPUF(cdx[i], INDEX_COUPON, YIELD_CURVE, adjCurves); assertEquals(puf[i], puf2, 1e-14); } for (int i = 0; i < n; ++i) { final IntrinsicIndexDataBundle sglCv = PSA.adjustCurves(puf[i], cdx[i], INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA); final IntrinsicIndexDataBundle mltCv = PSA.adjustCurves(new double[] {puf[i] }, new CDSAnalytic[] {cdx[i] }, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA); sglCv.equals(mltCv); } final double[] shortPufs = Arrays.copyOf(puf, n - 2); try { PSA.adjustCurves(shortPufs, cdx, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA); throw new RuntimeException(); } catch (final Exception e) { assertEquals("number of indexCDS (" + cdx.length + ") does not match number of indexPUF (" + shortPufs.length + ")", e.getMessage()); } final double negativeCoupon = -100. * 1.e-4; try { PSA.adjustCurves(puf, cdx, negativeCoupon, YIELD_CURVE, INTRINSIC_DATA); throw new RuntimeException(); } catch (final Exception e) { assertEquals("indexCoupon cannot be negative", e.getMessage()); } final double largeCoupon = 250.; try { PSA.adjustCurves(puf, cdx, largeCoupon, YIELD_CURVE, INTRINSIC_DATA); throw new RuntimeException(); } catch (final Exception e) { assertEquals("indexCoupon should be a fraction. The value of " + largeCoupon + " would be a coupon of " + largeCoupon * 1.e4, e.getMessage()); } final double[] largePufs = Arrays.copyOf(puf, n); final int position = 2; largePufs[position] += 10.; try { PSA.adjustCurves(largePufs, cdx, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA); throw new RuntimeException(); } catch (final Exception e) { assertEquals("indexPUF must be given as a fraction. Value of " + largePufs[position] + " is too high.", e.getMessage()); } final CDSAnalytic[] wrongCdx = Arrays.copyOf(cdx, n); wrongCdx[1] = cdx[2]; wrongCdx[2] = cdx[1]; try { PSA.adjustCurves(puf, wrongCdx, INDEX_COUPON, YIELD_CURVE, INTRINSIC_DATA); throw new RuntimeException(); } catch (final Exception e) { assertEquals("indexCDS must be in assending order of maturity", e.getMessage()); } }
@Test public void multiTermAdjustmentWithDefaultTest() { final CDSAnalytic[] cdx = FACTORY.makeCDX(TRADE_DATE, INDEX_PILLARS); final int n = cdx.length; final IntrinsicIndexDataBundle data = INTRINSIC_DATA.withDefault(0, 4, 78); final double[] puf = new double[n]; for (int i = 0; i < n; i++) { puf[i] = 1 - PRICES[i]; } final IntrinsicIndexDataBundle adjCurves = PSA.adjustCurves(puf, cdx, INDEX_COUPON, YIELD_CURVE, data); for (int i = 0; i < n; i++) { final double puf2 = INDEX_CAL.indexPUF(cdx[i], INDEX_COUPON, YIELD_CURVE, adjCurves); assertEquals(puf[i], puf2, 1e-14); } final int[] defaulted = new int[] {1, 33, 45, 89 }; BitSet bitset = new BitSet(INTRINSIC_DATA.getIndexSize()); final ISDACompliantCreditCurve[] ccs = INTRINSIC_DATA.getCreditCurves().clone(); final double[] rrs = new double[INTRINSIC_DATA.getIndexSize()]; for (int i = 0; i < defaulted.length; ++i) { bitset.set(defaulted[i]); ccs[defaulted[i]] = null; } for (int i = 0; i < INTRINSIC_DATA.getIndexSize(); ++i) { rrs[i] = 1. - INTRINSIC_DATA.getLGD(i); } final IntrinsicIndexDataBundle dataWithDefault = new IntrinsicIndexDataBundle(ccs, rrs, bitset); final IntrinsicIndexDataBundle dataWithDefaultAdj = PSA.adjustCurves(puf, cdx, INDEX_COUPON, YIELD_CURVE, dataWithDefault); for (int i = 0; i < n; i++) { final double puf2 = INDEX_CAL.indexPUF(cdx[i], INDEX_COUPON, YIELD_CURVE, dataWithDefaultAdj); assertEquals(puf[i], puf2, 1e-14); } }
@Test public void knotsCoincideTest() { final CDSAnalytic[] cdx = FACTORY.makeCDX(TRADE_DATE, INDEX_PILLARS); final int nPillars = cdx.length; final int indexSize = INTRINSIC_DATA.getIndexSize(); final double[] indexKnots = new double[nPillars]; final double[] rt = new double[nPillars]; final double[] puf = new double[nPillars]; for (int i = 0; i < nPillars; ++i) { indexKnots[i] = cdx[i].getProtectionEnd(); rt[i] = indexKnots[i] * 0.05; puf[i] = 1 - PRICES[i]; } final int position = 32; final ISDACompliantCreditCurve[] ccs = INTRINSIC_DATA.getCreditCurves().clone(); ccs[position] = ISDACompliantCreditCurve.makeFromRT(indexKnots, rt); final double[] rrs = new double[indexSize]; for (int i = 0; i < indexSize; ++i) { rrs[i] = 1. - INTRINSIC_DATA.getLGD(i); } final IntrinsicIndexDataBundle data = new IntrinsicIndexDataBundle(ccs, rrs); final IntrinsicIndexDataBundle dataAdj = PSA.adjustCurves(puf, cdx, INDEX_COUPON, YIELD_CURVE, data); for (int i = 0; i < nPillars; ++i) { final double puf2 = INDEX_CAL.indexPUF(cdx[i], INDEX_COUPON, YIELD_CURVE, dataAdj); assertEquals(puf[i], puf2, 1e-14); } }