/** * Copyright (C) 2013 - 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 org.testng.Assert; import org.testng.annotations.Test; import org.threeten.bp.Period; import org.threeten.bp.ZonedDateTime; import com.opengamma.analytics.financial.instrument.annuity.AnnuityCouponFixedDefinition; import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinition; import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedIbor; import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedIborMaster; import com.opengamma.analytics.financial.instrument.index.IborIndex; import com.opengamma.analytics.financial.instrument.payment.CouponDefinition; import com.opengamma.analytics.financial.instrument.payment.CouponIborDefinition; import com.opengamma.analytics.financial.instrument.swap.SwapDefinition; import com.opengamma.analytics.financial.interestrate.annuity.derivative.Annuity; import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponIbor; import com.opengamma.analytics.financial.interestrate.payments.derivative.Payment; import com.opengamma.analytics.financial.interestrate.payments.provider.CouponIborDiscountingMethod; import com.opengamma.analytics.financial.interestrate.swap.derivative.Swap; import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueDiscountingCalculator; import com.opengamma.analytics.financial.provider.description.MulticurveProviderDiscountDataSets; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount; import com.opengamma.analytics.financial.schedule.ScheduleCalculator; import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve; import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory; import com.opengamma.analytics.math.interpolation.Interpolator1D; import com.opengamma.analytics.math.interpolation.Interpolator1DFactory; import com.opengamma.financial.convention.calendar.Calendar; import com.opengamma.util.money.Currency; import com.opengamma.util.money.MultipleCurrencyAmount; import com.opengamma.util.test.TestGroup; import com.opengamma.util.time.DateUtils; /** * Test. */ @Test(groups = TestGroup.UNIT) public class DayPeriodPreCalculatedDiscountCurveTest { private static double TOLERANCE = 1e-10; // note the time periods passed in must be a whole number divided by 365.25, otherwise the pre calculated factors // will not line up private static double[] x = new double[] {0 / DateUtils.DAYS_PER_YEAR, 1 / DateUtils.DAYS_PER_YEAR, 2 / DateUtils.DAYS_PER_YEAR, 100 / DateUtils.DAYS_PER_YEAR, 293 / DateUtils.DAYS_PER_YEAR, 309 / DateUtils.DAYS_PER_YEAR, 428 / DateUtils.DAYS_PER_YEAR, 567 / DateUtils.DAYS_PER_YEAR, 5634 / DateUtils.DAYS_PER_YEAR }; private static double[] y = new double[] {1.0, 0.75, 0.5, 0.25, 0.15, 0.12, 0.10, 0.9, 0.85 }; private static InterpolatedDoublesCurve DOUBLES_CURVE = InterpolatedDoublesCurve.from(x, y, Interpolator1DFactory.LINEAR_INSTANCE); private static final DiscountCurve EXISTING_CURVE = DiscountCurve.from(DOUBLES_CURVE); @Test(groups = TestGroup.UNIT) public void testGetDiscountFactor() throws Exception { final DayPeriodPreCalculatedDiscountCurve curve = new DayPeriodPreCalculatedDiscountCurve("test", DOUBLES_CURVE, DateUtils.DAYS_PER_YEAR); curve.preCalculateDiscountFactors(15); for (int i = 0; i < x[x.length - 1]; i++) { final double t = i / DateUtils.DAYS_PER_YEAR; Assert.assertEquals(EXISTING_CURVE.getDiscountFactor(t), curve.getDiscountFactor(t), TOLERANCE); } } // Data for testing the curve on a swap private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2012, 11, 5); private static final MulticurveProviderDiscount MULTICURVES = MulticurveProviderDiscountDataSets.createMulticurveEurUsd(); private static final MulticurveProviderDiscount MULTICURVES_WITH_PRECALCULATED_DISCOUNT = MulticurveProviderDiscountDataSets.createMulticurveEurUsd(); private static final IborIndex[] INDEX_LIST = MulticurveProviderDiscountDataSets.getIndexesIborMulticurveEurUsd(); private static final IborIndex EURIBOR3M = INDEX_LIST[0]; private static final IborIndex EURIBOR6M = INDEX_LIST[1]; private static final Currency EUR = EURIBOR3M.getCurrency(); private static final Calendar CALENDAR = MulticurveProviderDiscountDataSets.getEURCalendar(); private static final ZonedDateTime START_DATE = DateUtils.getUTCDate(2013, 9, 9); private static final ZonedDateTime END_DATE_3 = ScheduleCalculator.getAdjustedDate(START_DATE, EURIBOR3M.getTenor(), EURIBOR3M, CALENDAR); private static final Period TOTAL_TENOR = EURIBOR3M.getTenor().plus(EURIBOR6M.getTenor()); private static final ZonedDateTime END_DATE_6 = ScheduleCalculator.getAdjustedDate(START_DATE, TOTAL_TENOR, EURIBOR3M, CALENDAR); // Definitions private static final double NOTIONAL = 100000.0; // 100m private static final double RATE = 0.0250; // 2.5% private static final CouponIborDefinition CPN_IBOR_3_DEFINITION = CouponIborDefinition.from(START_DATE, END_DATE_3, NOTIONAL, EURIBOR3M, CALENDAR); private static final CouponIborDefinition CPN_IBOR_6_DEFINITION = CouponIborDefinition.from(END_DATE_3, END_DATE_6, NOTIONAL, EURIBOR6M, CALENDAR); private static final AnnuityDefinition<CouponDefinition> ANNUITY_IBOR_DEFINITION = new AnnuityDefinition<CouponDefinition>( new CouponIborDefinition[] {CPN_IBOR_3_DEFINITION, CPN_IBOR_6_DEFINITION }, CALENDAR); private static final GeneratorSwapFixedIbor EUR1YEURIBOR6M = GeneratorSwapFixedIborMaster.getInstance().getGenerator("EUR1YEURIBOR6M", CALENDAR); private static final AnnuityCouponFixedDefinition ANNUITY_FIXED_DEFINITION = AnnuityCouponFixedDefinition.from(START_DATE, TOTAL_TENOR, EUR1YEURIBOR6M, NOTIONAL, RATE, true); private static final SwapDefinition SWAP_DEFINITION = new SwapDefinition(ANNUITY_FIXED_DEFINITION, ANNUITY_IBOR_DEFINITION); // Derivatives private static final CouponIbor CPN_IBOR_3 = (CouponIbor) CPN_IBOR_3_DEFINITION.toDerivative(REFERENCE_DATE); private static final CouponIbor CPN_IBOR_6 = (CouponIbor) CPN_IBOR_6_DEFINITION.toDerivative(REFERENCE_DATE); private static final Annuity<? extends Payment> ANNUITY_IBOR = ANNUITY_IBOR_DEFINITION.toDerivative(REFERENCE_DATE); private static final Annuity<? extends Payment> ANNUITY_FIXED = ANNUITY_FIXED_DEFINITION.toDerivative(REFERENCE_DATE); private static final Swap<? extends Payment, ? extends Payment> SWAP = SWAP_DEFINITION.toDerivative(REFERENCE_DATE); private static final Interpolator1D LINEAR_FLAT = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.LINEAR, Interpolator1DFactory.FLAT_EXTRAPOLATOR, Interpolator1DFactory.FLAT_EXTRAPOLATOR); private static final double[] EUR_DSC_TIME = new double[] {0.0, 182 / 365.25, 365 / 365.25, 731 / 365.25, 1826 / 365.25, 3652 / 365.25 }; private static final double[] EUR_DSC_DISCOUNT_FACTOR = new double[] {1.0, 0.99, .98, .97, 1.0, .99 }; private static final String EUR_DSC_NAME = "EUR Dsc"; /* private static final YieldAndDiscountCurve EUR_DSC = new YieldCurve(EUR_DSC_NAME, new InterpolatedDoublesCurve(EUR_DSC_TIME, EUR_DSC_RATE, LINEAR_FLAT, true, EUR_DSC_NAME));*/ private static final YieldAndDiscountCurve EUR_DSC = DiscountCurve.from(new InterpolatedDoublesCurve(EUR_DSC_TIME, EUR_DSC_DISCOUNT_FACTOR, LINEAR_FLAT, true, EUR_DSC_NAME)); private static final CouponIborDiscountingMethod METHOD_CPN_IBOR = CouponIborDiscountingMethod.getInstance(); private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance(); private static final double TOLERANCE_PV = 1.0E-10; @Test(enabled = false) /** * Tests the present value for a swap with the Ibor leg having different Ibor indexes (EURIBOR3M and EURIBOR6M). * this test passed onbly if the MODEL_DAYCOUNT in TimeCalculator.properties is set at Actul / 365.25 */ public void testWithSwap() { MULTICURVES.replaceCurve(EUR, EUR_DSC); final DayPeriodPreCalculatedDiscountCurve curve = new DayPeriodPreCalculatedDiscountCurve("test", new InterpolatedDoublesCurve(EUR_DSC_TIME, EUR_DSC_DISCOUNT_FACTOR, LINEAR_FLAT, true, EUR_DSC_NAME), 365.25); curve.preCalculateDiscountFactors(50); final MulticurveProviderDiscount MULTICURVES_WITH_PRECALCULATED_DISCOUNT = MULTICURVES.withDiscountFactor(EUR, curve); final MultipleCurrencyAmount pvCalcCpn3 = CPN_IBOR_3.accept(PVDC, MULTICURVES); final MultipleCurrencyAmount pvMethCpn3 = METHOD_CPN_IBOR.presentValue(CPN_IBOR_3, MULTICURVES); final MultipleCurrencyAmount pvCalcCpn6 = CPN_IBOR_6.accept(PVDC, MULTICURVES); final MultipleCurrencyAmount pvMethCpn6 = METHOD_CPN_IBOR.presentValue(CPN_IBOR_6, MULTICURVES); final MultipleCurrencyAmount pvCalcAnnIbor = ANNUITY_IBOR.accept(PVDC, MULTICURVES); final MultipleCurrencyAmount pvCalcAnnFixed = ANNUITY_FIXED.accept(PVDC, MULTICURVES); final MultipleCurrencyAmount pvCalcSwap = SWAP.accept(PVDC, MULTICURVES); final MultipleCurrencyAmount pvCalcCpn3_WITH_PRECALCULATED_DISCOUNT = CPN_IBOR_3.accept(PVDC, MULTICURVES_WITH_PRECALCULATED_DISCOUNT); final MultipleCurrencyAmount pvMethCpn3_WITH_PRECALCULATED_DISCOUNT = METHOD_CPN_IBOR.presentValue(CPN_IBOR_3, MULTICURVES_WITH_PRECALCULATED_DISCOUNT); final MultipleCurrencyAmount pvCalcCpn6_WITH_PRECALCULATED_DISCOUNT = CPN_IBOR_6.accept(PVDC, MULTICURVES_WITH_PRECALCULATED_DISCOUNT); final MultipleCurrencyAmount pvMethCpn6_WITH_PRECALCULATED_DISCOUNT = METHOD_CPN_IBOR.presentValue(CPN_IBOR_6, MULTICURVES_WITH_PRECALCULATED_DISCOUNT); final MultipleCurrencyAmount pvCalcAnnIbor_WITH_PRECALCULATED_DISCOUNT = ANNUITY_IBOR.accept(PVDC, MULTICURVES_WITH_PRECALCULATED_DISCOUNT); final MultipleCurrencyAmount pvCalcAnnFixed_WITH_PRECALCULATED_DISCOUNT = ANNUITY_FIXED.accept(PVDC, MULTICURVES_WITH_PRECALCULATED_DISCOUNT); final MultipleCurrencyAmount pvCalcSwap_WITH_PRECALCULATED_DISCOUNT = SWAP.accept(PVDC, MULTICURVES_WITH_PRECALCULATED_DISCOUNT); assertEquals("PresentValueDiscountingProviderCalculator: multiple Ibor index", pvCalcCpn3_WITH_PRECALCULATED_DISCOUNT.getAmount(EUR), pvCalcCpn3.getAmount(EUR), TOLERANCE_PV); assertEquals("PresentValueDiscountingProviderCalculator: multiple Ibor index", pvCalcCpn6_WITH_PRECALCULATED_DISCOUNT.getAmount(EUR), pvCalcCpn6.getAmount(EUR), TOLERANCE_PV); assertEquals("PresentValueDiscountingProviderCalculator: multiple Ibor index", pvCalcAnnIbor_WITH_PRECALCULATED_DISCOUNT.getAmount(EUR), pvCalcAnnIbor.getAmount(EUR), TOLERANCE_PV); assertEquals("PresentValueDiscountingProviderCalculator: multiple Ibor index", pvCalcAnnFixed.getAmount(EUR), pvCalcAnnFixed_WITH_PRECALCULATED_DISCOUNT.getAmount(EUR), TOLERANCE_PV); assertEquals("PresentValueDiscountingProviderCalculator: multiple Ibor index", pvMethCpn3.getAmount(EUR), pvMethCpn3_WITH_PRECALCULATED_DISCOUNT.getAmount(EUR), TOLERANCE_PV); assertEquals("PresentValueDiscountingProviderCalculator: multiple Ibor index", pvMethCpn6.getAmount(EUR), pvMethCpn6_WITH_PRECALCULATED_DISCOUNT.getAmount(EUR), TOLERANCE_PV); assertEquals("PresentValueDiscountingProviderCalculator: multiple Ibor index", pvCalcSwap_WITH_PRECALCULATED_DISCOUNT.getAmount(EUR), pvCalcSwap.getAmount(EUR), TOLERANCE_PV); } @Test /** * */ public void testPreCalculatedVsOutput() { final String preiInterpolatedCurveName = "preiInterpolated Discount curve"; final Interpolator1D logNaturalinterpolator = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.LOG_NATURAL_CUBIC_MONOTONE, Interpolator1DFactory.QUADRATIC_LEFT_EXTRAPOLATOR, Interpolator1DFactory.LINEAR_EXTRAPOLATOR); final double[] dscCurveTime = new double[] {0.0, 1 / 365.25, 2 / 365.25, 3 / 365.25, 91 / 365.25, 183 / 365.25, 274 / 365.25, 365 / 365.25, 457 / 365.25, 548 / 365.25, 639 / 365.25, 731 / 365.25, 1096 / 365.25, 1461 / 365.25, 1826 / 365.25, 2192 / 365.25, 2557 / 365.25, 2922 / 365.25, 3287 / 365.25, 3653 / 365.25, 4383 / 365.25, 5479 / 365.25, 7305 / 365.25, 9131 / 365.25, 10958 / 365.25, 14610 / 365.25, 18263 / 365.25 }; final double[] dscCurveDiscountFactor = new double[] {1.0, 0.999995414, 0.999990827, 0.999986241, 0.999583194, 0.999167209, 0.998770249, 0.998379852, 0.997966181, 0.997459857, 0.996773166, 0.995843348, 0.989078497, 0.976557279, 0.959377269, 0.938363477, 0.91453858, 0.888747447, 0.861693639, 0.83391463, 0.778517911, 0.700537471, 0.596392269, 0.516411342, 0.451196242, 0.3436152, 0.259911234 }; final DayPeriodPreCalculatedDiscountCurve periodPreCalculatedCurve = new DayPeriodPreCalculatedDiscountCurve("test", new InterpolatedDoublesCurve(dscCurveTime, dscCurveDiscountFactor, logNaturalinterpolator, true, preiInterpolatedCurveName), 365.25); periodPreCalculatedCurve.preCalculateDiscountFactors(50); final double[] outputTime = new double[] {0.0, 1 / 365.25, 2 / 365.25, 3 / 365.25, 4 / 365.25, 7 / 365.25, 8 / 365.25, 9 / 365.25, 17 / 365.25, 77 / 365.25, 91 / 365.25, 140 / 365.25, 183 / 365.25, 219 / 365.25, 274 / 365.25, 301 / 365.25, 365 / 365.25, 672 / 365.25, 1001 / 365.25, 2034 / 365.25, 9879 / 365.25, 13374 / 365.25, 16180 / 365.25 }; final double[] outputDiscountFactor = new double[] {1.0, 0.999995414, 0.999990827, 0.999986241, 0.999981654, 0.999967895, 0.999963309, 0.999958723, 0.999922035, 0.999647188, 0.999583194, 0.999360197, 0.999167209, 0.999008575, 0.998770249, 0.998654304, 0.998379852, 0.996469188, 0.991376737, 0.947845026, 0.488392208, 0.377151958, 0.304915694 }; for (int i = 0; i < outputDiscountFactor.length; i++) { assertEquals("DayPeriodPreCalculatedDiscountCurve: discount factor value" + outputTime[i] * 365.25, outputDiscountFactor[i], periodPreCalculatedCurve.getDiscountFactor(outputTime[i]), 1.0E-6); } } public void testPreCalculatedVsOriginalCurve() { final String curveName = "Discount curve"; final String preiInterpolatedCurveName = "preiInterpolated Discount curve"; final Interpolator1D logNaturalinterpolator = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.LOG_NATURAL_CUBIC_MONOTONE, Interpolator1DFactory.QUADRATIC_LEFT_EXTRAPOLATOR, Interpolator1DFactory.LINEAR_EXTRAPOLATOR); final double[] dscCurveTime = new double[] {0.0, 1 / 365.25, 2 / 365.25, 3 / 365.25, 91 / 365.25, 183 / 365.25, 274 / 365.25, 365 / 365.25, 457 / 365.25, 548 / 365.25, 639 / 365.25, 731 / 365.25, 1096 / 365.25, 1461 / 365.25, 1826 / 365.25, 2192 / 365.25, 2557 / 365.25, 2922 / 365.25, 3287 / 365.25, 3653 / 365.25, 4383 / 365.25, 5479 / 365.25, 7305 / 365.25, 9131 / 365.25, 10958 / 365.25, 14610 / 365.25, 18263 / 365.25 }; final double[] dscCurveDiscountFactor = new double[] {1.0, 0.999995414, 0.999990827, 0.999986241, 0.999583194, 0.999167209, 0.998770249, 0.998379852, 0.997966181, 0.997459857, 0.996773166, 0.995843348, 0.989078497, 0.976557279, 0.959377269, 0.938363477, 0.91453858, 0.888747447, 0.861693639, 0.83391463, 0.778517911, 0.700537471, 0.596392269, 0.516411342, 0.451196242, 0.3436152, 0.259911234 }; final double[] dscCurveYields = new double[dscCurveDiscountFactor.length]; dscCurveYields[0] = 1.0; for (int i = 1; i < dscCurveYields.length; i++) { dscCurveYields[i] = -Math.log(dscCurveDiscountFactor[i]) / dscCurveTime[i]; } final YieldAndDiscountCurve discountCurve = new DiscountCurve(curveName, new InterpolatedDoublesCurve(dscCurveTime, dscCurveDiscountFactor, logNaturalinterpolator, true, preiInterpolatedCurveName)); final DayPeriodPreCalculatedDiscountCurve periodPreCalculatedCurve = new DayPeriodPreCalculatedDiscountCurve("test", new InterpolatedDoublesCurve(dscCurveTime, dscCurveDiscountFactor, logNaturalinterpolator, true, preiInterpolatedCurveName), 365.25); periodPreCalculatedCurve.preCalculateDiscountFactors(50); final double[] outputTime = new double[] {0.0, 1 / 365.25, 2 / 365.25, 3 / 365.25, 4 / 365.25, 7 / 365.25, 8 / 365.25, 9 / 365.25, 17 / 365.25, 77 / 365.25, 91 / 365.25, 140 / 365.25, 183 / 365.25, 219 / 365.25, 274 / 365.25, 301 / 365.25, 365 / 365.25, 672 / 365.25, 1001 / 365.25, 2034 / 365.25, 9879 / 365.25, 13374 / 365.25, 16180 / 365.25 }; final double[] outputDiscountFactor = new double[] {1.0, 0.999995414, 0.999990827, 0.999986241, 0.999981654, 0.999967895, 0.999963309, 0.999958723, 0.999922035, 0.999647188, 0.999583194, 0.999360197, 0.999167209, 0.999008575, 0.998770249, 0.998654304, 0.998379852, 0.996469188, 0.991376737, 0.947845026, 0.488392208, 0.377151958, 0.304915694 }; for (int i = 0; i < outputDiscountFactor.length; i++) { assertEquals("DayPeriodPreCalculatedDiscountCurve: discount factor value" + outputTime[i] * 365.25, discountCurve.getDiscountFactor(outputTime[i]), periodPreCalculatedCurve.getDiscountFactor(outputTime[i]), 1.0E-14); } } }