/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.pricer.rate; import static com.opengamma.strata.basics.currency.Currency.USD; import static com.opengamma.strata.basics.index.PriceIndices.GB_HICP; import static com.opengamma.strata.basics.index.PriceIndices.US_CPI_U; 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 java.time.temporal.ChronoUnit.MONTHS; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.time.LocalDate; import java.time.YearMonth; import java.util.Optional; import org.testng.annotations.Test; import com.opengamma.strata.basics.index.PriceIndexObservation; import com.opengamma.strata.collect.array.DoubleArray; import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeries; import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeriesBuilder; import com.opengamma.strata.market.ShiftType; import com.opengamma.strata.market.curve.CurveMetadata; import com.opengamma.strata.market.curve.CurveName; import com.opengamma.strata.market.curve.Curves; import com.opengamma.strata.market.curve.InterpolatedNodalCurve; import com.opengamma.strata.market.curve.InflationNodalCurve; import com.opengamma.strata.market.curve.SeasonalityDefinition; import com.opengamma.strata.market.curve.interpolator.CurveInterpolator; import com.opengamma.strata.market.curve.interpolator.CurveInterpolators; import com.opengamma.strata.market.param.CurrencyParameterSensitivities; import com.opengamma.strata.market.param.UnitParameterSensitivities; import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder; /** * Tests {@link SimplePriceIndexValues}. */ @Test public class SimplePriceIndexValuesTest { private static final LocalDate VAL_DATE = LocalDate.of(2015, 5, 3); private static final YearMonth VAL_MONTH = YearMonth.of(2015, 5); // USD HICP, CPURNSA Index private static final double[] USCPI_VALUES = new double[] { 211.143, 212.193, 212.709, 213.240, 213.856, 215.693, 215.351, 215.834, 215.969, 216.177, 216.330, 215.949, // 2009 216.687, 216.741, 217.631, 218.009, 218.178, 217.965, 218.011, 218.312, 218.439, 218.711, 218.803, 219.179, // 2010 220.223, 221.309, 223.467, 224.906, 225.964, 225.722, 225.922, 226.545, 226.889, 226.421, 226.230, 225.672, // 2011 226.655, 227.663, 229.392, 230.085, 229.815, 229.478, 229.104, 230.379, 231.407, 231.317, 230.221, 229.601, // 2012 230.280, 232.166, 232.773, 232.531, 232.945, 233.504, 233.596, 233.877, 234.149, 233.546, 233.069, 233.049, // 2013 233.916, 234.781, 236.293, 237.072, 237.900, 238.343, 238.250, 237.852, 238.031, 237.433, 236.151, 234.812, // 2014 233.707, 234.722, 236.119}; // 2015 private static final LocalDate USCPI_START_DATE = LocalDate.of(2009, 1, 31); private static final LocalDateDoubleTimeSeries USCPI_TS; static { LocalDateDoubleTimeSeriesBuilder builder = LocalDateDoubleTimeSeries.builder(); for (int i = 0; i < USCPI_VALUES.length; i++) { builder.put(USCPI_START_DATE.plusMonths(i), USCPI_VALUES[i]); } USCPI_TS = builder.build(); } private static final DoubleArray TIMES = DoubleArray.of(9.0, 21.0, 57.0, 117.0); private static final DoubleArray VALUES = DoubleArray.of(240.500, 245.000, 265.000, 286.000); private static final DoubleArray VALUES2 = DoubleArray.of(243.500, 248.000, 268.000, 289.000); private static final CurveInterpolator INTERPOLATOR = CurveInterpolators.LINEAR; private static final CurveName NAME = CurveName.of("USD-HICP"); private static final CurveMetadata METADATA = Curves.prices(NAME); private static final InterpolatedNodalCurve CURVE_NOFIX = InterpolatedNodalCurve.of(METADATA, TIMES, VALUES, INTERPOLATOR); private static final InterpolatedNodalCurve CURVE2_NOFIX = InterpolatedNodalCurve.of(METADATA, TIMES, VALUES2, INTERPOLATOR); private static final DoubleArray SEASONALITY_MULTIPLICATIVE = DoubleArray.of( 1.002754153722096, 1.001058905136103, 1.006398754528882, 1.000862459308375, 0.998885402944655, 0.995571243121412, 1.001419845026233, 1.001663068058397, 0.999147014890734, 0.998377467899150, 0.999570726482709, 0.994346721844999); private static final SimplePriceIndexValues INSTANCE = SimplePriceIndexValues.of(US_CPI_U, VAL_DATE, CURVE_NOFIX, USCPI_TS); private static final YearMonth[] TEST_MONTHS = new YearMonth[] { YearMonth.of(2015, 1), YearMonth.of(2015, 5), YearMonth.of(2016, 5), YearMonth.of(2016, 6), YearMonth.of(2024, 12)}; private static final PriceIndexObservation[] TEST_OBS = new PriceIndexObservation[] { PriceIndexObservation.of(US_CPI_U, YearMonth.of(2015, 1)), PriceIndexObservation.of(US_CPI_U, YearMonth.of(2015, 5)), PriceIndexObservation.of(US_CPI_U, YearMonth.of(2016, 5)), PriceIndexObservation.of(US_CPI_U, YearMonth.of(2016, 6)), PriceIndexObservation.of(US_CPI_U, YearMonth.of(2024, 12))}; private static final double TOLERANCE_VALUE = 1.0E-10; private static final double TOLERANCE_DELTA = 1.0E-6; //------------------------------------------------------------------------- @SuppressWarnings("deprecation") public void test_NO_SEASONALITY() { assertEquals(SimplePriceIndexValues.NO_SEASONALITY, DoubleArray.filled(12, 1d)); } @SuppressWarnings("deprecation") public void test_of_noSeasonality() { SimplePriceIndexValues test = SimplePriceIndexValues.of(US_CPI_U, VAL_DATE, CURVE_NOFIX, USCPI_TS); assertEquals(test.getIndex(), US_CPI_U); assertEquals(test.getValuationDate(), VAL_DATE); assertEquals(test.getSeasonality(), DoubleArray.filled(12, 1d)); assertEquals(test.getCurve(), CURVE_NOFIX); assertEquals(test.getParameterCount(), CURVE_NOFIX.getParameterCount()); assertEquals(test.getParameter(0), CURVE_NOFIX.getParameter(0)); assertEquals(test.getParameterMetadata(0), CURVE_NOFIX.getParameterMetadata(0)); assertEquals(test.withParameter(0, 1d).getCurve(), CURVE_NOFIX.withParameter(0, 1d)); assertEquals(test.withPerturbation((i, v, m) -> v + 1d).getCurve(), CURVE_NOFIX.withPerturbation((i, v, m) -> v + 1d)); assertEquals(test.findData(CURVE_NOFIX.getName()), Optional.of(CURVE_NOFIX)); assertEquals(test.findData(CurveName.of("Rubbish")), Optional.empty()); // check PriceIndexValues PriceIndexValues test2 = PriceIndexValues.of(US_CPI_U, VAL_DATE, CURVE_NOFIX, USCPI_TS); assertEquals(test, test2); } @SuppressWarnings("deprecation") public void test_of_seasonality() { SimplePriceIndexValues test = SimplePriceIndexValues.of(US_CPI_U, VAL_DATE, CURVE_NOFIX, USCPI_TS, SEASONALITY_MULTIPLICATIVE); assertEquals(test.getIndex(), US_CPI_U); assertEquals(test.getValuationDate(), VAL_DATE); assertEquals(test.getSeasonality(), SEASONALITY_MULTIPLICATIVE); YearMonth lastMonth = YearMonth.from(USCPI_TS.getLatestDate()); double nbMonth = YearMonth.from(VAL_DATE).until(lastMonth, MONTHS); InflationNodalCurve seasonalCurve = InflationNodalCurve.of( CURVE_NOFIX, VAL_DATE, lastMonth, nbMonth, SeasonalityDefinition.of(SEASONALITY_MULTIPLICATIVE, ShiftType.SCALED)); assertEquals(test.getCurve(), seasonalCurve); } @SuppressWarnings("deprecation") public void test_of_wrongSeasonalityLength() { assertThrowsIllegalArg(() -> SimplePriceIndexValues.of( US_CPI_U, VAL_DATE, CURVE_NOFIX, USCPI_TS, DoubleArray.EMPTY)); } @SuppressWarnings("deprecation") public void test_of_startDateBeforeFixing() { DoubleArray monthWrong = DoubleArray.of(-10.0, 21.0, 57.0, 117.0); InterpolatedNodalCurve interpolated = CURVE_NOFIX.toBuilder().xValues(monthWrong).build(); assertThrowsIllegalArg(() -> SimplePriceIndexValues.of( US_CPI_U, VAL_DATE, interpolated, USCPI_TS, SEASONALITY_MULTIPLICATIVE)); } //------------------------------------------------------------------------- public void test_valuePointSensitivity_fixing() { SimplePriceIndexValues test = SimplePriceIndexValues.of(US_CPI_U, VAL_DATE, CURVE_NOFIX, USCPI_TS); PriceIndexObservation obs = PriceIndexObservation.of(US_CPI_U, VAL_MONTH.minusMonths(3)); assertEquals(test.valuePointSensitivity(obs), PointSensitivityBuilder.none()); } public void test_valuePointSensitivity_forward() { YearMonth month = VAL_MONTH.plusMonths(3); SimplePriceIndexValues test = SimplePriceIndexValues.of(US_CPI_U, VAL_DATE, CURVE_NOFIX, USCPI_TS); PriceIndexObservation obs = PriceIndexObservation.of(US_CPI_U, month); InflationRateSensitivity expected = InflationRateSensitivity.of(obs, 1d); assertEquals(test.valuePointSensitivity(obs), expected); } //------------------------------------------------------------------------- // proper end-to-end tests are elsewhere public void test_parameterSensitivity() { SimplePriceIndexValues test = SimplePriceIndexValues.of(US_CPI_U, VAL_DATE, CURVE_NOFIX, USCPI_TS); InflationRateSensitivity point = InflationRateSensitivity.of(PriceIndexObservation.of(US_CPI_U, VAL_MONTH.plusMonths(3)), 1d); assertEquals(test.parameterSensitivity(point).size(), 1); } //------------------------------------------------------------------------- public void test_createParameterSensitivity() { SimplePriceIndexValues test = SimplePriceIndexValues.of(US_CPI_U, VAL_DATE, CURVE_NOFIX, USCPI_TS); DoubleArray sensitivities = DoubleArray.of(0.12, 0.15, 0.16, 0.17); CurrencyParameterSensitivities sens = test.createParameterSensitivity(USD, sensitivities); assertEquals(sens.getSensitivities().get(0), CURVE_NOFIX.createParameterSensitivity(USD, sensitivities)); } //------------------------------------------------------------------------- public void test_withCurve() { SimplePriceIndexValues test = SimplePriceIndexValues.of(US_CPI_U, VAL_DATE, CURVE_NOFIX, USCPI_TS).withCurve(CURVE2_NOFIX); assertEquals(test.getCurve(), CURVE2_NOFIX); } //------------------------------------------------------------------------- public void test_parameter_count() { assertEquals(INSTANCE.getParameterCount(), CURVE_NOFIX.getParameterCount()); } public void test_parameter() { assertEquals(INSTANCE.getParameter(2), CURVE_NOFIX.getParameter(2)); } public void test_parameter_metadata() { assertEquals(INSTANCE.getParameterMetadata(2), CURVE_NOFIX.getParameterMetadata(2)); } //------------------------------------------------------------------------- public void test_value() { for (int i = 0; i < TEST_MONTHS.length; i++) { double valueComputed = INSTANCE.value(TEST_OBS[i]); YearMonth fixingMonth = TEST_OBS[i].getFixingMonth(); double valueExpected; if (USCPI_TS.containsDate(fixingMonth.atEndOfMonth())) { valueExpected = USCPI_TS.get(fixingMonth.atEndOfMonth()).getAsDouble(); } else { double x = YearMonth.from(VAL_DATE).until(fixingMonth, MONTHS); valueExpected = CURVE_NOFIX.yValue(x); } assertEquals(valueComputed, valueExpected, TOLERANCE_VALUE, "test " + i); } } public void test_value_pts_sensitivity() { for (int i = 0; i < TEST_MONTHS.length; i++) { PointSensitivityBuilder ptsComputed = INSTANCE.valuePointSensitivity(TEST_OBS[i]); YearMonth fixingMonth = TEST_OBS[i].getFixingMonth(); PointSensitivityBuilder ptsExpected; if (USCPI_TS.containsDate(fixingMonth.atEndOfMonth())) { ptsExpected = PointSensitivityBuilder.none(); } else { ptsExpected = InflationRateSensitivity.of(TEST_OBS[i], 1d); } assertTrue(ptsComputed.build().equalWithTolerance(ptsExpected.build(), TOLERANCE_VALUE), "test " + i); } } public void test_value_parameter_sensitivity() { for (int i = 0; i < TEST_MONTHS.length; i++) { YearMonth fixingMonth = TEST_OBS[i].getFixingMonth(); if (!USCPI_TS.containsDate(fixingMonth.atEndOfMonth())) { InflationRateSensitivity ptsExpected = (InflationRateSensitivity) InflationRateSensitivity.of(TEST_OBS[i], 1d); CurrencyParameterSensitivities psComputed = INSTANCE.parameterSensitivity(ptsExpected); double x = YearMonth.from(VAL_DATE).until(fixingMonth, MONTHS); UnitParameterSensitivities sens1 = UnitParameterSensitivities.of(CURVE_NOFIX.yValueParameterSensitivity(x)); CurrencyParameterSensitivities psExpected = sens1.multipliedBy(ptsExpected.getCurrency(), ptsExpected.getSensitivity()); assertTrue(psComputed.equalWithTolerance(psExpected, TOLERANCE_DELTA), "test " + i); } } } //------------------------------------------------------------------------- public void coverage() { SimplePriceIndexValues instance1 = SimplePriceIndexValues.of(US_CPI_U, VAL_DATE, CURVE_NOFIX, USCPI_TS); coverImmutableBean(instance1); SimplePriceIndexValues test2 = SimplePriceIndexValues.of( GB_HICP, VAL_DATE.plusMonths(1), CURVE_NOFIX, LocalDateDoubleTimeSeries.of(VAL_MONTH.minusMonths(2).atEndOfMonth(), 100d)); coverBeanEquals(instance1, test2); } }