/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.bond.provider;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import org.testng.annotations.Test;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.financial.datasets.CalendarUSD;
import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinition;
import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinitionBuilder;
import com.opengamma.analytics.financial.instrument.bond.BillDataSets;
import com.opengamma.analytics.financial.instrument.bond.BillSecurityDefinition;
import com.opengamma.analytics.financial.instrument.bond.BillTotalReturnSwapDefinition;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexIborMaster;
import com.opengamma.analytics.financial.instrument.payment.CouponDefinition;
import com.opengamma.analytics.financial.instrument.payment.CouponFixedDefinition;
import com.opengamma.analytics.financial.instrument.payment.PaymentDefinition;
import com.opengamma.analytics.financial.instrument.payment.PaymentFixedDefinition;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitor;
import com.opengamma.analytics.financial.interestrate.annuity.derivative.Annuity;
import com.opengamma.analytics.financial.interestrate.bond.definition.BillSecurity;
import com.opengamma.analytics.financial.interestrate.bond.definition.BillTotalReturnSwap;
import com.opengamma.analytics.financial.interestrate.payments.derivative.Payment;
import com.opengamma.analytics.financial.provider.calculator.discounting.PV01CurveParametersCalculator;
import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueDiscountingCalculator;
import com.opengamma.analytics.financial.provider.calculator.issuer.PresentValueCurveSensitivityIssuerCalculator;
import com.opengamma.analytics.financial.provider.calculator.issuer.PresentValueIssuerCalculator;
import com.opengamma.analytics.financial.provider.description.IssuerProviderDiscountDataSets;
import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.ParameterIssuerProviderInterface;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyMulticurveSensitivity;
import com.opengamma.analytics.financial.util.AssertSensitivityObjects;
import com.opengamma.analytics.util.amount.ReferenceAmount;
import com.opengamma.analytics.util.time.TimeCalculator;
import com.opengamma.financial.convention.StubType;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.timeseries.precise.zdt.ImmutableZonedDateTimeDoubleTimeSeries;
import com.opengamma.timeseries.precise.zdt.ZonedDateTimeDoubleTimeSeries;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
* Test related to the bond total return swap pricing methodology by discounting of the cash-flows.
*/
public class BillTotalReturnSwapDiscountingMethodTest {
private static final Currency EUR = Currency.EUR;
private static final ZonedDateTime EFFECTIVE_DATE = DateUtils.getUTCDate(2014, 6, 25);
private static final ZonedDateTime TERMINATION_DATE = DateUtils.getUTCDate(2014, 12, 22);
private static final ZonedDateTime REFERENCE_DATE_1 = DateUtils.getUTCDate(2014, 6, 23); // Before effective date.
private static final ZonedDateTime REFERENCE_DATE_2 = DateUtils.getUTCDate(2014, 8, 18); // After effective date.
private static final double EFFECTIVE_TIME_1 = TimeCalculator.getTimeBetween(REFERENCE_DATE_1, EFFECTIVE_DATE);
private static final double EFFECTIVE_TIME_2 = TimeCalculator.getTimeBetween(REFERENCE_DATE_2, EFFECTIVE_DATE);
private static final double TERMINATION_TIME_1 = TimeCalculator.getTimeBetween(REFERENCE_DATE_1, TERMINATION_DATE);
private static final double TERMINATION_TIME_2 = TimeCalculator.getTimeBetween(REFERENCE_DATE_2, TERMINATION_DATE);
private static final ZonedDateTime[] FIXING_DATES = new ZonedDateTime[] {DateUtils.getUTCDate(2014, 2, 7), DateUtils.getUTCDate(2014, 6, 23),
DateUtils.getUTCDate(2014, 7, 18) };
private static final double[] FIXING_RATES = new double[] {0.0040, 0.0041, 0.0042 };
private static final ZonedDateTimeDoubleTimeSeries FIXING_TS = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(FIXING_DATES, FIXING_RATES);
private static final BillSecurityDefinition BELDEC14_DEFINITION = BillDataSets.billBel_20141218();
// Funding: unique fixed coupon in EUR: pay TRS bill, receive funding
private static final double NOTIONAL_TRS = 123456000;
private static final double NOTIONAL_BILL = 100000000;
private static final BillSecurity BELDEC14_1 = BELDEC14_DEFINITION.toDerivative(REFERENCE_DATE_1, EFFECTIVE_DATE);
private static final BillSecurity BELDEC14_2 = BELDEC14_DEFINITION.toDerivative(REFERENCE_DATE_2, EFFECTIVE_DATE);
// Funding: unique fixed coupon in EUR: receive TRS bond, pay funding
private static final double RATE = 0.0043;
private static final CouponFixedDefinition FUNDING_FIXED_CPN_REC_DEFINITION = new CouponFixedDefinition(EUR,
TERMINATION_DATE, EFFECTIVE_DATE, TERMINATION_DATE, 0.50, NOTIONAL_TRS, RATE);
private static final PaymentFixedDefinition FUNDING_FIXED_NTL_REC_DEFINITION = new PaymentFixedDefinition(EUR, TERMINATION_DATE, NOTIONAL_TRS);
private static final AnnuityDefinition<? extends PaymentDefinition> FUNDING_LEG_FIXED_REC_DEFINITION =
new AnnuityDefinition<>(new PaymentDefinition[] {FUNDING_FIXED_CPN_REC_DEFINITION, FUNDING_FIXED_NTL_REC_DEFINITION }, BELDEC14_DEFINITION.getCalendar());
private static final Annuity<? extends Payment> FUNDING_LEG_FIXED_REC_1 = FUNDING_LEG_FIXED_REC_DEFINITION.toDerivative(REFERENCE_DATE_1);
private static final Annuity<? extends Payment> FUNDING_LEG_FIXED_REC_2 = FUNDING_LEG_FIXED_REC_DEFINITION.toDerivative(REFERENCE_DATE_2);
private static final BillTotalReturnSwap TRS_PAY_FIXED_REC_1 =
new BillTotalReturnSwap(EFFECTIVE_TIME_1, TERMINATION_TIME_1, FUNDING_LEG_FIXED_REC_1, BELDEC14_1, -NOTIONAL_BILL);
private static final BillTotalReturnSwap TRS_PAY_FIXED_REC_2 =
new BillTotalReturnSwap(EFFECTIVE_TIME_2, TERMINATION_TIME_2, FUNDING_LEG_FIXED_REC_2, BELDEC14_2, -NOTIONAL_BILL);
// Funding: unique fixed coupon in EUR: pay TRS bond, receive funding
private static final CouponFixedDefinition FUNDING_FIXED_CPN_PAY_DEFINITION = new CouponFixedDefinition(EUR,
TERMINATION_DATE, EFFECTIVE_DATE, TERMINATION_DATE, 0.50, -NOTIONAL_TRS, RATE);
private static final PaymentFixedDefinition FUNDING_FIXED_NTL_PAY_DEFINITION = new PaymentFixedDefinition(EUR, TERMINATION_DATE, -NOTIONAL_TRS);
private static final AnnuityDefinition<? extends PaymentDefinition> FUNDING_LEG_FIXED_PAY_DEFINITION =
new AnnuityDefinition<>(new PaymentDefinition[] {FUNDING_FIXED_CPN_PAY_DEFINITION, FUNDING_FIXED_NTL_PAY_DEFINITION }, BELDEC14_DEFINITION.getCalendar());
private static final Annuity<? extends Payment> FUNDING_LEG_FIXED_PAY_1 = FUNDING_LEG_FIXED_PAY_DEFINITION.toDerivative(REFERENCE_DATE_1);
private static final BillTotalReturnSwap TRS_REC_FIXED_PAY_1 =
new BillTotalReturnSwap(EFFECTIVE_TIME_1, TERMINATION_TIME_1, FUNDING_LEG_FIXED_PAY_1, BELDEC14_1, NOTIONAL_BILL);
// Funding: multiple USD Libor coupons
private static final Calendar NYC = new CalendarUSD("NYC");
private static final double SPREAD = 0.0010;
private static final IborIndex USDLIBOR1M = IndexIborMaster.getInstance().getIndex("USDLIBOR1M");
private static final Currency USD = USDLIBOR1M.getCurrency();
private static final AnnuityDefinition<CouponDefinition> FUNDING_LEG_IBOR_PAY_DEFINITION = AnnuityDefinitionBuilder.couponIborSpreadWithNotional(EFFECTIVE_DATE,
TERMINATION_DATE, NOTIONAL_TRS, SPREAD, USDLIBOR1M, USDLIBOR1M.getDayCount(), USDLIBOR1M.getBusinessDayConvention(), true, USDLIBOR1M.getTenor(),
USDLIBOR1M.isEndOfMonth(), NYC, StubType.SHORT_START, 0, false, true);
private static final Annuity<? extends Payment> FUNDING_LEG_IBOR_PAY_1 = FUNDING_LEG_IBOR_PAY_DEFINITION.toDerivative(REFERENCE_DATE_1, FIXING_TS);
private static final BillTotalReturnSwapDefinition TRS_REC_IBOR_PAY_DEFINITION = new BillTotalReturnSwapDefinition(EFFECTIVE_DATE, TERMINATION_DATE,
FUNDING_LEG_IBOR_PAY_DEFINITION, BELDEC14_DEFINITION, NOTIONAL_BILL);
private static final BillTotalReturnSwap TRS_REC_IBOR_PAY_1_EFF = TRS_REC_IBOR_PAY_DEFINITION.toDerivative(REFERENCE_DATE_1, FIXING_TS);
private static final BillTotalReturnSwapDiscountingMethod METHOD_TRS_BND = BillTotalReturnSwapDiscountingMethod.getInstance();
private static final PresentValueIssuerCalculator PVIC = PresentValueIssuerCalculator.getInstance();
private static final PresentValueCurveSensitivityIssuerCalculator PVCSIC = PresentValueCurveSensitivityIssuerCalculator.getInstance();
private static final InstrumentDerivativeVisitor<ParameterIssuerProviderInterface, ReferenceAmount<Pair<String, Currency>>> PV01C =
new PV01CurveParametersCalculator<>(PVCSIC);
private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance();
private static final IssuerProviderDiscount ISSUER_MULTICURVE = IssuerProviderDiscountDataSets.getIssuerSpecificProvider();
private static final double TOLERANCE_PV = 1.0E-2;
private static final double TOLERANCE_PV_DELTA = 1.0E+1;
@Test
public void presentValueFixedSameCurrencyBeforeEffective() {
MultipleCurrencyAmount pvComputedPay = METHOD_TRS_BND.presentValue(TRS_PAY_FIXED_REC_1, ISSUER_MULTICURVE);
assertEquals("BillTRSDiscountingMethod: present value", 1, pvComputedPay.size()); // Bill and funding in same currency
assertTrue("BillTRSDiscountingMethod: present value", pvComputedPay.getAmount(EUR) != 0.0);
MultipleCurrencyAmount pvBillUnit = BELDEC14_1.accept(PVIC, ISSUER_MULTICURVE);
MultipleCurrencyAmount pvFunding = FUNDING_LEG_FIXED_REC_1.accept(PVDC, ISSUER_MULTICURVE.getMulticurveProvider());
MultipleCurrencyAmount pvExpected = pvBillUnit.multipliedBy(-NOTIONAL_BILL).plus(pvFunding);
assertEquals("BillTRSDiscountingMethod: present value", pvExpected.getAmount(EUR), pvComputedPay.getAmount(EUR), TOLERANCE_PV);
MultipleCurrencyAmount pvComputedRec = METHOD_TRS_BND.presentValue(TRS_REC_FIXED_PAY_1, ISSUER_MULTICURVE);
assertEquals("BillTRSDiscountingMethod: present value", -pvComputedPay.getAmount(EUR), pvComputedRec.getAmount(EUR), TOLERANCE_PV);
}
@Test
public void presentValueFixedSameCurrencyAfterEffective() {
MultipleCurrencyAmount pvComputed = METHOD_TRS_BND.presentValue(TRS_PAY_FIXED_REC_2, ISSUER_MULTICURVE);
assertEquals("BillTRSDiscountingMethod: present value", 1, pvComputed.size()); // Bill and funding in same currency
assertTrue("BillTRSDiscountingMethod: present value", pvComputed.getAmount(EUR) != 0.0);
MultipleCurrencyAmount pvBillUnit = BELDEC14_2.accept(PVIC, ISSUER_MULTICURVE);
MultipleCurrencyAmount pvFunding = FUNDING_LEG_FIXED_REC_2.accept(PVDC, ISSUER_MULTICURVE.getMulticurveProvider());
MultipleCurrencyAmount pvExpected = pvBillUnit.multipliedBy(-NOTIONAL_BILL).plus(pvFunding);
assertEquals("BillTRSDiscountingMethod: present value", pvExpected.getAmount(EUR), pvComputed.getAmount(EUR), TOLERANCE_PV); // Bill and funding in same currency
}
@Test
public void presentValueIborDiffCurrencyBeforeEffective() {
MultipleCurrencyAmount pvComputedRec = METHOD_TRS_BND.presentValue(TRS_REC_IBOR_PAY_1_EFF, ISSUER_MULTICURVE);
assertEquals("BillTRSDiscountingMethod: present value", 2, pvComputedRec.size()); // Bill and funding in different currency
assertTrue("BillTRSDiscountingMethod: present value", pvComputedRec.getAmount(EUR) != 0.0);
assertTrue("BillTRSDiscountingMethod: present value", pvComputedRec.getAmount(USD) != 0.0);
MultipleCurrencyAmount pvBillUnit = BELDEC14_1.accept(PVIC, ISSUER_MULTICURVE);
MultipleCurrencyAmount pvFunding = FUNDING_LEG_IBOR_PAY_1.accept(PVDC, ISSUER_MULTICURVE.getMulticurveProvider());
MultipleCurrencyAmount pvExpected = pvBillUnit.multipliedBy(NOTIONAL_BILL).plus(pvFunding);
assertEquals("BillTRSDiscountingMethod: present value", pvExpected.getAmount(EUR), pvComputedRec.getAmount(EUR), TOLERANCE_PV);
assertEquals("BillTRSDiscountingMethod: present value", pvFunding.getAmount(USD), pvComputedRec.getAmount(USD), TOLERANCE_PV);
}
@Test
public void presentValueLegs() {
MultipleCurrencyAmount pvBillLegExpected = TRS_REC_IBOR_PAY_1_EFF.getAsset().accept(PVIC, ISSUER_MULTICURVE).multipliedBy(NOTIONAL_BILL);
MultipleCurrencyAmount pvBillLegComputed = METHOD_TRS_BND.presentValueAssetLeg(TRS_REC_IBOR_PAY_1_EFF, ISSUER_MULTICURVE);
assertEquals("BillTRSDiscountingMethod: present value", pvBillLegExpected.getAmount(EUR), pvBillLegComputed.getAmount(EUR), TOLERANCE_PV);
MultipleCurrencyAmount pvFundingLegExpected = TRS_REC_IBOR_PAY_1_EFF.getFundingLeg().accept(PVDC, ISSUER_MULTICURVE.getMulticurveProvider());
MultipleCurrencyAmount pvFundingLegComputed = METHOD_TRS_BND.presentValueFundingLeg(TRS_REC_IBOR_PAY_1_EFF, ISSUER_MULTICURVE);
assertEquals("BillTRSDiscountingMethod: present value", pvFundingLegExpected.getAmount(USD), pvFundingLegComputed.getAmount(USD), TOLERANCE_PV);
}
@Test
public void presentValueMethodVsCalculator() {
MultipleCurrencyAmount pvMethod = METHOD_TRS_BND.presentValue(TRS_REC_IBOR_PAY_1_EFF, ISSUER_MULTICURVE);
MultipleCurrencyAmount pvCalculator = TRS_REC_IBOR_PAY_1_EFF.accept(PVIC, ISSUER_MULTICURVE);
assertEquals("BillTRSDiscountingMethod: present value", pvMethod.getAmount(EUR), pvCalculator.getAmount(EUR), TOLERANCE_PV);
assertEquals("BillTRSDiscountingMethod: present value", pvMethod.getAmount(USD), pvCalculator.getAmount(USD), TOLERANCE_PV);
}
@Test
public void presentValueCurveSensitivty() {
MultipleCurrencyMulticurveSensitivity pvcsComputed = METHOD_TRS_BND.presentValueCurveSensitivity(TRS_REC_IBOR_PAY_1_EFF, ISSUER_MULTICURVE).cleaned();
MultipleCurrencyMulticurveSensitivity pvcsFundingLeg = TRS_REC_IBOR_PAY_1_EFF.getFundingLeg().accept(PVCSIC, ISSUER_MULTICURVE).cleaned();
AssertSensitivityObjects.assertEquals("BillTRSDiscountingMethod: present value curve senstivity",
pvcsFundingLeg.getSensitivity(USD), pvcsComputed.getSensitivity(USD), TOLERANCE_PV_DELTA);
MultipleCurrencyMulticurveSensitivity pvcsBillLeg = TRS_REC_IBOR_PAY_1_EFF.getAsset().accept(PVCSIC, ISSUER_MULTICURVE).multipliedBy(NOTIONAL_BILL).cleaned();
AssertSensitivityObjects.assertEquals("BillTRSDiscountingMethod: present value curve senstivity",
pvcsBillLeg.getSensitivity(EUR), pvcsComputed.getSensitivity(EUR), TOLERANCE_PV_DELTA);
}
@Test
public void pv01() {
ReferenceAmount<Pair<String, Currency>> pv01Computed = TRS_REC_IBOR_PAY_1_EFF.accept(PV01C, ISSUER_MULTICURVE);
ReferenceAmount<Pair<String, Currency>> pv01Funding = TRS_REC_IBOR_PAY_1_EFF.getFundingLeg().accept(PV01C, ISSUER_MULTICURVE);
ReferenceAmount<Pair<String, Currency>> pv01Bill = TRS_REC_IBOR_PAY_1_EFF.getAsset().accept(PV01C, ISSUER_MULTICURVE);
pv01Bill = pv01Bill.multiplyBy(NOTIONAL_BILL);
assertEquals("BillTRSDiscountingMethod: pv01", pv01Computed.getMap().size(), 3); // Dsc, Libor, Govt
assertEquals("BillTRSDiscountingMethod: pv01", pv01Funding.getMap().size(), 2); // Dsc, Libor
assertEquals("BillTRSDiscountingMethod: pv01", pv01Bill.getMap().size(), 1); // Govt
double pv01BillExpected = -4823.349602769501; // Hardcoded value
assertEquals("BillTRSDiscountingMethod: pv01", pv01Bill.getMap().get(Pairs.of(ISSUER_MULTICURVE.getName(BELDEC14_DEFINITION.getIssuerEntity()), EUR)), pv01BillExpected, TOLERANCE_PV_DELTA);
assertEquals("BillTRSDiscountingMethod: pv01", pv01Bill.getMap().get(Pairs.of(ISSUER_MULTICURVE.getName(BELDEC14_DEFINITION.getIssuerEntity()), EUR)),
pv01Computed.getMap().get(Pairs.of(ISSUER_MULTICURVE.getName(BELDEC14_DEFINITION.getIssuerEntity()), EUR)), TOLERANCE_PV_DELTA);
}
}