/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.view.helper;
import static org.testng.Assert.assertEquals;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.threeten.bp.Instant;
import com.opengamma.core.position.Portfolio;
import com.opengamma.core.position.PortfolioNode;
import com.opengamma.core.position.Position;
import com.opengamma.core.position.impl.SimplePortfolio;
import com.opengamma.core.position.impl.SimplePortfolioNode;
import com.opengamma.core.position.impl.SimplePosition;
import com.opengamma.core.security.Security;
import com.opengamma.core.security.impl.SimpleSecurityLink;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.function.CompiledFunctionDefinition;
import com.opengamma.engine.function.CompiledFunctionRepository;
import com.opengamma.engine.function.FunctionCompilationContext;
import com.opengamma.engine.function.FunctionDefinition;
import com.opengamma.engine.function.FunctionInvoker;
import com.opengamma.engine.function.FunctionParameters;
import com.opengamma.engine.function.InMemoryCompiledFunctionRepository;
import com.opengamma.engine.function.MarketDataAliasingFunction;
import com.opengamma.engine.function.MarketDataSourcingFunction;
import com.opengamma.engine.function.exclusion.AbstractFunctionExclusionGroups;
import com.opengamma.engine.marketdata.availability.MarketDataAvailabilityFilter;
import com.opengamma.engine.marketdata.availability.OptimisticMarketDataAvailabilityFilter;
import com.opengamma.engine.target.ComputationTargetType;
import com.opengamma.engine.value.ValueProperties;
import com.opengamma.engine.value.ValuePropertyNames;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.id.UniqueId;
import com.opengamma.util.test.TestGroup;
@Test(groups = TestGroup.UNIT)
public class AvailablePortfolioOutputsTest {
private static final String SECURITY_TYPE_1 = "Bond";
private static final String SECURITY_TYPE_2 = "Option";
private static final String CURRENCY_1 = "USD";
private static final String CURRENCY_2 = "GBP";
private static final String VALUE_1 = "Foo";
private static final String VALUE_2 = "Bar";
private static final String FUNCTION_1_TYPE_1_POSITION = "T1-V1-P";
private static final String FUNCTION_1_TYPE_1_SECURITY = "T1-V1-S";
private static final String FUNCTION_2_TYPE_1_POSITION = "T1-V2-P";
private static final String FUNCTION_TYPE_2_POSITION = "T2-P";
private static final String FUNCTION_SUM_NODE = "VSUM-N";
private static final String WILDCARD = "*";
private Portfolio _testPortfolio;
private CompiledFunctionRepository _functionRepository;
private MarketDataAvailabilityFilter _marketDataAvailability;
private SimplePosition createPosition(final String securityType, final String currency, final String securityId) {
final SimplePosition position = new SimplePosition();
position.setUniqueId(UniqueId.of("Position", securityType + "-" + currency + "-" + securityId));
position.setQuantity(BigDecimal.ONE);
final SimpleSecurityLink link = new SimpleSecurityLink();
link.setTarget(new Security() {
@Override
public ExternalIdBundle getExternalIdBundle() {
return ExternalIdBundle.EMPTY;
}
@Override
public String getName() {
return currency;
}
@Override
public String getSecurityType() {
return securityType;
}
@Override
public UniqueId getUniqueId() {
return UniqueId.of("Security", securityType + "-" + currency + "-" + securityId);
}
@Override
public Map<String, String> getAttributes() {
return new HashMap<String, String>();
}
@Override
public void setAttributes(final Map<String, String> attributes) {
}
@Override
public void addAttribute(final String key, final String value) {
}
});
position.setSecurityLink(link);
return position;
}
private SimplePortfolioNode createChildNode(final String securityType, final String currency) {
final SimplePortfolioNode node = new SimplePortfolioNode(currency + "-" + securityType);
node.setUniqueId(UniqueId.of("Node", securityType + "-" + currency));
node.addPosition(createPosition(securityType, currency, "A"));
node.addPosition(createPosition(securityType, currency, "B"));
return node;
}
private SimplePortfolioNode createRootNode() {
final SimplePortfolioNode node = new SimplePortfolioNode("Root");
node.setUniqueId(UniqueId.of("Node", "0"));
node.addChildNode(createChildNode(SECURITY_TYPE_1, CURRENCY_1));
node.addChildNode(createChildNode(SECURITY_TYPE_2, CURRENCY_1));
node.addChildNode(createChildNode(SECURITY_TYPE_1, CURRENCY_2));
node.addChildNode(createChildNode(SECURITY_TYPE_2, CURRENCY_2));
return node;
}
private Portfolio createPortfolio() {
final SimplePortfolio portfolio = new SimplePortfolio("Test");
portfolio.setRootNode(createRootNode());
return portfolio;
}
private static abstract class MockFunction<T> implements CompiledFunctionDefinition {
private final String _id;
private final ComputationTargetType _targetType;
protected MockFunction(final String id, final ComputationTargetType targetType) {
_id = id;
_targetType = targetType;
}
@Override
public Set<ValueRequirement> getAdditionalRequirements(final FunctionCompilationContext context, final ComputationTarget target, final Set<ValueSpecification> inputs,
final Set<ValueSpecification> outputs) {
throw new UnsupportedOperationException();
}
@Override
public Instant getEarliestInvocationTime() {
return null;
}
@Override
public FunctionDefinition getFunctionDefinition() {
return new FunctionDefinition() {
@Override
public CompiledFunctionDefinition compile(final FunctionCompilationContext context, final Instant atInstant) {
throw new UnsupportedOperationException();
}
@Override
public FunctionParameters getDefaultParameters() {
throw new UnsupportedOperationException();
}
@Override
public String getShortName() {
throw new UnsupportedOperationException();
}
@Override
public String getUniqueId() {
return _id;
}
@Override
public void init(final FunctionCompilationContext context) {
throw new UnsupportedOperationException();
}
};
}
@Override
public FunctionInvoker getFunctionInvoker() {
throw new UnsupportedOperationException();
}
@Override
public Instant getLatestInvocationTime() {
return null;
}
@Override
public boolean canHandleMissingRequirements() {
return false;
}
protected ValueProperties.Builder properties() {
return ValueProperties.with(ValuePropertyNames.FUNCTION, _id);
}
@Override
public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target, final Map<ValueSpecification, ValueRequirement> inputs) {
return getResults(context, target);
}
@Override
public ComputationTargetType getTargetType() {
return _targetType;
}
protected abstract boolean canApplyTo(T target);
@SuppressWarnings("unchecked")
@Override
public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) {
return canApplyTo((T) target.getValue());
}
protected abstract Set<ValueSpecification> getResults(ComputationTargetSpecification targetSpec, T target);
@SuppressWarnings("unchecked")
@Override
public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) {
return getResults(target.toSpecification(), (T) target.getValue());
}
protected abstract Set<ValueRequirement> getRequirements(T target, ValueRequirement desiredResult);
@SuppressWarnings("unchecked")
@Override
public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredResult) {
return getRequirements((T) target.getValue(), desiredResult);
}
}
private static abstract class MockPortfolioNodeFunction extends MockFunction<PortfolioNode> {
public MockPortfolioNodeFunction(final String id) {
super(id, ComputationTargetType.PORTFOLIO_NODE);
}
}
private static abstract class MockPositionFunction extends MockFunction<Position> {
public MockPositionFunction(final String id) {
super(id, ComputationTargetType.POSITION);
}
}
private static abstract class MockSecurityFunction extends MockFunction<Security> {
public MockSecurityFunction(final String id) {
super(id, ComputationTargetType.SECURITY);
}
}
private CompiledFunctionRepository createFunctionRepository() {
final InMemoryCompiledFunctionRepository repository = new InMemoryCompiledFunctionRepository(new FunctionCompilationContext());
repository.addFunction(MarketDataSourcingFunction.INSTANCE);
repository.addFunction(MarketDataAliasingFunction.INSTANCE);
repository.addFunction(new MockSecurityFunction(FUNCTION_1_TYPE_1_SECURITY) {
@Override
protected boolean canApplyTo(final Security node) {
return SECURITY_TYPE_1.equals(node.getSecurityType());
}
@Override
protected Set<ValueRequirement> getRequirements(final Security node, final ValueRequirement desiredResult) {
return Collections.emptySet();
}
@Override
protected Set<ValueSpecification> getResults(final ComputationTargetSpecification targetSpec, final Security security) {
return Collections.singleton(new ValueSpecification(VALUE_1, targetSpec, properties().with(ValuePropertyNames.CURRENCY, security.getName()).get()));
}
});
repository.addFunction(new MockPositionFunction(FUNCTION_1_TYPE_1_POSITION) {
@Override
public boolean canApplyTo(final Position position) {
// TODO: try with just "return true" and rely on the downstream function
return SECURITY_TYPE_1.equals(position.getSecurity().getSecurityType());
}
@Override
public Set<ValueSpecification> getResults(final ComputationTargetSpecification targetSpec, final Position position) {
return Collections.singleton(new ValueSpecification(VALUE_1, targetSpec, properties().with(ValuePropertyNames.CURRENCY, position.getSecurity().getName()).get()));
}
@Override
public Set<ValueRequirement> getRequirements(final Position position, final ValueRequirement desiredValue) {
return Collections.singleton(new ValueRequirement(VALUE_1, ComputationTargetSpecification.of(position.getSecurity())));
}
});
repository.addFunction(new MockPositionFunction(FUNCTION_2_TYPE_1_POSITION) {
@Override
protected boolean canApplyTo(final Position position) {
return SECURITY_TYPE_1.equals(position.getSecurity().getSecurityType());
}
@Override
protected Set<ValueSpecification> getResults(final ComputationTargetSpecification targetSpec, final Position position) {
return Collections.singleton(new ValueSpecification(VALUE_2, targetSpec, properties().with(ValuePropertyNames.CURRENCY, position.getSecurity().getName()).get()));
}
@Override
public Set<ValueRequirement> getRequirements(final Position position, final ValueRequirement desiredValue) {
return Collections.emptySet();
}
});
repository.addFunction(new MockPositionFunction(FUNCTION_TYPE_2_POSITION) {
@Override
protected boolean canApplyTo(final Position position) {
return SECURITY_TYPE_2.equals(position.getSecurity().getSecurityType());
}
@Override
protected Set<ValueSpecification> getResults(final ComputationTargetSpecification targetSpec, final Position position) {
final Set<ValueSpecification> result = new HashSet<ValueSpecification>();
result.add(new ValueSpecification(VALUE_1, targetSpec, properties().with(ValuePropertyNames.CURRENCY, position.getSecurity().getName()).get()));
result.add(new ValueSpecification(VALUE_2, targetSpec, properties().with(ValuePropertyNames.CURRENCY, position.getSecurity().getName()).get()));
return result;
}
@Override
public Set<ValueRequirement> getRequirements(final Position position, final ValueRequirement desiredValue) {
return Collections.emptySet();
}
});
repository.addFunction(new MockPortfolioNodeFunction(FUNCTION_SUM_NODE) {
@Override
protected boolean canApplyTo(final PortfolioNode node) {
return true;
}
@Override
protected Set<ValueSpecification> getResults(final ComputationTargetSpecification targetSpec, final PortfolioNode node) {
final Set<ValueSpecification> result = new HashSet<ValueSpecification>();
result.add(new ValueSpecification(VALUE_1, targetSpec, properties().withAny(ValuePropertyNames.CURRENCY).get()));
result.add(new ValueSpecification(VALUE_2, targetSpec, properties().withAny(ValuePropertyNames.CURRENCY).get()));
return result;
}
@Override
public Set<ValueRequirement> getRequirements(final PortfolioNode node, final ValueRequirement desiredValue) {
return Collections.emptySet();
}
});
return repository;
}
@BeforeClass
public void init() {
_testPortfolio = createPortfolio();
_functionRepository = createFunctionRepository();
_marketDataAvailability = new OptimisticMarketDataAvailabilityFilter();
}
public void testGetSecurityTypes() {
final AvailableOutputs outputs = new AvailablePortfolioOutputs(_testPortfolio, _functionRepository, null, _marketDataAvailability, WILDCARD);
final Set<String> securityTypes = outputs.getSecurityTypes();
assertEquals(securityTypes, new HashSet<String>(Arrays.asList(SECURITY_TYPE_1, SECURITY_TYPE_2)));
}
public void testGetTypedPositionOutputs() {
final AvailableOutputs outputs = new AvailablePortfolioOutputs(_testPortfolio, _functionRepository, null, _marketDataAvailability, WILDCARD);
Set<AvailableOutput> available = outputs.getPositionOutputs(SECURITY_TYPE_1);
final AvailableOutputImpl value1Type1 = new AvailableOutputImpl(VALUE_1, WILDCARD);
value1Type1.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_1_TYPE_1_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_1);
final AvailableOutputImpl value2Type1 = new AvailableOutputImpl(VALUE_2, WILDCARD);
value2Type1.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_2_TYPE_1_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_1);
assertEquals(available, new HashSet<AvailableOutput>(Arrays.asList(value1Type1, value2Type1)));
available = outputs.getPositionOutputs(SECURITY_TYPE_2);
final AvailableOutputImpl value1Type2 = new AvailableOutputImpl(VALUE_1, WILDCARD);
value1Type2.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_TYPE_2_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_2);
final AvailableOutputImpl value2Type2 = new AvailableOutputImpl(VALUE_2, WILDCARD);
value2Type2.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_TYPE_2_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_2);
assertEquals(available, new HashSet<AvailableOutput>(Arrays.asList(value1Type2, value2Type2)));
}
public void testGetPortfolioNodeOutputs() {
final AvailableOutputs outputs = new AvailablePortfolioOutputs(_testPortfolio, _functionRepository, null, _marketDataAvailability, WILDCARD);
final Set<AvailableOutput> available = outputs.getPortfolioNodeOutputs();
final AvailableOutputImpl value1 = new AvailableOutputImpl(VALUE_1, WILDCARD);
value1.setPortfolioNodeProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_SUM_NODE).withAny(ValuePropertyNames.CURRENCY).get());
final AvailableOutputImpl value2 = new AvailableOutputImpl(VALUE_2, WILDCARD);
value2.setPortfolioNodeProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_SUM_NODE).withAny(ValuePropertyNames.CURRENCY).get());
assertEquals(available, new HashSet<AvailableOutput>(Arrays.asList(value1, value2)));
}
public void testGetPositionOutputs() {
final AvailableOutputs outputs = new AvailablePortfolioOutputs(_testPortfolio, _functionRepository, null, _marketDataAvailability, WILDCARD);
final Set<AvailableOutput> available = outputs.getPositionOutputs();
final AvailableOutputImpl value1 = new AvailableOutputImpl(VALUE_1, WILDCARD);
value1.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_1_TYPE_1_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_1);
value1.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_TYPE_2_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_2);
final AvailableOutputImpl value2 = new AvailableOutputImpl(VALUE_2, WILDCARD);
value2.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_2_TYPE_1_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_1);
value2.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_TYPE_2_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_2);
assertEquals(available, new HashSet<AvailableOutput>(Arrays.asList(value1, value2)));
}
public void testGetOutputs() {
final AvailableOutputs outputs = new AvailablePortfolioOutputs(_testPortfolio, _functionRepository, null, _marketDataAvailability, WILDCARD);
final Set<AvailableOutput> available = outputs.getOutputs();
final AvailableOutputImpl value1 = new AvailableOutputImpl(VALUE_1, WILDCARD);
value1.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_1_TYPE_1_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_1);
value1.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_TYPE_2_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_2);
value1.setPortfolioNodeProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_SUM_NODE).withAny(ValuePropertyNames.CURRENCY).get());
final AvailableOutputImpl value2 = new AvailableOutputImpl(VALUE_2, WILDCARD);
value2.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_2_TYPE_1_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_1);
value2.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_TYPE_2_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_2);
value2.setPortfolioNodeProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_SUM_NODE).withAny(ValuePropertyNames.CURRENCY).get());
assertEquals(available, new HashSet<AvailableOutput>(Arrays.asList(value1, value2)));
}
public void testWithNoExclusion() {
final AvailableOutputs outputs = new AvailablePortfolioOutputs(_testPortfolio, _functionRepository, new AbstractFunctionExclusionGroups() {
@Override
protected String getKey(final FunctionDefinition function) {
return null;
}
}, _marketDataAvailability, WILDCARD);
final Set<AvailableOutput> available = outputs.getOutputs();
final AvailableOutputImpl value1 = new AvailableOutputImpl(VALUE_1, WILDCARD);
value1.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_1_TYPE_1_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_1);
value1.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_TYPE_2_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_2);
value1.setPortfolioNodeProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_SUM_NODE).withAny(ValuePropertyNames.CURRENCY).get());
final AvailableOutputImpl value2 = new AvailableOutputImpl(VALUE_2, WILDCARD);
value2.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_2_TYPE_1_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_1);
value2.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_TYPE_2_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_2);
value2.setPortfolioNodeProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_SUM_NODE).withAny(ValuePropertyNames.CURRENCY).get());
assertEquals(available, new HashSet<AvailableOutput>(Arrays.asList(value1, value2)));
}
public void testWithExclusion() {
final AvailableOutputs outputs = new AvailablePortfolioOutputs(_testPortfolio, _functionRepository, new AbstractFunctionExclusionGroups() {
@Override
protected String getKey(final FunctionDefinition function) {
if (FUNCTION_1_TYPE_1_POSITION.equals(function.getUniqueId()) || FUNCTION_1_TYPE_1_SECURITY.equals(function.getUniqueId())) {
return "group";
} else {
return null;
}
}
}, _marketDataAvailability, WILDCARD);
final Set<AvailableOutput> available = outputs.getOutputs();
final AvailableOutputImpl value1 = new AvailableOutputImpl(VALUE_1, WILDCARD);
value1.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_TYPE_2_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_2);
value1.setPortfolioNodeProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_SUM_NODE).withAny(ValuePropertyNames.CURRENCY).get());
final AvailableOutputImpl value2 = new AvailableOutputImpl(VALUE_2, WILDCARD);
value2.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_2_TYPE_1_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_1);
value2.setPositionProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_TYPE_2_POSITION).with(ValuePropertyNames.CURRENCY, CURRENCY_1, CURRENCY_2).get(), SECURITY_TYPE_2);
value2.setPortfolioNodeProperties(ValueProperties.with(ValuePropertyNames.FUNCTION, FUNCTION_SUM_NODE).withAny(ValuePropertyNames.CURRENCY).get());
assertEquals(available, new HashSet<AvailableOutput>(Arrays.asList(value1, value2)));
}
}