/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.analytics.model.equity.futures; import java.util.HashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.threeten.bp.Period; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitor; import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve; import com.opengamma.analytics.financial.simpleinstruments.pricing.SimpleFutureDataBundle; import com.opengamma.core.security.Security; import com.opengamma.core.value.MarketDataRequirementNames; import com.opengamma.engine.ComputationTarget; import com.opengamma.engine.function.FunctionCompilationContext; import com.opengamma.engine.function.FunctionInputs; 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.future.FuturesFunction; import com.opengamma.financial.analytics.timeseries.DateConstraint; import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesBundle; import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils; import com.opengamma.financial.security.FinancialSecurityUtils; import com.opengamma.financial.security.future.EquityFutureSecurity; import com.opengamma.financial.security.future.EquityIndexDividendFutureSecurity; import com.opengamma.financial.security.future.FutureSecurity; import com.opengamma.financial.security.future.IndexFutureSecurity; import com.opengamma.id.ExternalIdBundle; import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolutionResult; import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolver; import com.opengamma.util.money.Currency; /** * This function will produce all valueRequirements that the EquityFutureSecurity offers. A trade may produce additional generic ones, e.g. date and number of contracts.. * @param <T> The type of the data that the calculator produces */ public class EquityDividendYieldFuturesFunction<T> extends FuturesFunction<T> { /** The calculation method name */ public static final String CALCULATION_METHOD_NAME = "DividendYield"; /** The logger */ private static final Logger s_logger = LoggerFactory.getLogger(EquityDividendYieldFuturesFunction.class); /** * @param valueRequirementName String describes the value requested * @param calculator The calculator * @param closingPriceField The field name of the historical time series for price, e.g. "PX_LAST", "Close". Set in *FunctionConfiguration * @param costOfCarryField The field name of the historical time series for cost of carry e.g. "COST_OF_CARRY". Set in *FunctionConfiguration * @param resolutionKey The key defining how the time series resolution is to occur e.g. "DEFAULT_TSS_CONFIG" */ public EquityDividendYieldFuturesFunction(final String valueRequirementName, final InstrumentDerivativeVisitor<SimpleFutureDataBundle, T> calculator, String closingPriceField, String costOfCarryField, String resolutionKey) { super(valueRequirementName, calculator, closingPriceField, costOfCarryField, resolutionKey); } @Override protected ValueProperties.Builder createValueProperties(final ComputationTarget target) { final Currency ccy = FinancialSecurityUtils.getCurrency(target.getTrade().getSecurity()); final ValueProperties.Builder properties = createValueProperties() .with(ValuePropertyNames.CURRENCY, ccy.getCode()) .with(ValuePropertyNames.CALCULATION_METHOD, CALCULATION_METHOD_NAME) .withAny(ValuePropertyNames.CURVE) .withAny(ValuePropertyNames.CURVE_CALCULATION_CONFIG); return properties; } @Override protected ValueProperties.Builder createValueProperties(final ComputationTarget target, final ValueRequirement desiredValue) { final String fundingCurveName = desiredValue.getConstraint(ValuePropertyNames.CURVE); final String curveConfigName = desiredValue.getConstraint(ValuePropertyNames.CURVE_CALCULATION_CONFIG); final Currency ccy = FinancialSecurityUtils.getCurrency(target.getTrade().getSecurity()); final ValueProperties.Builder properties = createValueProperties() .with(ValuePropertyNames.CURRENCY, ccy.getCode()) .with(ValuePropertyNames.CURVE, fundingCurveName) .with(ValuePropertyNames.CURVE_CALCULATION_CONFIG, curveConfigName) .with(ValuePropertyNames.CALCULATION_METHOD, CALCULATION_METHOD_NAME); return properties; } @Override protected SimpleFutureDataBundle getFutureDataBundle(final FutureSecurity security, final FunctionInputs inputs, final HistoricalTimeSeriesBundle timeSeriesBundle, final ValueRequirement desiredValue) { final Double spotUnderlyer = getSpot(inputs); Double dividendYield = timeSeriesBundle.get(MarketDataRequirementNames.DIVIDEND_YIELD, getSpotAssetId(security)).getTimeSeries().getLatestValue(); final String fundingCurveName = desiredValue.getConstraint(ValuePropertyNames.CURVE); final String curveConfigName = desiredValue.getConstraint(ValuePropertyNames.CURVE_CALCULATION_CONFIG); final YieldAndDiscountCurve fundingCurve = getYieldCurve(security, inputs, fundingCurveName, curveConfigName); return new SimpleFutureDataBundle(fundingCurve, null, spotUnderlyer, dividendYield, null); } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { final Security security = target.getTrade().getSecurity(); return security instanceof EquityFutureSecurity || security instanceof EquityIndexDividendFutureSecurity || security instanceof IndexFutureSecurity; } @Override public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) { final FutureSecurity security = (FutureSecurity) target.getTrade().getSecurity(); final Set<ValueRequirement> requirements = new HashSet<ValueRequirement>(); // Spot final ValueRequirement refPriceReq = getReferencePriceRequirement(context, security); if (refPriceReq == null) { return null; } requirements.add(refPriceReq); // Funding curve final String fundingCurveName = getFundingCurveName(desiredValue); if (fundingCurveName == null) { return null; } // Curve configuration final String curveConfigName = getCurveConfigName(desiredValue); if (curveConfigName == null) { return null; } final ValueRequirement curveReq = getDiscountCurveRequirement(fundingCurveName, curveConfigName, security); if (curveReq == null) { return null; } requirements.add(curveReq); final ValueRequirement dividendYieldReq = getDividendYieldRequirement(context, security); if (dividendYieldReq == null) { return null; } requirements.add(dividendYieldReq); requirements.add(getSpotAssetRequirement(security)); return requirements; } private String getFundingCurveName(final ValueRequirement desiredValue) { final Set<String> fundingCurves = desiredValue.getConstraints().getValues(ValuePropertyNames.CURVE); if (fundingCurves == null || fundingCurves.size() != 1) { s_logger.info("Could not find {} requirement. Looking for a default..", ValuePropertyNames.CURVE); return null; } final String fundingCurveName = fundingCurves.iterator().next(); return fundingCurveName; } private String getCurveConfigName(final ValueRequirement desiredValue) { final Set<String> curveConfigNames = desiredValue.getConstraints().getValues(ValuePropertyNames.CURVE_CALCULATION_CONFIG); if (curveConfigNames == null || curveConfigNames.size() != 1) { s_logger.info("Could not find {} requirement. Looking for a default..", ValuePropertyNames.CURVE_CALCULATION_CONFIG); return null; } final String curveConfigName = curveConfigNames.iterator().next(); return curveConfigName; } private ValueRequirement getDiscountCurveRequirement(final String fundingCurveName, final String curveCalculationConfigName, final FutureSecurity security) { final ValueProperties properties = ValueProperties.builder() .with(ValuePropertyNames.CURVE, fundingCurveName) .with(ValuePropertyNames.CURVE_CALCULATION_CONFIG, curveCalculationConfigName) .get(); return new ValueRequirement(ValueRequirementNames.YIELD_CURVE, ComputationTargetType.PRIMITIVE, security.getCurrency().getUniqueId(), properties); } private YieldAndDiscountCurve getYieldCurve(final FutureSecurity security, final FunctionInputs inputs, final String fundingCurveName, final String curveCalculationConfigName) { final Object curveObject = inputs.getValue(ValueRequirementNames.YIELD_CURVE); if (curveObject == null) { throw new OpenGammaRuntimeException("Could not get yield curve"); } return (YieldAndDiscountCurve) curveObject; } private ValueRequirement getDividendYieldRequirement(final FunctionCompilationContext context, final FutureSecurity security) { final HistoricalTimeSeriesResolver resolver = OpenGammaCompilationContext.getHistoricalTimeSeriesResolver(context); final HistoricalTimeSeriesResolutionResult timeSeries = resolver.resolve(ExternalIdBundle.of(getSpotAssetId(security)), null, null, null, MarketDataRequirementNames.DIVIDEND_YIELD, null); if (timeSeries == null) { return null; } return HistoricalTimeSeriesFunctionUtils.createHTSRequirement(timeSeries, MarketDataRequirementNames.DIVIDEND_YIELD, DateConstraint.VALUATION_TIME.minus(Period.ofDays(7)), true, DateConstraint.VALUATION_TIME, true); } }