/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.sesame.marketdata.scenarios; 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 org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNotNull; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.testng.annotations.Test; import org.threeten.bp.Instant; import org.threeten.bp.Period; import org.threeten.bp.ZonedDateTime; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.opengamma.analytics.financial.forex.method.FXMatrix; 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.curve.multicurve.MulticurveDiscountBuildingRepository; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount; import com.opengamma.analytics.math.curve.ConstantDoublesCurve; import com.opengamma.analytics.math.matrix.DoubleMatrix2D; import com.opengamma.financial.analytics.curve.ConfigDBCurveSpecificationBuilder; import com.opengamma.financial.analytics.curve.credit.CurveSpecificationBuilder; import com.opengamma.id.VersionCorrection; import com.opengamma.service.ServiceContext; import com.opengamma.service.ThreadLocalServiceContext; import com.opengamma.service.VersionCorrectionProvider; import com.opengamma.sesame.CurveNodeConverterFn; import com.opengamma.sesame.DefaultCurveNodeConverterFn; import com.opengamma.sesame.MulticurveBundle; import com.opengamma.sesame.component.RetrievalPeriod; import com.opengamma.sesame.config.FunctionModelConfig; import com.opengamma.sesame.engine.ComponentMap; import com.opengamma.sesame.engine.FixedInstantVersionCorrectionProvider; import com.opengamma.sesame.graph.FunctionModel; import com.opengamma.sesame.interestrate.InterestRateMockSources; import com.opengamma.sesame.marketdata.DefaultHistoricalMarketDataFn; import com.opengamma.sesame.marketdata.EmptyMarketDataFactory; import com.opengamma.sesame.marketdata.EmptyMarketDataSpec; import com.opengamma.sesame.marketdata.FxMatrixId; import com.opengamma.sesame.marketdata.HistoricalMarketDataFn; import com.opengamma.sesame.marketdata.MarketDataEnvironment; import com.opengamma.sesame.marketdata.MarketDataEnvironmentBuilder; import com.opengamma.sesame.marketdata.MarketDataRequirement; import com.opengamma.sesame.marketdata.MulticurveId; import com.opengamma.sesame.marketdata.MulticurveMarketDataBuilder; import com.opengamma.sesame.marketdata.SingleValueRequirement; import com.opengamma.sesame.marketdata.builders.MarketDataEnvironmentFactory; import com.opengamma.util.money.Currency; import com.opengamma.util.test.TestGroup; import com.opengamma.util.tuple.Pair; @Test(groups = TestGroup.UNIT) public class ScenarioFrameworkTest { /** * Tests applying a parallel shift to a calibrated curve built by the engine */ public void curveOutputsParallelShift() { FunctionModelConfig curveBuilderConfig = config( arguments( function( DefaultCurveNodeConverterFn.class, argument("timeSeriesDuration", RetrievalPeriod.of(Period.ofYears(1)))), function( MulticurveDiscountBuildingRepository.class, argument("toleranceAbs", 1e-9), argument("toleranceRel", 1e-9), argument("stepMaximum", 1000)), function( ConfigDBCurveSpecificationBuilder.class, argument("versionCorrection", VersionCorrection.LATEST))), implementations( CurveSpecificationBuilder.class, ConfigDBCurveSpecificationBuilder.class, CurveNodeConverterFn.class, DefaultCurveNodeConverterFn.class, HistoricalMarketDataFn.class, DefaultHistoricalMarketDataFn.class)); Map<Class<?>, Object> components = InterestRateMockSources.generateBaseComponents(); VersionCorrectionProvider vcProvider = new FixedInstantVersionCorrectionProvider(Instant.now()); ServiceContext serviceContext = ServiceContext.of(components).with(VersionCorrectionProvider.class, vcProvider); ThreadLocalServiceContext.init(serviceContext); ComponentMap componentMap = ComponentMap.of(components); MulticurveMarketDataBuilder builder = FunctionModel.build( MulticurveMarketDataBuilder.class, curveBuilderConfig, componentMap); MarketDataEnvironment baseMarketData = InterestRateMockSources.createMarketDataEnvironment(); FXMatrix fxMatrix = new FXMatrix(); MarketDataEnvironment suppliedData = baseMarketData.toBuilder().add(FxMatrixId.of(Currency.USD), fxMatrix).build(); SingleValueRequirement curveReq = SingleValueRequirement.of(MulticurveId.of("USD_ON-OIS_LIBOR3M-FRAIRS_1U")); String curveName = "USD-ON-OIS"; double shiftAmount = 0.01; SinglePerturbationMapping mapping = SinglePerturbationMapping.builder() .filter(new CurveNameMulticurveFilter(curveName)) .perturbation(MulticurveOutputParallelShift.absolute(shiftAmount)) .build(); List<SinglePerturbationMapping> mappings = ImmutableList.of(mapping); SingleScenarioDefinition scenario = SingleScenarioDefinition.of("scenarioName", mappings); MarketDataEnvironmentFactory environmentFactory = new MarketDataEnvironmentFactory(new EmptyMarketDataFactory(), builder); ZonedDateTime valuationTime = ZonedDateTime.now(); MarketDataEnvironment perturbedData = environmentFactory.build( suppliedData, ImmutableSet.<MarketDataRequirement>of(curveReq), scenario, EmptyMarketDataSpec.INSTANCE, valuationTime); MarketDataEnvironment unperturbedData = environmentFactory.build( suppliedData, ImmutableSet.<MarketDataRequirement>of(curveReq), SingleScenarioDefinition.base(), EmptyMarketDataSpec.INSTANCE, valuationTime); MulticurveBundle unperturbedBundle = (MulticurveBundle) unperturbedData.getData().get(curveReq); YieldAndDiscountCurve unperturbedCurve = unperturbedBundle.getMulticurveProvider().getCurve(curveName); MulticurveBundle perturbedBundle = (MulticurveBundle) perturbedData.getData().get(curveReq); YieldAndDiscountCurve perturbedCurve = perturbedBundle.getMulticurveProvider().getCurve(curveName); assertEquals(unperturbedCurve.getInterestRate(0.1) + shiftAmount, perturbedCurve.getInterestRate(0.1)); assertEquals(unperturbedCurve.getInterestRate(1d) + shiftAmount, perturbedCurve.getInterestRate(1d)); } /** * Tests applying a parallel shift to a calibrated curve supplied by the user */ public void suppliedCurveOutputsParallelShift() { MulticurveId multicurveId = MulticurveId.of("curveBundle"); MulticurveProviderDiscount multicurve = new MulticurveProviderDiscount(); ConstantDoublesCurve curve = new ConstantDoublesCurve(1.5, "curveName"); YieldCurve yieldCurve = YieldCurve.from(curve); multicurve.setCurve(Currency.USD, yieldCurve); LinkedHashMap<String, Pair<CurveBuildingBlock, DoubleMatrix2D>> emptyMap = new LinkedHashMap<>(); MulticurveBundle bundle = new MulticurveBundle(multicurve, new CurveBuildingBlockBundle(emptyMap)); ZonedDateTime valuationTime = ZonedDateTime.now(); MarketDataEnvironment suppliedData = new MarketDataEnvironmentBuilder() .add(multicurveId, bundle) .valuationTime(valuationTime) .build(); MarketDataEnvironmentFactory environmentFactory = new MarketDataEnvironmentFactory(new EmptyMarketDataFactory()); SinglePerturbationMapping mapping = SinglePerturbationMapping.builder() .filter(new CurveNameMulticurveFilter("curveName")) .perturbation(MulticurveOutputParallelShift.absolute(0.1)) .build(); List<SinglePerturbationMapping> mappings = ImmutableList.of(mapping); SingleScenarioDefinition scenario = SingleScenarioDefinition.of("scenarioName", mappings); MarketDataEnvironment perturbedMarketData = environmentFactory.build( suppliedData, ImmutableSet.<MarketDataRequirement>of(), scenario, EmptyMarketDataSpec.INSTANCE, valuationTime); SingleValueRequirement bundleRequirement = SingleValueRequirement.of(multicurveId); MulticurveBundle perturbedBundle = (MulticurveBundle) perturbedMarketData.getData().get(bundleRequirement); MulticurveProviderDiscount perturbedMulticurve = perturbedBundle.getMulticurveProvider(); YieldAndDiscountCurve perturbedCurve = perturbedMulticurve.getDiscountingCurves().get(Currency.USD); assertEquals(1.6, perturbedCurve.getInterestRate(0d)); assertEquals(1.6, perturbedCurve.getInterestRate(1d)); } /** * Tests CyclePerturbations.applyPerturbations applying a parallel shift to a calibrated curve */ public void cyclePerturbationsApplyPerturbations() { SinglePerturbationMapping mapping = SinglePerturbationMapping.builder() .filter(new CurveNameMulticurveFilter("curveName")) .perturbation(MulticurveOutputParallelShift.absolute(0.1)) .build(); MulticurveProviderDiscount multicurve = new MulticurveProviderDiscount(); ConstantDoublesCurve curve = new ConstantDoublesCurve(1.5, "curveName"); YieldCurve yieldCurve = YieldCurve.from(curve); multicurve.setCurve(Currency.USD, yieldCurve); LinkedHashMap<String, Pair<CurveBuildingBlock, DoubleMatrix2D>> emptyMap = new LinkedHashMap<>(); MulticurveBundle bundle = new MulticurveBundle(multicurve, new CurveBuildingBlockBundle(emptyMap)); MulticurveId multicurveId = MulticurveId.of("curveBundle"); MarketDataEnvironment marketData = new MarketDataEnvironmentBuilder() .add(multicurveId, bundle) .valuationTime(ZonedDateTime.now()) .build(); SingleValueRequirement bundleRequirement = SingleValueRequirement.of(multicurveId); List<SinglePerturbationMapping> mappings = ImmutableList.of(mapping); SingleScenarioDefinition scenario = SingleScenarioDefinition.of("scenarioName", mappings); ImmutableSet<SingleValueRequirement> requirements = ImmutableSet.of(bundleRequirement); CyclePerturbations cyclePerturbations = new CyclePerturbations(requirements, scenario); MarketDataEnvironment perturbedData = cyclePerturbations.apply(marketData); MulticurveBundle perturbedBundle = (MulticurveBundle) perturbedData.getData().get(bundleRequirement); assertNotNull(perturbedBundle); MulticurveProviderDiscount perturbedMulticurve = perturbedBundle.getMulticurveProvider(); YieldAndDiscountCurve perturbedCurve = perturbedMulticurve.getDiscountingCurves().get(Currency.USD); assertEquals(1.6, perturbedCurve.getInterestRate(0d)); assertEquals(1.6, perturbedCurve.getInterestRate(1d)); } }