/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.product.swap; import static com.opengamma.strata.basics.date.DayCounts.ACT_360; import static com.opengamma.strata.basics.date.DayCounts.ACT_365F; import static com.opengamma.strata.basics.index.OvernightIndices.CHF_TOIS; import static com.opengamma.strata.basics.index.OvernightIndices.GBP_SONIA; import static com.opengamma.strata.basics.index.OvernightIndices.USD_FED_FUND; import static com.opengamma.strata.collect.TestHelper.assertSerialization; import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg; import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; import static com.opengamma.strata.collect.TestHelper.date; import static com.opengamma.strata.product.swap.NegativeRateMethod.ALLOW_NEGATIVE; import static com.opengamma.strata.product.swap.NegativeRateMethod.NOT_NEGATIVE; import static com.opengamma.strata.product.swap.OvernightAccrualMethod.AVERAGED; import static com.opengamma.strata.product.swap.OvernightAccrualMethod.COMPOUNDED; import static org.testng.Assert.assertEquals; import java.time.LocalDate; import java.util.Optional; import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.opengamma.strata.basics.ReferenceData; import com.opengamma.strata.basics.index.Index; import com.opengamma.strata.basics.schedule.Frequency; import com.opengamma.strata.basics.schedule.RollConventions; import com.opengamma.strata.basics.schedule.Schedule; import com.opengamma.strata.basics.schedule.SchedulePeriod; import com.opengamma.strata.basics.value.ValueAdjustment; import com.opengamma.strata.basics.value.ValueSchedule; import com.opengamma.strata.basics.value.ValueStep; import com.opengamma.strata.product.rate.OvernightAveragedRateComputation; import com.opengamma.strata.product.rate.OvernightCompoundedRateComputation; /** * Test. */ @Test public class OvernightRateCalculationTest { private static final ReferenceData REF_DATA = ReferenceData.standard(); private static final LocalDate DATE_01_05 = date(2014, 1, 5); private static final LocalDate DATE_01_06 = date(2014, 1, 6); private static final LocalDate DATE_02_05 = date(2014, 2, 5); private static final LocalDate DATE_03_05 = date(2014, 3, 5); private static final LocalDate DATE_04_05 = date(2014, 4, 5); private static final LocalDate DATE_04_07 = date(2014, 4, 7); private static final SchedulePeriod ACCRUAL1 = SchedulePeriod.of(DATE_01_06, DATE_02_05, DATE_01_05, DATE_02_05); private static final SchedulePeriod ACCRUAL2 = SchedulePeriod.of(DATE_02_05, DATE_03_05, DATE_02_05, DATE_03_05); private static final SchedulePeriod ACCRUAL3 = SchedulePeriod.of(DATE_03_05, DATE_04_07, DATE_03_05, DATE_04_05); private static final Schedule ACCRUAL_SCHEDULE = Schedule.builder() .periods(ACCRUAL1, ACCRUAL2, ACCRUAL3) .frequency(Frequency.P1M) .rollConvention(RollConventions.DAY_5) .build(); private static final Schedule PAYMENT_SCHEDULE = Schedule.builder() .periods(SchedulePeriod.of(DATE_01_06, DATE_04_07, DATE_01_05, DATE_04_05)) .frequency(Frequency.P3M) .rollConvention(RollConventions.DAY_5) .build(); //------------------------------------------------------------------------- public void test_of() { OvernightRateCalculation test = OvernightRateCalculation.of(GBP_SONIA); assertEquals(test.getType(), SwapLegType.OVERNIGHT); assertEquals(test.getDayCount(), ACT_365F); assertEquals(test.getIndex(), GBP_SONIA); assertEquals(test.getAccrualMethod(), COMPOUNDED); assertEquals(test.getNegativeRateMethod(), ALLOW_NEGATIVE); assertEquals(test.getRateCutOffDays(), 0); assertEquals(test.getGearing(), Optional.empty()); assertEquals(test.getSpread(), Optional.empty()); } public void test_builder_ensureDefaults() { OvernightRateCalculation test = OvernightRateCalculation.builder() .index(GBP_SONIA) .build(); assertEquals(test.getDayCount(), ACT_365F); assertEquals(test.getIndex(), GBP_SONIA); assertEquals(test.getAccrualMethod(), COMPOUNDED); assertEquals(test.getNegativeRateMethod(), ALLOW_NEGATIVE); assertEquals(test.getRateCutOffDays(), 0); assertEquals(test.getGearing(), Optional.empty()); assertEquals(test.getSpread(), Optional.empty()); } public void test_builder_noIndex() { assertThrowsIllegalArg(() -> OvernightRateCalculation.builder().build()); } //------------------------------------------------------------------------- public void test_collectIndices() { OvernightRateCalculation test = OvernightRateCalculation.builder() .dayCount(ACT_365F) .index(GBP_SONIA) .build(); ImmutableSet.Builder<Index> builder = ImmutableSet.builder(); test.collectIndices(builder); assertEquals(builder.build(), ImmutableSet.of(GBP_SONIA)); } //------------------------------------------------------------------------- public void test_expand_simple() { OvernightRateCalculation test = OvernightRateCalculation.builder() .dayCount(ACT_365F) .index(GBP_SONIA) .build(); RateAccrualPeriod rap1 = RateAccrualPeriod.builder(ACCRUAL1) .yearFraction(ACCRUAL1.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(GBP_SONIA, DATE_01_06, DATE_02_05, 0, REF_DATA)) .build(); RateAccrualPeriod rap2 = RateAccrualPeriod.builder(ACCRUAL2) .yearFraction(ACCRUAL2.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(GBP_SONIA, DATE_02_05, DATE_03_05, 0, REF_DATA)) .build(); RateAccrualPeriod rap3 = RateAccrualPeriod.builder(ACCRUAL3) .yearFraction(ACCRUAL3.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(GBP_SONIA, DATE_03_05, DATE_04_07, 0, REF_DATA)) .build(); ImmutableList<RateAccrualPeriod> periods = test.createAccrualPeriods(ACCRUAL_SCHEDULE, ACCRUAL_SCHEDULE, REF_DATA); assertEquals(periods, ImmutableList.of(rap1, rap2, rap3)); } public void test_expand_tomNext() { OvernightRateCalculation test = OvernightRateCalculation.builder() .dayCount(ACT_360) .index(CHF_TOIS) .build(); RateAccrualPeriod rap1 = RateAccrualPeriod.builder(ACCRUAL1) .yearFraction(ACCRUAL1.yearFraction(ACT_360, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(CHF_TOIS, DATE_01_06, DATE_02_05, 0, REF_DATA)) .build(); RateAccrualPeriod rap2 = RateAccrualPeriod.builder(ACCRUAL2) .yearFraction(ACCRUAL2.yearFraction(ACT_360, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(CHF_TOIS, DATE_02_05, DATE_03_05, 0, REF_DATA)) .build(); RateAccrualPeriod rap3 = RateAccrualPeriod.builder(ACCRUAL3) .yearFraction(ACCRUAL3.yearFraction(ACT_360, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(CHF_TOIS, DATE_03_05, DATE_04_07, 0, REF_DATA)) .build(); ImmutableList<RateAccrualPeriod> periods = test.createAccrualPeriods(ACCRUAL_SCHEDULE, ACCRUAL_SCHEDULE, REF_DATA); assertEquals(periods, ImmutableList.of(rap1, rap2, rap3)); } public void test_expand_rateCutOffDays_accrualIsPaymentPeriod() { OvernightRateCalculation test = OvernightRateCalculation.builder() .dayCount(ACT_365F) .index(GBP_SONIA) .rateCutOffDays(2) .build(); RateAccrualPeriod rap1 = RateAccrualPeriod.builder(ACCRUAL1) .yearFraction(ACCRUAL1.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(GBP_SONIA, DATE_01_06, DATE_02_05, 2, REF_DATA)) .build(); RateAccrualPeriod rap2 = RateAccrualPeriod.builder(ACCRUAL2) .yearFraction(ACCRUAL2.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(GBP_SONIA, DATE_02_05, DATE_03_05, 2, REF_DATA)) .build(); RateAccrualPeriod rap3 = RateAccrualPeriod.builder(ACCRUAL3) .yearFraction(ACCRUAL3.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(GBP_SONIA, DATE_03_05, DATE_04_07, 2, REF_DATA)) .build(); ImmutableList<RateAccrualPeriod> periods = test.createAccrualPeriods(ACCRUAL_SCHEDULE, ACCRUAL_SCHEDULE, REF_DATA); assertEquals(periods, ImmutableList.of(rap1, rap2, rap3)); } public void test_expand_rateCutOffDays_threeAccrualsInPaymentPeriod() { OvernightRateCalculation test = OvernightRateCalculation.builder() .dayCount(ACT_365F) .index(GBP_SONIA) .rateCutOffDays(2) .build(); RateAccrualPeriod rap1 = RateAccrualPeriod.builder(ACCRUAL1) .yearFraction(ACCRUAL1.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(GBP_SONIA, DATE_01_06, DATE_02_05, 0, REF_DATA)) .build(); RateAccrualPeriod rap2 = RateAccrualPeriod.builder(ACCRUAL2) .yearFraction(ACCRUAL2.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(GBP_SONIA, DATE_02_05, DATE_03_05, 0, REF_DATA)) .build(); RateAccrualPeriod rap3 = RateAccrualPeriod.builder(ACCRUAL3) .yearFraction(ACCRUAL3.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightCompoundedRateComputation.of(GBP_SONIA, DATE_03_05, DATE_04_07, 2, REF_DATA)) .build(); ImmutableList<RateAccrualPeriod> periods = test.createAccrualPeriods(ACCRUAL_SCHEDULE, PAYMENT_SCHEDULE, REF_DATA); assertEquals(periods, ImmutableList.of(rap1, rap2, rap3)); } public void test_expand_gearingSpreadEverythingElse() { OvernightRateCalculation test = OvernightRateCalculation.builder() .dayCount(ACT_365F) .index(GBP_SONIA) .accrualMethod(AVERAGED) .negativeRateMethod(NOT_NEGATIVE) .rateCutOffDays(2) .gearing(ValueSchedule.of(1d, ValueStep.of(2, ValueAdjustment.ofReplace(2d)))) .spread(ValueSchedule.of(0d, ValueStep.of(1, ValueAdjustment.ofReplace(-0.025d)))) .build(); RateAccrualPeriod rap1 = RateAccrualPeriod.builder(ACCRUAL1) .yearFraction(ACCRUAL1.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightAveragedRateComputation.of(GBP_SONIA, DATE_01_06, DATE_02_05, 0, REF_DATA)) .negativeRateMethod(NOT_NEGATIVE) .build(); RateAccrualPeriod rap2 = RateAccrualPeriod.builder(ACCRUAL2) .yearFraction(ACCRUAL2.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightAveragedRateComputation.of(GBP_SONIA, DATE_02_05, DATE_03_05, 0, REF_DATA)) .negativeRateMethod(NOT_NEGATIVE) .spread(-0.025d) .build(); RateAccrualPeriod rap3 = RateAccrualPeriod.builder(ACCRUAL3) .yearFraction(ACCRUAL3.yearFraction(ACT_365F, ACCRUAL_SCHEDULE)) .rateComputation(OvernightAveragedRateComputation.of(GBP_SONIA, DATE_03_05, DATE_04_07, 2, REF_DATA)) .negativeRateMethod(NOT_NEGATIVE) .gearing(2d) .spread(-0.025d) .build(); ImmutableList<RateAccrualPeriod> periods = test.createAccrualPeriods(ACCRUAL_SCHEDULE, PAYMENT_SCHEDULE, REF_DATA); assertEquals(periods, ImmutableList.of(rap1, rap2, rap3)); } //------------------------------------------------------------------------- public void coverage() { OvernightRateCalculation test = OvernightRateCalculation.builder() .dayCount(ACT_365F) .index(GBP_SONIA) .build(); coverImmutableBean(test); OvernightRateCalculation test2 = OvernightRateCalculation.builder() .dayCount(ACT_360) .index(USD_FED_FUND) .accrualMethod(AVERAGED) .negativeRateMethod(NOT_NEGATIVE) .rateCutOffDays(2) .gearing(ValueSchedule.of(2d)) .spread(ValueSchedule.of(-0.025d)) .build(); coverBeanEquals(test, test2); } public void test_serialization() { OvernightRateCalculation test = OvernightRateCalculation.builder() .dayCount(ACT_365F) .index(GBP_SONIA) .build(); assertSerialization(test); } }