/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.instrument.annuity;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
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.payment.CouponFixedDefinition;
import com.opengamma.analytics.financial.instrument.payment.CouponIborDefinition;
import com.opengamma.analytics.financial.instrument.payment.CouponIborSpreadDefinition;
import com.opengamma.analytics.financial.interestrate.annuity.derivative.Annuity;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponFixed;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponIbor;
import com.opengamma.analytics.financial.interestrate.payments.derivative.Payment;
import com.opengamma.analytics.financial.schedule.ScheduleCalculator;
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.financial.convention.frequency.PeriodFrequency;
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.
*/
@Test(groups = TestGroup.UNIT)
public class AnnuityCouponIborDefinitionTest {
//Libor3m
private static final Period INDEX_TENOR = Period.ofMonths(3);
private static final PeriodFrequency INDEX_FREQUENCY = PeriodFrequency.QUARTERLY;
private static final int SETTLEMENT_DAYS = 2;
private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
private static final DayCount DAY_COUNT = 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, INDEX_TENOR, SETTLEMENT_DAYS, DAY_COUNT, BUSINESS_DAY, IS_EOM, "Ibor");
//Annuity description
private static final Period ANNUITY_TENOR = Period.ofYears(2);
private static final ZonedDateTime SETTLEMENT_DATE = DateUtils.getUTCDate(2011, 3, 17);
private static final boolean IS_PAYER = true;
private static final double NOTIONAL = 1000000;
private static final ZonedDateTime MATURITY_DATE = SETTLEMENT_DATE.plus(ANNUITY_TENOR);
private static final ZonedDateTime[] PAYMENT_DATES_UNADJUSTED = ScheduleCalculator.getUnadjustedDateSchedule(SETTLEMENT_DATE, MATURITY_DATE, INDEX_FREQUENCY);
private static final ZonedDateTime[] PAYMENT_DATES = ScheduleCalculator.getAdjustedDateSchedule(PAYMENT_DATES_UNADJUSTED, BUSINESS_DAY, CALENDAR, false);
private static final AnnuityCouponIborDefinition IBOR_ANNUITY = AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 3, 15); //For conversion to derivative
private static final double FIXING_RATE = 0.05;
private static final DoubleTimeSeries<ZonedDateTime> FIXING_TS;
static {
FIXING_TS = ImmutableZonedDateTimeDoubleTimeSeries.of(REFERENCE_DATE, FIXING_RATE);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullConversionDate() {
IBOR_ANNUITY.toDerivative(null, FIXING_TS);
}
@Test
public void test() {
final CouponIborDefinition[] coupons = new CouponIborDefinition[PAYMENT_DATES.length];
final double sign = IS_PAYER ? -1.0 : 1.0;
//First coupon uses settlement date
CouponFixedDefinition coupon = new CouponFixedDefinition(CUR, PAYMENT_DATES[0], SETTLEMENT_DATE, PAYMENT_DATES[0], DAY_COUNT.getDayCountFraction(SETTLEMENT_DATE, PAYMENT_DATES[0]), sign
* NOTIONAL, 0.0);
ZonedDateTime fixingDate = ScheduleCalculator.getAdjustedDate(SETTLEMENT_DATE, -SETTLEMENT_DAYS, CALENDAR);
coupons[0] = CouponIborDefinition.from(coupon, fixingDate, INDEX, CALENDAR);
for (int loopcpn = 1; loopcpn < PAYMENT_DATES.length; loopcpn++) {
coupon = new CouponFixedDefinition(CUR, PAYMENT_DATES[loopcpn], PAYMENT_DATES[loopcpn - 1], PAYMENT_DATES[loopcpn], DAY_COUNT.getDayCountFraction(PAYMENT_DATES[loopcpn - 1],
PAYMENT_DATES[loopcpn]), sign * NOTIONAL, 0.0);
fixingDate = ScheduleCalculator.getAdjustedDate(PAYMENT_DATES[loopcpn - 1], -SETTLEMENT_DAYS, CALENDAR);
coupons[loopcpn] = CouponIborDefinition.from(coupon, fixingDate, INDEX, CALENDAR);
}
final AnnuityCouponIborDefinition iborAnnuity = new AnnuityCouponIborDefinition(coupons, INDEX, CALENDAR);
// assertEquals(iborAnnuity.getPayments(), coupons);
assertEquals(iborAnnuity.isPayer(), IS_PAYER);
for (int loopcpn = 0; loopcpn < PAYMENT_DATES.length; loopcpn++) {
assertEquals(iborAnnuity.getNthPayment(loopcpn), coupons[loopcpn]);
assertEquals(iborAnnuity.getPayments()[loopcpn], coupons[loopcpn]);
}
final AnnuityCouponIborDefinition iborAnnuity2 = AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
assertEquals(iborAnnuity, iborAnnuity2);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullPayments() {
new AnnuityCouponIborDefinition(null, INDEX, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullIndex() {
new AnnuityCouponIborDefinition(IBOR_ANNUITY.getPayments(), null, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testOneNullPayment() {
final CouponIborDefinition[] coupons = new CouponIborDefinition[PAYMENT_DATES.length];
//First coupon uses settlement date
CouponFixedDefinition coupon = new CouponFixedDefinition(CUR, PAYMENT_DATES[0], SETTLEMENT_DATE, PAYMENT_DATES[0], DAY_COUNT.getDayCountFraction(SETTLEMENT_DATE, PAYMENT_DATES[0]), NOTIONAL, 0.0);
ZonedDateTime fixingDate = ScheduleCalculator.getAdjustedDate(SETTLEMENT_DATE, -SETTLEMENT_DAYS, CALENDAR);
coupons[0] = null;
for (int loopcpn = 1; loopcpn < PAYMENT_DATES.length; loopcpn++) {
coupon = new CouponFixedDefinition(CUR, PAYMENT_DATES[loopcpn], PAYMENT_DATES[loopcpn - 1], PAYMENT_DATES[loopcpn], DAY_COUNT.getDayCountFraction(PAYMENT_DATES[loopcpn - 1],
PAYMENT_DATES[loopcpn]), NOTIONAL, 0.0);
fixingDate = ScheduleCalculator.getAdjustedDate(PAYMENT_DATES[loopcpn - 1], -SETTLEMENT_DAYS, CALENDAR);
coupons[loopcpn] = CouponIborDefinition.from(coupon, fixingDate, INDEX, CALENDAR);
}
new AnnuityCouponIborDefinition(coupons, INDEX, CALENDAR);
}
@Test
public void testFrom() {
final ZonedDateTime settleDate = DateUtils.getUTCDate(2014, 3, 20);
final Period indexTenor = Period.ofMonths(3);
final DayCount dayCount = DayCounts.ACT_360;
final IborIndex index = new IborIndex(CUR, indexTenor, SETTLEMENT_DAYS, dayCount, BUSINESS_DAY, IS_EOM, "Ibor");
final AnnuityCouponIborDefinition iborAnnuity = AnnuityCouponIborDefinition.from(settleDate, Period.ofYears(1), NOTIONAL, index, IS_PAYER, CALENDAR);
final ZonedDateTime[] paymentDates = new ZonedDateTime[] {DateUtils.getUTCDate(2014, 6, 20), DateUtils.getUTCDate(2014, 9, 22), DateUtils.getUTCDate(2014, 12, 22),
DateUtils.getUTCDate(2015, 03, 20) };
final ZonedDateTime[] fixingDates = new ZonedDateTime[] {DateUtils.getUTCDate(2014, 3, 18), DateUtils.getUTCDate(2014, 6, 18), DateUtils.getUTCDate(2014, 9, 18),
DateUtils.getUTCDate(2014, 12, 18) };
final ZonedDateTime[] startPeriodDates = new ZonedDateTime[] {DateUtils.getUTCDate(2014, 3, 20), DateUtils.getUTCDate(2014, 6, 20), DateUtils.getUTCDate(2014, 9, 22),
DateUtils.getUTCDate(2014, 12, 22) };
final ZonedDateTime[] endPeriodDates = new ZonedDateTime[] {DateUtils.getUTCDate(2014, 6, 20), DateUtils.getUTCDate(2014, 9, 22), DateUtils.getUTCDate(2014, 12, 22),
DateUtils.getUTCDate(2015, 03, 23) };
for (int loopcpn = 0; loopcpn < iborAnnuity.getPayments().length; loopcpn++) {
assertEquals(paymentDates[loopcpn], iborAnnuity.getNthPayment(loopcpn).getPaymentDate());
assertEquals(fixingDates[loopcpn], iborAnnuity.getNthPayment(loopcpn).getFixingDate());
assertEquals(startPeriodDates[loopcpn], iborAnnuity.getNthPayment(loopcpn).getFixingPeriodStartDate());
assertEquals(endPeriodDates[loopcpn], iborAnnuity.getNthPayment(loopcpn).getFixingPeriodEndDate());
}
}
@Test
public void testEqualHash() {
final CouponIborDefinition[] coupons = new CouponIborDefinition[PAYMENT_DATES.length];
//First coupon uses settlement date
CouponFixedDefinition coupon = new CouponFixedDefinition(CUR, PAYMENT_DATES[0], SETTLEMENT_DATE, PAYMENT_DATES[0], DAY_COUNT.getDayCountFraction(SETTLEMENT_DATE, PAYMENT_DATES[0]), NOTIONAL, 0.0);
ZonedDateTime fixingDate = ScheduleCalculator.getAdjustedDate(SETTLEMENT_DATE, -SETTLEMENT_DAYS, CALENDAR);
coupons[0] = CouponIborDefinition.from(coupon, fixingDate, INDEX, CALENDAR);
for (int loopcpn = 1; loopcpn < PAYMENT_DATES.length; loopcpn++) {
coupon = new CouponFixedDefinition(CUR, PAYMENT_DATES[loopcpn], PAYMENT_DATES[loopcpn - 1], PAYMENT_DATES[loopcpn], DAY_COUNT.getDayCountFraction(PAYMENT_DATES[loopcpn - 1],
PAYMENT_DATES[loopcpn]), NOTIONAL, 0.0);
fixingDate = ScheduleCalculator.getAdjustedDate(PAYMENT_DATES[loopcpn - 1], -SETTLEMENT_DAYS, CALENDAR);
coupons[loopcpn] = CouponIborDefinition.from(coupon, fixingDate, INDEX, CALENDAR);
}
final AnnuityCouponIborDefinition iborAnnuity = new AnnuityCouponIborDefinition(coupons, INDEX, CALENDAR);
final AnnuityCouponIborDefinition iborAnnuity2 = new AnnuityCouponIborDefinition(coupons, INDEX, CALENDAR);
assertEquals(iborAnnuity, iborAnnuity2);
assertEquals(iborAnnuity.hashCode(), iborAnnuity2.hashCode());
AnnuityCouponIborDefinition modifiedIborAnnuity = AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
assertFalse(iborAnnuity.equals(modifiedIborAnnuity));
final CouponIborDefinition[] couponsModified = new CouponIborDefinition[PAYMENT_DATES.length];
CouponFixedDefinition couponModified = new CouponFixedDefinition(CUR, PAYMENT_DATES[0], SETTLEMENT_DATE, PAYMENT_DATES[0], DAY_COUNT.getDayCountFraction(SETTLEMENT_DATE, PAYMENT_DATES[0]),
NOTIONAL, 0.0);
fixingDate = ScheduleCalculator.getAdjustedDate(SETTLEMENT_DATE, -SETTLEMENT_DAYS, CALENDAR);
couponsModified[0] = CouponIborDefinition.from(couponModified, fixingDate, INDEX, CALENDAR);
for (int loopcpn = 1; loopcpn < PAYMENT_DATES.length; loopcpn++) {
couponModified = new CouponFixedDefinition(CUR, PAYMENT_DATES[loopcpn], PAYMENT_DATES[loopcpn - 1], PAYMENT_DATES[loopcpn], DAY_COUNT.getDayCountFraction(PAYMENT_DATES[loopcpn - 1],
PAYMENT_DATES[loopcpn]), NOTIONAL + 5.0, 0.0);
fixingDate = ScheduleCalculator.getAdjustedDate(PAYMENT_DATES[loopcpn - 1], -SETTLEMENT_DAYS, CALENDAR);
couponsModified[loopcpn] = CouponIborDefinition.from(couponModified, fixingDate, INDEX, CALENDAR);
}
modifiedIborAnnuity = new AnnuityCouponIborDefinition(couponsModified, INDEX, CALENDAR);
assertFalse(iborAnnuity.equals(modifiedIborAnnuity));
}
@Test
public void testToDerivativeAfterFixing() {
final Payment[] couponIborConverted = new Payment[PAYMENT_DATES.length];
ZonedDateTime date = REFERENCE_DATE.plusMonths(1);
for (int loopcpn = 0; loopcpn < PAYMENT_DATES.length; loopcpn++) {
couponIborConverted[loopcpn] = IBOR_ANNUITY.getNthPayment(loopcpn).toDerivative(date, FIXING_TS);
}
Annuity<Payment> referenceAnnuity = new Annuity<>(couponIborConverted);
Annuity<? extends Payment> convertedDefinition = IBOR_ANNUITY.toDerivative(date, FIXING_TS);
assertEquals(referenceAnnuity, convertedDefinition);
assertTrue(convertedDefinition.getNthPayment(0) instanceof CouponFixed);
assertEquals(((CouponFixed) convertedDefinition.getNthPayment(0)).getFixedRate(), FIXING_RATE, 0);
for (int i = 1; i < PAYMENT_DATES.length; i++) {
assertTrue(convertedDefinition.getNthPayment(i) instanceof CouponIbor);
}
date = REFERENCE_DATE;
for (int loopcpn = 0; loopcpn < PAYMENT_DATES.length; loopcpn++) {
couponIborConverted[loopcpn] = IBOR_ANNUITY.getNthPayment(loopcpn).toDerivative(date, FIXING_TS);
}
referenceAnnuity = new Annuity<>(couponIborConverted);
convertedDefinition = IBOR_ANNUITY.toDerivative(date, FIXING_TS);
assertEquals(referenceAnnuity, convertedDefinition);
assertTrue(convertedDefinition.getNthPayment(0) instanceof CouponFixed);
assertEquals(((CouponFixed) convertedDefinition.getNthPayment(0)).getFixedRate(), FIXING_RATE, 0);
for (int i = 1; i < PAYMENT_DATES.length; i++) {
assertTrue(convertedDefinition.getNthPayment(i) instanceof CouponIbor);
}
}
@Test
public void testToDerivativeBeforeFixing() {
final Payment[] couponIborConverted = new Payment[PAYMENT_DATES.length];
final ZonedDateTime date = REFERENCE_DATE.minusDays(1);
for (int loopcpn = 0; loopcpn < PAYMENT_DATES.length; loopcpn++) {
couponIborConverted[loopcpn] = IBOR_ANNUITY.getNthPayment(loopcpn).toDerivative(date, FIXING_TS);
}
final Annuity<Payment> referenceAnnuity = new Annuity<>(couponIborConverted);
final Annuity<? extends Payment> convertedDefinition = IBOR_ANNUITY.toDerivative(date, FIXING_TS);
assertEquals(referenceAnnuity, convertedDefinition);
for (int i = 0; i < PAYMENT_DATES.length; i++) {
assertTrue(convertedDefinition.getNthPayment(i) instanceof CouponIbor);
}
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNullSettlementDate1() {
AnnuityCouponIborDefinition.from(null, ANNUITY_TENOR, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNullSettlementDate2() {
AnnuityCouponIborDefinition.from(null, MATURITY_DATE, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNullSettlementDate3() {
AnnuityCouponIborDefinition.fromAccrualUnadjusted(null, MATURITY_DATE, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNullPeriod() {
AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, (Period) null, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNullMaturityDate1() {
AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, (ZonedDateTime) null, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNullMaturityDate2() {
AnnuityCouponIborDefinition.fromAccrualUnadjusted(SETTLEMENT_DATE, null, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNegativeNotional1() {
AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, -NOTIONAL, INDEX, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNegativeNotional2() {
AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, MATURITY_DATE, -NOTIONAL, INDEX, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNegativeNotional3() {
AnnuityCouponIborDefinition.fromAccrualUnadjusted(SETTLEMENT_DATE, MATURITY_DATE, -NOTIONAL, INDEX, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNullIndex1() {
AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, null, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNullIndex2() {
AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, null, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNullIndex3() {
AnnuityCouponIborDefinition.fromAccrualUnadjusted(SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, null, IS_PAYER, CALENDAR);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testStaticConstructionNullAnnuity() {
AnnuityCouponIborDefinition.from(null);
}
@Test
public void testStaticConstruction() {
AnnuityCouponIborDefinition definition1 = AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
AnnuityCouponIborDefinition definition2 = AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
assertEquals(definition1, definition2);
assertEquals(IS_PAYER, definition1.isPayer());
definition2 = AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, INDEX, !IS_PAYER, CALENDAR);
assertFalse(definition1.equals(definition2));
definition2 = AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, INDEX, !IS_PAYER, CALENDAR);
assertFalse(definition1.equals(definition2));
definition1 = AnnuityCouponIborDefinition.fromAccrualUnadjusted(SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
definition2 = AnnuityCouponIborDefinition.fromAccrualUnadjusted(SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, INDEX, !IS_PAYER, CALENDAR);
assertFalse(definition1.equals(definition2));
}
@Test
public void testNoSpread() {
final AnnuityCouponIborDefinition definition = AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, INDEX, IS_PAYER, CALENDAR);
final CouponIborDefinition[] noSpreadCoupons = definition.getPayments();
final int n = noSpreadCoupons.length;
final double spread = 0.01;
final CouponIborSpreadDefinition[] spreadCoupons = new CouponIborSpreadDefinition[n];
for (int i = 0; i < n; i++) {
final CouponIborDefinition coupon = noSpreadCoupons[i];
spreadCoupons[i] = new CouponIborSpreadDefinition(coupon.getCurrency(), coupon.getPaymentDate(), coupon.getAccrualStartDate(), coupon.getAccrualEndDate(), coupon.getPaymentYearFraction(),
coupon.getNotional(), coupon.getFixingDate(), coupon.getIndex(), spread, coupon.getCalendar());
}
assertEquals(definition, AnnuityCouponIborDefinition.from(new AnnuityCouponIborSpreadDefinition(spreadCoupons, CALENDAR)));
}
}