/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.instrument.payment; import static org.testng.AssertJUnit.assertEquals; import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; import org.testng.annotations.Test; import org.threeten.bp.Period; import org.threeten.bp.ZonedDateTime; import com.opengamma.analytics.financial.instrument.index.IborIndex; import com.opengamma.analytics.financial.instrument.index.IndexIborMaster; import com.opengamma.analytics.financial.interestrate.payments.derivative.Coupon; import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponFixed; import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponIborCompounding; import com.opengamma.analytics.financial.schedule.ScheduleCalculator; import com.opengamma.analytics.util.time.TimeCalculator; import com.opengamma.financial.convention.StubType; import com.opengamma.financial.convention.businessday.BusinessDayConvention; import com.opengamma.financial.convention.businessday.BusinessDayConventions; import com.opengamma.financial.convention.calendar.Calendar; import com.opengamma.financial.convention.calendar.MondayToFridayCalendar; import com.opengamma.timeseries.DoubleTimeSeries; import com.opengamma.timeseries.precise.zdt.ImmutableZonedDateTimeDoubleTimeSeries; import com.opengamma.util.test.TestGroup; import com.opengamma.util.time.DateUtils; /** * Tests related to the building of compounded Ibor coupons. */ @Test(groups = TestGroup.UNIT) public class CouponIborCompoundingDefinitionTest { private static final Calendar NYC = new MondayToFridayCalendar("NYC"); private static final IndexIborMaster MASTER_IBOR = IndexIborMaster.getInstance(); private static final IborIndex USDLIBOR1M = MASTER_IBOR.getIndex("USDLIBOR1M"); private static final BusinessDayConvention PREC = BusinessDayConventions.PRECEDING; private static final Period TENOR_3M = Period.ofMonths(3); private static final ZonedDateTime START_DATE = DateUtils.getUTCDate(2012, 8, 24); private static final double NOTIONAL = 123454321; private static final CouponIborCompoundingDefinition CPN_FROM_INDEX_DEFINITION = CouponIborCompoundingDefinition.from(NOTIONAL, START_DATE, TENOR_3M, USDLIBOR1M, NYC); private static final CouponIborCompoundingDefinition CPN_FROM_INDEX_DEFINITON_INITIAL_RATE = CouponIborCompoundingDefinition.from( USDLIBOR1M.getCurrency(), CPN_FROM_INDEX_DEFINITION.getPaymentDate(), CPN_FROM_INDEX_DEFINITION.getAccrualStartDate(), CPN_FROM_INDEX_DEFINITION.getAccrualEndDate(), CPN_FROM_INDEX_DEFINITION.getPaymentYearFraction(), CPN_FROM_INDEX_DEFINITION.getNotional(), CPN_FROM_INDEX_DEFINITION.getIndex(), CPN_FROM_INDEX_DEFINITION.getAccrualStartDates(), CPN_FROM_INDEX_DEFINITION.getAccrualEndDates(), CPN_FROM_INDEX_DEFINITION.getPaymentAccrualFactors(), CPN_FROM_INDEX_DEFINITION.getFixingDates(), CPN_FROM_INDEX_DEFINITION.getFixingPeriodStartDates(), CPN_FROM_INDEX_DEFINITION.getFixingPeriodEndDates(), CPN_FROM_INDEX_DEFINITION.getFixingPeriodAccrualFactors(), 0.002); private static final ZonedDateTime[] ACCRUAL_END_DATES = ScheduleCalculator.getAdjustedDateSchedule(START_DATE, TENOR_3M, true, false, USDLIBOR1M, NYC); private static final int NB_SUB_PERIOD = ACCRUAL_END_DATES.length; private static final ZonedDateTime[] ACCRUAL_START_DATES = new ZonedDateTime[NB_SUB_PERIOD]; private static final double[] PAYMENT_ACCRUAL_FACTORS = new double[NB_SUB_PERIOD]; private static final double PAYMENT_ACCRUAL_FACTOR; static { ACCRUAL_START_DATES[0] = START_DATE; for (int loopsub = 1; loopsub < NB_SUB_PERIOD; loopsub++) { ACCRUAL_START_DATES[loopsub] = ACCRUAL_END_DATES[loopsub - 1]; } double af = 0.0; for (int loopsub = 0; loopsub < NB_SUB_PERIOD; loopsub++) { PAYMENT_ACCRUAL_FACTORS[loopsub] = USDLIBOR1M.getDayCount().getDayCountFraction(ACCRUAL_START_DATES[loopsub], ACCRUAL_END_DATES[loopsub]); af += PAYMENT_ACCRUAL_FACTORS[loopsub]; } PAYMENT_ACCRUAL_FACTOR = af; } private static final ZonedDateTime[] FIXING_DATES = ScheduleCalculator.getAdjustedDate(ACCRUAL_START_DATES, -USDLIBOR1M.getSpotLag(), NYC); private static final ZonedDateTime[] FIXING_PERIOD_END_DATES = ScheduleCalculator.getAdjustedDate(ACCRUAL_START_DATES, USDLIBOR1M, NYC); private static final double[] FIXING_ACCRUAL_FACTORS = new double[NB_SUB_PERIOD]; static { for (int loopsub = 0; loopsub < NB_SUB_PERIOD; loopsub++) { FIXING_ACCRUAL_FACTORS[loopsub] = USDLIBOR1M.getDayCount().getDayCountFraction(ACCRUAL_START_DATES[loopsub], FIXING_PERIOD_END_DATES[loopsub]); } } private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2012, 8, 17); private static final double[] FIXING_TIMES = TimeCalculator.getTimeBetween(REFERENCE_DATE, FIXING_DATES); private static final double[] FIXING_PERIOD_END_TIMES = TimeCalculator.getTimeBetween(REFERENCE_DATE, FIXING_PERIOD_END_DATES); private static final double[] ACCRUAL_START_TIMES = TimeCalculator.getTimeBetween(REFERENCE_DATE, ACCRUAL_START_DATES); private static final double[] ACCRUAL_END_TIMES = TimeCalculator.getTimeBetween(REFERENCE_DATE, ACCRUAL_END_DATES); private static final double PAYMENT_TIME = ACCRUAL_END_TIMES[NB_SUB_PERIOD - 1]; private static final String DSC_NAME = "Dsc_USD"; private static final String FWD_NAME = "Forward1M_USD"; private static final double[] FIXING_RATES = new double[] {0.0010, 0.0011, 0.0012, 0.0013 }; private static final DoubleTimeSeries<ZonedDateTime> FIXING_TS = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC( new ZonedDateTime[] {DateUtils.getUTCDate(2012, 8, 21), DateUtils.getUTCDate(2012, 8, 22), DateUtils.getUTCDate(2012, 9, 20), DateUtils.getUTCDate(2012, 10, 22) }, FIXING_RATES); @Test public void from() { final CouponIborCompoundingDefinition cpnFromAccrualDates = CouponIborCompoundingDefinition.from(ACCRUAL_END_DATES[NB_SUB_PERIOD - 1], NOTIONAL, USDLIBOR1M, ACCRUAL_START_DATES, ACCRUAL_END_DATES, PAYMENT_ACCRUAL_FACTORS, NYC); assertEquals("CouponIborCompoundedDefinition: from", cpnFromAccrualDates, CPN_FROM_INDEX_DEFINITION); assertArrayEquals("CouponIborCompoundedDefinition: getter", ACCRUAL_START_DATES, CPN_FROM_INDEX_DEFINITION.getAccrualStartDates()); assertArrayEquals("CouponIborCompoundedDefinition: getter", ACCRUAL_START_DATES, CPN_FROM_INDEX_DEFINITION.getFixingPeriodStartDates()); assertArrayEquals("CouponIborCompoundedDefinition: getter", ACCRUAL_END_DATES, CPN_FROM_INDEX_DEFINITION.getAccrualEndDates()); assertArrayEquals("CouponIborCompoundedDefinition: getter", FIXING_DATES, CPN_FROM_INDEX_DEFINITION.getFixingDates()); assertArrayEquals("CouponIborCompoundedDefinition: getter", FIXING_PERIOD_END_DATES, CPN_FROM_INDEX_DEFINITION.getFixingPeriodEndDates()); } @Test public void fromShortStub() { final ZonedDateTime startDate = DateUtils.getUTCDate(2012, 8, 7); final ZonedDateTime endDate = DateUtils.getUTCDate(2012, 11, 23); final CouponIborCompoundingDefinition cpn = CouponIborCompoundingDefinition.from(NOTIONAL, startDate, endDate, USDLIBOR1M, StubType.SHORT_START, PREC, true, NYC); assertEquals("CouponIborCompoundedSpreadDefinition: from", startDate, cpn.getAccrualStartDate()); assertEquals("CouponIborCompoundedSpreadDefinition: from", cpn.getAccrualStartDate(), cpn.getAccrualStartDates()[0]); int nbSubPeriod = cpn.getAccrualStartDates().length; for (int loops = 0; loops < nbSubPeriod; loops++) { assertEquals("CouponIborCompoundedSpreadDefinition: dates - " + loops, cpn.getAccrualEndDates()[nbSubPeriod - 1 - loops], ScheduleCalculator.getAdjustedDate(endDate, Period.ofMonths(-loops), PREC, NYC, false)); assertEquals("CouponIborCompoundedSpreadDefinition: dates - " + loops, cpn.getFixingPeriodEndDates()[loops], ScheduleCalculator.getAdjustedDate(cpn.getFixingPeriodStartDates()[loops], USDLIBOR1M, NYC)); } } @Test public void getter() { assertEquals("CouponIborCompoundedDefinition: getter", USDLIBOR1M, CPN_FROM_INDEX_DEFINITION.getIndex()); assertEquals("CouponIborCompoundedDefinition: getter", START_DATE, CPN_FROM_INDEX_DEFINITION.getAccrualStartDate()); assertEquals("CouponIborCompoundedDefinition: getter", START_DATE, CPN_FROM_INDEX_DEFINITION.getAccrualStartDates()[0]); assertEquals("CouponIborCompoundedDefinition: getter", CPN_FROM_INDEX_DEFINITION.getPaymentDate(), CPN_FROM_INDEX_DEFINITION.getAccrualEndDates()[CPN_FROM_INDEX_DEFINITION.getAccrualEndDates().length - 1]); } @Test(expectedExceptions = IllegalArgumentException.class) public void wrongDate() { CPN_FROM_INDEX_DEFINITION.toDerivative(DateUtils.getUTCDate(2012, 8, 25)); } @Test public void toDerivativeNoTS() { final CouponIborCompounding cpnConverted = CPN_FROM_INDEX_DEFINITION.toDerivative(REFERENCE_DATE); final CouponIborCompounding cpnExpected = new CouponIborCompounding(USDLIBOR1M.getCurrency(), PAYMENT_TIME, PAYMENT_ACCRUAL_FACTOR, NOTIONAL, NOTIONAL, USDLIBOR1M, PAYMENT_ACCRUAL_FACTORS, FIXING_TIMES, ACCRUAL_START_TIMES, FIXING_PERIOD_END_TIMES, FIXING_ACCRUAL_FACTORS); assertEquals("CouponIborCompoundedDefinition: toDerivatives", cpnExpected, cpnConverted); final Coupon cpnConverted2 = CPN_FROM_INDEX_DEFINITION.toDerivative(REFERENCE_DATE, FIXING_TS); assertEquals("CouponIborCompoundedDefinition: toDerivatives", cpnExpected, cpnConverted2); } @Test public void toDerivativeAfter1Fixing() { final ZonedDateTime referenceDate = DateUtils.getUTCDate(2012, 8, 28); final double paymentTime = TimeCalculator.getTimeBetween(referenceDate, CPN_FROM_INDEX_DEFINITION.getPaymentDate()); final double accruedNotional = (1.0 + PAYMENT_ACCRUAL_FACTORS[0] * FIXING_RATES[1]) * NOTIONAL; final double[] paymentAccrualFactorsLeft = new double[NB_SUB_PERIOD - 1]; System.arraycopy(PAYMENT_ACCRUAL_FACTORS, 1, paymentAccrualFactorsLeft, 0, NB_SUB_PERIOD - 1); final double[] fixingTimesLeft = new double[NB_SUB_PERIOD - 1]; System.arraycopy(TimeCalculator.getTimeBetween(referenceDate, FIXING_DATES), 1, fixingTimesLeft, 0, NB_SUB_PERIOD - 1); final double[] fixingPeriodStartTimesLeft = new double[NB_SUB_PERIOD - 1]; System.arraycopy(TimeCalculator.getTimeBetween(referenceDate, ACCRUAL_START_DATES), 1, fixingPeriodStartTimesLeft, 0, NB_SUB_PERIOD - 1); final double[] fixingPeriodEndTimesLeft = new double[NB_SUB_PERIOD - 1]; System.arraycopy(TimeCalculator.getTimeBetween(referenceDate, FIXING_PERIOD_END_DATES), 1, fixingPeriodEndTimesLeft, 0, NB_SUB_PERIOD - 1); final double[] fixingPeriodAccrualFactorsLeft = new double[NB_SUB_PERIOD - 1]; System.arraycopy(FIXING_ACCRUAL_FACTORS, 1, fixingPeriodAccrualFactorsLeft, 0, NB_SUB_PERIOD - 1); final Coupon cpnConverted = CPN_FROM_INDEX_DEFINITION.toDerivative(referenceDate, FIXING_TS); final CouponIborCompounding cpnExpected = new CouponIborCompounding(USDLIBOR1M.getCurrency(), paymentTime, PAYMENT_ACCRUAL_FACTOR, NOTIONAL, accruedNotional, USDLIBOR1M, paymentAccrualFactorsLeft, fixingTimesLeft, fixingPeriodStartTimesLeft, fixingPeriodEndTimesLeft, fixingPeriodAccrualFactorsLeft); assertEquals("CouponIborCompoundedDefinition: toDerivatives", cpnExpected, cpnConverted); } @Test public void toDerivativeAfter2Fixing() { final ZonedDateTime referenceDate = DateUtils.getUTCDate(2012, 9, 20); final double paymentTime = TimeCalculator.getTimeBetween(referenceDate, CPN_FROM_INDEX_DEFINITION.getPaymentDate()); final double accruedNotional = (1.0 + PAYMENT_ACCRUAL_FACTORS[0] * FIXING_RATES[1]) * (1.0 + PAYMENT_ACCRUAL_FACTORS[1] * FIXING_RATES[2]) * NOTIONAL; final double[] paymentAccrualFactorsLeft = new double[] {PAYMENT_ACCRUAL_FACTORS[2] }; final double[] fixingTimesLeft = new double[] {TimeCalculator.getTimeBetween(referenceDate, FIXING_DATES[2]) }; final double[] fixingPeriodStartTimesLeft = new double[] {TimeCalculator.getTimeBetween(referenceDate, ACCRUAL_START_DATES[2]) }; final double[] fixingPeriodEndTimesLeft = new double[] {TimeCalculator.getTimeBetween(referenceDate, FIXING_PERIOD_END_DATES[2]) }; final double[] fixingPeriodAccrualFactorsLeft = new double[] {FIXING_ACCRUAL_FACTORS[2] }; final Coupon cpnConverted = CPN_FROM_INDEX_DEFINITION.toDerivative(referenceDate, FIXING_TS); final CouponIborCompounding cpnExpected = new CouponIborCompounding(USDLIBOR1M.getCurrency(), paymentTime, PAYMENT_ACCRUAL_FACTOR, NOTIONAL, accruedNotional, USDLIBOR1M, paymentAccrualFactorsLeft, fixingTimesLeft, fixingPeriodStartTimesLeft, fixingPeriodEndTimesLeft, fixingPeriodAccrualFactorsLeft); assertEquals("CouponIborCompoundedDefinition: toDerivatives", cpnExpected, cpnConverted); } @Test public void toDerivativeAfterLastFixing() { final ZonedDateTime referenceDate = DateUtils.getUTCDate(2012, 10, 25); final Coupon cpnConverted = CPN_FROM_INDEX_DEFINITION.toDerivative(referenceDate, FIXING_TS); final double rate = ((1.0 + PAYMENT_ACCRUAL_FACTORS[0] * FIXING_RATES[1]) * (1.0 + PAYMENT_ACCRUAL_FACTORS[1] * FIXING_RATES[2]) * (1.0 + PAYMENT_ACCRUAL_FACTORS[2] * FIXING_RATES[3]) - 1.0) / PAYMENT_ACCRUAL_FACTOR; final double paymentTime = TimeCalculator.getTimeBetween(referenceDate, CPN_FROM_INDEX_DEFINITION.getPaymentDate()); final CouponFixed cpnExpected = new CouponFixed(USDLIBOR1M.getCurrency(), paymentTime, PAYMENT_ACCRUAL_FACTOR, NOTIONAL, rate, ACCRUAL_START_DATES[0], ACCRUAL_END_DATES[NB_SUB_PERIOD - 1]); assertEquals("CouponIborCompoundedDefinition: toDerivatives", cpnExpected, cpnConverted); } @Test public void toDerivativeAfter1FixingInitialRate() { final ZonedDateTime referenceDate = DateUtils.getUTCDate(2012, 8, 28); final double paymentTime = TimeCalculator.getTimeBetween(referenceDate, CPN_FROM_INDEX_DEFINITION.getPaymentDate()); final double accruedNotional = (1.0 + PAYMENT_ACCRUAL_FACTORS[0] * CPN_FROM_INDEX_DEFINITON_INITIAL_RATE.getInitialRate()) * NOTIONAL; final double[] paymentAccrualFactorsLeft = new double[NB_SUB_PERIOD - 1]; System.arraycopy(PAYMENT_ACCRUAL_FACTORS, 1, paymentAccrualFactorsLeft, 0, NB_SUB_PERIOD - 1); final double[] fixingTimesLeft = new double[NB_SUB_PERIOD - 1]; System.arraycopy(TimeCalculator.getTimeBetween(referenceDate, FIXING_DATES), 1, fixingTimesLeft, 0, NB_SUB_PERIOD - 1); final double[] fixingPeriodStartTimesLeft = new double[NB_SUB_PERIOD - 1]; System.arraycopy(TimeCalculator.getTimeBetween(referenceDate, ACCRUAL_START_DATES), 1, fixingPeriodStartTimesLeft, 0, NB_SUB_PERIOD - 1); final double[] fixingPeriodEndTimesLeft = new double[NB_SUB_PERIOD - 1]; System.arraycopy(TimeCalculator.getTimeBetween(referenceDate, FIXING_PERIOD_END_DATES), 1, fixingPeriodEndTimesLeft, 0, NB_SUB_PERIOD - 1); final double[] fixingPeriodAccrualFactorsLeft = new double[NB_SUB_PERIOD - 1]; System.arraycopy(FIXING_ACCRUAL_FACTORS, 1, fixingPeriodAccrualFactorsLeft, 0, NB_SUB_PERIOD - 1); final Coupon cpnConverted = CPN_FROM_INDEX_DEFINITON_INITIAL_RATE.toDerivative(referenceDate, FIXING_TS); final CouponIborCompounding cpnExpected = new CouponIborCompounding(USDLIBOR1M.getCurrency(), paymentTime, PAYMENT_ACCRUAL_FACTOR, NOTIONAL, accruedNotional, USDLIBOR1M, paymentAccrualFactorsLeft, fixingTimesLeft, fixingPeriodStartTimesLeft, fixingPeriodEndTimesLeft, fixingPeriodAccrualFactorsLeft); assertEquals("CouponIborCompoundedDefinition: toDerivatives", cpnExpected, cpnConverted); } @Test public void toDerivativeAfter2FixingInitialRate() { final ZonedDateTime referenceDate = DateUtils.getUTCDate(2012, 9, 20); final double paymentTime = TimeCalculator.getTimeBetween(referenceDate, CPN_FROM_INDEX_DEFINITION.getPaymentDate()); final double accruedNotional = (1.0 + PAYMENT_ACCRUAL_FACTORS[0] * CPN_FROM_INDEX_DEFINITON_INITIAL_RATE.getInitialRate()) * (1.0 + PAYMENT_ACCRUAL_FACTORS[1] * FIXING_RATES[2]) * NOTIONAL; final double[] paymentAccrualFactorsLeft = new double[] {PAYMENT_ACCRUAL_FACTORS[2] }; final double[] fixingTimesLeft = new double[] {TimeCalculator.getTimeBetween(referenceDate, FIXING_DATES[2]) }; final double[] fixingPeriodStartTimesLeft = new double[] {TimeCalculator.getTimeBetween(referenceDate, ACCRUAL_START_DATES[2]) }; final double[] fixingPeriodEndTimesLeft = new double[] {TimeCalculator.getTimeBetween(referenceDate, FIXING_PERIOD_END_DATES[2]) }; final double[] fixingPeriodAccrualFactorsLeft = new double[] {FIXING_ACCRUAL_FACTORS[2] }; final Coupon cpnConverted = CPN_FROM_INDEX_DEFINITON_INITIAL_RATE.toDerivative(referenceDate, FIXING_TS); final CouponIborCompounding cpnExpected = new CouponIborCompounding(USDLIBOR1M.getCurrency(), paymentTime, PAYMENT_ACCRUAL_FACTOR, NOTIONAL, accruedNotional, USDLIBOR1M, paymentAccrualFactorsLeft, fixingTimesLeft, fixingPeriodStartTimesLeft, fixingPeriodEndTimesLeft, fixingPeriodAccrualFactorsLeft); assertEquals("CouponIborCompoundedDefinition: toDerivatives", cpnExpected, cpnConverted); } @Test public void toDerivativeAfterLastFixingInitialRate() { final ZonedDateTime referenceDate = DateUtils.getUTCDate(2012, 10, 25); final Coupon cpnConverted = CPN_FROM_INDEX_DEFINITON_INITIAL_RATE.toDerivative(referenceDate, FIXING_TS); final double rate = ((1.0 + PAYMENT_ACCRUAL_FACTORS[0] * CPN_FROM_INDEX_DEFINITON_INITIAL_RATE.getInitialRate()) * (1.0 + PAYMENT_ACCRUAL_FACTORS[1] * FIXING_RATES[2]) * (1.0 + PAYMENT_ACCRUAL_FACTORS[2] * FIXING_RATES[3]) - 1.0) / PAYMENT_ACCRUAL_FACTOR; final double paymentTime = TimeCalculator.getTimeBetween(referenceDate, CPN_FROM_INDEX_DEFINITION.getPaymentDate()); final CouponFixed cpnExpected = new CouponFixed(USDLIBOR1M.getCurrency(), paymentTime, PAYMENT_ACCRUAL_FACTOR, NOTIONAL, rate, ACCRUAL_START_DATES[0], ACCRUAL_END_DATES[NB_SUB_PERIOD - 1]); assertEquals("CouponIborCompoundedDefinition: toDerivatives", cpnExpected, cpnConverted); } }