/** * Copyright (C) 2014 - 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.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertTrue; import java.util.Arrays; import org.testng.annotations.Test; import org.testng.internal.junit.ArrayAsserts; import org.threeten.bp.Period; import org.threeten.bp.ZonedDateTime; import com.opengamma.analytics.financial.instrument.index.IborIndex; 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.CouponIborAverageFixingDates; import com.opengamma.analytics.financial.schedule.ScheduleCalculator; import com.opengamma.analytics.util.time.TimeCalculator; 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.financial.convention.daycount.DayCount; import com.opengamma.financial.convention.daycount.DayCounts; import com.opengamma.timeseries.DoubleTimeSeries; import com.opengamma.timeseries.precise.zdt.ImmutableZonedDateTimeDoubleTimeSeries; import com.opengamma.util.money.Currency; import com.opengamma.util.test.TestGroup; import com.opengamma.util.time.DateUtils; /** * */ @Test(groups = TestGroup.UNIT) public class CouponIborAverageFixingDatesDefinitionTest { private static final Period TENOR = Period.ofMonths(1); private static final int SETTLEMENT_DAYS = 2; private static final Calendar CALENDAR = new MondayToFridayCalendar("A"); private static final DayCount DAY_COUNT_INDEX = DayCounts.ACT_360; private static final BusinessDayConvention BUSINESS_DAY = BusinessDayConventions.MODIFIED_FOLLOWING; private static final boolean IS_EOM = true; private static final Currency CUR = Currency.EUR; private static final IborIndex INDEX = new IborIndex(CUR, TENOR, SETTLEMENT_DAYS, DAY_COUNT_INDEX, BUSINESS_DAY, IS_EOM, "Index"); private static final int NUM_OBS = 6; private static final ZonedDateTime ACCRUAL_START_DATE = DateUtils.getUTCDate(2011, 1, 6); private static final ZonedDateTime ACCRUAL_END_DATE = DateUtils.getUTCDate(2011, 7, 4); private static final ZonedDateTime PAYMENT_DATE = DateUtils.getUTCDate(2011, 7, 6); // The above dates are not standard but selected for insure correct testing. private static final ZonedDateTime[] FIXING_DATES = new ZonedDateTime[NUM_OBS]; private static final double[] WEIGHTS = new double[NUM_OBS]; static { for (int i = 0; i < NUM_OBS; ++i) { FIXING_DATES[i] = DateUtils.getUTCDate(2011, i + 1, 3); WEIGHTS[i] = 2. * (NUM_OBS - i) / NUM_OBS / (NUM_OBS + 1.); } } private static final DayCount DAY_COUNT_PAYMENT = DayCounts.ACT_365; private static final double ACCRUAL_FACTOR = DAY_COUNT_PAYMENT.getDayCountFraction(ACCRUAL_START_DATE, ACCRUAL_END_DATE); private static final double NOTIONAL = 1000000; private static final CouponIborAverageFixingDatesDefinition DFN1 = new CouponIborAverageFixingDatesDefinition(CUR, PAYMENT_DATE, ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, INDEX, FIXING_DATES, WEIGHTS, CALENDAR); private static final ZonedDateTime REFERENCE_DATE_BEFORE_FISRT_FIXING = DateUtils.getUTCDate(2010, 12, 27); private static final ZonedDateTime REFERENCE_DATE_AFTER_LAST_FIXING = DateUtils.getUTCDate(2011, 7, 4); private static final ZonedDateTime REFERENCE_DATE_ON_2ND_FIXING = DateUtils.getUTCDate(2011, 2, 3); private static final ZonedDateTime REFERENCE_DATE_AFTER_2_FIXING = DateUtils.getUTCDate(2011, 2, 16); private static ZonedDateTime[] EXP_START_DATES = new ZonedDateTime[NUM_OBS]; private static ZonedDateTime[] EXP_END_DATES = new ZonedDateTime[NUM_OBS]; private static double[] FIX_ACC_FACTORS = new double[NUM_OBS]; static { for (int i = 0; i < NUM_OBS; ++i) { EXP_START_DATES[i] = ScheduleCalculator.getAdjustedDate(FIXING_DATES[i], INDEX.getSpotLag(), CALENDAR); EXP_END_DATES[i] = ScheduleCalculator.getAdjustedDate(EXP_START_DATES[i], INDEX.getTenor(), INDEX.getBusinessDayConvention(), CALENDAR, INDEX.isEndOfMonth()); FIX_ACC_FACTORS[i] = INDEX.getDayCount().getDayCountFraction(EXP_START_DATES[i], EXP_END_DATES[i], CALENDAR); } } private static final CouponIborAverageFixingDatesDefinition DFN2 = new CouponIborAverageFixingDatesDefinition(CUR, PAYMENT_DATE, ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, INDEX, FIXING_DATES, WEIGHTS, EXP_START_DATES, EXP_END_DATES, FIX_ACC_FACTORS); private static final DoubleTimeSeries<ZonedDateTime> FIXING_TS1 = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(new ZonedDateTime[] {DateUtils.getUTCDate(2010, 12, 7) }, new double[] {0.01 }); private static final double[] FIXING_TS2_VALUES = {0.011, 0.012, 0.013, 0.014, 0.015, 0.016 }; private static final DoubleTimeSeries<ZonedDateTime> FIXING_TS2 = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC( new ZonedDateTime[] {DateUtils.getUTCDate(2011, 1, 3), DateUtils.getUTCDate(2011, 2, 3), DateUtils.getUTCDate(2011, 3, 3), DateUtils.getUTCDate(2011, 4, 3), DateUtils.getUTCDate(2011, 5, 3), DateUtils.getUTCDate(2011, 6, 3) }, FIXING_TS2_VALUES); private static final double[] FIXING_2_EX_VALUES = {0.011 }; private static final DoubleTimeSeries<ZonedDateTime> FIXING_2_EX = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC( new ZonedDateTime[] {DateUtils.getUTCDate(2011, 1, 3) }, FIXING_2_EX_VALUES); private static final double[] FIXING_2_IN_VALUES = {0.011, 0.012 }; private static final DoubleTimeSeries<ZonedDateTime> FIXING_2_IN = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC( new ZonedDateTime[] {DateUtils.getUTCDate(2011, 1, 3), DateUtils.getUTCDate(2011, 2, 3) }, FIXING_2_IN_VALUES); private static final double TOLERANCE_TIME = 1.0E-6; private static final double TOLERANCE_AMOUNT = 1.0E-2; private static final double TOLERANCE_RATE = 1.0E-8; @Test public void toDerivativeBeforeFirstFixing() { final Coupon derivative1 = DFN1.toDerivative(REFERENCE_DATE_BEFORE_FISRT_FIXING, FIXING_TS1); assertTrue((derivative1 instanceof CouponIborAverageFixingDates)); final CouponIborAverageFixingDates coupon = (CouponIborAverageFixingDates) derivative1; double[] fixingTime = TimeCalculator.getTimeBetween(REFERENCE_DATE_BEFORE_FISRT_FIXING, FIXING_DATES); double[] fixingStart = TimeCalculator.getTimeBetween(REFERENCE_DATE_BEFORE_FISRT_FIXING, DFN1.getFixingPeriodStartDate()); double[] fixingEnd = TimeCalculator.getTimeBetween(REFERENCE_DATE_BEFORE_FISRT_FIXING, DFN1.getFixingPeriodEndDate()); ArrayAsserts.assertArrayEquals("CouponIborAverageFixingDatesDefinition: toDerivative", coupon.getFixingTime(), fixingTime, TOLERANCE_TIME); ArrayAsserts.assertArrayEquals("CouponIborAverageFixingDatesDefinition: toDerivative", coupon.getFixingPeriodStartTime(), fixingStart, TOLERANCE_TIME); ArrayAsserts.assertArrayEquals("CouponIborAverageFixingDatesDefinition: toDerivative", coupon.getFixingPeriodEndTime(), fixingEnd, TOLERANCE_TIME); assertEquals("CouponIborAverageFixingDatesDefinition: toDerivative", coupon.getNotional(), NOTIONAL); } @Test public void toDerivativeAfterLastFixing() { final Coupon derivative = DFN1.toDerivative(REFERENCE_DATE_AFTER_LAST_FIXING, FIXING_TS2); assertTrue((derivative instanceof CouponFixed)); final CouponFixed coupon = (CouponFixed) derivative; double amountExpected = 0; for (int loopfix = 0; loopfix < NUM_OBS; loopfix++) { amountExpected += FIXING_TS2_VALUES[loopfix] * DFN1.getWeight()[loopfix]; } amountExpected *= NOTIONAL * DFN1.getPaymentYearFraction(); assertEquals("CouponIborAverageFixingDatesDefinition: toDerivative", coupon.getAmount(), amountExpected, TOLERANCE_AMOUNT); } @Test public void toDerivativeOn2ndFixing() { final Coupon derivativeEx = DFN1.toDerivative(REFERENCE_DATE_ON_2ND_FIXING, FIXING_2_EX); assertTrue((derivativeEx instanceof CouponIborAverageFixingDates)); final CouponIborAverageFixingDates couponEx = (CouponIborAverageFixingDates) derivativeEx; double amountExpectedEx = FIXING_2_EX_VALUES[0] * DFN1.getWeight()[0]; assertEquals("CouponIborAverageFixingDatesDefinition: toDerivative", couponEx.getAmountAccrued(), amountExpectedEx, TOLERANCE_RATE); final Coupon derivativeIn = DFN1.toDerivative(REFERENCE_DATE_ON_2ND_FIXING, FIXING_2_IN); assertTrue((derivativeIn instanceof CouponIborAverageFixingDates)); final CouponIborAverageFixingDates couponIn = (CouponIborAverageFixingDates) derivativeIn; double amountExpectedIn = FIXING_2_IN_VALUES[0] * DFN1.getWeight()[0] + FIXING_2_IN_VALUES[1] * DFN1.getWeight()[1]; assertEquals("CouponIborAverageFixingDatesDefinition: toDerivative", couponIn.getAmountAccrued(), amountExpectedIn, TOLERANCE_RATE); } @Test public void toDerivativeAfter2nd() { final DoubleTimeSeries<ZonedDateTime> fixingTS3 = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(new ZonedDateTime[] {DateUtils.getUTCDate(2011, 1, 3), DateUtils.getUTCDate(2011, 2, 3) }, new double[] {0.01, 0.02 }); final CouponIborAverageFixingDates derivative3 = (CouponIborAverageFixingDates) DFN1.toDerivative(REFERENCE_DATE_AFTER_2_FIXING, fixingTS3); assertEquals(NUM_OBS - 2, derivative3.getFixingPeriodAccrualFactor().length); assertEquals(NUM_OBS - 2, derivative3.getFixingPeriodEndTime().length); assertEquals(NUM_OBS - 2, derivative3.getFixingPeriodStartTime().length); assertEquals(NUM_OBS - 2, derivative3.getFixingTime().length); assertEquals(NUM_OBS - 2, derivative3.getWeight().length); final double refValue = WEIGHTS[0] * fixingTS3.getValueAtIndex(0) + WEIGHTS[1] * fixingTS3.getValueAtIndex(1); assertEquals(refValue, derivative3.getAmountAccrued(), 1.e-14); } @Test public void toDerivativeException() { try { DFN1.toDerivative(PAYMENT_DATE.plusDays(10), FIXING_TS1); throw new RuntimeException(); } catch (final Exception e) { assertEquals("date is after payment date", e.getMessage()); } try { DFN1.toDerivative(DateUtils.getUTCDate(2011, 7, 3), FIXING_TS1); throw new RuntimeException(); } catch (final Exception e) { assertEquals("Could not get fixing value for date " + FIXING_DATES[0], e.getMessage()); } } @Test public void exceptionTest() { try { new CouponIborAverageFixingDatesDefinition(Currency.GBP, PAYMENT_DATE, ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, INDEX, FIXING_DATES, WEIGHTS, CALENDAR); throw new RuntimeException(); } catch (final Exception e) { assertEquals("index currency different from payment currency", e.getMessage()); } try { new CouponIborAverageFixingDatesDefinition(Currency.USD, PAYMENT_DATE, ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, INDEX, FIXING_DATES, WEIGHTS, EXP_START_DATES, EXP_END_DATES, FIX_ACC_FACTORS); throw new RuntimeException(); } catch (final Exception e) { assertEquals("index currency different from payment currency", e.getMessage()); } final double[] shortWeight = Arrays.copyOf(WEIGHTS, NUM_OBS - 1); try { new CouponIborAverageFixingDatesDefinition(CUR, PAYMENT_DATE, ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, INDEX, FIXING_DATES, shortWeight, CALENDAR); throw new RuntimeException(); } catch (final Exception e) { assertEquals("weight length different from fixingDate length", e.getMessage()); } try { new CouponIborAverageFixingDatesDefinition(CUR, PAYMENT_DATE, ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, INDEX, FIXING_DATES, shortWeight, EXP_START_DATES, EXP_END_DATES, FIX_ACC_FACTORS); throw new RuntimeException(); } catch (final Exception e) { assertEquals("weight length different from fixingDate length", e.getMessage()); } final ZonedDateTime[] shortStartDates = Arrays.copyOf(EXP_START_DATES, NUM_OBS - 1); try { new CouponIborAverageFixingDatesDefinition(CUR, PAYMENT_DATE, ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, INDEX, FIXING_DATES, WEIGHTS, shortStartDates, EXP_END_DATES, FIX_ACC_FACTORS); throw new RuntimeException(); } catch (final Exception e) { assertEquals("fixingPeriodStartDate length different from fixingDate length", e.getMessage()); } final ZonedDateTime[] shortEndDates = Arrays.copyOf(EXP_END_DATES, NUM_OBS - 1); try { new CouponIborAverageFixingDatesDefinition(CUR, PAYMENT_DATE, ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, INDEX, FIXING_DATES, WEIGHTS, EXP_START_DATES, shortEndDates, FIX_ACC_FACTORS); throw new RuntimeException(); } catch (final Exception e) { assertEquals("fixingPeriodEndDate length different from fixingDate length", e.getMessage()); } final double[] shortFcc = Arrays.copyOf(FIX_ACC_FACTORS, NUM_OBS - 1); try { new CouponIborAverageFixingDatesDefinition(CUR, PAYMENT_DATE, ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, INDEX, FIXING_DATES, WEIGHTS, EXP_START_DATES, EXP_END_DATES, shortFcc); throw new RuntimeException(); } catch (final Exception e) { assertEquals("fixingPeriodAccrualFactor length different from fixingDate length", e.getMessage()); } final ZonedDateTime afterPayment = PAYMENT_DATE.plusDays(1); try { DFN1.toDerivative(afterPayment); throw new RuntimeException(); } catch (final Exception e) { assertEquals("date is after payment date", e.getMessage()); } final ZonedDateTime afterFixing = FIXING_DATES[0].plusDays(1); try { DFN1.toDerivative(afterFixing); throw new RuntimeException(); } catch (final Exception e) { assertEquals("Do not have any fixing data but are asking for a derivative at " + afterFixing + " which is after fixing date " + FIXING_DATES[0], e.getMessage()); } } @Test public void consistencyTest() { final CouponIborAverageFixingDatesDefinition dfn1WithDouble = DFN1.withNotional(NOTIONAL * 2); assertEquals(DFN1.getIndex(), DFN2.getIndex()); assertEquals(DFN1.getIndex(), dfn1WithDouble.getIndex()); for (int i = 0; i < NUM_OBS; ++i) { assertEquals(DFN1.getWeight()[i], DFN2.getWeight()[i]); assertEquals(DFN1.getFixingDate()[i], DFN2.getFixingDate()[i]); assertEquals(DFN1.getFixingPeriodStartDate()[i], DFN2.getFixingPeriodStartDate()[i]); assertEquals(DFN1.getFixingPeriodEndDate()[i], DFN2.getFixingPeriodEndDate()[i]); assertEquals(DFN1.getWeight()[i], dfn1WithDouble.getWeight()[i]); assertEquals(DFN1.getFixingDate()[i], dfn1WithDouble.getFixingDate()[i]); assertEquals(DFN1.getFixingPeriodStartDate()[i], dfn1WithDouble.getFixingPeriodStartDate()[i]); assertEquals(DFN1.getFixingPeriodEndDate()[i], dfn1WithDouble.getFixingPeriodEndDate()[i]); } final CouponIborAverageFixingDatesDefinition dfn1 = CouponIborAverageFixingDatesDefinition.from(CUR, PAYMENT_DATE, ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, INDEX, FIXING_DATES, WEIGHTS, CALENDAR); final CouponIborAverageFixingDatesDefinition dfn2 = CouponIborAverageFixingDatesDefinition.from(CUR, PAYMENT_DATE, ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, INDEX, FIXING_DATES, WEIGHTS, EXP_START_DATES, EXP_END_DATES, FIX_ACC_FACTORS); assertTrue(DFN1.equals(dfn1)); assertEquals(DFN1.hashCode(), dfn1.hashCode()); assertTrue(DFN2.equals(dfn2)); assertEquals(DFN2.hashCode(), dfn2.hashCode()); assertFalse(DFN1.hashCode() == dfn1WithDouble.hashCode()); assertFalse(DFN1.equals(dfn1WithDouble)); assertTrue(DFN1.toDerivative(REFERENCE_DATE_BEFORE_FISRT_FIXING).equals(dfn1.toDerivative(REFERENCE_DATE_BEFORE_FISRT_FIXING))); } }