/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.model.equity.option;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.Sets;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.core.position.Position;
import com.opengamma.core.security.Security;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.function.AbstractFunction;
import com.opengamma.engine.function.FunctionCompilationContext;
import com.opengamma.engine.function.FunctionExecutionContext;
import com.opengamma.engine.function.FunctionInputs;
import com.opengamma.engine.target.ComputationTargetType;
import com.opengamma.engine.value.ComputedValue;
import com.opengamma.engine.value.ValueProperties;
import com.opengamma.engine.value.ValuePropertyNames;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueRequirementNames;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.financial.security.FinancialSecurity;
import com.opengamma.financial.security.FinancialSecurityUtils;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.async.AsynchronousExecution;
/**
* Extends existing Greek functions, reported at {@link Security} levels to sum over {@link Position}s. <p>
* e.g. If a view asks for {@link ValueRequirementNames#POSITION_DELTA}, this will create a requirement for
* {@link ValueRequirementNames#DELTA}. <p>
* NOTE! DELTA in the example, is the mathematical dV/dS, and does not contain any unit contract size.
* The POSITION_DELTA *does* include any contract multiplier. <p>
* The properties of the position-level requirement will match those of the security level requirement.
*/
// TODO Review the scope of this Function. e.g. by creating a canApplyTo(). [PLAT-5522]
public class PositionGreeksFunction extends AbstractFunction.NonCompiledInvoker {
/** The output requirement name */
private final String _positionReqName;
/** The input requirement name */
private final String _securityReqName;
/** */
private static final PositionGreekContractMultiplier s_contractMultiplier = PositionGreekContractMultiplier.getInstance();
/**
* @param positionReqName The output requirement name, not null
* @param securityReqName The input requirement name, not null
*/
public PositionGreeksFunction(final String positionReqName, final String securityReqName) {
ArgumentChecker.notNull(positionReqName, "position requirement name");
ArgumentChecker.notNull(securityReqName, "security requirement name");
_positionReqName = positionReqName;
_securityReqName = securityReqName;
}
@Override
public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target,
final Set<ValueRequirement> desiredValues) throws AsynchronousExecution {
// 1. Get Security Greek
// Confirm the desired Value is in our advertised set
final ValueRequirement desiredValue = desiredValues.iterator().next();
final String desiredName = desiredValue.getValueName();
// Ensure the securityGreek's value was successfully obtained
Double secGreekValue = null;
final ComputedValue inputVal = inputs.getComputedValue(getSecurityReqName());
if (inputVal != null) {
secGreekValue = (Double) inputVal.getValue();
} else {
throw new OpenGammaRuntimeException("Did not satisfy requirement," + getSecurityReqName() + ", for trade " + target.getPositionOrTrade().getUniqueId());
}
// 2a. Scale to mathematical Greek by point value for a single contract (unit Notional)
final FinancialSecurity security = (FinancialSecurity) target.getPositionOrTrade().getSecurity();
final Double contractGreekValue = secGreekValue * security.accept(s_contractMultiplier);
// 2b. Scale by the position quantity
final Double posGreekValue = contractGreekValue * target.getPositionOrTrade().getQuantity().doubleValue();
// 3. Create specification and return
final ValueSpecification valueSpecification = new ValueSpecification(desiredName, target.toSpecification(), desiredValue.getConstraints());
final ComputedValue result = new ComputedValue(valueSpecification, posGreekValue);
return Sets.newHashSet(result);
}
@Override
public ComputationTargetType getTargetType() {
return ComputationTargetType.POSITION_OR_TRADE;
}
@Override
public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) {
return Collections.singleton(new ValueSpecification(getPositionReqName(), target.toSpecification(), ValueProperties.all()));
}
@Override
public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target, final Map<ValueSpecification, ValueRequirement> inputs) {
// inputs provide the properties of the required security greek. These we pass through to the position
final ValueSpecification secGreekSpec = inputs.keySet().iterator().next();
if (secGreekSpec.getValueName() != getSecurityReqName()) {
return null;
}
final Security security = target.getPositionOrTrade().getSecurity();
final String currency = FinancialSecurityUtils.getCurrency(security).getCode();
final ValueProperties properties = secGreekSpec.getProperties().copy()
.withoutAny(ValuePropertyNames.FUNCTION).with(ValuePropertyNames.FUNCTION, getUniqueId())
.withoutAny(ValuePropertyNames.CURRENCY).with(ValuePropertyNames.CURRENCY, currency)
.get();
return Collections.singleton(new ValueSpecification(getPositionReqName(), target.toSpecification(), properties));
}
@Override
public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) {
if (!desiredValue.getValueName().equals(getPositionReqName())) {
return null;
}
final ValueRequirement secGreekReq = new ValueRequirement(getSecurityReqName(), ComputationTargetSpecification.of(target.getPositionOrTrade().getSecurity()),
desiredValue.getConstraints().withoutAny(ValuePropertyNames.FUNCTION));
final Set<ValueRequirement> requirements = Sets.newHashSet(secGreekReq);
return requirements;
}
/**
* Gets the output (position) requirement name.
* @return The output requirement name
*/
public String getPositionReqName() {
return _positionReqName;
}
/**
* Gets the input (security) requirement name.
* @return The input requirement name
*/
public String getSecurityReqName() {
return _securityReqName;
}
}