/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.view;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.threeten.bp.LocalDate;
import com.google.common.collect.Sets;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.function.FunctionCompilationContext;
import com.opengamma.engine.function.FunctionExecutionContext;
import com.opengamma.engine.marketdata.spec.FixedHistoricalMarketDataSpecification;
import com.opengamma.engine.marketdata.spec.HistoricalShockMarketDataSpecification;
import com.opengamma.engine.marketdata.spec.MarketDataSpecification;
import com.opengamma.engine.value.ComputedValue;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueRequirementNames;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.engine.view.ViewComputationResultModel;
import com.opengamma.engine.view.compilation.CompiledViewDefinition;
import com.opengamma.engine.view.execution.ViewCycleExecutionOptions;
import com.opengamma.engine.view.execution.ViewExecutionFlags;
/**
* Runs an execution sequence over a series of historical dates, returning the results as time-series.
*/
public class HistoricalViewEvaluationFunction extends ViewEvaluationFunction<HistoricalViewEvaluationTarget, HistoricalViewEvaluationResultBuilder> {
/**
* Name of a property on an output value that contains the market data used rather than the computed results.
*/
public static final String MARKET_DATA_PROPERTY_NAME = "Type";
/**
* Value taken by the {@link #MARKET_DATA_PROPERTY_NAME} property when the output contains market data used rather than the computed results.
*/
public static final String MARKET_DATA_PROPERTY_VALUE = "MarketData";
public HistoricalViewEvaluationFunction() {
super(ValueRequirementNames.HISTORICAL_TIME_SERIES, HistoricalViewEvaluationTarget.class);
}
protected ValueSpecification getMarketDataResultSpec(final ComputationTargetSpecification targetSpec) {
return new ValueSpecification(ValueRequirementNames.HISTORICAL_TIME_SERIES, targetSpec, createValueProperties().with(MARKET_DATA_PROPERTY_NAME, MARKET_DATA_PROPERTY_VALUE).get());
}
// CompiledFunctionDefinition
@Override
public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) {
final Set<ValueSpecification> results = super.getResults(context, target);
results.add(getMarketDataResultSpec(target.toSpecification()));
return results;
}
// ViewEvaluationFunction
@Override
protected ViewCycleExecutionOptions getDefaultCycleOptions(FunctionExecutionContext context) {
return ViewCycleExecutionOptions.builder().setValuationTime(context.getValuationTime()).setResolverVersionCorrection(context.getComputationTargetResolver().getVersionCorrection()).create();
}
@Override
protected EnumSet<ViewExecutionFlags> getViewExecutionFlags(Set<ValueRequirement> desiredValues) {
final EnumSet<ViewExecutionFlags> flags = super.getViewExecutionFlags(desiredValues);
for (ValueRequirement desiredValue : desiredValues) {
if (!MARKET_DATA_PROPERTY_VALUE.equals(desiredValue.getConstraint(MARKET_DATA_PROPERTY_NAME))) {
return flags;
}
}
// No result values were requested, so don't bother executing the cycles
flags.add(ViewExecutionFlags.FETCH_MARKET_DATA_ONLY);
return flags;
}
@Override
protected HistoricalViewEvaluationResultBuilder createResultBuilder(final ViewEvaluationTarget target, final Set<ValueRequirement> desiredValues) {
boolean includeMarketData = false;
for (ValueRequirement desiredValue : desiredValues) {
if (MARKET_DATA_PROPERTY_VALUE.equals(desiredValue.getConstraint(MARKET_DATA_PROPERTY_NAME))) {
includeMarketData = true;
break;
}
}
return new HistoricalViewEvaluationResultBuilder(target.getViewDefinition(), includeMarketData);
}
@Override
protected void store(ViewComputationResultModel results, HistoricalViewEvaluationResultBuilder resultBuilder) {
resultBuilder.store(getResultsDate(results.getViewCycleExecutionOptions()), results);
}
@Override
protected void store(CompiledViewDefinition compiledViewDefinition, HistoricalViewEvaluationResultBuilder resultBuilder) {
resultBuilder.store(compiledViewDefinition);
}
@Override
protected Set<ComputedValue> buildResults(ComputationTarget target, HistoricalViewEvaluationResultBuilder resultBuilder) {
final Map<String, HistoricalViewEvaluationResult> viewResults = resultBuilder.getResults();
final Set<ComputedValue> results = Sets.newHashSetWithExpectedSize(viewResults.size() + 1);
final ComputationTargetSpecification targetSpec = target.toSpecification();
for (final Map.Entry<String, HistoricalViewEvaluationResult> viewResult : viewResults.entrySet()) {
String calcConfigName = viewResult.getKey();
HistoricalViewEvaluationResult value = viewResult.getValue();
results.add(new ComputedValue(getResultSpec(calcConfigName, targetSpec), value));
}
final HistoricalViewEvaluationMarketData viewMarketData = resultBuilder.getMarketData();
if (viewMarketData != null) {
results.add(new ComputedValue(getMarketDataResultSpec(targetSpec), viewMarketData));
}
return results;
}
//-------------------------------------------------------------------------
private LocalDate getResultsDate(ViewCycleExecutionOptions cycleExecutionOptions) {
// NOTE jonathan 2013-02-28 -- could imagine using constraints
List<MarketDataSpecification> marketDataSpecifications = cycleExecutionOptions.getMarketDataSpecifications();
if (marketDataSpecifications.size() != 1) {
throw new OpenGammaRuntimeException("Expected cycle execution options to contain exactly 1 market data specification but found " +
marketDataSpecifications.size() + ": " + cycleExecutionOptions);
}
MarketDataSpecification marketDataSpec = marketDataSpecifications.get(0);
if (marketDataSpec instanceof FixedHistoricalMarketDataSpecification) {
return ((FixedHistoricalMarketDataSpecification) marketDataSpec).getSnapshotDate();
} else if (marketDataSpec instanceof HistoricalShockMarketDataSpecification) {
MarketDataSpecification spec2 = ((HistoricalShockMarketDataSpecification) marketDataSpec).getHistoricalSpecification2();
if (spec2 instanceof FixedHistoricalMarketDataSpecification) {
return ((FixedHistoricalMarketDataSpecification) spec2).getSnapshotDate();
} else {
throw new OpenGammaRuntimeException("Unsupported inner market data specification: " + spec2);
}
} else {
throw new OpenGammaRuntimeException("Unsupported market data specification: " + marketDataSpec);
}
}
}