/**
* Copyright (C) 2015 - 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.basics.currency.Currency.USD;
import static org.testng.Assert.assertEquals;
import java.util.Map.Entry;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.basics.index.Index;
import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.collect.tuple.Pair;
import com.opengamma.strata.market.curve.Curve;
import com.opengamma.strata.market.curve.InterpolatedNodalCurve;
import com.opengamma.strata.market.curve.NodalCurve;
import com.opengamma.strata.market.param.CurrencyParameterSensitivities;
import com.opengamma.strata.pricer.DiscountFactors;
import com.opengamma.strata.pricer.SimpleDiscountFactors;
import com.opengamma.strata.pricer.ZeroRateDiscountFactors;
import com.opengamma.strata.pricer.bond.RepoGroup;
import com.opengamma.strata.pricer.bond.ImmutableLegalEntityDiscountingProvider;
import com.opengamma.strata.pricer.bond.LegalEntityGroup;
import com.opengamma.strata.pricer.datasets.LegalEntityDiscountingProviderDataSets;
import com.opengamma.strata.pricer.datasets.RatesProviderDataSets;
import com.opengamma.strata.pricer.rate.ImmutableRatesProvider;
/**
* Tests {@link RatesFiniteDifferenceSensitivityCalculator}.
*/
public class RatesFiniteDifferenceSensitivityCalculatorTest {
private static final RatesFiniteDifferenceSensitivityCalculator FD_CALCULATOR =
RatesFiniteDifferenceSensitivityCalculator.DEFAULT;
private static final double TOLERANCE_DELTA = 1.0E-8;
@Test
public void sensitivity_single_curve() {
CurrencyParameterSensitivities sensiComputed = FD_CALCULATOR.sensitivity(RatesProviderDataSets.SINGLE_USD, this::fn);
DoubleArray times = RatesProviderDataSets.TIMES_1;
assertEquals(sensiComputed.size(), 1);
DoubleArray s = sensiComputed.getSensitivities().get(0).getSensitivity();
assertEquals(s.size(), times.size());
for (int i = 0; i < times.size(); i++) {
assertEquals(s.get(i), times.get(i) * 4.0d, TOLERANCE_DELTA);
}
}
@Test
public void sensitivity_multi_curve() {
CurrencyParameterSensitivities sensiComputed = FD_CALCULATOR.sensitivity(RatesProviderDataSets.MULTI_CPI_USD, this::fn);
DoubleArray times1 = RatesProviderDataSets.TIMES_1;
DoubleArray times2 = RatesProviderDataSets.TIMES_2;
DoubleArray times3 = RatesProviderDataSets.TIMES_3;
DoubleArray times4 = RatesProviderDataSets.TIMES_4;
assertEquals(sensiComputed.size(), 4);
DoubleArray s1 = sensiComputed.getSensitivity(RatesProviderDataSets.USD_DSC_NAME, USD).getSensitivity();
assertEquals(s1.size(), times1.size());
for (int i = 0; i < times1.size(); i++) {
assertEquals(times1.get(i) * 2.0d, s1.get(i), TOLERANCE_DELTA);
}
DoubleArray s2 = sensiComputed.getSensitivity(RatesProviderDataSets.USD_L3_NAME, USD).getSensitivity();
assertEquals(s2.size(), times2.size());
for (int i = 0; i < times2.size(); i++) {
assertEquals(times2.get(i), s2.get(i), TOLERANCE_DELTA);
}
DoubleArray s3 = sensiComputed.getSensitivity(RatesProviderDataSets.USD_L6_NAME, USD).getSensitivity();
assertEquals(s3.size(), times3.size());
for (int i = 0; i < times3.size(); i++) {
assertEquals(times3.get(i), s3.get(i), TOLERANCE_DELTA);
}
DoubleArray s4 = sensiComputed.getSensitivity(RatesProviderDataSets.USD_CPI_NAME, USD).getSensitivity();
assertEquals(s4.size(), times4.size());
for (int i = 0; i < times4.size(); i++) {
assertEquals(times4.get(i), s4.get(i), TOLERANCE_DELTA);
}
}
// private function for testing. Returns the sum of rates multiplied by time
private CurrencyAmount fn(ImmutableRatesProvider provider) {
double result = 0.0;
// Currency
ImmutableMap<Currency, Curve> mapCurrency = provider.getDiscountCurves();
for (Entry<Currency, Curve> entry : mapCurrency.entrySet()) {
InterpolatedNodalCurve curveInt = checkInterpolated(entry.getValue());
result += sumProduct(curveInt);
}
// Index
ImmutableMap<Index, Curve> mapIndex = provider.getIndexCurves();
for (Entry<Index, Curve> entry : mapIndex.entrySet()) {
InterpolatedNodalCurve curveInt = checkInterpolated(entry.getValue());
result += sumProduct(curveInt);
}
return CurrencyAmount.of(USD, result);
}
// compute the sum of the product of times and rates
private double sumProduct(NodalCurve curveInt) {
double result = 0.0;
DoubleArray x = curveInt.getXValues();
DoubleArray y = curveInt.getYValues();
int nbNodePoint = x.size();
for (int i = 0; i < nbNodePoint; i++) {
result += x.get(i) * y.get(i);
}
return result;
}
// check that the curve is InterpolatedNodalCurve
private InterpolatedNodalCurve checkInterpolated(Curve curve) {
ArgChecker.isTrue(curve instanceof InterpolatedNodalCurve, "Curve should be a InterpolatedNodalCurve");
return (InterpolatedNodalCurve) curve;
}
//-------------------------------------------------------------------------
@Test
public void sensitivity_legalEntity_Zero() {
CurrencyParameterSensitivities sensiComputed = FD_CALCULATOR.sensitivity(
LegalEntityDiscountingProviderDataSets.ISSUER_REPO_ZERO, this::fn);
DoubleArray timeIssuer = LegalEntityDiscountingProviderDataSets.ISSUER_TIME_USD;
DoubleArray timesRepo = LegalEntityDiscountingProviderDataSets.REPO_TIME_USD;
assertEquals(sensiComputed.size(), 2);
DoubleArray sensiIssuer = sensiComputed.getSensitivity(
LegalEntityDiscountingProviderDataSets.META_ZERO_ISSUER_USD.getCurveName(), USD).getSensitivity();
assertEquals(sensiIssuer.size(), timeIssuer.size());
for (int i = 0; i < timeIssuer.size(); i++) {
assertEquals(timeIssuer.get(i), sensiIssuer.get(i), TOLERANCE_DELTA);
}
DoubleArray sensiRepo = sensiComputed.getSensitivity(
LegalEntityDiscountingProviderDataSets.META_ZERO_REPO_USD.getCurveName(), USD).getSensitivity();
assertEquals(sensiRepo.size(), timesRepo.size());
for (int i = 0; i < timesRepo.size(); i++) {
assertEquals(timesRepo.get(i), sensiRepo.get(i), TOLERANCE_DELTA);
}
}
@Test
public void sensitivity_legalEntity_Simple() {
CurrencyParameterSensitivities sensiComputed = FD_CALCULATOR.sensitivity(
LegalEntityDiscountingProviderDataSets.ISSUER_REPO_SIMPLE, this::fn);
DoubleArray timeIssuer = LegalEntityDiscountingProviderDataSets.ISSUER_TIME_USD;
DoubleArray timesRepo = LegalEntityDiscountingProviderDataSets.REPO_TIME_USD;
assertEquals(sensiComputed.size(), 2);
DoubleArray sensiIssuer = sensiComputed.getSensitivity(
LegalEntityDiscountingProviderDataSets.META_SIMPLE_ISSUER_USD.getCurveName(), USD).getSensitivity();
assertEquals(sensiIssuer.size(), timeIssuer.size());
for (int i = 0; i < timeIssuer.size(); i++) {
assertEquals(timeIssuer.get(i), sensiIssuer.get(i), TOLERANCE_DELTA);
}
DoubleArray sensiRepo = sensiComputed.getSensitivity(
LegalEntityDiscountingProviderDataSets.META_SIMPLE_REPO_USD.getCurveName(), USD).getSensitivity();
assertEquals(sensiRepo.size(), timesRepo.size());
for (int i = 0; i < timesRepo.size(); i++) {
assertEquals(timesRepo.get(i), sensiRepo.get(i), TOLERANCE_DELTA);
}
}
// private function for testing. Returns the sum of rates multiplied by time
private CurrencyAmount fn(ImmutableLegalEntityDiscountingProvider provider) {
double result = 0.0;
// issuer curve
ImmutableMap<Pair<LegalEntityGroup, Currency>, DiscountFactors> mapLegal = provider.metaBean().issuerCurves()
.get(provider);
for (Entry<Pair<LegalEntityGroup, Currency>, DiscountFactors> entry : mapLegal.entrySet()) {
InterpolatedNodalCurve curveInt = checkInterpolated(checkDiscountFactors(entry.getValue()));
result += sumProduct(curveInt);
}
// repo curve
ImmutableMap<Pair<RepoGroup, Currency>, DiscountFactors> mapRepo = provider.metaBean().repoCurves().get(provider);
for (Entry<Pair<RepoGroup, Currency>, DiscountFactors> entry : mapRepo.entrySet()) {
InterpolatedNodalCurve curveInt = checkInterpolated(checkDiscountFactors(entry.getValue()));
result += sumProduct(curveInt);
}
return CurrencyAmount.of(USD, result);
}
private Curve checkDiscountFactors(DiscountFactors discountFactors) {
if (discountFactors instanceof ZeroRateDiscountFactors) {
return ((ZeroRateDiscountFactors) discountFactors).getCurve();
} else if (discountFactors instanceof SimpleDiscountFactors) {
return ((SimpleDiscountFactors) discountFactors).getCurve();
}
throw new IllegalArgumentException("Not supported");
}
}