/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.interestrate.curve; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; import org.testng.annotations.Test; import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve; import com.opengamma.analytics.math.interpolation.Interpolator1D; import com.opengamma.analytics.math.interpolation.LinearInterpolator1D; import com.opengamma.util.test.TestGroup; /** * Tests related to the construction of yield and discounting curves. */ @Test(groups = TestGroup.UNIT) public class YieldAndDiscountCurveTest { private static final double[] TIME = new double[] {1, 2, 3}; private static final double[] RATES = new double[] {0.03, 0.04, 0.05}; private static final double[] DF_VALUES = new double[] {Math.exp(-0.03), Math.exp(-0.08), Math.exp(-0.15)}; private static final Interpolator1D INTERPOLATOR = new LinearInterpolator1D(); private static final InterpolatedDoublesCurve R = InterpolatedDoublesCurve.from(TIME, RATES, INTERPOLATOR); private static final InterpolatedDoublesCurve DF = InterpolatedDoublesCurve.from(TIME, DF_VALUES, INTERPOLATOR); private static final YieldCurve YIELD = YieldCurve.from(R); private static final DiscountCurve DISCOUNT = DiscountCurve.from(DF); private static final int COMPOUNDING = 2; private static final YieldPeriodicCurve YIELD_PERIODIC = YieldPeriodicCurve.from(COMPOUNDING, R); private static final double TOLERANCE_RATE = 1.0E-10; private static final double TOLERANCE_PV = 1.0E-10; private static final double TOLERANCE_SENSI = 1.0E-6; @Test(expectedExceptions = IllegalArgumentException.class) public void nullName() { new YieldCurve(null, R); } @Test(expectedExceptions = IllegalArgumentException.class) public void nullCurve() { new YieldCurve("Name", null); } @Test(expectedExceptions = IllegalArgumentException.class) public void nullNamePer() { new YieldPeriodicCurve(null, COMPOUNDING, R); } @Test(expectedExceptions = IllegalArgumentException.class) public void nullCurvePer() { new YieldPeriodicCurve("Name", COMPOUNDING, null); } @Test(expectedExceptions = IllegalArgumentException.class) public void nullNameDsc() { new DiscountCurve(null, R); } @Test(expectedExceptions = IllegalArgumentException.class) public void nullCurveDsc() { new DiscountCurve("Name", null); } @Test public void testHashCodeAndEquals() { YieldAndDiscountCurve other = YieldCurve.from(R); assertEquals(other, YIELD); assertEquals(other.hashCode(), YIELD.hashCode()); other = YieldCurve.from(DF); assertFalse(other.equals(YIELD)); } @Test public void testGetters() { assertEquals(YIELD.getCurve(), R); assertEquals(YIELD.getInterestRate(1.4), R.getYValue(1.4), 1e-15); assertEquals(YIELD.getDiscountFactor(1.5), Math.exp(-1.5 * R.getYValue(1.5)), 1e-15); assertEquals(DISCOUNT.getInterestRate(1.4), -Math.log(DF.getYValue(1.4)) / 1.4, 1e-15); assertEquals(DISCOUNT.getDiscountFactor(1.5), DF.getYValue(1.5), 1e-15); } @Test public void gettersYieldPeriodic() { assertEquals("YieldPeriodicCurve: getter", YIELD_PERIODIC.getCurve(), R); double point = 1.5; assertEquals("YieldPeriodicCurve: getter", YIELD_PERIODIC.getPeriodicInterestRate(point, COMPOUNDING), R.getYValue(point), TOLERANCE_RATE); double rate = R.getYValue(point); double dfannual = Math.pow(1.0 + rate / COMPOUNDING, -COMPOUNDING); double df = Math.pow(1.0 + rate / COMPOUNDING, -point * COMPOUNDING); assertEquals("YieldPeriodicCurve: getter", YIELD_PERIODIC.getDiscountFactor(point), df, TOLERANCE_PV); assertEquals("YieldPeriodicCurve: getter", YIELD_PERIODIC.getInterestRate(point), -Math.log(dfannual), TOLERANCE_PV); } @Test public void interestRateParameterSensitivityYieldPeriodic() { int nbPt = 20; double shift = 1.0E-6; double[] time = new double[nbPt + 1]; double[] rt = new double[nbPt + 1]; double[][] ps = new double[nbPt + 1][]; for (int looppt = 0; looppt <= nbPt; looppt++) { time[looppt] = TIME[0] + looppt * (TIME[TIME.length - 1] - TIME[0]) / nbPt; rt[looppt] = YIELD_PERIODIC.getInterestRate(time[looppt]); ps[looppt] = YIELD_PERIODIC.getInterestRateParameterSensitivity(time[looppt]); } for (int loopr = 0; loopr < RATES.length; loopr++) { double[] rateShift = RATES.clone(); rateShift[loopr] += shift; YieldPeriodicCurve yieldPeriodicShifted = YieldPeriodicCurve.from(COMPOUNDING, InterpolatedDoublesCurve.from(TIME, rateShift, new LinearInterpolator1D())); for (int looppt = 0; looppt <= nbPt; looppt++) { double r = yieldPeriodicShifted.getInterestRate(time[looppt]); assertEquals("ParameterSensitivity - YieldPeriodic", (r - rt[looppt]) / shift, ps[looppt][loopr], TOLERANCE_SENSI); } } } @Test public void interestRateParameterSensitivityDiscounting() { int nbPt = 20; double shift = 1.0E-6; double[] time = new double[nbPt + 1]; double[] rt = new double[nbPt + 1]; double[][] ps = new double[nbPt + 1][]; for (int looppt = 0; looppt <= nbPt; looppt++) { time[looppt] = TIME[0] + looppt * (TIME[TIME.length - 1] - TIME[0]) / nbPt; rt[looppt] = DISCOUNT.getInterestRate(time[looppt]); ps[looppt] = DISCOUNT.getInterestRateParameterSensitivity(time[looppt]); } for (int loopr = 0; loopr < RATES.length; loopr++) { double[] dfShift = DF_VALUES.clone(); dfShift[loopr] += shift; DiscountCurve discountShift = DiscountCurve.from(InterpolatedDoublesCurve.from(TIME, dfShift, new LinearInterpolator1D())); for (int looppt = 0; looppt <= nbPt; looppt++) { double r = discountShift.getInterestRate(time[looppt]); assertEquals("ParameterSensitivity - YieldPeriodic", (r - rt[looppt]) / shift, ps[looppt][loopr], TOLERANCE_SENSI); } } } @Test public void testShift() { double shift = 0.03; int nbPt = 20; YieldAndDiscountCurve shifted1 = YIELD.withParallelShift(shift); for (int looppt = 0; looppt <= nbPt; looppt++) { double time = TIME[0] + looppt * (TIME[TIME.length - 1] - TIME[0]) / nbPt; assertEquals("ParallelShift", YIELD.getInterestRate(time) + shift, shifted1.getInterestRate(time), TOLERANCE_RATE); } double timeShift = 1.5; YieldAndDiscountCurve shifted2 = YIELD.withSingleShift(timeShift, shift); for (int looppt = 0; looppt <= nbPt; looppt++) { double time = TIME[0] + looppt * (TIME[TIME.length - 1] - TIME[0]) / nbPt; double localShift = Math.abs(time - timeShift) < 1.0E-3 ? shift : 0.0; assertEquals("SingleShift", YIELD.getInterestRate(time) + localShift, shifted2.getInterestRate(time), TOLERANCE_RATE); } } @Test /** * Tests the build of a discount curve from yields (cc). */ public void discountCurveFromYieldsInterpolated() { DiscountCurve dfFromYields = DiscountCurve.fromYieldsInterpolated(TIME, RATES, INTERPOLATOR, "DF"); InterpolatedDoublesCurve curveInt = (InterpolatedDoublesCurve) dfFromYields.getCurve(); Double[] df = curveInt.getYData(); for (int loopyield = 0; loopyield < TIME.length; loopyield++) { assertEquals("DiscountCurve.fromYieldsInterpolated", RATES[loopyield], -Math.log(df[loopyield]) / TIME[loopyield], TOLERANCE_RATE); } assertEquals("DiscountCurve.fromYieldsInterpolated", INTERPOLATOR, curveInt.getInterpolator()); assertArrayEquals("DiscountCurve.fromYieldsInterpolated", TIME, curveInt.getXDataAsPrimitive(), TOLERANCE_RATE); } @Test /** * Tests the build of a discount curve from yields (cc). */ public void yieldCurveDiscountFactorInterpolated() { YieldCurve yFromDF = YieldCurve.fromDiscountFactorInterpolated(TIME, DF_VALUES, INTERPOLATOR, "Yield"); InterpolatedDoublesCurve curveInt = (InterpolatedDoublesCurve) yFromDF.getCurve(); Double[] y = curveInt.getYData(); for (int loopyield = 0; loopyield < TIME.length; loopyield++) { assertEquals("YieldCurve.fromDiscountFactorInterpolated", DF_VALUES[loopyield], Math.exp(-y[loopyield] * TIME[loopyield]), TOLERANCE_RATE); } assertEquals("DiscountCurve.fromYieldsInterpolated", INTERPOLATOR, curveInt.getInterpolator()); assertArrayEquals("DiscountCurve.fromYieldsInterpolated", TIME, curveInt.getXDataAsPrimitive(), TOLERANCE_RATE); } @Test /** * Tests the build of a discount curve from yields (cc). */ public void yieldPeriodicFromYieldsInterpolated() { YieldPeriodicCurve perFromYields = YieldPeriodicCurve.fromYieldsInterpolated(TIME, RATES, COMPOUNDING, INTERPOLATOR, "DF"); InterpolatedDoublesCurve curveInt = (InterpolatedDoublesCurve) perFromYields.getCurve(); Double[] yP = curveInt.getYData(); for (int loopyield = 0; loopyield < TIME.length; loopyield++) { assertEquals("YieldPeriodicCurve.fromYieldsInterpolated", RATES[loopyield], COMPOUNDING * Math.log(1.0 + yP[loopyield] / COMPOUNDING), TOLERANCE_RATE); } assertEquals("YieldPeriodicCurve.fromYieldsInterpolated", INTERPOLATOR, curveInt.getInterpolator()); assertArrayEquals("YieldPeriodicCurve.fromYieldsInterpolated", TIME, curveInt.getXDataAsPrimitive(), TOLERANCE_RATE); } }