/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.horizon;
import static org.testng.AssertJUnit.assertEquals;
import java.util.Collections;
import java.util.Map;
import org.testng.annotations.Test;
import org.threeten.bp.Period;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.financial.instrument.bond.BondFixedSecurityDefinition;
import com.opengamma.analytics.financial.instrument.bond.BondFixedTransactionDefinition;
import com.opengamma.analytics.financial.instrument.bond.BondTransactionDefinition;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexON;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitor;
import com.opengamma.analytics.financial.interestrate.bond.definition.BondFixedTransaction;
import com.opengamma.analytics.financial.interestrate.bond.definition.BondTransaction;
import com.opengamma.analytics.financial.legalentity.LegalEntity;
import com.opengamma.analytics.financial.legalentity.LegalEntityFilter;
import com.opengamma.analytics.financial.legalentity.LegalEntityShortName;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve;
import com.opengamma.analytics.financial.provider.calculator.issuer.PresentValueIssuerCalculator;
import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderInterface;
import com.opengamma.analytics.financial.provider.description.interestrate.ParameterIssuerProviderInterface;
import com.opengamma.analytics.financial.schedule.NoHolidayCalendar;
import com.opengamma.analytics.math.curve.ConstantDoublesCurve;
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.daycount.DayCount;
import com.opengamma.financial.convention.daycount.DayCounts;
import com.opengamma.financial.convention.yield.YieldConvention;
import com.opengamma.financial.convention.yield.YieldConventionFactory;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.CurrencyAmount;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
* Tests the constant spread horizon calculator for bonds.
*/
@Test(groups = TestGroup.UNIT)
public class BondConstantSpreadHorizonCalculatorTest {
/** Currency */
private static final Currency USD = Currency.USD;
/** Coupon frequency */
private static final Period PAYMENT_TENOR = Period.ofMonths(6);
/** Holiday calendar */
private static final Calendar CALENDAR = new NoHolidayCalendar();
/** Issuer name */
private static final String US_GOVT = "US";
/** Day-count */
private static final DayCount DAY_COUNT = DayCounts.ACT_ACT_ICMA;
/** Business day convention */
private static final BusinessDayConvention BUSINESS_DAY = BusinessDayConventions.FOLLOWING;
/** Is EOM */
private static final boolean IS_EOM = false;
/** Settlement days */
private static final int SETTLEMENT_DAYS = 1;
/** Bond yield convention */
private static final YieldConvention YIELD_CONVENTION = YieldConventionFactory.INSTANCE.getYieldConvention("STREET CONVENTION");
/** The coupon */
private static final double COUPON = 0.0123;
/** Bond future security */
private static final BondFixedSecurityDefinition SECURITY;
/** Quantity */
private static final int QUANTITY = 1000;
/** Reference date */
private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 6, 20);
/** Reference price */
private static final double REFERENCE_PRICE = 1.0;
/** Bond future transaction */
private static final BondTransactionDefinition<?, ?> TRANSACTION;
/** Horizon calculation date */
private static final ZonedDateTime HORIZON_DATE = REFERENCE_DATE.plusYears(1).plusDays(15);
/** Present value calculator */
private static final InstrumentDerivativeVisitor<ParameterIssuerProviderInterface, MultipleCurrencyAmount> PV_CALCULATOR = PresentValueIssuerCalculator.getInstance();
/** Horizon calculator */
private static final HorizonCalculator<BondTransactionDefinition<?, ?>, IssuerProviderInterface, Double> CALCULATOR = BondConstantSpreadHorizonCalculator.getInstance();
/** Constant issuer and discounting curves */
private static final IssuerProviderDiscount FLAT_ISSUER_MULTICURVES;
/** Accuracy */
private static final double EPS = 1e-9;
static {
SECURITY = BondFixedSecurityDefinition.from(USD, REFERENCE_DATE.plusYears(10), REFERENCE_DATE, PAYMENT_TENOR, COUPON, SETTLEMENT_DAYS,
CALENDAR, DAY_COUNT, BUSINESS_DAY, YIELD_CONVENTION, IS_EOM, new LegalEntity(US_GOVT, US_GOVT, null, null, null));
TRANSACTION = new BondFixedTransactionDefinition(SECURITY, QUANTITY, REFERENCE_DATE, REFERENCE_PRICE);
final YieldCurve flatIssuer = YieldCurve.from(ConstantDoublesCurve.from(0.02));
final YieldCurve flatDiscounting = YieldCurve.from(ConstantDoublesCurve.from(0.01));
final Map<Currency, YieldAndDiscountCurve> discounting = Collections.<Currency, YieldAndDiscountCurve>singletonMap(USD, flatDiscounting);
final Map<IborIndex, YieldAndDiscountCurve> ibor = Collections.emptyMap();
final Map<IndexON, YieldAndDiscountCurve> on = Collections.emptyMap();
final Pair<Object, LegalEntityFilter<LegalEntity>> issuerKey = Pairs.<Object, LegalEntityFilter<LegalEntity>>of(US_GOVT, new LegalEntityShortName());
final Map<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> issuer = Collections.<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve>singletonMap(issuerKey, flatIssuer);
FLAT_ISSUER_MULTICURVES = new IssuerProviderDiscount(discounting, ibor, on, issuer, new FXMatrix());
}
/**
* Tests the exception thrown when the bond future is null
*/
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullDefinition() {
CALCULATOR.getTheta(null, HORIZON_DATE, FLAT_ISSUER_MULTICURVES, 1, CALENDAR);
}
/**
* Tests the exception thrown when the horizon date is null
*/
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullDate() {
CALCULATOR.getTheta(TRANSACTION, null, FLAT_ISSUER_MULTICURVES, 1, CALENDAR);
}
/**
* Tests the exception thrown when the curve data is null
*/
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullData() {
CALCULATOR.getTheta(TRANSACTION, HORIZON_DATE, null, 1, CALENDAR);
}
/**
* Tests the exception thrown when the number of days forward is too large
*/
@Test(expectedExceptions = IllegalArgumentException.class)
public void testDaysForward1() {
CALCULATOR.getTheta(TRANSACTION, HORIZON_DATE, FLAT_ISSUER_MULTICURVES, 2, CALENDAR);
}
/**
* Tests the exception thrown when the number of days backward is too large
*/
@Test(expectedExceptions = IllegalArgumentException.class)
public void testDaysForward2() {
CALCULATOR.getTheta(TRANSACTION, HORIZON_DATE, FLAT_ISSUER_MULTICURVES, -2, CALENDAR);
}
/**
* Tests the horizon calculation when the curves are flat.
*/
@Test
public void testConstantCurves() {
final BondFixedTransaction today = (BondFixedTransaction) TRANSACTION.toDerivative(HORIZON_DATE);
final BondFixedTransaction tomorrow = (BondFixedTransaction) TRANSACTION.toDerivative(HORIZON_DATE.plusDays(1));
final MultipleCurrencyAmount pvToday = today.accept(PV_CALCULATOR, FLAT_ISSUER_MULTICURVES);
final MultipleCurrencyAmount pvTomorrow = tomorrow.accept(PV_CALCULATOR, FLAT_ISSUER_MULTICURVES);
MultipleCurrencyAmount expected = HorizonCalculator.subtract(pvTomorrow, pvToday);
MultipleCurrencyAmount actual = CALCULATOR.getTheta(TRANSACTION, HORIZON_DATE, FLAT_ISSUER_MULTICURVES, 1, CALENDAR, REFERENCE_PRICE);
assertMCAEquals(expected, actual);
final BondTransaction<?> yesterday = TRANSACTION.toDerivative(HORIZON_DATE.minusDays(1));
final MultipleCurrencyAmount pvYesterday = yesterday.accept(PV_CALCULATOR, FLAT_ISSUER_MULTICURVES);
expected = HorizonCalculator.subtract(pvYesterday, pvToday);
actual = CALCULATOR.getTheta(TRANSACTION, HORIZON_DATE, FLAT_ISSUER_MULTICURVES, -1, CALENDAR, REFERENCE_PRICE);
assertMCAEquals(expected, actual);
}
/**
* Checks multiple currency amounts for equality to within a specific accuracy.
* @param expected The expected object
* @param actual The actual object
*/
private void assertMCAEquals(final MultipleCurrencyAmount expected, final MultipleCurrencyAmount actual) {
final int length = expected.getCurrencyAmounts().length;
assertEquals(length, actual.getCurrencyAmounts().length);
for (int i = 0; i < length; i++) {
final CurrencyAmount ca = expected.getCurrencyAmounts()[i];
assertEquals(ca.getAmount(), actual.getAmount(ca.getCurrency()), EPS);
}
}
}