/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.calc.runner; import static com.opengamma.strata.basics.currency.Currency.EUR; import static com.opengamma.strata.basics.currency.Currency.GBP; import static com.opengamma.strata.basics.currency.Currency.USD; import static com.opengamma.strata.collect.CollectProjectAssertions.assertThat; import static com.opengamma.strata.collect.Guavate.toImmutableList; import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; import static com.opengamma.strata.collect.TestHelper.date; import static org.assertj.core.api.Assertions.assertThat; import static org.testng.Assert.assertNotNull; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.opengamma.strata.basics.CalculationTarget; import com.opengamma.strata.basics.ReferenceData; import com.opengamma.strata.basics.ReferenceDataNotFoundException; import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.basics.currency.CurrencyAmount; import com.opengamma.strata.basics.currency.FxRate; import com.opengamma.strata.calc.Measure; import com.opengamma.strata.calc.ReportingCurrency; import com.opengamma.strata.calc.TestingMeasures; import com.opengamma.strata.calc.marketdata.MarketDataRequirements; import com.opengamma.strata.calc.marketdata.TestId; import com.opengamma.strata.calc.marketdata.TestObservableId; import com.opengamma.strata.collect.array.DoubleArray; import com.opengamma.strata.collect.result.FailureReason; import com.opengamma.strata.collect.result.Result; import com.opengamma.strata.data.FxRateId; import com.opengamma.strata.data.MarketDataId; import com.opengamma.strata.data.MarketDataNotFoundException; import com.opengamma.strata.data.ObservableId; import com.opengamma.strata.data.ObservableSource; import com.opengamma.strata.data.scenario.CurrencyScenarioArray; import com.opengamma.strata.data.scenario.ImmutableScenarioMarketData; import com.opengamma.strata.data.scenario.ScenarioArray; import com.opengamma.strata.data.scenario.ScenarioMarketData; /** * Test {@link CalculationTask}. */ @Test public class CalculationTaskTest { static final ObservableSource OBS_SOURCE = ObservableSource.of("MarketDataVendor"); private static final ReferenceData REF_DATA = ReferenceData.standard(); private static final ReportingCurrency NATURAL = ReportingCurrency.NATURAL; private static final ReportingCurrency REPORTING_CURRENCY_USD = ReportingCurrency.of(Currency.USD); private static final TestTarget TARGET = new TestTarget(); private static final Set<Measure> MEASURES = ImmutableSet.of(TestingMeasures.PRESENT_VALUE, TestingMeasures.PRESENT_VALUE_MULTI_CCY); public void requirements() { CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, NATURAL); CalculationTask task = CalculationTask.of(TARGET, new TestFunction(), cell); MarketDataRequirements requirements = task.requirements(REF_DATA); Set<? extends MarketDataId<?>> nonObservables = requirements.getNonObservables(); ImmutableSet<? extends ObservableId> observables = requirements.getObservables(); ImmutableSet<ObservableId> timeSeries = requirements.getTimeSeries(); MarketDataId<?> timeSeriesId = TestObservableId.of("3", OBS_SOURCE); assertThat(timeSeries).hasSize(1); assertThat(timeSeries.iterator().next()).isEqualTo(timeSeriesId); MarketDataId<?> nonObservableId = new TestId("1"); assertThat(nonObservables).hasSize(1); assertThat(nonObservables.iterator().next()).isEqualTo(nonObservableId); MarketDataId<?> observableId = TestObservableId.of("2", OBS_SOURCE); assertThat(observables).hasSize(1); assertThat(observables.iterator().next()).isEqualTo(observableId); } /** * Test that the result is converted to the reporting currency if it implements ScenarioFxConvertible and * the FX rates are available in the market data. */ public void convertResultCurrencyUsingReportingCurrency() { DoubleArray values = DoubleArray.of(1, 2, 3); List<FxRate> rates = ImmutableList.of(1.61, 1.62, 1.63).stream() .map(rate -> FxRate.of(GBP, USD, rate)) .collect(toImmutableList()); CurrencyScenarioArray list = CurrencyScenarioArray.of(GBP, values); ScenarioMarketData marketData = ImmutableScenarioMarketData.builder(date(2011, 3, 8)) .addScenarioValue(FxRateId.of(GBP, USD), rates) .build(); ConvertibleFunction fn = ConvertibleFunction.of(() -> list, GBP); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); DoubleArray expectedValues = DoubleArray.of(1 * 1.61, 2 * 1.62, 3 * 1.63); CurrencyScenarioArray expectedArray = CurrencyScenarioArray.of(USD, expectedValues); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result).hasValue(expectedArray); } /** * Test that the result is not converted if the isCurrencyConvertible flag on the measure is false. */ public void currencyConversionHonoursConvertibleFlagOnMeasure() { DoubleArray values = DoubleArray.of(1, 2, 3); List<FxRate> rates = ImmutableList.of(1.61, 1.62, 1.63).stream() .map(rate -> FxRate.of(GBP, USD, rate)) .collect(toImmutableList()); CurrencyScenarioArray list = CurrencyScenarioArray.of(GBP, values); ScenarioMarketData marketData = ImmutableScenarioMarketData.builder(date(2011, 3, 8)) .addScenarioValue(FxRateId.of(GBP, USD), rates) .build(); ConvertibleFunction fn = ConvertibleFunction.of(() -> list, GBP); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE_MULTI_CCY, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); CurrencyScenarioArray expectedArray = CurrencyScenarioArray.of(GBP, values); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result).hasValue(expectedArray); } /** * Test that the result is converted to the reporting currency if it implements ScenarioFxConvertible and * the FX rates are available in the market data. The "natural" currency is taken from the function. */ public void convertResultCurrencyUsingDefaultReportingCurrency() { DoubleArray values = DoubleArray.of(1, 2, 3); List<FxRate> rates = ImmutableList.of(1.61, 1.62, 1.63).stream() .map(rate -> FxRate.of(GBP, USD, rate)) .collect(toImmutableList()); CurrencyScenarioArray list = CurrencyScenarioArray.of(GBP, values); ScenarioMarketData marketData = ImmutableScenarioMarketData.builder(date(2011, 3, 8)) .addScenarioValue(FxRateId.of(GBP, USD), rates) .build(); ConvertibleFunction fn = ConvertibleFunction.of(() -> list, USD); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, NATURAL); CalculationTask task = CalculationTask.of(TARGET, fn, cell); DoubleArray expectedValues = DoubleArray.of(1 * 1.61, 2 * 1.62, 3 * 1.63); CurrencyScenarioArray expectedArray = CurrencyScenarioArray.of(USD, expectedValues); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result).hasValue(expectedArray); } /** * Test that the result is returned unchanged if it is a failure. */ public void convertResultCurrencyFailure() { ConvertibleFunction fn = ConvertibleFunction.of(() -> { throw new RuntimeException("This is a failure"); }, GBP); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ScenarioMarketData.empty(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result) .isFailure(FailureReason.CALCULATION_FAILED) .hasFailureMessageMatching("Error when invoking function 'ConvertibleFunction' for ID '123': This is a failure"); } /** * Test the result is returned unchanged if using ReportingCurrency.NONE. */ public void convertResultCurrencyNoConversionRequested() { SupplierFunction<CurrencyAmount> fn = SupplierFunction.of(() -> CurrencyAmount.of(EUR, 1d)); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, ReportingCurrency.NONE); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ImmutableScenarioMarketData.builder(date(2011, 3, 8)).build(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result).hasValue(ScenarioArray.of(CurrencyAmount.of(EUR, 1d))); } /** * Test the result is returned unchanged if it is not ScenarioFxConvertible. */ public void convertResultCurrencyNotConvertible() { TestFunction fn = new TestFunction(); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ImmutableScenarioMarketData.builder(date(2011, 3, 8)).build(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result).hasValue(ScenarioArray.of("bar")); } /** * Test a non-convertible result is returned even if there is no reporting currency. */ public void nonConvertibleResultReturnedWhenNoReportingCurrency() { TestFunction fn = new TestFunction(); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, NATURAL); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ImmutableScenarioMarketData.builder(date(2011, 3, 8)).build(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result).hasValue(ScenarioArray.of("bar")); } /** * Test that a failure is returned if currency conversion fails. */ public void convertResultCurrencyConversionFails() { DoubleArray values = DoubleArray.of(1, 2, 3); CurrencyScenarioArray list = CurrencyScenarioArray.of(GBP, values); // Market data doesn't include FX rates, conversion to USD will fail ScenarioMarketData marketData = ScenarioMarketData.empty(); ConvertibleFunction fn = ConvertibleFunction.of(() -> list, GBP); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result) .isFailure(FailureReason.CURRENCY_CONVERSION) .hasFailureMessageMatching("Failed to convert value '.*' to currency 'USD'"); } /** * Tests that executing a function wraps its return value in a success result. */ public void execute() { SupplierFunction<String> fn = SupplierFunction.of(() -> "foo"); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ImmutableScenarioMarketData.builder(date(2011, 3, 8)).build(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result).hasValue(ScenarioArray.of("foo")); } /** * Test executing a bad function that fails to return expected measure. */ public void executeMissingMeasure() { // function claims it supports 'PresentValueMultiCurrency' but fails to return it when asked MeasureCheckFunction fn = new MeasureCheckFunction(ImmutableSet.of(TestingMeasures.PRESENT_VALUE), Optional.of("123")); CalculationTaskCell cell0 = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTaskCell cell1 = CalculationTaskCell.of(0, 1, TestingMeasures.PRESENT_VALUE_MULTI_CCY, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell0, cell1); ScenarioMarketData marketData = ScenarioMarketData.empty(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result0 = calculationResults.getCells().get(0).getResult(); assertThat(result0) .isSuccess() .hasValue(ImmutableSet.of(TestingMeasures.PRESENT_VALUE, TestingMeasures.PRESENT_VALUE_MULTI_CCY)); Result<?> result1 = calculationResults.getCells().get(1).getResult(); assertThat(result1) .isFailure(FailureReason.CALCULATION_FAILED) .hasFailureMessageMatching( "Function 'MeasureCheckFunction' did not return requested measure 'PresentValueMultiCurrency' for ID '123'"); } /** * Tests that executing a function filters the set of measures sent to function. */ public void executeFilterMeasures() { // function does not support 'ParRate', so it should not be asked for it MeasureCheckFunction fn = new MeasureCheckFunction(ImmutableSet.of(TestingMeasures.PRESENT_VALUE), Optional.of("123")); CalculationTaskCell cell0 = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTaskCell cell1 = CalculationTaskCell.of(0, 1, TestingMeasures.PAR_RATE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell0, cell1); ScenarioMarketData marketData = ScenarioMarketData.empty(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result0 = calculationResults.getCells().get(0).getResult(); assertThat(result0) .isSuccess() .hasValue(ImmutableSet.of(TestingMeasures.PRESENT_VALUE)); // ParRate not requested Result<?> result1 = calculationResults.getCells().get(1).getResult(); assertThat(result1) .isFailure(FailureReason.UNSUPPORTED) .hasFailureMessageMatching("Measure 'ParRate' is not supported by function 'MeasureCheckFunction'"); } /** * Tests that executing a function that throws an exception wraps the exception in a failure result. */ public void executeException() { SupplierFunction<String> fn = SupplierFunction.of(() -> { throw new IllegalArgumentException("foo"); }); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ScenarioMarketData.empty(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result) .isFailure(FailureReason.CALCULATION_FAILED) .hasFailureMessageMatching("Error when invoking function 'SupplierFunction' for ID '123': foo"); } /** * Tests that executing a function that throws a market data exception wraps the exception in a failure result. */ public void executeException_marketData() { SupplierFunction<String> fn = SupplierFunction.of(() -> { throw new MarketDataNotFoundException("foo"); }); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ScenarioMarketData.empty(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result) .isFailure(FailureReason.MISSING_DATA) .hasFailureMessageMatching("Missing market data when invoking function 'SupplierFunction' for ID '123': foo"); } /** * Tests that executing a function that throws a market data exception wraps the exception in a failure result. * Target has no identifier. */ public void executeException_marketData_noIdentifier() { SupplierFunction<String> fn = SupplierFunction.of(() -> { throw new MarketDataNotFoundException("foo"); }, Optional.empty()); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ScenarioMarketData.empty(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result) .isFailure(FailureReason.MISSING_DATA) .hasFailureMessageMatching("Missing market data when invoking function 'SupplierFunction': foo: for target '.*'"); } /** * Tests that executing a function that throws a reference data exception wraps the exception in a failure result. */ public void executeException_referenceData() { SupplierFunction<String> fn = SupplierFunction.of(() -> { throw new ReferenceDataNotFoundException("foo"); }); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ScenarioMarketData.empty(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result) .isFailure(FailureReason.MISSING_DATA) .hasFailureMessageMatching("Missing reference data when invoking function 'SupplierFunction' for ID '123': foo"); } /** * Tests that executing a function that throws an unsupported exception wraps the exception in a failure result. */ public void executeException_unsupported() { SupplierFunction<String> fn = SupplierFunction.of(() -> { throw new UnsupportedOperationException("foo"); }); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ScenarioMarketData.empty(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result) .isFailure(FailureReason.UNSUPPORTED) .hasFailureMessageMatching("Unsupported operation when invoking function 'SupplierFunction' for ID '123': foo"); } /** * Tests that executing a function that returns a success result returns the underlying result without wrapping it. */ public void executeSuccessResultValue() { SupplierFunction<Result<ScenarioArray<String>>> fn = SupplierFunction.of(() -> Result.success(ScenarioArray.of("foo"))); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ImmutableScenarioMarketData.builder(date(2011, 3, 8)).build(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result).hasValue(ScenarioArray.of("foo")); } /** * Tests that executing a function that returns a failure result returns the underlying result without wrapping it. */ public void executeFailureResultValue() { SupplierFunction<Result<String>> fn = SupplierFunction.of(() -> Result.failure(FailureReason.NOT_APPLICABLE, "bar")); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); ScenarioMarketData marketData = ScenarioMarketData.empty(); CalculationResults calculationResults = task.execute(marketData, REF_DATA); Result<?> result = calculationResults.getCells().get(0).getResult(); assertThat(result).isFailure(FailureReason.NOT_APPLICABLE).hasFailureMessageMatching("bar"); } /** * Tests that requirements are added for the FX rates needed to convert the results into the reporting currency. */ public void fxConversionRequirements() { OutputCurrenciesFunction fn = new OutputCurrenciesFunction(); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); MarketDataRequirements requirements = task.requirements(REF_DATA); assertThat(requirements.getNonObservables()).containsOnly( FxRateId.of(GBP, USD, OBS_SOURCE), FxRateId.of(EUR, USD, OBS_SOURCE)); } /** * Tests that no requirements are added when not performing currency conversion. */ public void fxConversionRequirements_noConversion() { OutputCurrenciesFunction fn = new OutputCurrenciesFunction(); CalculationTaskCell cell = CalculationTaskCell.of(0, 0, TestingMeasures.PRESENT_VALUE, ReportingCurrency.NONE); CalculationTask task = CalculationTask.of(TARGET, fn, cell); MarketDataRequirements requirements = task.requirements(REF_DATA); assertThat(requirements.getNonObservables()).isEmpty(); } public void testToString() { OutputCurrenciesFunction fn = new OutputCurrenciesFunction(); CalculationTaskCell cell = CalculationTaskCell.of(1, 2, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask task = CalculationTask.of(TARGET, fn, cell); assertThat(task.toString()) .isEqualTo("CalculationTask[CalculationTaskCell[(1, 2), measure=PresentValue, currency=Specific:USD]]"); } //------------------------------------------------------------------------- public void coverage() { OutputCurrenciesFunction fn = new OutputCurrenciesFunction(); CalculationTaskCell cell = CalculationTaskCell.of(1, 2, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask test = CalculationTask.of(TARGET, fn, cell); coverImmutableBean(test); OutputCurrenciesFunction fn2 = new OutputCurrenciesFunction(); CalculationTaskCell cell2 = CalculationTaskCell.of(1, 3, TestingMeasures.PRESENT_VALUE, REPORTING_CURRENCY_USD); CalculationTask test2 = CalculationTask.of(new TestTarget(), fn2, cell2); coverBeanEquals(test, test2); assertNotNull(CalculationTask.meta()); } //------------------------------------------------------------------------- static class TestTarget implements CalculationTarget { } //------------------------------------------------------------------------- /** * Function that returns a value that is not currency convertible. */ public static final class TestFunction implements CalculationFunction<TestTarget> { @Override public Class<TestTarget> targetType() { return TestTarget.class; } @Override public Set<Measure> supportedMeasures() { return MEASURES; } @Override public Currency naturalCurrency(TestTarget trade, ReferenceData refData) { return USD; } @Override public FunctionRequirements requirements( TestTarget target, Set<Measure> measures, CalculationParameters parameters, ReferenceData refData) { return FunctionRequirements.builder() .valueRequirements( ImmutableSet.of( TestId.of("1"), TestObservableId.of("2"))) .timeSeriesRequirements(TestObservableId.of("3")) .observableSource(OBS_SOURCE) .build(); } @Override public Map<Measure, Result<?>> calculate( TestTarget target, Set<Measure> measures, CalculationParameters parameters, ScenarioMarketData marketData, ReferenceData refData) { ScenarioArray<String> array = ScenarioArray.of("bar"); return ImmutableMap.of(TestingMeasures.PRESENT_VALUE, Result.success(array)); } } //------------------------------------------------------------------------- /** * Function that returns a value that is currency convertible. */ private static final class ConvertibleFunction implements CalculationFunction<TestTarget> { private final Supplier<CurrencyScenarioArray> supplier; private final Currency naturalCurrency; static ConvertibleFunction of(Supplier<CurrencyScenarioArray> supplier, Currency naturalCurrency) { return new ConvertibleFunction(supplier, naturalCurrency); } private ConvertibleFunction(Supplier<CurrencyScenarioArray> supplier, Currency naturalCurrency) { this.supplier = supplier; this.naturalCurrency = naturalCurrency; } @Override public Class<TestTarget> targetType() { return TestTarget.class; } @Override public Set<Measure> supportedMeasures() { return MEASURES; } @Override public Optional<String> identifier(TestTarget target) { return Optional.of("123"); } @Override public Currency naturalCurrency(TestTarget trade, ReferenceData refData) { return naturalCurrency; } @Override public FunctionRequirements requirements( TestTarget target, Set<Measure> measures, CalculationParameters parameters, ReferenceData refData) { return FunctionRequirements.empty(); } @Override public Map<Measure, Result<?>> calculate( TestTarget target, Set<Measure> measures, CalculationParameters parameters, ScenarioMarketData marketData, ReferenceData refData) { Result<CurrencyScenarioArray> result = Result.success(supplier.get()); return ImmutableMap.of(TestingMeasures.PRESENT_VALUE, result, TestingMeasures.PRESENT_VALUE_MULTI_CCY, result); } } //------------------------------------------------------------------------- /** * Function that returns a value from a Supplier. */ private static final class SupplierFunction<T> implements CalculationFunction<TestTarget> { private final Supplier<T> supplier; private final Optional<String> id; public static <T> SupplierFunction<T> of(Supplier<T> supplier) { return of(supplier, Optional.of("123")); } public static <T> SupplierFunction<T> of(Supplier<T> supplier, Optional<String> id) { return new SupplierFunction<>(supplier, id); } private SupplierFunction(Supplier<T> supplier, Optional<String> id) { this.supplier = supplier; this.id = id; } @Override public Class<TestTarget> targetType() { return TestTarget.class; } @Override public Set<Measure> supportedMeasures() { return MEASURES; } @Override public Optional<String> identifier(TestTarget target) { return id; } @Override public Currency naturalCurrency(TestTarget trade, ReferenceData refData) { return USD; } @Override public FunctionRequirements requirements( TestTarget target, Set<Measure> measures, CalculationParameters parameters, ReferenceData refData) { return FunctionRequirements.empty(); } @SuppressWarnings("unchecked") @Override public Map<Measure, Result<?>> calculate( TestTarget target, Set<Measure> measures, CalculationParameters parameters, ScenarioMarketData marketData, ReferenceData refData) { T obj = supplier.get(); if (obj instanceof Result<?>) { return ImmutableMap.of(TestingMeasures.PRESENT_VALUE, (Result<?>) obj); } ScenarioArray<Object> array = ScenarioArray.of(obj); return ImmutableMap.of(TestingMeasures.PRESENT_VALUE, Result.success(array)); } } //------------------------------------------------------------------------- /** * Function that returns a value from a Supplier. */ private static final class MeasureCheckFunction implements CalculationFunction<TestTarget> { private final Set<Measure> resultMeasures; private final Optional<String> id; private MeasureCheckFunction(Set<Measure> resultMeasures, Optional<String> id) { this.resultMeasures = resultMeasures; this.id = id; } @Override public Class<TestTarget> targetType() { return TestTarget.class; } @Override public Set<Measure> supportedMeasures() { return MEASURES; } @Override public Optional<String> identifier(TestTarget target) { return id; } @Override public Currency naturalCurrency(TestTarget trade, ReferenceData refData) { return USD; } @Override public FunctionRequirements requirements( TestTarget target, Set<Measure> measures, CalculationParameters parameters, ReferenceData refData) { return FunctionRequirements.empty(); } @SuppressWarnings("unchecked") @Override public Map<Measure, Result<?>> calculate( TestTarget target, Set<Measure> measures, CalculationParameters parameters, ScenarioMarketData marketData, ReferenceData refData) { Map<Measure, Result<?>> map = new HashMap<>(); for (Measure measure : resultMeasures) { map.put(measure, Result.success(measures)); } return map; } } //------------------------------------------------------------------------- /** * Function that returns requirements containing output currencies. */ private static final class OutputCurrenciesFunction implements CalculationFunction<TestTarget> { @Override public Class<TestTarget> targetType() { return TestTarget.class; } @Override public Set<Measure> supportedMeasures() { return MEASURES; } @Override public Currency naturalCurrency(TestTarget trade, ReferenceData refData) { return USD; } @Override public FunctionRequirements requirements( TestTarget target, Set<Measure> measures, CalculationParameters parameters, ReferenceData refData) { return FunctionRequirements.builder() .outputCurrencies(GBP, EUR, USD) .observableSource(OBS_SOURCE) .build(); } @Override public Map<Measure, Result<?>> calculate( TestTarget target, Set<Measure> measures, CalculationParameters parameters, ScenarioMarketData marketData, ReferenceData refData) { throw new UnsupportedOperationException("calculate not implemented"); } } }