/**
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.inflation;
import static com.opengamma.sesame.config.ConfigBuilder.argument;
import static com.opengamma.sesame.config.ConfigBuilder.arguments;
import static com.opengamma.sesame.config.ConfigBuilder.config;
import static com.opengamma.sesame.config.ConfigBuilder.function;
import static com.opengamma.sesame.config.ConfigBuilder.implementations;
import static com.opengamma.util.money.Currency.USD;
import static com.opengamma.util.result.ResultTestUtils.assertSuccess;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.closeTo;
import static org.mockito.Mockito.mock;
import static org.testng.AssertJUnit.assertEquals;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.threeten.bp.Instant;
import org.threeten.bp.LocalDate;
import org.threeten.bp.LocalTime;
import org.threeten.bp.OffsetTime;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.opengamma.analytics.financial.instrument.index.IndexPrice;
import com.opengamma.analytics.financial.model.interestrate.curve.PriceIndexCurveSimple;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve;
import com.opengamma.analytics.financial.provider.curve.CurveBuildingBlock;
import com.opengamma.analytics.financial.provider.curve.CurveBuildingBlockBundle;
import com.opengamma.analytics.financial.provider.description.inflation.InflationIssuerProviderDiscount;
import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve;
import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory;
import com.opengamma.analytics.math.interpolation.Interpolator1D;
import com.opengamma.analytics.math.interpolation.Interpolator1DFactory;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.analytics.math.matrix.IdentityMatrix;
import com.opengamma.core.config.ConfigSource;
import com.opengamma.core.config.impl.ConfigItem;
import com.opengamma.core.convention.ConventionSource;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeriesSource;
import com.opengamma.core.holiday.HolidaySource;
import com.opengamma.core.holiday.impl.WeekendHolidaySource;
import com.opengamma.core.id.ExternalSchemes;
import com.opengamma.core.legalentity.LegalEntitySource;
import com.opengamma.core.link.ConfigLink;
import com.opengamma.core.position.Counterparty;
import com.opengamma.core.position.impl.SimpleCounterparty;
import com.opengamma.core.position.impl.SimpleTrade;
import com.opengamma.core.region.RegionSource;
import com.opengamma.core.region.impl.SimpleRegion;
import com.opengamma.core.security.SecuritySource;
import com.opengamma.financial.analytics.curve.CurveDefinition;
import com.opengamma.financial.analytics.curve.exposure.CurrencyExposureFunction;
import com.opengamma.financial.analytics.curve.exposure.ExposureFunctions;
import com.opengamma.financial.analytics.ircurve.strips.ContinuouslyCompoundedRateNode;
import com.opengamma.financial.analytics.ircurve.strips.CurveNode;
import com.opengamma.financial.analytics.model.fixedincome.BucketedCurveSensitivities;
import com.opengamma.financial.convention.ConventionBundleSource;
import com.opengamma.financial.convention.businessday.BusinessDayConvention;
import com.opengamma.financial.convention.businessday.BusinessDayConventions;
import com.opengamma.financial.convention.daycount.DayCounts;
import com.opengamma.financial.convention.frequency.Frequency;
import com.opengamma.financial.convention.frequency.SimpleFrequency;
import com.opengamma.financial.currency.CurrencyMatrix;
import com.opengamma.financial.security.index.PriceIndex;
import com.opengamma.financial.security.swap.FixedInflationSwapLeg;
import com.opengamma.financial.security.swap.InflationIndexSwapLeg;
import com.opengamma.financial.security.swap.InterestRateNotional;
import com.opengamma.financial.security.swap.InterpolationMethod;
import com.opengamma.financial.security.swap.Notional;
import com.opengamma.financial.security.swap.ZeroCouponInflationSwapSecurity;
import com.opengamma.id.ExternalId;
import com.opengamma.id.UniqueId;
import com.opengamma.master.config.ConfigDocument;
import com.opengamma.master.config.ConfigMaster;
import com.opengamma.master.config.impl.InMemoryConfigMaster;
import com.opengamma.master.config.impl.MasterConfigSource;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolver;
import com.opengamma.master.region.RegionDocument;
import com.opengamma.master.region.RegionMaster;
import com.opengamma.master.region.impl.InMemoryRegionMaster;
import com.opengamma.master.region.impl.MasterRegionSource;
import com.opengamma.master.security.SecurityDocument;
import com.opengamma.master.security.SecurityMaster;
import com.opengamma.master.security.impl.InMemorySecurityMaster;
import com.opengamma.master.security.impl.MasterSecuritySource;
import com.opengamma.service.ServiceContext;
import com.opengamma.service.ThreadLocalServiceContext;
import com.opengamma.service.VersionCorrectionProvider;
import com.opengamma.sesame.CurveDefinitionCurveLabellingFn;
import com.opengamma.sesame.CurveDefinitionFn;
import com.opengamma.sesame.CurveLabellingFn;
import com.opengamma.sesame.CurveSelector;
import com.opengamma.sesame.DefaultCurveDefinitionFn;
import com.opengamma.sesame.DefaultFixingsFn;
import com.opengamma.sesame.Environment;
import com.opengamma.sesame.FixingsFn;
import com.opengamma.sesame.InflationProviderBundle;
import com.opengamma.sesame.MarketExposureSelector;
import com.opengamma.sesame.cache.FunctionCache;
import com.opengamma.sesame.cache.NoOpFunctionCache;
import com.opengamma.sesame.config.FunctionModelConfig;
import com.opengamma.sesame.engine.CalculationArguments;
import com.opengamma.sesame.engine.ComponentMap;
import com.opengamma.sesame.engine.FixedInstantVersionCorrectionProvider;
import com.opengamma.sesame.engine.FunctionRunner;
import com.opengamma.sesame.graph.FunctionModel;
import com.opengamma.sesame.marketdata.DefaultHistoricalMarketDataFn;
import com.opengamma.sesame.marketdata.EmptyMarketDataFactory;
import com.opengamma.sesame.marketdata.EmptyMarketDataSpec;
import com.opengamma.sesame.marketdata.HistoricalMarketDataFn;
import com.opengamma.sesame.marketdata.InflationMulticurveId;
import com.opengamma.sesame.marketdata.MarketDataEnvironment;
import com.opengamma.sesame.marketdata.MarketDataEnvironmentBuilder;
import com.opengamma.sesame.marketdata.RawId;
import com.opengamma.sesame.marketdata.builders.MarketDataBuilder;
import com.opengamma.sesame.marketdata.builders.MarketDataBuilders;
import com.opengamma.sesame.marketdata.builders.MarketDataEnvironmentFactory;
import com.opengamma.sesame.trade.ZeroCouponInflationSwapTrade;
import com.opengamma.timeseries.date.localdate.ImmutableLocalDateDoubleTimeSeries;
import com.opengamma.timeseries.date.localdate.LocalDateDoubleTimeSeries;
import com.opengamma.timeseries.date.localdate.LocalDateDoubleTimeSeriesBuilder;
import com.opengamma.util.function.Function;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.result.Result;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.time.Tenor;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
@Test(groups = TestGroup.UNIT)
public class ZeroCouponInflationSwapTest {
/**
* PV matching SwapZeroCouponInflationDiscountingUsdE2ETest
*/
private static final double EXPECTED_PV1 = 0d;
private static final double EXPECTED_PV2 = 557423.3817;
private static final double EXPECTED_PAR_RATE1 = 0.0200;
private static final double EXPECTED_PAR_RATE2 = 0.02104793312426101;
private static final double STD_TOLERANCE_PV = 1.0E-3;
private static final double STD_TOLERANCE_RATE = 1.0E-8;
private static final ZonedDateTime VALUATION_TIME = DateUtils.getUTCDate(2014, 10, 9);
private static final String CURVE_BUNDLE = "Curve Bundle";
private static final CalculationArguments ARGS =
CalculationArguments.builder()
.valuationTime(VALUATION_TIME)
.marketDataSpecification(EmptyMarketDataSpec.INSTANCE)
.build();
private FunctionRunner _functionRunner;
private ZeroCouponInflationSwapFn _function;
private ZeroCouponInflationSwapTrade _trade1 = createZCInflationTrade(DateUtils.getUTCDate(2014, 10, 9),
DateUtils.getUTCDate(2016, 10, 11),
0.02);
private ZeroCouponInflationSwapTrade _trade2 = createZCInflationTrade(DateUtils.getUTCDate(2014, 1, 8),
DateUtils.getUTCDate(2019, 1, 10),
0.01);
private static final ExternalId CONVENTION_ID = ExternalId.of("CONVENTION", "TEST");
private static final ExternalId REGION_ID = ExternalSchemes.financialRegionId("US");
private static final Interpolator1D LINEAR_FLAT = CombinedInterpolatorExtrapolatorFactory.getInterpolator(
Interpolator1DFactory.LINEAR,
Interpolator1DFactory.FLAT_EXTRAPOLATOR,
Interpolator1DFactory.FLAT_EXTRAPOLATOR);
// Discounting Curve
private static final String USD_DSC_NAME = "USD Dsc";
private static final double[] USD_DSC_TIME = new double[] {0.0027397260273972603, 0.0136986301369863, 0.1095890410958904,
0.18904109589041096, 0.27123287671232876, 0.5178082191780822,
0.7671232876712328, 1.0191780821917809, 2.025218953514485,
3.0246575342465754, 4.021917808219178, 5.019178082191781,
6.019754472640168, 7.024657534246575, 8.024657534246575,
9.024657534246575, 10.019754472640168};
private static final double[] USD_DSC_RATE = new double[] {0.0016222186172986138, 0.001622209965572477, 7.547616096755544E-4,
9.003947315389025E-4, 9.833562990057003E-4, 9.300905368344651E-4,
0.0010774349342544426, 0.001209299356175582, 0.003243498783874946,
0.007148138535707508, 0.011417234937364525, 0.015484713638367467,
0.01894872475170524, 0.02177798040124286, 0.024146976832379798,
0.02610320121432829, 0.027814843351943817 };
private static final YieldAndDiscountCurve USD_DSC_CURVE =
new YieldCurve(USD_DSC_NAME, new InterpolatedDoublesCurve(USD_DSC_TIME,
USD_DSC_RATE,
LINEAR_FLAT,
true,
USD_DSC_NAME));
// Index Curve
private static final String USD_INDEX_NAME = "US CPI-U";
private static ExternalId PRICE_INDEX_ID = ExternalId.of("SEC", USD_INDEX_NAME);
private static final double[] USD_INDEX_VALUE = new double[] {242.88404516129032, 248.03712245417105, 252.98128118335094,
258.0416354687366, 263.20242369585515, 268.4653023378886,
273.83617795725064, 279.3124974961296, 284.8987721100803,
290.5954768446179, 302.3336095056465, 320.8351638061777,
354.2203489141063, 391.08797576744865, 431.7913437911175};
private static final double[] USD_INDEX_TIME = new double[] {0.893150684931507, 1.894071412530878, 2.893150684931507,
3.893150684931507, 4.893150684931507, 5.894071412530878,
6.893150684931507, 7.893150684931507, 8.893150684931507,
9.894071412530877, 11.893150684931507, 14.893150684931507,
19.893150684931506, 24.893150684931506, 29.894071412530877 };
private static final PriceIndexCurveSimple USD_PRICE_INDEX_CURVE =
new PriceIndexCurveSimple(InterpolatedDoublesCurve.from(USD_INDEX_TIME,
USD_INDEX_VALUE,
LINEAR_FLAT,
USD_INDEX_NAME));
private static InflationProviderBundle buildCurveBundle() {
IndexPrice PRICE_INDEX_USD = new IndexPrice(USD_INDEX_NAME, USD);
InflationIssuerProviderDiscount provider = new InflationIssuerProviderDiscount();
provider.setCurve(USD, USD_DSC_CURVE);
provider.setCurve(PRICE_INDEX_USD, USD_PRICE_INDEX_CURVE);
CurveBuildingBlockBundle blockBundle = new CurveBuildingBlockBundle();
blockBundle.add(USD_DSC_NAME,
buildCurveBlock(USD_DSC_NAME, USD_DSC_CURVE.getNumberOfParameters()),
buildJacobian(USD_DSC_CURVE.getNumberOfParameters()));
blockBundle.add(USD_INDEX_NAME,
buildCurveBlock(USD_INDEX_NAME, USD_PRICE_INDEX_CURVE.getNumberOfParameters()),
buildJacobian(USD_PRICE_INDEX_CURVE.getNumberOfParameters()));
return InflationProviderBundle.builder()
.curveBuildingBlockBundle(blockBundle)
.parameterInflationProvider(provider)
.build();
}
private static DoubleMatrix2D buildJacobian(int params) {
// have pre-calibrated curve so jacobian is the identity matrix
return new IdentityMatrix(params);
}
private static CurveBuildingBlock buildCurveBlock(String configCurveName, int params) {
LinkedHashMap<String, Pair<Integer, Integer>> curveBlock = Maps.newLinkedHashMap();
curveBlock.put(configCurveName, Pairs.of(0, params));
return new CurveBuildingBlock(curveBlock);
}
private static MarketDataEnvironment getMarketDataEnvironment() {
MarketDataEnvironmentBuilder builder = new MarketDataEnvironmentBuilder();
builder.add(InflationMulticurveId.of(CURVE_BUNDLE), buildCurveBundle());
builder.add(RawId.of(PRICE_INDEX_ID.toBundle()), createFlatTimeSeries());
builder.valuationTime(VALUATION_TIME);
return builder.build();
}
private ZeroCouponInflationSwapTrade createZCInflationTrade(ZonedDateTime tradeDate,
ZonedDateTime maturity,
double rate) {
ZonedDateTime effectiveDate = tradeDate.plusDays(2);
String counterpartyName = "TEST";
Frequency frequency = SimpleFrequency.SEMI_ANNUAL;
BusinessDayConvention convention = BusinessDayConventions.MODIFIED_FOLLOWING;
Notional notional = new InterestRateNotional(USD, 10_000_000);
boolean eom = true;
SimpleCounterparty counterparty = new SimpleCounterparty(ExternalId.of(Counterparty.DEFAULT_SCHEME, counterpartyName));
FixedInflationSwapLeg payLeg = new FixedInflationSwapLeg(DayCounts.ACT_360,
frequency,
REGION_ID,
convention,
notional,
eom,
rate);
InflationIndexSwapLeg receiveLeg = new InflationIndexSwapLeg(DayCounts.ACT_360,
frequency,
REGION_ID,
convention,
notional,
eom,
PRICE_INDEX_ID,
3,
3,
InterpolationMethod.MONTH_START_LINEAR);
ZeroCouponInflationSwapSecurity security = new ZeroCouponInflationSwapSecurity(tradeDate,
effectiveDate,
maturity,
counterpartyName,
payLeg,
receiveLeg);
SimpleTrade trade = new SimpleTrade(security,
BigDecimal.valueOf(1),
counterparty,
LocalDate.of(2000, 1, 1),
OffsetTime.of(LocalTime.of(0, 0), ZoneOffset.UTC));
trade.setPremium(0.0);
trade.setPremiumCurrency(USD);
return new ZeroCouponInflationSwapTrade(trade);
}
private static ImmutableMap<Class<?>, Object> generateBaseComponents() {
return generateComponentMap(holidaySource(),
regionSource(),
mock(ConventionSource.class),
mock(ConventionBundleSource.class),
mock(LegalEntitySource.class),
configSource(),
securitySource(),
mock(HistoricalTimeSeriesSource.class),
mock(HistoricalTimeSeriesResolver.class),
mock(CurrencyMatrix.class));
}
private static HolidaySource holidaySource() {
return new WeekendHolidaySource();
}
private static LocalDateDoubleTimeSeries createFlatTimeSeries() {
LocalDateDoubleTimeSeriesBuilder seriesBuilder = ImmutableLocalDateDoubleTimeSeries.builder();
//see StandardTimeSeriesInflationDataSets for full set
seriesBuilder.put(LocalDate.of(2013, 10, 31), 233.546);
seriesBuilder.put(LocalDate.of(2013, 11, 30), 233.069);
seriesBuilder.put(LocalDate.of(2014, 7, 31), 238.25);
seriesBuilder.put(LocalDate.of(2014, 8, 31), 237.852);
return seriesBuilder.build();
}
private static RegionSource regionSource() {
RegionMaster regionMaster = new InMemoryRegionMaster();
SimpleRegion regionUs = new SimpleRegion();
regionUs.addExternalId(REGION_ID);
regionUs.addExternalId(ExternalSchemes.currencyRegionId(USD));
regionUs.setUniqueId(UniqueId.of("REGION", "1"));
regionMaster.add(new RegionDocument(regionUs));
return new MasterRegionSource(regionMaster);
}
private static CurveNode buildCurveNode(Tenor tenor) {
//Not the correct node to use for inflation, but in this case it is only used for labeling
return new ContinuouslyCompoundedRateNode("Mapper", tenor, tenor.toFormattedString().substring(1));
}
private static ConfigSource configSource() {
ConfigMaster configMaster = new InMemoryConfigMaster();
Set<CurveNode> indexNodes = new LinkedHashSet<>();
for (double years : USD_INDEX_TIME) {
Tenor tenor = Tenor.parse("P" + Math.round(years * 365) + "D");
indexNodes.add(buildCurveNode(tenor));
}
Set<CurveNode> discountingNodes = new LinkedHashSet<>();
for (double years : USD_DSC_TIME) {
Tenor tenor = Tenor.parse("P" + Math.round(years * 365) + "D");
discountingNodes.add(buildCurveNode(tenor));
}
CurveDefinition indexDefinition = new CurveDefinition(USD_INDEX_NAME, indexNodes);
CurveDefinition discountingDefinition = new CurveDefinition(USD_DSC_NAME, discountingNodes);
configMaster.add(new ConfigDocument(ConfigItem.of(indexDefinition)));
configMaster.add(new ConfigDocument(ConfigItem.of(discountingDefinition)));
return new MasterConfigSource(configMaster);
}
private static SecuritySource securitySource() {
SecurityMaster securityMaster = new InMemorySecurityMaster();
PriceIndex priceIndex = new PriceIndex(USD_INDEX_NAME, CONVENTION_ID);
priceIndex.setUniqueId(UniqueId.of("SEC", "1"));
priceIndex.setExternalIdBundle(PRICE_INDEX_ID.toBundle());
securityMaster.add(new SecurityDocument(priceIndex));
return new MasterSecuritySource(securityMaster);
}
private static ImmutableMap<Class<?>, Object> generateComponentMap(Object... components) {
ImmutableMap.Builder<Class<?>, Object> builder = ImmutableMap.builder();
for (Object component : components) {
builder.put(component.getClass().getInterfaces()[0], component);
}
return builder.build();
}
public static ExposureFunctions exposureFunction() {
List<String> exposureFunctions = ImmutableList.of(CurrencyExposureFunction.NAME);
Map<ExternalId, String> idsToNames = new HashMap<>();
idsToNames.put(ExternalId.of("CurrencyISO", "USD"), CURVE_BUNDLE);
return new ExposureFunctions("Exposure", exposureFunctions, idsToNames);
}
@BeforeClass
public void setUpClass() throws IOException {
FunctionModelConfig config =
config(
arguments(
function(
MarketExposureSelector.class,
argument("exposureFunctions", ConfigLink.resolved(exposureFunction())))),
implementations(
InflationSwapConverterFn.class, DefaultInflationSwapConverterFn.class,
ZeroCouponInflationSwapFn.class, DiscountingZeroCouponInflationSwapFn.class,
HistoricalMarketDataFn.class, DefaultHistoricalMarketDataFn.class,
CurveSelector.class, MarketExposureSelector.class,
CurveLabellingFn.class, CurveDefinitionCurveLabellingFn.class,
CurveDefinitionFn.class, DefaultCurveDefinitionFn.class,
FixingsFn.class, DefaultFixingsFn.class,
FunctionCache.class, NoOpFunctionCache.class
));
Map<Class<?>, Object> components = generateBaseComponents();
VersionCorrectionProvider vcProvider = new FixedInstantVersionCorrectionProvider(Instant.now());
ServiceContext serviceContext = ServiceContext.of(components).with(VersionCorrectionProvider.class, vcProvider);
ThreadLocalServiceContext.init(serviceContext);
ComponentMap componentMap = ComponentMap.of(components);
ConfigLink<CurrencyMatrix> currencyMatrixLink = ConfigLink.resolved(componentMap.getComponent(CurrencyMatrix.class));
List<MarketDataBuilder> builders = MarketDataBuilders.standard(componentMap, "dataSource", currencyMatrixLink);
MarketDataEnvironmentFactory environmentFactory = new MarketDataEnvironmentFactory(new EmptyMarketDataFactory(), builders);
_functionRunner = new FunctionRunner(environmentFactory);
_function = FunctionModel.build(ZeroCouponInflationSwapFn.class, config, ComponentMap.of(components));
}
@Test
public void testCalculatePVTrade1() throws Exception {
MarketDataEnvironment ENV = getMarketDataEnvironment();
Result<MultipleCurrencyAmount> resultPV = _functionRunner.runFunction(
ARGS, ENV, new Function<Environment, Result<MultipleCurrencyAmount>>() {
@Override
public Result<MultipleCurrencyAmount> apply(Environment env) {
return _function.calculatePV(env, _trade1);
}
});
assertSuccess(resultPV);
MultipleCurrencyAmount mca = resultPV.getValue();
assertThat(mca.getCurrencyAmount(USD).getAmount(), is(closeTo(EXPECTED_PV1, STD_TOLERANCE_PV)));
}
@Test
public void testCalculateParRateTrade1() throws Exception {
MarketDataEnvironment ENV = getMarketDataEnvironment();
Result<Double> resultParRate = _functionRunner.runFunction(
ARGS, ENV, new Function<Environment, Result<Double>>() {
@Override
public Result<Double> apply(Environment env) {
return _function.calculateParRate(env, _trade1);
}
});
assertSuccess(resultParRate);
assertThat(resultParRate.getValue(), is(closeTo(EXPECTED_PAR_RATE1, STD_TOLERANCE_RATE)));
}
@Test
public void testCalculateBucketedPV01Trade1() throws Exception {
MarketDataEnvironment ENV = getMarketDataEnvironment();
Result<BucketedCurveSensitivities> result = _functionRunner.runFunction(
ARGS, ENV, new Function<Environment, Result<BucketedCurveSensitivities>>() {
@Override
public Result<BucketedCurveSensitivities> apply(Environment env) {
return _function.calculateBucketedPV01(env, _trade1);
}
});
assertSuccess(result);
BucketedCurveSensitivities mcps = result.getValue();
double[] expectedDsc = new double[] {0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d};
double[] expectedIndex = new double[] {0.2391924970613193, 3.9334293371931075, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d };
assertArrayRelative("BucketedPV01Trade1 Index",
expectedIndex,
mcps.getSensitivities().get(Pairs.of(USD_INDEX_NAME, USD)).getValues(),
STD_TOLERANCE_PV);
assertArrayRelative("BucketedPV01Trade1 Discounting",
expectedDsc,
mcps.getSensitivities().get(Pairs.of(USD_DSC_NAME, USD)).getValues(),
STD_TOLERANCE_PV);
}
@Test
public void testCalculatePVTrade2() throws Exception {
MarketDataEnvironment ENV = getMarketDataEnvironment();
Result<MultipleCurrencyAmount> resultPV = _functionRunner.runFunction(
ARGS, ENV, new Function<Environment, Result<MultipleCurrencyAmount>>() {
@Override
public Result<MultipleCurrencyAmount> apply(Environment env) {
return _function.calculatePV(env, _trade2);
}
});
assertSuccess(resultPV);
MultipleCurrencyAmount mca = resultPV.getValue();
assertThat(mca.getCurrencyAmount(USD).getAmount(), is(closeTo(EXPECTED_PV2, STD_TOLERANCE_PV)));
}
@Test
public void testCalculateParRateTrade2() throws Exception {
MarketDataEnvironment ENV = getMarketDataEnvironment();
Result<Double> resultParRate = _functionRunner.runFunction(
ARGS, ENV, new Function<Environment, Result<Double>>() {
@Override
public Result<Double> apply(Environment env) {
return _function.calculateParRate(env, _trade2);
}
});
assertSuccess(resultParRate);
assertThat(resultParRate.getValue(), is(closeTo(EXPECTED_PAR_RATE2, STD_TOLERANCE_RATE)));
}
@Test
public void testCalculateBucketedPV01Trade2() throws Exception {
MarketDataEnvironment ENV = getMarketDataEnvironment();
Result<BucketedCurveSensitivities> result = _functionRunner.runFunction(
ARGS, ENV, new Function<Environment, Result<BucketedCurveSensitivities>>() {
@Override
public Result<BucketedCurveSensitivities> apply(Environment env) {
return _function.calculateBucketedPV01(env, _trade2);
}
});
assertSuccess(result);
BucketedCurveSensitivities mcps = result.getValue();
double[] expectedDsc = new double[] {0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, -181.78857803005081, -55.38361696256043, 0d, 0d, 0d, 0d, 0d };
double[] expectedIndex = new double[] {0d, 0d, 0d, 3.2884348703648847, 0.7763062873998817, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d, 0d };
assertArrayRelative("BucketedPV01Trade2 Index",
expectedIndex,
mcps.getSensitivities().get(Pairs.of(USD_INDEX_NAME, USD)).getValues(),
STD_TOLERANCE_PV);
assertArrayRelative("BucketedPV01Trade2 Discounting",
expectedDsc,
mcps.getSensitivities().get(Pairs.of(USD_DSC_NAME, USD)).getValues(),
STD_TOLERANCE_PV);
}
private static void assertArrayRelative(String message, double[] expected, double[] obtained, double relativeTol) {
int nData = expected.length;
assertEquals(message, nData, obtained.length);
for (int i = 0; i < nData; ++i) {
double ref = Math.max(Math.abs(expected[i]), 1.0);
assertThat(message, obtained[i], is(closeTo(expected[i], ref * relativeTol)));
}
}
}