/**
* Copyright (C) 2012 - 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.HashSet;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.ZonedDateTime;
import com.google.common.collect.Sets;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.financial.equity.StaticReplicationDataBundle;
import com.opengamma.analytics.financial.instrument.InstrumentDefinition;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivative;
import com.opengamma.analytics.financial.model.interestrate.curve.ForwardCurve;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve;
import com.opengamma.analytics.financial.model.volatility.surface.BlackVolatilitySurface;
import com.opengamma.analytics.financial.provider.calculator.generic.LastTimeCalculator;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeries;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeriesSource;
import com.opengamma.core.holiday.HolidaySource;
import com.opengamma.core.region.RegionSource;
import com.opengamma.core.security.Security;
import com.opengamma.core.security.SecuritySource;
import com.opengamma.core.value.MarketDataRequirementNames;
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.OpenGammaCompilationContext;
import com.opengamma.financial.analytics.conversion.BondFutureSecurityConverter;
import com.opengamma.financial.analytics.conversion.BondSecurityConverter;
import com.opengamma.financial.analytics.conversion.EquityOptionsConverter;
import com.opengamma.financial.analytics.conversion.FutureSecurityConverterDeprecated;
import com.opengamma.financial.analytics.conversion.InterestRateFutureSecurityConverterDeprecated;
import com.opengamma.financial.analytics.model.CalculationPropertyNamesAndValues;
import com.opengamma.financial.analytics.model.InstrumentTypeProperties;
import com.opengamma.financial.analytics.model.curve.forward.ForwardCurveValuePropertyNames;
import com.opengamma.financial.analytics.model.equity.EquitySecurityUtils;
import com.opengamma.financial.analytics.model.volatility.surface.black.BlackVolatilitySurfacePropertyNamesAndValues;
import com.opengamma.financial.analytics.model.volatility.surface.black.BlackVolatilitySurfacePropertyUtils;
import com.opengamma.financial.convention.ConventionBundleSource;
import com.opengamma.financial.security.FinancialSecurity;
import com.opengamma.financial.security.FinancialSecurityTypes;
import com.opengamma.financial.security.FinancialSecurityUtils;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.id.ExternalScheme;
import com.opengamma.id.VersionCorrection;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.async.AsynchronousExecution;
/**
* Abstract base class for Equity and Equity Index Options
*/
public abstract class EquityOptionFunction extends AbstractFunction.NonCompiledInvoker {
/** The logger */
private static final Logger s_logger = LoggerFactory.getLogger(EquityOptionFunction.class);
//TODO the next three properties should be moved from this class after checking that there's no others that match
/** Property name for the discounting curve */
public static final String PROPERTY_DISCOUNTING_CURVE_NAME = "DiscountingCurveName";
/** Property name for the discounting curve configuration */
public static final String PROPERTY_DISCOUNTING_CURVE_CONFIG = "DiscountingCurveConfig";
/** The value requirement name */
private final String[] _valueRequirementNames;
/** Converts the security to the form used in analytics */
private EquityOptionsConverter _converter; // set in init(), not constructor
/** The type this function operates on */
private static final ComputationTargetType TYPE = FinancialSecurityTypes.EQUITY_INDEX_OPTION_SECURITY.or(FinancialSecurityTypes.EQUITY_OPTION_SECURITY);
/**
* @param valueRequirementNames A list of value requirement names, not null or empty
*/
public EquityOptionFunction(final String... valueRequirementNames) {
ArgumentChecker.notEmpty(valueRequirementNames, "value requirement names");
_valueRequirementNames = valueRequirementNames;
}
@Override
public void init(final FunctionCompilationContext context) {
final HolidaySource holidaySource = OpenGammaCompilationContext.getHolidaySource(context);
final RegionSource regionSource = OpenGammaCompilationContext.getRegionSource(context);
final ConventionBundleSource conventionSource = OpenGammaCompilationContext.getConventionBundleSource(context);
final SecuritySource securitySource = OpenGammaCompilationContext.getSecuritySource(context);
final InterestRateFutureSecurityConverterDeprecated irFutureConverter = new InterestRateFutureSecurityConverterDeprecated(holidaySource, conventionSource, regionSource);
final BondSecurityConverter bondConverter = new BondSecurityConverter(holidaySource, conventionSource, regionSource);
final BondFutureSecurityConverter bondFutureConverter = new BondFutureSecurityConverter(securitySource, bondConverter);
final FutureSecurityConverterDeprecated futureSecurityConverter = new FutureSecurityConverterDeprecated(bondFutureConverter);
_converter = new EquityOptionsConverter(futureSecurityConverter, securitySource);
}
@Override
public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target,
final Set<ValueRequirement> desiredValues) throws AsynchronousExecution {
// 1. Build the analytic derivative to be priced
final ZonedDateTime now = ZonedDateTime.now(executionContext.getValuationClock());
final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
final ExternalId underlyingId = FinancialSecurityUtils.getUnderlyingId(security);
final InstrumentDefinition<?> defn = security.accept(_converter);
final InstrumentDerivative derivative = defn.toDerivative(now);
if (derivative.accept(LastTimeCalculator.getInstance()) < 0.0) {
throw new OpenGammaRuntimeException("Equity option has already settled; " + security.toString());
}
// 2. Build up the market data bundle
final StaticReplicationDataBundle market = buildMarketBundle(underlyingId, executionContext, inputs, target, desiredValues);
// 3. Create result properties
final ValueRequirement desiredValue = desiredValues.iterator().next();
final ValueProperties resultProperties = desiredValue.getConstraints().copy()
.with(ValuePropertyNames.FUNCTION, getUniqueId())
.get();
// 4. The Calculation - what we came here to do
return computeValues(derivative, market, inputs, desiredValues, target.toSpecification(), resultProperties);
}
/**
* Constructs a market data bundle
*
* @param underlyingId The underlying id of the index option
* @param executionContext The execution context
* @param inputs The market data inputs
* @param target The target
* @param desiredValues The desired values of the function
* @return The market data bundle used in pricing
*/
// buildMarketBundle is re-used by EquityIndexVanillaBarrierOptionFunction, hence is available to call */
protected StaticReplicationDataBundle buildMarketBundle(final ExternalId underlyingId, final FunctionExecutionContext executionContext,
final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) {
// 1. The Funding Curve
final Object discountingObject = inputs.getValue(ValueRequirementNames.YIELD_CURVE);
if (discountingObject == null) {
throw new OpenGammaRuntimeException("Could not get discounting curve");
}
if (!(discountingObject instanceof YieldCurve)) { //TODO: make it more generic
throw new IllegalArgumentException("Can only handle YieldCurve");
}
final YieldCurve discountingCurve = (YieldCurve) discountingObject;
// 2. The Vol Surface
final Object volSurfaceObject = inputs.getValue(ValueRequirementNames.BLACK_VOLATILITY_SURFACE);
if (volSurfaceObject == null || !(volSurfaceObject instanceof BlackVolatilitySurface)) {
throw new OpenGammaRuntimeException("Could not get volatility surface");
}
final BlackVolatilitySurface<?> blackVolSurf = (BlackVolatilitySurface<?>) volSurfaceObject;
// 3. Forward Curve
final Object forwardCurveObject = inputs.getValue(ValueRequirementNames.FORWARD_CURVE);
if (forwardCurveObject == null) {
throw new OpenGammaRuntimeException("Could not get forward curve");
}
final ForwardCurve forwardCurve = (ForwardCurve) forwardCurveObject;
final StaticReplicationDataBundle market = new StaticReplicationDataBundle(blackVolSurf, discountingCurve, forwardCurve);
return market;
}
/**
* Calculates the result
*
* @param derivative The derivative
* @param market The market data bundle
* @param inputs The market data inputs
* @param desiredValues The desired values
* @param targetSpec The target specification of the result
* @param resultProperties The result properties
* @return The result of the calculation
*/
protected abstract Set<ComputedValue> computeValues(final InstrumentDerivative derivative, final StaticReplicationDataBundle market, final FunctionInputs inputs,
final Set<ValueRequirement> desiredValues, final ComputationTargetSpecification targetSpec, final ValueProperties resultProperties);
@Override
public ComputationTargetType getTargetType() {
return TYPE;
}
@Override
public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) {
final ValueProperties properties = ValueProperties.all();
final Set<ValueSpecification> result = new HashSet<>();
for (final String valueRequirementName : _valueRequirementNames) {
result.add(new ValueSpecification(valueRequirementName, target.toSpecification(), properties));
}
return result;
}
@Override
public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) {
final ValueProperties constraints = desiredValue.getConstraints();
String discountingCurveName = null;
String discountingCurveConfig = null;
String surfaceName = null;
String surfaceCalculationMethod = null;
String surfaceSmileInterpolator = null;
String forwardCurveName = null;
String forwardCurveCalculationMethod = null;
int check = 8; // the number of properties we're looking out for below
ValueProperties.Builder additionalConstraintsBuilder = null;
if ((constraints.getProperties() == null) || (constraints.getProperties().size() < check)) {
return null;
}
for (final String property : constraints.getProperties()) {
switch (property) {
case ValuePropertyNames.CALCULATION_METHOD:
if (constraints.getStrictValue(property) == null) {
return null;
}
check--;
break;
case PROPERTY_DISCOUNTING_CURVE_NAME:
discountingCurveName = constraints.getStrictValue(property);
if (discountingCurveName == null) {
return null;
}
check--;
break;
case PROPERTY_DISCOUNTING_CURVE_CONFIG:
discountingCurveConfig = constraints.getStrictValue(property);
if (discountingCurveConfig == null) {
return null;
}
check--;
break;
case ValuePropertyNames.SURFACE:
surfaceName = constraints.getStrictValue(property);
if (surfaceName == null) {
return null;
}
check--;
break;
case ValuePropertyNames.SURFACE_CALCULATION_METHOD:
surfaceCalculationMethod = constraints.getStrictValue(property);
if (surfaceCalculationMethod == null) {
return null;
}
check--;
break;
case BlackVolatilitySurfacePropertyNamesAndValues.PROPERTY_SMILE_INTERPOLATOR:
surfaceSmileInterpolator = constraints.getStrictValue(property);
if (surfaceSmileInterpolator == null) {
return null;
}
check--;
break;
case ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_NAME:
forwardCurveName = constraints.getStrictValue(property);
if (forwardCurveName == null) {
return null;
}
check--;
break;
case ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD:
forwardCurveCalculationMethod = constraints.getStrictValue(property);
if (forwardCurveCalculationMethod == null) {
return null;
}
check--;
break;
default:
if (additionalConstraintsBuilder == null) {
additionalConstraintsBuilder = ValueProperties.builder();
}
final Set<String> values = constraints.getValues(property);
if (values.isEmpty()) {
additionalConstraintsBuilder.withAny(property);
} else {
additionalConstraintsBuilder.with(property, values);
}
break;
}
}
if (check > 0) {
// One or more of the properties we were looking for was unconstrained
return null;
}
final ValueProperties additionalConstraints = (additionalConstraintsBuilder != null) ? additionalConstraintsBuilder.get() : ValueProperties.none();
// Get security and its underlying's ExternalId.
final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
final HistoricalTimeSeriesSource tsSource = OpenGammaCompilationContext.getHistoricalTimeSeriesSource(context); // TODO: Do we still require tsSource? Was used to access id bundles
final SecuritySource securitySource = OpenGammaCompilationContext.getSecuritySource(context);
final ExternalId underlyingId = getWeakUnderlyingId(FinancialSecurityUtils.getUnderlyingId(security), tsSource, securitySource, context.getComputationTargetResolver().getVersionCorrection(),
surfaceName);
if (underlyingId == null) {
return null;
}
// Discounting curve
final ValueRequirement discountingReq = getDiscountCurveRequirement(discountingCurveName, discountingCurveConfig, security, additionalConstraints);
// Forward curve
final ValueRequirement forwardCurveReq = getForwardCurveRequirement(forwardCurveName, forwardCurveCalculationMethod, underlyingId, additionalConstraints);
if (forwardCurveReq == null) {
return null;
}
// Volatility Surface
final ValueRequirement volReq = getVolatilitySurfaceRequirement(tsSource, securitySource, desiredValue, security, surfaceName, forwardCurveName,
surfaceCalculationMethod, underlyingId, additionalConstraints); // FIXME: Change signature: Remove desireValue - Add surfaceSmileInterpolator
if (volReq == null) {
return null;
}
// Return the set
return Sets.newHashSet(discountingReq, volReq, forwardCurveReq);
}
/**
* Adjusts the properties of the function inputs: <p>
* <ul>
* <li> {@link ValueRequirementNames#YIELD_CURVE} - removes the {@link ValuePropertyNames#FUNCTION} and {@link ValuePropertyNames#CURRENCY}
* properties and remaps {@link ValuePropertyNames#CURVE} -> {@link EquityOptionFunction#PROPERTY_DISCOUNTING_CURVE_NAME} and
* {@link ValuePropertyNames#CURVE_CALCULATION_CONFIG} -> {@link EquityOptionFunction#PROPERTY_DISCOUNTING_CURVE_CONFIG}.
* <li> {@link ValueRequirementNames#BLACK_VOLATILITY_SURFACE} removes the {@link ValuePropertyNames#FUNCTION} and
* {@link InstrumentTypeProperties#PROPERTY_SURFACE_INSTRUMENT_TYPE} properties.
* <li> {@link ValueRequirementNames#FORWARD_CURVE} - removes the {@link ValuePropertyNames#FUNCTION} and {@link ValuePropertyNames#CURRENCY}
* properties and remaps {@link ValuePropertyNames#CURVE} -> {@link ForwardCurveValuePropertyNames#PROPERTY_FORWARD_CURVE_NAME}.
* </ul>
* <p>
* @param input The resolved input
* @param properties The properties to be adjusted
*/
protected void extractInputProperties(final ValueSpecification input, final ValueProperties.Builder properties) {
final String inputName = input.getValueName();
if (ValueRequirementNames.YIELD_CURVE.equals(inputName)) {
final ValueProperties curveProperties = input.getProperties().copy()
.withoutAny(ValuePropertyNames.FUNCTION)
.withoutAny(ValuePropertyNames.CURVE)
.withoutAny(ValuePropertyNames.CURRENCY)
.get();
properties
.with(PROPERTY_DISCOUNTING_CURVE_NAME, input.getProperty(ValuePropertyNames.CURVE))
.with(PROPERTY_DISCOUNTING_CURVE_CONFIG, input.getProperty(ValuePropertyNames.CURVE_CALCULATION_CONFIG));
for (final String property : curveProperties.getProperties()) {
properties.with(property, curveProperties.getValues(property));
}
return;
}
if (inputName.equals(ValueRequirementNames.BLACK_VOLATILITY_SURFACE)) {
final ValueProperties surfaceProperties = input.getProperties().copy()
.withoutAny(ValuePropertyNames.FUNCTION)
.withoutAny(InstrumentTypeProperties.PROPERTY_SURFACE_INSTRUMENT_TYPE)
.get();
for (final String property : surfaceProperties.getProperties()) {
properties.with(property, surfaceProperties.getValues(property));
}
return;
}
if (inputName.equals(ValueRequirementNames.FORWARD_CURVE)) {
final ValueProperties forwardCurveProperties = input.getProperties().copy()
.withoutAny(ValuePropertyNames.FUNCTION)
.withoutAny(ValuePropertyNames.CURVE)
.withoutAny(ValuePropertyNames.CURVE_CURRENCY)
.get();
properties.with(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_NAME, input.getProperty(ValuePropertyNames.CURVE));
for (final String property : forwardCurveProperties.getProperties()) {
properties.with(property, forwardCurveProperties.getValues(property));
}
return;
}
}
@Override
public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target, final Map<ValueSpecification, ValueRequirement> inputs) {
final ValueProperties.Builder properties = createValueProperties()
.with(ValuePropertyNames.CALCULATION_METHOD, getCalculationMethod())
.with(CalculationPropertyNamesAndValues.PROPERTY_MODEL_TYPE, getModelType())
.with(ValuePropertyNames.CURRENCY, FinancialSecurityUtils.getCurrency(target.getSecurity()).getCode());
for (final Map.Entry<ValueSpecification, ValueRequirement> entry : inputs.entrySet()) {
extractInputProperties(entry.getKey(), properties);
}
final ValueProperties propertiesImpl = properties.get();
final Set<ValueSpecification> results = new HashSet<>();
for (final String valueRequirement : _valueRequirementNames) {
results.add(new ValueSpecification(valueRequirement, target.toSpecification(), propertiesImpl));
}
return results;
}
/**
* Converts result properties with a currency property to one without.
*
* @param resultsWithCurrency The set of results with the currency property set
* @return A set of results without a currency property
*/
protected Set<ValueSpecification> getResultsWithoutCurrency(final Set<ValueSpecification> resultsWithCurrency) {
final Set<ValueSpecification> resultsWithoutCurrency = Sets.newHashSetWithExpectedSize(resultsWithCurrency.size());
for (final ValueSpecification spec : resultsWithCurrency) {
final String name = spec.getValueName();
final ComputationTargetSpecification targetSpec = spec.getTargetSpecification();
final ValueProperties properties = spec.getProperties().copy()
.withoutAny(ValuePropertyNames.CURRENCY)
.get();
resultsWithoutCurrency.add(new ValueSpecification(name, targetSpec, properties));
}
return resultsWithoutCurrency;
}
/**
* Gets the discounting curve requirement
* @param fundingCurveName The discounting curve name
* @param curveCalculationConfigName The curve calculation configuration name
* @param security The security
* @param additionalConstraints The additional constraints
* @return The discounting curve requirement
*/
private static ValueRequirement getDiscountCurveRequirement(final String fundingCurveName, final String curveCalculationConfigName, final Security security,
final ValueProperties additionalConstraints) {
final ValueProperties properties = ValueProperties.builder() // TODO: Update to this => additionalConstraints.copy() [PLAT-5524]
.with(ValuePropertyNames.CURVE, fundingCurveName)
.with(ValuePropertyNames.CURVE_CALCULATION_CONFIG, curveCalculationConfigName)
.get();
return new ValueRequirement(ValueRequirementNames.YIELD_CURVE, ComputationTargetSpecification.of(FinancialSecurityUtils.getCurrency(security)), properties);
}
/**
* Gets the forward curve requirement
* @param forwardCurveName The forward curve name
* @param forwardCurveCalculationMethod The curve calculation method
* @param underlyingBuid The underlying id of the security
* @param additionalConstraints The additional constraints
* @return The forward curve requirement
*/
private static ValueRequirement getForwardCurveRequirement(final String forwardCurveName, final String forwardCurveCalculationMethod, final ExternalId underlyingBuid,
final ValueProperties additionalConstraints) {
final ValueProperties properties = ValueProperties.builder() // TODO: Update to this => additionalConstraints.copy() [PLAT-5524]
.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, underlyingBuid, properties);
}
/**
* Gets the volatility surface requirement
* @param tsSource The time series source
* @param securitySource The security source
* @param desiredValue The desired value
* @param security The security
* @param surfaceName The volatility surface name
* @param forwardCurveName The forward curve name
* @param surfaceCalculationMethod The surface calculation method
* @param underlyingBuid The underlying id of the seucirty
* @param additionalConstraints The additional requirements
* @return The volatility surface requirement
*/
protected ValueRequirement getVolatilitySurfaceRequirement(final HistoricalTimeSeriesSource tsSource, final SecuritySource securitySource,
final ValueRequirement desiredValue, final Security security, final String surfaceName, final String forwardCurveName,
final String surfaceCalculationMethod, final ExternalId underlyingBuid, final ValueProperties additionalConstraints) {
// 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_OPTION, ComputationTargetType.PRIMITIVE, underlyingBuid);
// TODO Casey - Replace above with below - ie pass additional constraints [PLAT-5524]
//return BlackVolatilitySurfacePropertyUtils.getSurfaceRequirement(desiredValue, additionalConstraints, surfaceName, forwardCurveName,
//InstrumentTypeProperties.EQUITY_OPTION, ComputationTargetType.PRIMITIVE, underlyingBuid);
}
/**
* Remaps the scheme of the underlying (e .g. from a Bloomberg ticker to a Bloomberg weak ticker) to match that
* of the volatility surface
* @param underlyingId The underlying id
* @param tsSource The time series source
* @param securitySource The security source
* @param versionCorrection The version correction
* @param surfaceName The surface name
* @return The weak underlying id.
*/
private static ExternalId getWeakUnderlyingId(final ExternalId underlyingId, final HistoricalTimeSeriesSource tsSource, final SecuritySource securitySource,
final VersionCorrection versionCorrection, final String surfaceName) {
/* scheme we return i.e. BBG_WEAK */
final ExternalScheme desiredScheme = EquitySecurityUtils.getTargetType(surfaceName);
/* scheme we look for i.e. BBG */
final ExternalScheme sourceScheme = EquitySecurityUtils.getRemappedScheme(desiredScheme);
if (desiredScheme == null) { // surface name is unknown
return null;
}
if (underlyingId.isScheme(desiredScheme)) {
return underlyingId;
}
if (underlyingId.isScheme(sourceScheme)) {
return ExternalId.of(desiredScheme, underlyingId.getValue());
}
// load underlying and search its ids for the right one
final Security underlyingSecurity = securitySource.getSingle(ExternalIdBundle.of(underlyingId), versionCorrection);
if (underlyingSecurity == null || underlyingSecurity.getExternalIdBundle().getExternalId(desiredScheme) == null) {
// no underlying in db (or lacks desired scheme) - get from timeseries
final HistoricalTimeSeries historicalTimeSeries = tsSource.getHistoricalTimeSeries(MarketDataRequirementNames.MARKET_VALUE, ExternalIdBundle.of(underlyingId), null, null, true, null, true, 1);
if (historicalTimeSeries == null) {
s_logger.error("Require a time series for " + underlyingId);
return null;
}
final ExternalIdBundle idBundle = tsSource.getExternalIdBundle(historicalTimeSeries.getUniqueId());
if (idBundle.getExternalId(sourceScheme) != null) {
return ExternalId.of(desiredScheme, idBundle.getExternalId(sourceScheme).getValue());
}
}
if (underlyingSecurity != null && underlyingSecurity.getExternalIdBundle().getExternalId(sourceScheme) != null) {
return ExternalId.of(desiredScheme, underlyingSecurity.getExternalIdBundle().getExternalId(sourceScheme).getValue());
}
s_logger.error("Couldn't get ticker of type " + sourceScheme + " only have " + underlyingId);
return null;
}
/**
* Gets the value requirement names
*
* @return The value requirement names
*/
protected String[] getValueRequirementNames() {
return _valueRequirementNames;
}
/**
* Gets the calculation method.
*
* @return The calculation method
*/
protected abstract String getCalculationMethod();
/**
* Gets the model type.
*
* @return The model type
*/
protected abstract String getModelType();
}