/** * 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 java.util.LinkedHashMap; import org.testng.annotations.Test; import org.threeten.bp.Period; import org.threeten.bp.ZoneOffset; import org.threeten.bp.ZonedDateTime; import com.opengamma.analytics.financial.instrument.bond.BondCapitalIndexedSecurityDefinition; import com.opengamma.analytics.financial.instrument.bond.BondCapitalIndexedTransactionDefinition; import com.opengamma.analytics.financial.instrument.bond.BondDataSetsUsd; import com.opengamma.analytics.financial.instrument.bond.BondFixedSecurityDefinition; import com.opengamma.analytics.financial.instrument.bond.BondFixedTransactionDefinition; import com.opengamma.analytics.financial.instrument.index.GeneratorAttributeIR; import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedInflationMaster; import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedInflationZeroCoupon; import com.opengamma.analytics.financial.instrument.index.IndexPrice; import com.opengamma.analytics.financial.instrument.inflation.CouponInflationZeroCouponInterpolationGearingDefinition; import com.opengamma.analytics.financial.instrument.swap.SwapFixedInflationZeroCouponDefinition; import com.opengamma.analytics.financial.interestrate.InstrumentDerivative; import com.opengamma.analytics.financial.interestrate.bond.definition.BondCapitalIndexedTransaction; import com.opengamma.analytics.financial.interestrate.bond.definition.BondFixedTransaction; import com.opengamma.analytics.financial.interestrate.datasets.StandardDataSetsGovtUsInflationUSD; import com.opengamma.analytics.financial.interestrate.datasets.StandardDataSetsInflationUSD; import com.opengamma.analytics.financial.interestrate.datasets.StandardTimeSeriesInflationDataSets; import com.opengamma.analytics.financial.provider.calculator.inflation.MarketQuoteInflationSensitivityBlockCalculator; import com.opengamma.analytics.financial.provider.calculator.inflation.PresentValueDiscountingInflationCalculator; import com.opengamma.analytics.financial.provider.calculator.inflationissuer.PresentValueCurveSensitivityIssuerInflationCalculator; import com.opengamma.analytics.financial.provider.calculator.inflationissuer.PresentValueDiscountingInflationIssuerCalculator; import com.opengamma.analytics.financial.provider.calculator.issuer.PresentValueIssuerCalculator; import com.opengamma.analytics.financial.provider.curve.CurveBuildingBlockBundle; import com.opengamma.analytics.financial.provider.description.inflation.InflationIssuerProviderDiscount; import com.opengamma.analytics.financial.provider.description.inflation.InflationProviderDiscount; import com.opengamma.analytics.financial.provider.description.inflation.ParameterInflationIssuerProviderInterface; import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderDiscount; import com.opengamma.analytics.financial.provider.sensitivity.inflation.MultipleCurrencyInflationSensitivity; import com.opengamma.analytics.financial.provider.sensitivity.inflation.ParameterSensitivityInflationParameterCalculator; import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyParameterSensitivity; import com.opengamma.analytics.financial.schedule.ScheduleCalculator; import com.opengamma.analytics.financial.util.AssertSensitivityObjects; import com.opengamma.analytics.math.matrix.DoubleMatrix1D; 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.test.TestGroup; import com.opengamma.util.time.DateUtils; import com.opengamma.util.tuple.ObjectsPair; import com.opengamma.util.tuple.Pair; /** * End-to-end tests for (inflation) capital indexed bonds. */ @Test(groups = TestGroup.UNIT) public class BondCapitalIndexedDiscountingE2ETest { private static final ZonedDateTime CALIBRATION_DATE = DateUtils.getUTCDate(2014, 10, 9); private static final Currency USD = Currency.USD; private static final GeneratorSwapFixedInflationZeroCoupon GENERATOR_ZCINFLATION_US = GeneratorSwapFixedInflationMaster.getInstance().getGenerator("USCPI"); private static final IndexPrice US_CPI = GENERATOR_ZCINFLATION_US.getIndexPrice(); private static final ZonedDateTimeDoubleTimeSeries HTS_CPI = StandardTimeSeriesInflationDataSets.timeSeriesUsCpi(CALIBRATION_DATE); private static final ZonedDateTimeDoubleTimeSeries HTS_EMPTY = ImmutableZonedDateTimeDoubleTimeSeries.ofEmpty(ZoneOffset.UTC); /** Calculators **/ private static final BondCapitalIndexedSecurityDiscountingMethod METHOD_CAPIND_BOND_SEC = BondCapitalIndexedSecurityDiscountingMethod.getInstance(); private static final PresentValueIssuerCalculator PVIssuerC = PresentValueIssuerCalculator.getInstance(); private static final PresentValueDiscountingInflationCalculator PVInflC = PresentValueDiscountingInflationCalculator.getInstance(); private static final PresentValueDiscountingInflationIssuerCalculator PVInflIssuerC = PresentValueDiscountingInflationIssuerCalculator.getInstance(); private static final PresentValueCurveSensitivityIssuerInflationCalculator PVCSInflIssuerC = PresentValueCurveSensitivityIssuerInflationCalculator.getInstance(); private static final ParameterSensitivityInflationParameterCalculator<ParameterInflationIssuerProviderInterface> PSIC = new ParameterSensitivityInflationParameterCalculator<>(PVCSInflIssuerC); private static final MarketQuoteInflationSensitivityBlockCalculator<ParameterInflationIssuerProviderInterface> MQISBC = new MarketQuoteInflationSensitivityBlockCalculator<>(PSIC); /** Bond fixed coupon 2019 */ private static final BondFixedSecurityDefinition UST_SEC_DEFINITION = BondDataSetsUsd.bondUST_20190930(1.0); private static final double QUANTITY = 10000000; // 10m private static final ZonedDateTime SETTLE_DATE_FIXED = DateUtils.getUTCDate(2014, 10, 15); private static final double TRADE_PRICE_FIXED = 0.99; private static final BondFixedTransactionDefinition UST_TRA_DEFINITION = new BondFixedTransactionDefinition(UST_SEC_DEFINITION, QUANTITY, SETTLE_DATE_FIXED, TRADE_PRICE_FIXED); private static final BondFixedTransaction UST_TRA = UST_TRA_DEFINITION.toDerivative(CALIBRATION_DATE); /** Zero-coupon Inflation US (linear interpolation of Price Index). 5Y aged. */ private static final double NOTIONAL = 10_000_000; private static final ZonedDateTime ACCRUAL_START_DATE_2 = DateUtils.getUTCDate(2014, 1, 8); private static final GeneratorAttributeIR ZCI_2_ATTR = new GeneratorAttributeIR(Period.ofYears(5)); private static final double RATE_FIXED_2 = 0.0100; private static final SwapFixedInflationZeroCouponDefinition ZCI_2_DEFINITION = GENERATOR_ZCINFLATION_US.generateInstrument(ACCRUAL_START_DATE_2, RATE_FIXED_2, NOTIONAL, ZCI_2_ATTR); private static final InstrumentDerivative ZCI_2 = ZCI_2_DEFINITION.toDerivative(ACCRUAL_START_DATE_2, new ZonedDateTimeDoubleTimeSeries[] {HTS_EMPTY, HTS_CPI}); /** Bond Inflation (TIPS) 2016 */ private static final BondCapitalIndexedSecurityDefinition<CouponInflationZeroCouponInterpolationGearingDefinition> TIPS_16_SEC_DEFINITION = BondDataSetsUsd.bondTIPS_20160115(1.0); private static final double QUANTITY_TIPS_1 = 10000000; // 10m private static final ZonedDateTime SETTLE_DATE_TIPS_1 = DateUtils.getUTCDate(2014, 10, 15); private static final double TRADE_PRICE_TIPS_1 = 0.99; private static final BondCapitalIndexedTransactionDefinition<CouponInflationZeroCouponInterpolationGearingDefinition> TIPS_16_TRA_DEFINITION = new BondCapitalIndexedTransactionDefinition<>(TIPS_16_SEC_DEFINITION, QUANTITY_TIPS_1, SETTLE_DATE_TIPS_1, TRADE_PRICE_TIPS_1); private static final BondCapitalIndexedTransaction<?> TIPS_16_TRA = TIPS_16_TRA_DEFINITION.toDerivative(CALIBRATION_DATE, HTS_CPI); /** Curves **/ private static final Pair<IssuerProviderDiscount, CurveBuildingBlockBundle> ISSUER_GOVT_PAIR = StandardDataSetsGovtUsInflationUSD.getCurvesUsdOisUsGovt(CALIBRATION_DATE); private static final IssuerProviderDiscount ISSUER_GOVT = ISSUER_GOVT_PAIR.getFirst(); // private static final CurveBuildingBlockBundle BLOCK_GOVT = ISSUER_GOVT_PAIR.getSecond(); private static final Pair<InflationProviderDiscount, CurveBuildingBlockBundle> INFL_PAIR = StandardDataSetsInflationUSD.getCurvesUsdOisUsCpi(CALIBRATION_DATE); private static final InflationProviderDiscount INFL = INFL_PAIR.getFirst(); // private static final CurveBuildingBlockBundle INFL_BLOCK = INFL_PAIR.getSecond(); private static final Pair<InflationIssuerProviderDiscount, CurveBuildingBlockBundle> INFL_ISSUER_GOVT_PAIR = StandardDataSetsGovtUsInflationUSD.getCurvesUsdOisUsGovtUsCpi(CALIBRATION_DATE); private static final InflationIssuerProviderDiscount INFL_ISSUER_GOVT = INFL_ISSUER_GOVT_PAIR.getFirst(); private static final CurveBuildingBlockBundle INFL_ISSUER_GOVT_BLOCK = INFL_ISSUER_GOVT_PAIR.getSecond(); private static final Pair<InflationIssuerProviderDiscount, CurveBuildingBlockBundle> INFL_ISSUER_GOVT_2_PAIR = StandardDataSetsGovtUsInflationUSD.getCurvesUsdOisUsGovtUsCpiCurrentSeasonality(CALIBRATION_DATE); private static final InflationIssuerProviderDiscount INFL_ISSUER_GOVT_2 = INFL_ISSUER_GOVT_2_PAIR.getFirst(); private static final CurveBuildingBlockBundle INFL_ISSUER_GOVT_2_BLOCK = INFL_ISSUER_GOVT_2_PAIR.getSecond(); private static final double TOLERANCE_PV = 1.0E-3; private static final double TOLERANCE_PV_DELTA = 1.0E-1; private static final double TOLERANCE_PRICE = 1.0E-8; private static final double BP1 = 1.0E-4; @Test public void presentValueBondFixed() { double pvExpected = 232186.2416; MultipleCurrencyAmount pvComputedIs = UST_TRA.accept(PVIssuerC, ISSUER_GOVT); assertEquals("BondCapitalIndexedDiscountingE2E: present value bond fixed", pvExpected, pvComputedIs.getAmount(USD), TOLERANCE_PV); MultipleCurrencyAmount pvComputedInIs = UST_TRA.accept(PVInflIssuerC, INFL_ISSUER_GOVT); assertEquals("BondCapitalIndexedDiscountingE2E: present value bond fixed", pvExpected, pvComputedInIs.getAmount(USD), TOLERANCE_PV); } @Test public void presentValueSwap() { double pvExpected = 697518.0714; MultipleCurrencyAmount pvIn = ZCI_2.accept(PVInflC, INFL); assertEquals("BondCapitalIndexedDiscountingE2E: present value ZC", pvExpected, pvIn.getAmount(USD), TOLERANCE_PV); MultipleCurrencyAmount pvInIs = ZCI_2.accept(PVInflIssuerC, INFL_ISSUER_GOVT); assertEquals("BondCapitalIndexedDiscountingE2E: present value ZC", pvExpected, pvInIs.getAmount(USD), TOLERANCE_PV); } @Test public void presentValueTips() { double pvExpected = 471980.9359; MultipleCurrencyAmount pv1 = TIPS_16_TRA.accept(PVInflIssuerC, INFL_ISSUER_GOVT); assertEquals("BondCapitalIndexedDiscountingE2E: present value TIPS", pvExpected, pv1.getAmount(USD), TOLERANCE_PV); } @Test public void presentValueTipsSeasonalityCurrent() { double pvExpected = 431401.1262; MultipleCurrencyAmount pv1 = TIPS_16_TRA.accept(PVInflIssuerC, INFL_ISSUER_GOVT_2); assertEquals("BondCapitalIndexedDiscountingE2E: present value TIPS", pvExpected, pv1.getAmount(USD), TOLERANCE_PV); } @Test public void bucketeParameterInflationProviderInterfacedPV01Tips() { final double[] deltaDsc = {-0.0250,15.3801,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000, 0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000}; final double[] deltaGovt = {-2.7315,-1.1653,-1060.3815,263.5878,0.0000,0.0000}; final double[] deltaCpi = {954.1522,524.2191,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000}; final LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensitivity = new LinkedHashMap<>(); sensitivity.put(ObjectsPair.of(INFL_ISSUER_GOVT.getName(USD), USD), new DoubleMatrix1D(deltaDsc)); sensitivity.put(ObjectsPair.of(INFL_ISSUER_GOVT.getIssuerProvider().getName(TIPS_16_SEC_DEFINITION.getIssuerEntity()), USD), new DoubleMatrix1D(deltaGovt)); sensitivity.put(ObjectsPair.of(INFL_ISSUER_GOVT.getName(US_CPI), USD), new DoubleMatrix1D(deltaCpi)); MultipleCurrencyParameterSensitivity pvpsExpected = new MultipleCurrencyParameterSensitivity(sensitivity); MultipleCurrencyParameterSensitivity pvpsComputed = MQISBC.fromInstrument(TIPS_16_TRA, INFL_ISSUER_GOVT, INFL_ISSUER_GOVT_BLOCK).multipliedBy(BP1); AssertSensitivityObjects.assertEquals("BondCapitalIndexedDiscountingE2E", pvpsExpected, pvpsComputed, TOLERANCE_PV_DELTA); } @Test public void bucketeParameterInflationProviderInterfacedPV01TipsSeasonalityCurrent() { final double[] deltaDsc = {-0.0123,15.3801,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000, 0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000}; final double[] deltaGovt = {-2.6934,-1.1980,-1056.9639,262.7236,0.0000,0.0000}; final double[] deltaCpi = {994.7588,522.2729,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.0000}; final LinkedHashMap<Pair<String, Currency>, DoubleMatrix1D> sensitivity = new LinkedHashMap<>(); sensitivity.put(ObjectsPair.of(INFL_ISSUER_GOVT.getName(USD), USD), new DoubleMatrix1D(deltaDsc)); sensitivity.put(ObjectsPair.of(INFL_ISSUER_GOVT.getIssuerProvider().getName(TIPS_16_SEC_DEFINITION.getIssuerEntity()), USD), new DoubleMatrix1D(deltaGovt)); sensitivity.put(ObjectsPair.of(INFL_ISSUER_GOVT.getName(US_CPI), USD), new DoubleMatrix1D(deltaCpi)); MultipleCurrencyParameterSensitivity pvpsExpected = new MultipleCurrencyParameterSensitivity(sensitivity); MultipleCurrencyParameterSensitivity pvpsComputed = MQISBC.fromInstrument(TIPS_16_TRA, INFL_ISSUER_GOVT_2, INFL_ISSUER_GOVT_2_BLOCK).multipliedBy(BP1); @SuppressWarnings("unused") MultipleCurrencyInflationSensitivity pvcsPoint = TIPS_16_TRA.accept(PVCSInflIssuerC, INFL_ISSUER_GOVT_2); @SuppressWarnings("unused") MultipleCurrencyParameterSensitivity pvcsParam = PSIC.calculateSensitivity(TIPS_16_TRA, INFL_ISSUER_GOVT_2); AssertSensitivityObjects.assertEquals("BondCapitalIndexedDiscountingE2E", pvpsExpected, pvpsComputed, TOLERANCE_PV_DELTA); } @Test public void cleanRealPriceTips() { double cleanRealPriceExpected = 1.0259067846; double cleanRealPrice = METHOD_CAPIND_BOND_SEC.cleanRealPriceFromCurves(TIPS_16_TRA.getBondStandard(), INFL_ISSUER_GOVT_2); assertEquals("BondCapitalIndexedDiscountingE2E: clean real price TIPS", cleanRealPriceExpected, cleanRealPrice, TOLERANCE_PRICE); } @Test public void yieldRealTips() { double yieldRealExpected = -6.680422530633629E-4; double yieldReal = METHOD_CAPIND_BOND_SEC.yieldRealFromCurves(TIPS_16_TRA.getBondStandard(), INFL_ISSUER_GOVT_2); assertEquals("BondCapitalIndexedDiscountingE2E: real yield TIPS", yieldRealExpected, yieldReal, TOLERANCE_PRICE); } @Test public void consistencyPricePvTips() { double cleanRealPrice = METHOD_CAPIND_BOND_SEC.cleanRealPriceFromCurves(TIPS_16_TRA.getBondStandard(), INFL_ISSUER_GOVT_2); ZonedDateTime settleDateStandard = ScheduleCalculator.getAdjustedDate(CALIBRATION_DATE, TIPS_16_SEC_DEFINITION.getSettlementDays(), TIPS_16_SEC_DEFINITION.getCalendar()); BondCapitalIndexedTransactionDefinition<CouponInflationZeroCouponInterpolationGearingDefinition> tipsAtmDefinition = new BondCapitalIndexedTransactionDefinition<>(TIPS_16_SEC_DEFINITION, QUANTITY_TIPS_1, settleDateStandard, cleanRealPrice); BondCapitalIndexedTransaction<?> tipsAtm = tipsAtmDefinition.toDerivative(CALIBRATION_DATE, HTS_CPI); MultipleCurrencyAmount pv1 = tipsAtm.accept(PVInflIssuerC, INFL_ISSUER_GOVT_2); assertEquals("BondCapitalIndexedDiscountingE2E: present value TIPS", 0.0, pv1.getAmount(USD), TOLERANCE_PV); } }