/**
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.sensitivity;
import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import org.testng.annotations.Test;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.date.Tenor;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.market.curve.CurveName;
import com.opengamma.strata.market.param.CurrencyParameterSensitivities;
import com.opengamma.strata.market.param.CurrencyParameterSensitivity;
import com.opengamma.strata.market.param.LabelDateParameterMetadata;
import com.opengamma.strata.market.param.ParameterMetadata;
import com.opengamma.strata.market.param.TenorParameterMetadata;
/**
* Tests {@link CurveSensitivityUtils}.
*/
@Test
public class CurveSensitivityUtilsTest {
private static final CurveName NAME_1 = CurveName.of("CURVE 1");
private static final Currency CCY_1 = Currency.EUR;
private static final CurveName NAME_2 = CurveName.of("CURVE 2");
private static final Currency CCY_2 = Currency.USD;
private static final List<LocalDate> TARGET_DATES = new ArrayList<>();
static {
TARGET_DATES.add(LocalDate.of(2016, 8, 18));
TARGET_DATES.add(LocalDate.of(2020, 1, 5));
TARGET_DATES.add(LocalDate.of(2025, 12, 20));
TARGET_DATES.add(LocalDate.of(2045, 7, 4));
}
private static final List<LocalDate> SENSITIVITY_DATES = new ArrayList<>();
static {
SENSITIVITY_DATES.add(LocalDate.of(2016, 8, 17));
SENSITIVITY_DATES.add(LocalDate.of(2016, 8, 18));
SENSITIVITY_DATES.add(LocalDate.of(2016, 8, 19));
SENSITIVITY_DATES.add(LocalDate.of(2019, 1, 5));
SENSITIVITY_DATES.add(LocalDate.of(2020, 1, 5));
SENSITIVITY_DATES.add(LocalDate.of(2021, 1, 5));
SENSITIVITY_DATES.add(LocalDate.of(2024, 12, 25));
SENSITIVITY_DATES.add(LocalDate.of(2025, 12, 20));
SENSITIVITY_DATES.add(LocalDate.of(2026, 12, 15));
SENSITIVITY_DATES.add(LocalDate.of(2045, 7, 4));
SENSITIVITY_DATES.add(LocalDate.of(2055, 7, 4));
}
private static final double SENSITIVITY_AMOUNT = 123.45;
private static final double[] WEIGHTS_HC =
{1.0, 1.0, 0.999190283, 0.295546559, 0.0, 0.831801471, 0.165441176, 1.0, 0.94955157, 0.0, 0.0 };
// weights externally provided and hard-coded here
private static final int[] WEIGHTS_START = {0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 2 };
private static final double TOLERANCE_SENSI = 1.0E-5;
public void hard_coded_value_one_curve_one_date_dated() {
Function<LocalDate, ParameterMetadata> parameterMetadataFunction =
(d) -> LabelDateParameterMetadata.of(d, "test");
Function<CurrencyParameterSensitivities, CurrencyParameterSensitivities> rebucketFunction =
(s) -> CurveSensitivityUtils.linearRebucketing(s, TARGET_DATES);
test_from_functions_one_curve_one_date(parameterMetadataFunction, rebucketFunction);
}
public void hard_coded_value_one_curve_one_date_tenor() {
final LocalDate sensitivityDate = LocalDate.of(2015, 8, 18);
Function<LocalDate, ParameterMetadata> parameterMetadataFunction =
(d) -> TenorParameterMetadata.of(Tenor
.of(Period.ofDays((int) (d.toEpochDay() - sensitivityDate.toEpochDay()))));
Function<CurrencyParameterSensitivities, CurrencyParameterSensitivities> rebucketFunction =
(s) -> CurveSensitivityUtils.linearRebucketing(s, TARGET_DATES, sensitivityDate);
test_from_functions_one_curve_one_date(parameterMetadataFunction, rebucketFunction);
}
public void hard_coded_value_one_curve_one_date_dated_sd() {
final LocalDate sensitivityDate = LocalDate.of(2015, 8, 18);
Function<LocalDate, ParameterMetadata> parameterMetadataFunction =
(d) -> LabelDateParameterMetadata.of(d, "test");
Function<CurrencyParameterSensitivities, CurrencyParameterSensitivities> rebucketFunction =
(s) -> CurveSensitivityUtils.linearRebucketing(s, TARGET_DATES, sensitivityDate);
test_from_functions_one_curve_one_date(parameterMetadataFunction, rebucketFunction);
}
private void test_from_functions_one_curve_one_date(
Function<LocalDate, ParameterMetadata> parameterMetadataFunction,
Function<CurrencyParameterSensitivities, CurrencyParameterSensitivities> rebucketFunction) {
for (int loopdate = 0; loopdate < SENSITIVITY_DATES.size(); loopdate++) {
List<ParameterMetadata> pmdInput = new ArrayList<>();
pmdInput.add(parameterMetadataFunction.apply(SENSITIVITY_DATES.get(loopdate)));
CurrencyParameterSensitivity s =
CurrencyParameterSensitivity.of(NAME_1, pmdInput, CCY_1, DoubleArray.of(SENSITIVITY_AMOUNT));
CurrencyParameterSensitivities s2 = CurrencyParameterSensitivities.of(s);
CurrencyParameterSensitivities sTarget = rebucketFunction.apply(s2);
assertTrue(sTarget.getSensitivities().size() == 1);
CurrencyParameterSensitivity sTarget1 = sTarget.getSensitivities().get(0);
assertTrue(sTarget1.getMarketDataName().equals(NAME_1));
assertTrue(sTarget1.getCurrency().equals(CCY_1));
assertTrue(sTarget1.getSensitivity().size() == TARGET_DATES.size());
assertEquals(sTarget1.getSensitivity().get(WEIGHTS_START[loopdate]),
WEIGHTS_HC[loopdate] * SENSITIVITY_AMOUNT, TOLERANCE_SENSI);
assertEquals(sTarget1.getSensitivity().get(WEIGHTS_START[loopdate] + 1),
(1.0d - WEIGHTS_HC[loopdate]) * SENSITIVITY_AMOUNT, TOLERANCE_SENSI);
}
}
public void hard_coded_value_one_curve_all_dates() {
Function<LocalDate, ParameterMetadata> parameterMetadataFunction =
(d) -> LabelDateParameterMetadata.of(d, "test");
Function<CurrencyParameterSensitivities, CurrencyParameterSensitivities> rebucketFunction =
(s) -> CurveSensitivityUtils.linearRebucketing(s, TARGET_DATES);
test_from_functions_one_curve_all_dates(parameterMetadataFunction, rebucketFunction);
}
public void hard_coded_value_one_curve_all_dates_tenor() {
final LocalDate sensitivityDate = LocalDate.of(2015, 8, 18);
Function<LocalDate, ParameterMetadata> parameterMetadataFunction =
(d) -> TenorParameterMetadata.of(Tenor
.of(Period.ofDays((int) (d.toEpochDay() - sensitivityDate.toEpochDay()))));
Function<CurrencyParameterSensitivities, CurrencyParameterSensitivities> rebucketFunction =
(s) -> CurveSensitivityUtils.linearRebucketing(s, TARGET_DATES, sensitivityDate);
test_from_functions_one_curve_all_dates(parameterMetadataFunction, rebucketFunction);
}
public void hard_coded_value_one_curve_all_dates_dated_sd() {
final LocalDate sensitivityDate = LocalDate.of(2015, 8, 18);
Function<LocalDate, ParameterMetadata> parameterMetadataFunction =
(d) -> LabelDateParameterMetadata.of(d, "test");
Function<CurrencyParameterSensitivities, CurrencyParameterSensitivities> rebucketFunction =
(s) -> CurveSensitivityUtils.linearRebucketing(s, TARGET_DATES, sensitivityDate);
test_from_functions_one_curve_all_dates(parameterMetadataFunction, rebucketFunction);
}
private void test_from_functions_one_curve_all_dates(
Function<LocalDate, ParameterMetadata> parameterMetadataFunction,
Function<CurrencyParameterSensitivities, CurrencyParameterSensitivities> rebucketFunction) {
List<ParameterMetadata> pmdInput = new ArrayList<>();
double[] sensiExpected = new double[TARGET_DATES.size()];
for (int loopdate = 0; loopdate < SENSITIVITY_DATES.size(); loopdate++) {
pmdInput.add(parameterMetadataFunction.apply(SENSITIVITY_DATES.get(loopdate)));
sensiExpected[WEIGHTS_START[loopdate]] += WEIGHTS_HC[loopdate] * SENSITIVITY_AMOUNT;
sensiExpected[WEIGHTS_START[loopdate] + 1] += (1.0d - WEIGHTS_HC[loopdate]) * SENSITIVITY_AMOUNT;
}
DoubleArray sens = DoubleArray.of(SENSITIVITY_DATES.size(), (d) -> SENSITIVITY_AMOUNT);
CurrencyParameterSensitivity s = CurrencyParameterSensitivity.of(NAME_1, pmdInput, CCY_1, sens);
CurrencyParameterSensitivities s2 = CurrencyParameterSensitivities.of(s);
CurrencyParameterSensitivities sTarget = rebucketFunction.apply(s2);
assertTrue(sTarget.getSensitivities().size() == 1);
CurrencyParameterSensitivity sTarget1 = sTarget.getSensitivities().get(0);
assertTrue(sTarget1.getMarketDataName().equals(NAME_1));
assertTrue(sTarget1.getCurrency().equals(CCY_1));
assertTrue(sTarget1.getSensitivity().size() == TARGET_DATES.size());
for (int looptarget = 0; looptarget < TARGET_DATES.size(); looptarget++) {
assertEquals(sTarget1.getSensitivity().get(looptarget), sensiExpected[looptarget], TOLERANCE_SENSI);
}
}
public void hard_coded_value_two_curves_one_date() {
for (int loopdate = 0; loopdate < SENSITIVITY_DATES.size() - 1; loopdate++) {
List<ParameterMetadata> pmdInput1 = new ArrayList<>();
pmdInput1.add(LabelDateParameterMetadata.of(SENSITIVITY_DATES.get(loopdate), "test"));
CurrencyParameterSensitivity s1 =
CurrencyParameterSensitivity.of(NAME_1, pmdInput1, CCY_1, DoubleArray.of(SENSITIVITY_AMOUNT));
List<ParameterMetadata> pmdInput2 = new ArrayList<>();
pmdInput2.add(LabelDateParameterMetadata.of(SENSITIVITY_DATES.get(loopdate + 1), "test"));
CurrencyParameterSensitivity s2 =
CurrencyParameterSensitivity.of(NAME_2, pmdInput2, CCY_2, DoubleArray.of(SENSITIVITY_AMOUNT));
CurrencyParameterSensitivities sList = CurrencyParameterSensitivities.of(s1, s2);
CurrencyParameterSensitivities sTarget = CurveSensitivityUtils.linearRebucketing(sList, TARGET_DATES);
assertTrue(sTarget.getSensitivities().size() == 2);
CurrencyParameterSensitivity sTarget1 = sTarget.getSensitivities().get(0);
assertTrue(sTarget1.getMarketDataName().equals(NAME_1));
assertTrue(sTarget1.getCurrency().equals(CCY_1));
assertTrue(sTarget1.getSensitivity().size() == TARGET_DATES.size());
assertEquals(sTarget1.getSensitivity().get(WEIGHTS_START[loopdate]),
WEIGHTS_HC[loopdate] * SENSITIVITY_AMOUNT, TOLERANCE_SENSI);
assertEquals(sTarget1.getSensitivity().get(WEIGHTS_START[loopdate] + 1),
(1.0d - WEIGHTS_HC[loopdate]) * SENSITIVITY_AMOUNT, TOLERANCE_SENSI);
CurrencyParameterSensitivity sTarget2 = sTarget.getSensitivities().get(1);
assertTrue(sTarget2.getMarketDataName().equals(NAME_2));
assertTrue(sTarget2.getCurrency().equals(CCY_2));
assertTrue(sTarget2.getSensitivity().size() == TARGET_DATES.size());
assertEquals(sTarget2.getSensitivity().get(WEIGHTS_START[loopdate + 1]),
WEIGHTS_HC[loopdate + 1] * SENSITIVITY_AMOUNT, TOLERANCE_SENSI);
assertEquals(sTarget2.getSensitivity().get(WEIGHTS_START[loopdate + 1] + 1),
(1.0d - WEIGHTS_HC[loopdate + 1]) * SENSITIVITY_AMOUNT, TOLERANCE_SENSI);
}
}
public void missing_metadata() {
CurrencyParameterSensitivity s1 =
CurrencyParameterSensitivity.of(NAME_1, CCY_1, DoubleArray.of(SENSITIVITY_AMOUNT));
CurrencyParameterSensitivities s2 = CurrencyParameterSensitivities.of(s1);
assertThrowsIllegalArg(() -> CurveSensitivityUtils.linearRebucketing(s2, TARGET_DATES));
final LocalDate sensitivityDate = LocalDate.of(2015, 8, 18);
assertThrowsIllegalArg(() -> CurveSensitivityUtils.linearRebucketing(s2, TARGET_DATES, sensitivityDate));
}
public void wrong_metadata() {
List<ParameterMetadata> pmdInput = new ArrayList<>();
pmdInput.add(TenorParameterMetadata.of(Tenor.TENOR_10M));
CurrencyParameterSensitivity s1 =
CurrencyParameterSensitivity.of(NAME_1, pmdInput, CCY_1, DoubleArray.of(SENSITIVITY_AMOUNT));
CurrencyParameterSensitivities s2 = CurrencyParameterSensitivities.of(s1);
assertThrowsIllegalArg(() -> CurveSensitivityUtils.linearRebucketing(s2, TARGET_DATES));
}
}