/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.sesame.fxforward; import static com.opengamma.sesame.config.ConfigBuilder.argument; import static com.opengamma.sesame.config.ConfigBuilder.arguments; import static com.opengamma.sesame.config.ConfigBuilder.column; import static com.opengamma.sesame.config.ConfigBuilder.config; import static com.opengamma.sesame.config.ConfigBuilder.configureView; import static com.opengamma.sesame.config.ConfigBuilder.function; import static com.opengamma.sesame.config.ConfigBuilder.implementations; import static com.opengamma.sesame.config.ConfigBuilder.nonPortfolioOutput; import static com.opengamma.sesame.config.ConfigBuilder.output; import static com.opengamma.util.money.Currency.EUR; import static com.opengamma.util.money.Currency.GBP; import static com.opengamma.util.money.Currency.JPY; import static com.opengamma.util.money.Currency.USD; import static com.opengamma.util.result.FailureStatus.MISSING_DATA; import static com.opengamma.util.result.SuccessStatus.SUCCESS; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.mockito.Mockito.mock; import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertTrue; import java.io.IOException; import java.net.URI; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; import org.hamcrest.MatcherAssert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.Test; import org.threeten.bp.Period; import org.threeten.bp.ZoneOffset; import org.threeten.bp.ZonedDateTime; import com.codahale.metrics.MetricRegistry; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.opengamma.core.config.ConfigSource; import com.opengamma.core.convention.ConventionSource; import com.opengamma.core.historicaltimeseries.HistoricalTimeSeriesSource; import com.opengamma.core.holiday.HolidaySource; import com.opengamma.core.id.ExternalSchemes; import com.opengamma.core.legalentity.LegalEntitySource; import com.opengamma.core.link.ConfigLink; import com.opengamma.core.position.Trade; import com.opengamma.core.position.impl.SimpleTrade; import com.opengamma.core.region.RegionSource; import com.opengamma.core.security.SecuritySource; import com.opengamma.core.security.impl.SimpleSecurityLink; import com.opengamma.core.value.MarketDataRequirementNames; import com.opengamma.financial.analytics.CurrencyLabelledMatrix1D; import com.opengamma.financial.analytics.conversion.FXForwardSecurityConverter; import com.opengamma.financial.analytics.curve.ConfigDBCurveConstructionConfigurationSource; import com.opengamma.financial.analytics.curve.CurveConstructionConfiguration; import com.opengamma.financial.analytics.curve.CurveConstructionConfigurationSource; import com.opengamma.financial.analytics.curve.exposure.ConfigDBInstrumentExposuresProvider; import com.opengamma.financial.analytics.curve.exposure.ExposureFunctions; import com.opengamma.financial.analytics.curve.exposure.InstrumentExposuresProvider; import com.opengamma.financial.convention.ConventionBundleSource; import com.opengamma.financial.currency.CurrencyMatrix; import com.opengamma.financial.currency.CurrencyPair; import com.opengamma.financial.security.FinancialSecurityVisitor; import com.opengamma.financial.security.fx.FXForwardSecurity; import com.opengamma.id.ExternalId; import com.opengamma.id.ExternalIdBundle; import com.opengamma.id.UniqueId; import com.opengamma.id.VersionCorrection; import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolver; import com.opengamma.master.historicaltimeseries.impl.RemoteHistoricalTimeSeriesResolver; import com.opengamma.service.ServiceContext; import com.opengamma.service.ThreadLocalServiceContext; import com.opengamma.service.VersionCorrectionProvider; import com.opengamma.sesame.CurrencyPairsFn; import com.opengamma.sesame.CurveDefinitionFn; import com.opengamma.sesame.CurveNodeConverterFn; import com.opengamma.sesame.CurveSpecificationFn; import com.opengamma.sesame.CurveSpecificationMarketDataFn; import com.opengamma.sesame.DefaultCurrencyPairsFn; import com.opengamma.sesame.DefaultCurveDefinitionFn; import com.opengamma.sesame.DefaultCurveNodeConverterFn; import com.opengamma.sesame.DefaultCurveSpecificationFn; import com.opengamma.sesame.DefaultCurveSpecificationMarketDataFn; import com.opengamma.sesame.DefaultDiscountingMulticurveBundleFn; import com.opengamma.sesame.DefaultDiscountingMulticurveBundleResolverFn; import com.opengamma.sesame.DefaultFXMatrixFn; import com.opengamma.sesame.DirectExecutorService; import com.opengamma.sesame.DiscountingMulticurveBundleFn; import com.opengamma.sesame.DiscountingMulticurveBundleResolverFn; import com.opengamma.sesame.DiscountingMulticurveCombinerFn; import com.opengamma.sesame.ExposureFunctionsDiscountingMulticurveCombinerFn; import com.opengamma.sesame.FXMatrixFn; import com.opengamma.sesame.FixingsFn; import com.opengamma.sesame.MarketDataResourcesLoader; import com.opengamma.sesame.MarketExposureSelector; import com.opengamma.sesame.MulticurveBundle; import com.opengamma.sesame.OutputNames; import com.opengamma.sesame.RootFinderConfiguration; import com.opengamma.sesame.SimpleEnvironment; import com.opengamma.sesame.cache.CachingProxyDecorator; import com.opengamma.sesame.cache.NoOpCacheInvalidator; import com.opengamma.sesame.component.RetrievalPeriod; import com.opengamma.sesame.component.StringSet; import com.opengamma.sesame.config.EngineUtils; import com.opengamma.sesame.config.FunctionModelConfig; import com.opengamma.sesame.config.ViewConfig; import com.opengamma.sesame.engine.ComponentMap; import com.opengamma.sesame.engine.CycleArguments; import com.opengamma.sesame.engine.FixedInstantVersionCorrectionProvider; import com.opengamma.sesame.engine.FunctionService; import com.opengamma.sesame.engine.ResultItem; import com.opengamma.sesame.engine.Results; import com.opengamma.sesame.engine.View; import com.opengamma.sesame.engine.ViewFactory; import com.opengamma.sesame.function.AvailableImplementations; import com.opengamma.sesame.function.AvailableImplementationsImpl; import com.opengamma.sesame.function.AvailableOutputs; import com.opengamma.sesame.function.AvailableOutputsImpl; import com.opengamma.sesame.function.FunctionMetadata; import com.opengamma.sesame.function.scenarios.curvedata.FunctionTestUtils; import com.opengamma.sesame.graph.FunctionBuilder; import com.opengamma.sesame.graph.FunctionModel; import com.opengamma.sesame.marketdata.DefaultHistoricalMarketDataFn; import com.opengamma.sesame.marketdata.DefaultMarketDataFn; import com.opengamma.sesame.marketdata.FieldName; import com.opengamma.sesame.marketdata.HistoricalMarketDataFn; import com.opengamma.sesame.marketdata.MarketDataEnvironment; import com.opengamma.sesame.marketdata.MarketDataEnvironmentBuilder; import com.opengamma.sesame.marketdata.MarketDataFn; import com.opengamma.sesame.marketdata.RawId; import com.opengamma.sesame.trace.TracingProxy; import com.opengamma.util.money.Currency; import com.opengamma.util.result.Result; import com.opengamma.util.result.ResultStatus; import com.opengamma.util.test.TestGroup; @Test(groups = TestGroup.UNIT) public class FXForwardPVFnTest { private static final Logger s_logger = LoggerFactory.getLogger(FXForwardPVFnTest.class); private static final AtomicLong s_nextId = new AtomicLong(0); @Test public void buildGraph() { FunctionMetadata calculatePV = EngineUtils.createMetadata(FXForwardPVFn.class, "calculatePV"); FunctionModelConfig config = createFunctionConfig(); ComponentMap componentMap = componentMap(ConfigSource.class, ConventionSource.class, ConventionBundleSource.class, HistoricalTimeSeriesResolver.class, SecuritySource.class, HolidaySource.class, HistoricalTimeSeriesSource.class, MarketDataFn.class, HistoricalMarketDataFn.class, LegalEntitySource.class, RegionSource.class); FunctionModel functionModel = FunctionModel.forFunction(calculatePV, config, componentMap.getComponentTypes()); Object fn = functionModel.build(new FunctionBuilder(), componentMap).getReceiver(); assertTrue(fn instanceof FXForwardPVFn); System.out.println(functionModel.prettyPrint(true)); } //@Test(groups = TestGroup.INTEGRATION) @Test(groups = TestGroup.INTEGRATION, enabled = false) public void executeAgainstRemoteServerWithNoData() throws IOException { Result<CurrencyLabelledMatrix1D> pv = executeAgainstRemoteServer(Collections.<ExternalIdBundle, Double>emptyMap()); assertNotNull(pv); MatcherAssert.assertThat(pv.getStatus(), is((ResultStatus) MISSING_DATA)); } //@Test(groups = TestGroup.INTEGRATION) @Test(groups = TestGroup.INTEGRATION, enabled = false) public void executeAgainstRemoteServerWithData() throws IOException { Result<CurrencyLabelledMatrix1D> pv = executeAgainstRemoteServer( MarketDataResourcesLoader.getData("marketdata.properties", ExternalSchemes.BLOOMBERG_TICKER)); assertNotNull(pv); assertThat(pv.getStatus(), is((ResultStatus) SUCCESS)); } private Result<CurrencyLabelledMatrix1D> executeAgainstRemoteServer(Map<ExternalIdBundle, Double> marketDataMap) { String serverUrl = "http://localhost:8080"; URI htsResolverUri = URI.create(serverUrl + "/jax/components/HistoricalTimeSeriesResolver/shared"); HistoricalTimeSeriesResolver htsResolver = new RemoteHistoricalTimeSeriesResolver(htsResolverUri); Map<Class<?>, Object> comps = ImmutableMap.<Class<?>, Object>of(HistoricalTimeSeriesResolver.class, htsResolver); ComponentMap componentMap = ComponentMap.loadComponents(serverUrl).with(comps); CachingProxyDecorator cachingDecorator = new CachingProxyDecorator(FunctionTestUtils.createCacheProvider()); FXForwardPVFn pvFunction = FunctionModel.build(FXForwardPVFn.class, createFunctionConfig(), componentMap, TracingProxy.INSTANCE, cachingDecorator); ExternalId regionId = ExternalId.of(ExternalSchemes.FINANCIAL, "US"); ZonedDateTime forwardDate = ZonedDateTime.of(2014, 11, 7, 12, 0, 0, 0, ZoneOffset.UTC); FXForwardSecurity security = new FXForwardSecurity(EUR, 10_000_000, USD, 14_000_000, forwardDate, regionId); security.setUniqueId(UniqueId.of("sec", "123")); //TracingProxy.start(new FullTracer()); Result<CurrencyLabelledMatrix1D> result = null; ZonedDateTime valuationTime = ZonedDateTime.of(2013, 11, 1, 9, 0, 0, 0, ZoneOffset.UTC); FieldName fieldName = FieldName.of(MarketDataRequirementNames.MARKET_VALUE); MarketDataEnvironment marketData = createMarketDataEnvironment(marketDataMap, fieldName); SimpleEnvironment env = new SimpleEnvironment(valuationTime, marketData.toBundle()); for (int i = 0; i < 100; i++) { result = pvFunction.calculatePV(env, security); System.out.println(); } //System.out.println(TracingProxy.end().prettyPrint()); return result; } //@Test(groups = TestGroup.INTEGRATION) @Test(groups = TestGroup.INTEGRATION, enabled = false) public void executeYieldCurveAgainstRemoteServer() throws IOException { // String serverUrl = "http://devsvr-lx-2:8080"; String serverUrl = "http://localhost:8080"; URI htsResolverUri = URI.create(serverUrl + "/jax/components/HistoricalTimeSeriesResolver/shared"); HistoricalTimeSeriesResolver htsResolver = new RemoteHistoricalTimeSeriesResolver(htsResolverUri); ZonedDateTime valuationTime = ZonedDateTime.of(2013, 11, 1, 9, 0, 0, 0, ZoneOffset.UTC); Map<ExternalIdBundle, Double> marketDataMap = MarketDataResourcesLoader.getData("yield-curve-marketdata.properties", ExternalSchemes.BLOOMBERG_TICKER); marketDataMap.put(ExternalIdBundle.of(ExternalSchemes.BLOOMBERG_TICKER, "JPY Curncy"), 98.86); Map<Class<?>, Object> comps = ImmutableMap.<Class<?>, Object>of(HistoricalTimeSeriesResolver.class, htsResolver); ComponentMap componentMap = ComponentMap.loadComponents(serverUrl).with(comps); DiscountingMulticurveBundleResolverFn bundleProvider = FunctionModel.build(DiscountingMulticurveBundleResolverFn.class, createFunctionConfig(), componentMap); ConfigSource configSource = componentMap.getComponent(ConfigSource.class); CurveConstructionConfiguration curveConfig = configSource.get(CurveConstructionConfiguration.class, "Z-Marc JPY Dsc - FX USD", VersionCorrection.LATEST) .iterator().next().getValue(); FieldName fieldName = FieldName.of(MarketDataRequirementNames.MARKET_VALUE); MarketDataEnvironment marketData = createMarketDataEnvironment(marketDataMap, fieldName); SimpleEnvironment env = new SimpleEnvironment(valuationTime, marketData.toBundle()); Result<MulticurveBundle> result = bundleProvider.generateBundle(env, curveConfig); assertNotNull(result); assertThat(result.getStatus(), is((ResultStatus) SUCCESS)); // Can examine result.getValue().getCurve("Z-Marc JPY Discounting - USD FX")) which should match view } //@Test(groups = TestGroup.INTEGRATION) @Test(groups = TestGroup.INTEGRATION, enabled = false) public void curveBundleOnly() throws IOException { ZonedDateTime valuationTime = ZonedDateTime.of(2013, 11, 1, 9, 0, 0, 0, ZoneOffset.UTC); ConfigLink<CurrencyMatrix> currencyMatrixLink = ConfigLink.resolvable("BloombergLiveData", CurrencyMatrix.class); ViewConfig viewConfig = configureView( "Curve Bundle only", nonPortfolioOutput( "Curve Bundle", output(OutputNames.DISCOUNTING_MULTICURVE_BUNDLE, config( arguments( function( RootFinderConfiguration.class, argument("rootFinderAbsoluteTolerance", 1e-9), argument("rootFinderRelativeTolerance", 1e-9), argument("rootFinderMaxIterations", 1000)), function( DefaultCurrencyPairsFn.class, argument("currencyPairs", ImmutableSet.of( CurrencyPair.of(USD, JPY), CurrencyPair.of(EUR, USD), CurrencyPair.of(GBP, USD)))), function( DefaultDiscountingMulticurveBundleFn.class, argument("impliedCurveNames", StringSet.of()), argument("curveConfig", ConfigLink.resolvable("USD", CurveConstructionConfiguration.class)))))))); AvailableOutputs availableOutputs = new AvailableOutputsImpl(); availableOutputs.register(DiscountingMulticurveBundleFn.class); AvailableImplementations availableImplementations = new AvailableImplementationsImpl(); availableImplementations.register(DiscountingFXForwardPVFn.class, DefaultCurrencyPairsFn.class, FXForwardSecurityConverter.class, ConfigDBInstrumentExposuresProvider.class, DefaultCurveSpecificationMarketDataFn.class, ExposureFunctionsDiscountingMulticurveCombinerFn.class, DefaultFXMatrixFn.class, DefaultCurveDefinitionFn.class, DefaultDiscountingMulticurveBundleFn.class, DefaultCurveSpecificationFn.class, ConfigDBCurveConstructionConfigurationSource.class, FixingsFn.class, FXForwardDiscountingCalculatorFn.class, DefaultMarketDataFn.class, DefaultHistoricalMarketDataFn.class); String serverUrl = "http://devsvr-lx-2:8080"; URI htsResolverUri = URI.create(serverUrl + "/jax/components/HistoricalTimeSeriesResolver/shared"); HistoricalTimeSeriesResolver htsResolver = new RemoteHistoricalTimeSeriesResolver(htsResolverUri); Map<Class<?>, Object> comps = ImmutableMap.<Class<?>, Object>of(HistoricalTimeSeriesResolver.class, htsResolver); ComponentMap componentMap = ComponentMap.loadComponents(serverUrl).with(comps); VersionCorrectionProvider vcProvider = new FixedInstantVersionCorrectionProvider(); ServiceContext serviceContext = ServiceContext.of(componentMap.getComponents()).with(VersionCorrectionProvider.class, vcProvider); ThreadLocalServiceContext.init(serviceContext); ViewFactory viewFactory = new ViewFactory(new DirectExecutorService(), componentMap, availableOutputs, availableImplementations, FunctionModelConfig.EMPTY, EnumSet.noneOf(FunctionService.class), FunctionTestUtils.createCacheBuilder(), new NoOpCacheInvalidator(), Optional.<MetricRegistry>absent()); View view = viewFactory.createView(viewConfig); Map<ExternalIdBundle, Double> marketDataMap = MarketDataResourcesLoader.getData("/marketdata.properties", ExternalSchemes.BLOOMBERG_TICKER); FieldName fieldName = FieldName.of(MarketDataRequirementNames.MARKET_VALUE); MarketDataEnvironment marketData = createMarketDataEnvironment(marketDataMap, fieldName); CycleArguments cycleArguments = CycleArguments.builder(marketData).valuationTime(valuationTime).build(); Results results = view.run(cycleArguments); System.out.println(results); ResultItem resultItem = results.get("Curve Bundle"); Result<?> result = resultItem.getResult(); assertTrue(result.isSuccess()); Object value = result.getValue(); assertNotNull(value); System.out.println(value); } //@Test(groups = TestGroup.INTEGRATION) @Test(groups = TestGroup.INTEGRATION, enabled = false) public void engine() throws Exception { //int nTrades = 1_000_000; //int nTrades = 10_000; int nTrades = 1_000; //int nTrades = 1; //int nTrades = 2; long startTrades = System.currentTimeMillis(); List<Trade> trades = Lists.newArrayListWithCapacity(nTrades); for (int i = 0; i < nTrades; i++) { trades.add(createRandomFxForwardTrade()); } s_logger.info("created {} trades in {}ms", nTrades, System.currentTimeMillis() - startTrades); ConfigLink<ExposureFunctions> exposureConfig = ConfigLink.resolvable("Exposure Config", ExposureFunctions.class); ViewConfig viewConfig = configureView( "FX forward PV view", column( "Present Value", output( OutputNames.FX_PRESENT_VALUE, FXForwardSecurity.class, config( arguments( function( MarketExposureSelector.class, argument("exposureFunctions", exposureConfig)), function( RootFinderConfiguration.class, argument("rootFinderAbsoluteTolerance", 1e-9), argument("rootFinderRelativeTolerance", 1e-9), argument("rootFinderMaxIterations", 1000)), function( DefaultCurrencyPairsFn.class, argument( "currencyPairs", ImmutableSet.of(CurrencyPair.of(USD, JPY), CurrencyPair.of(EUR, USD), CurrencyPair.of(GBP, USD)))), function( DefaultDiscountingMulticurveBundleFn.class, argument("impliedCurveNames", StringSet.of()))))))); ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 2); String serverUrl = "http://devsvr-lx-2:8080"; URI htsResolverUri = URI.create(serverUrl + "/jax/components/HistoricalTimeSeriesResolver/shared"); HistoricalTimeSeriesResolver htsResolver = new RemoteHistoricalTimeSeriesResolver(htsResolverUri); Map<Class<?>, Object> comps = ImmutableMap.<Class<?>, Object>of(HistoricalTimeSeriesResolver.class, htsResolver); long startComponents = System.currentTimeMillis(); ComponentMap componentMap = ComponentMap.loadComponents(serverUrl).with(comps); s_logger.info("loaded components in {}ms", System.currentTimeMillis() - startComponents); AvailableOutputs availableOutputs = new AvailableOutputsImpl(); availableOutputs.register(FXForwardPVFn.class); AvailableImplementations availableImplementations = new AvailableImplementationsImpl(); availableImplementations.register(DiscountingFXForwardPVFn.class, DefaultCurrencyPairsFn.class, FXForwardSecurityConverter.class, ConfigDBInstrumentExposuresProvider.class, DefaultCurveSpecificationMarketDataFn.class, DefaultFXMatrixFn.class, DefaultCurveDefinitionFn.class, DefaultDiscountingMulticurveBundleFn.class, ExposureFunctionsDiscountingMulticurveCombinerFn.class, DefaultCurveSpecificationFn.class, ConfigDBCurveConstructionConfigurationSource.class, FixingsFn.class, FXForwardDiscountingCalculatorFn.class); long startEngine = System.currentTimeMillis(); VersionCorrectionProvider vcProvider = new FixedInstantVersionCorrectionProvider(); ServiceContext serviceContext = ServiceContext.of(componentMap.getComponents()).with(VersionCorrectionProvider.class, vcProvider); ThreadLocalServiceContext.init(serviceContext); ViewFactory viewFactory = new ViewFactory(executor, componentMap, availableOutputs, availableImplementations, FunctionModelConfig.EMPTY, EnumSet.of(FunctionService.CACHING, FunctionService.TRACING), FunctionTestUtils.createCacheBuilder(), new NoOpCacheInvalidator(), Optional.<MetricRegistry>absent()); s_logger.info("created engine in {}ms", System.currentTimeMillis() - startEngine); long graphStart = System.currentTimeMillis(); View view = viewFactory.createView(viewConfig, FXForwardSecurity.class); s_logger.info("view built in {}ms", System.currentTimeMillis() - graphStart); //@SuppressWarnings("unchecked") //Set<Pair<Integer, Integer>> traceFunctions = Sets.newHashSet(Pairs.of(0, 0), Pairs.of(1, 0)); //CycleArguments cycleArguments = new CycleArguments(valuationTime, marketDataFactory, traceFunctions); ZonedDateTime valuationTime = ZonedDateTime.of(2013, 11, 1, 9, 0, 0, 0, ZoneOffset.UTC); Map<ExternalIdBundle, Double> marketDataMap = MarketDataResourcesLoader.getData("marketdata.properties", ExternalSchemes.BLOOMBERG_TICKER); FieldName fieldName = FieldName.of(MarketDataRequirementNames.MARKET_VALUE); MarketDataEnvironment marketData = createMarketDataEnvironment(marketDataMap, fieldName); CycleArguments cycleArguments = CycleArguments.builder(marketData).valuationTime(valuationTime).build(); //int nRuns = 1; int nRuns = 20; for (int i = 0; i < nRuns; i++) { long start = System.currentTimeMillis(); view.run(cycleArguments, trades); //Results results = view.run(cycleArguments); //System.out.println(results.get(0, 0).getCallGraph().prettyPrint()); //System.out.println(results.get(1, 0).getCallGraph().prettyPrint()); long time = System.currentTimeMillis() - start; s_logger.info("view executed in {}ms", time); Thread.sleep(1000); } } private MarketDataEnvironment createMarketDataEnvironment(Map<ExternalIdBundle, Double> marketData, FieldName fieldName) { MarketDataEnvironmentBuilder builder = new MarketDataEnvironmentBuilder(); for (Map.Entry<ExternalIdBundle, Double> entry : marketData.entrySet()) { builder.add(RawId.of(entry.getKey(), fieldName), entry.getValue()); } return builder.build(); } private static Trade createRandomFxForwardTrade() { ExternalId regionId = ExternalId.of(ExternalSchemes.FINANCIAL, "US"); double usdAmount = 10_000_000 * Math.random(); double eurAmount = usdAmount * (1.31 + 0.04 * Math.random()); Currency payCcy; Currency recCcy; double payAmount; double recAmount; if (Math.random() < 0.5) { payAmount = usdAmount; payCcy = USD; recAmount = eurAmount; recCcy = EUR; } else { payAmount = eurAmount; payCcy = EUR; recAmount = usdAmount; recCcy = USD; } ZonedDateTime forwardDate = ZonedDateTime.now().plusWeeks((long) (104 * Math.random())); FXForwardSecurity security = new FXForwardSecurity(payCcy, payAmount, recCcy, recAmount, forwardDate, regionId); String id = Long.toString(s_nextId.getAndIncrement()); security.setUniqueId(UniqueId.of("fxFwdSec", id)); security.setName("FX forward " + id); SimpleTrade trade = new SimpleTrade(); SimpleSecurityLink securityLink = new SimpleSecurityLink(ExternalId.of("fxFwdSecEx", id)); securityLink.setTarget(security); trade.setSecurityLink(securityLink); trade.setUniqueId(UniqueId.of("fxFwdTrd", id)); return trade; } private static FunctionModelConfig createFunctionConfig() { return config( arguments( function( MarketExposureSelector.class, argument("exposureFunctions", ConfigLink.resolved(mock(ExposureFunctions.class)))), function( RootFinderConfiguration.class, argument("rootFinderAbsoluteTolerance", 1e-9), argument("rootFinderRelativeTolerance", 1e-9), argument("rootFinderMaxIterations", 1000)), function( DefaultCurveNodeConverterFn.class, argument("timeSeriesDuration", RetrievalPeriod.of(Period.ofYears(1)))), function( DefaultCurrencyPairsFn.class, argument("currencyPairs", ImmutableSet.of(CurrencyPair.of(USD, JPY), CurrencyPair.of(EUR, USD), CurrencyPair.of(GBP, USD)))), function( DefaultDiscountingMulticurveBundleFn.class, argument("impliedCurveNames", StringSet.of()))), implementations( FXForwardPVFn.class, DiscountingFXForwardPVFn.class, FXForwardCalculatorFn.class, FXForwardDiscountingCalculatorFn.class, CurrencyPairsFn.class, DefaultCurrencyPairsFn.class, FinancialSecurityVisitor.class, FXForwardSecurityConverter.class, InstrumentExposuresProvider.class, ConfigDBInstrumentExposuresProvider.class, CurveSpecificationMarketDataFn.class, DefaultCurveSpecificationMarketDataFn.class, FXMatrixFn.class, DefaultFXMatrixFn.class, CurveDefinitionFn.class, DefaultCurveDefinitionFn.class, DiscountingMulticurveBundleFn.class, DefaultDiscountingMulticurveBundleFn.class, DiscountingMulticurveBundleResolverFn.class, DefaultDiscountingMulticurveBundleResolverFn.class, DiscountingMulticurveCombinerFn.class, ExposureFunctionsDiscountingMulticurveCombinerFn.class, CurveSpecificationFn.class, DefaultCurveSpecificationFn.class, CurveConstructionConfigurationSource.class, ConfigDBCurveConstructionConfigurationSource.class, CurveNodeConverterFn.class, DefaultCurveNodeConverterFn.class)); } private static ComponentMap componentMap(Class<?>... componentTypes) { Map<Class<?>, Object> compMap = Maps.newHashMap(); for (Class<?> componentType : componentTypes) { compMap.put(componentType, mock(componentType)); } return ComponentMap.of(compMap); } }