/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.model.futureoption;
import java.util.Set;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.core.security.Security;
import com.opengamma.core.security.SecuritySource;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.function.FunctionCompilationContext;
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.ValueRequirementNames;
import com.opengamma.financial.OpenGammaCompilationContext;
import com.opengamma.financial.analytics.model.InstrumentTypeProperties;
import com.opengamma.financial.analytics.model.curve.forward.ForwardCurveValuePropertyNames;
import com.opengamma.financial.analytics.model.equity.option.EquityOptionFunction;
import com.opengamma.financial.analytics.model.volatility.surface.black.BlackVolatilitySurfacePropertyUtils;
import com.opengamma.financial.security.FinancialSecurity;
import com.opengamma.financial.security.FinancialSecurityTypes;
import com.opengamma.financial.security.future.EquityFutureSecurity;
import com.opengamma.financial.security.future.IndexFutureSecurity;
import com.opengamma.financial.security.option.EquityIndexFutureOptionSecurity;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
/**
*
*/
public abstract class EquityFutureOptionFunction extends FutureOptionFunction {
/**
* @param valueRequirementNames The value requirement names
*/
public EquityFutureOptionFunction(final String... valueRequirementNames) {
super(valueRequirementNames);
}
@Override
public ComputationTargetType getTargetType() {
return FinancialSecurityTypes.EQUITY_INDEX_FUTURE_OPTION_SECURITY;
}
@Override
public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) {
final ValueProperties constraints = desiredValue.getConstraints();
final Set<String> calculationMethod = constraints.getValues(ValuePropertyNames.CALCULATION_METHOD);
if (calculationMethod == null || calculationMethod.isEmpty()) {
return null;
}
if (calculationMethod != null && calculationMethod.size() == 1) {
if (!getCalculationMethod().equals(Iterables.getOnlyElement(calculationMethod))) {
return null;
}
}
final EquityIndexFutureOptionSecurity security = (EquityIndexFutureOptionSecurity) target.getSecurity();
final Set<String> discountingCurveNames = constraints.getValues(EquityOptionFunction.PROPERTY_DISCOUNTING_CURVE_NAME);
if (discountingCurveNames == null || discountingCurveNames.size() != 1) {
return null;
}
final Set<String> discountingCurveConfigs = constraints.getValues(EquityOptionFunction.PROPERTY_DISCOUNTING_CURVE_CONFIG);
if (discountingCurveConfigs == null || discountingCurveConfigs.size() != 1) {
return null;
}
final String discountingCurveName = Iterables.getOnlyElement(discountingCurveNames);
final String discountingCurveConfig = Iterables.getOnlyElement(discountingCurveConfigs);
final ValueRequirement discountingReq = getDiscountCurveRequirement(discountingCurveName, discountingCurveConfig, security);
final Set<String> surfaceNames = constraints.getValues(ValuePropertyNames.SURFACE);
if (surfaceNames == null || surfaceNames.size() != 1) {
return null;
}
final String volSurfaceName = Iterables.getOnlyElement(surfaceNames);
final Set<String> surfaceCalculationMethods = constraints.getValues(ValuePropertyNames.SURFACE_CALCULATION_METHOD);
if (surfaceCalculationMethods == null || surfaceCalculationMethods.size() != 1) {
return null;
}
final String surfaceCalculationMethod = Iterables.getOnlyElement(surfaceCalculationMethods);
final Set<String> forwardCurveNames = constraints.getValues(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_NAME);
if (forwardCurveNames == null || forwardCurveNames.size() != 1) {
return null;
}
final Set<String> forwardCurveCalculationMethods = constraints.getValues(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD);
if (forwardCurveCalculationMethods == null || forwardCurveCalculationMethods.size() != 1) {
return null;
}
final ExternalIdBundle underlyingFutureId = ExternalIdBundle.of(security.getUnderlyingId());
final SecuritySource securitySource = OpenGammaCompilationContext.getSecuritySource(context);
final ExternalId underlyingIndexId;
Security underlyingFuture = securitySource.getSingle(underlyingFutureId);
if (underlyingFuture == null) {
throw new OpenGammaRuntimeException("The underlying (" + underlyingFutureId.toString() + ") of EquityIndexFutureOption (" + security.getName() +
") was not found in security source. Please try to reload.");
} else if (underlyingFuture instanceof EquityFutureSecurity) {
underlyingIndexId = ((EquityFutureSecurity) underlyingFuture).getUnderlyingId();
} else if (underlyingFuture instanceof IndexFutureSecurity) {
underlyingIndexId = ((IndexFutureSecurity) underlyingFuture).getUnderlyingId();
} else {
throw new OpenGammaRuntimeException("The Security type of the future underlying the Index Future Option must be added to this function: "
+ underlyingFuture.getClass());
}
final String forwardCurveCalculationMethod = Iterables.getOnlyElement(forwardCurveCalculationMethods);
final String forwardCurveName = Iterables.getOnlyElement(forwardCurveNames);
final ValueRequirement volReq = getVolatilitySurfaceRequirement(desiredValue, volSurfaceName, forwardCurveName, surfaceCalculationMethod, underlyingIndexId);
final ValueRequirement forwardCurveReq = getForwardCurveRequirement(forwardCurveName, forwardCurveCalculationMethod, underlyingIndexId);
return Sets.newHashSet(discountingReq, forwardCurveReq, volReq);
}
@Override
protected ValueRequirement getVolatilitySurfaceRequirement(final ValueRequirement desiredValue, final FinancialSecurity security, final String surfaceName,
final String forwardCurveName, final String surfaceCalculationMethod) {
throw new UnsupportedOperationException();
}
private ValueRequirement getVolatilitySurfaceRequirement(final ValueRequirement desiredValue, final String surfaceName, final String forwardCurveName,
final String surfaceCalculationMethod, final ExternalId underlyingBuid) {
// REVIEW Andrew 2012-01-17 -- Could we pass a CTRef to the getSurfaceRequirement and use the underlyingBuid external identifier directly with a target type of SECURITY
// TODO Casey - Replace desiredValue with smileInterpolatorName in BlackVolatilitySurfacePropertyUtils.getSurfaceRequirement
return BlackVolatilitySurfacePropertyUtils.getSurfaceRequirement(desiredValue, ValueProperties.none(), surfaceName, forwardCurveName,
InstrumentTypeProperties.EQUITY_FUTURE_OPTION, ComputationTargetType.PRIMITIVE, underlyingBuid);
}
@Override
protected ValueRequirement getForwardCurveRequirement(final FinancialSecurity security, final String forwardCurveName, final String forwardCurveCalculationMethod) {
throw new UnsupportedOperationException();
}
private ValueRequirement getForwardCurveRequirement(final String forwardCurveName, final String forwardCurveCalculationMethod, final ExternalId underlyingIndexId) {
final ValueProperties properties = ValueProperties.builder()
.with(ValuePropertyNames.CURVE, forwardCurveName)
.with(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD, forwardCurveCalculationMethod)
.get();
// REVIEW Andrew 2012-01-17 -- Why can't we just use the underlyingBuid external identifier directly here, with a target type of SECURITY, and shift the logic into the reference resolver?
return new ValueRequirement(ValueRequirementNames.FORWARD_CURVE, ComputationTargetType.PRIMITIVE, underlyingIndexId, properties);
}
@Override
protected String getSurfaceName(final FinancialSecurity security, final String surfaceName) {
return surfaceName;
}
}