/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.analytics.model.curve.interestrate; import static com.opengamma.engine.value.ValuePropertyNames.CURVE; import static com.opengamma.engine.value.ValuePropertyNames.CURVE_CALCULATION_CONFIG; import static com.opengamma.engine.value.ValueRequirementNames.YIELD_CURVE; import static com.opengamma.engine.value.ValueRequirementNames.YIELD_CURVE_CONVERSION_HISTORICAL_TIME_SERIES; import static com.opengamma.engine.value.ValueRequirementNames.YIELD_CURVE_HISTORICAL_TIME_SERIES; import static com.opengamma.engine.value.ValueRequirementNames.YIELD_CURVE_SERIES; import static com.opengamma.engine.value.ValueRequirementNames.YIELD_CURVE_SPEC; import static com.opengamma.financial.analytics.model.curve.interestrate.MultiYieldCurvePropertiesAndDefaults.PROPERTY_DECOMPOSITION; import static com.opengamma.financial.analytics.model.curve.interestrate.MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_ABSOLUTE_TOLERANCE; import static com.opengamma.financial.analytics.model.curve.interestrate.MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_MAX_ITERATIONS; import static com.opengamma.financial.analytics.model.curve.interestrate.MultiYieldCurvePropertiesAndDefaults.PROPERTY_ROOT_FINDER_RELATIVE_TOLERANCE; import static com.opengamma.financial.analytics.model.curve.interestrate.MultiYieldCurvePropertiesAndDefaults.PROPERTY_USE_FINITE_DIFFERENCE; import static com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils.DATA_FIELD_PROPERTY; import static com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils.END_DATE_PROPERTY; import static com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils.INCLUDE_END_PROPERTY; import static com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils.INCLUDE_START_PROPERTY; import static com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils.RESOLUTION_KEY_PROPERTY; import static com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils.START_DATE_PROPERTY; import static com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils.YES_VALUE; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.analytics.financial.interestrate.YieldCurveBundle; import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve; 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.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.ValueSpecification; import com.opengamma.financial.analytics.ircurve.InterpolatedYieldCurveSpecificationWithSecurities; import com.opengamma.financial.analytics.ircurve.YieldCurveDefinition; import com.opengamma.financial.analytics.ircurve.calcconfig.ConfigDBCurveCalculationConfigSource; import com.opengamma.financial.analytics.ircurve.calcconfig.MultiCurveCalculationConfig; import com.opengamma.financial.analytics.model.curve.MultiCurveFunction; import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesBundle; /** * Base class for functions that construct yield curves and the Jacobian from {@link YieldCurveDefinition} and {@link MultiCurveCalculationConfig}s using root-finding. * * @deprecated This function uses configuration objects that have been superseded. Use functions that descend from {@link MultiCurveFunction} */ @Deprecated public abstract class MultiYieldCurveSeriesFunction extends AbstractFunction.NonCompiledInvoker { /** The logger */ private static final Logger s_logger = LoggerFactory.getLogger(MultiYieldCurveSeriesFunction.class); private ConfigDBCurveCalculationConfigSource _curveCalculationConfigSource; @Override public void init(final FunctionCompilationContext context) { _curveCalculationConfigSource = ConfigDBCurveCalculationConfigSource.init(context, this); } @Override public ComputationTargetType getTargetType() { return ComputationTargetType.CURRENCY; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { final ValueProperties curveProperties = getCurveSeriesProperties(); final ValueSpecification curve = new ValueSpecification(YIELD_CURVE_SERIES, target.toSpecification(), curveProperties); return Sets.newHashSet(curve); } @Override public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) { ValueProperties.Builder seriesConstraints = null; final ValueProperties constraints = desiredValue.getConstraints(); Set<String> values = desiredValue.getConstraints().getValues(DATA_FIELD_PROPERTY); if ((values == null) || values.isEmpty()) { seriesConstraints = desiredValue.getConstraints().copy().with(DATA_FIELD_PROPERTY, MarketDataRequirementNames.MARKET_VALUE); } else if (values.size() > 1) { seriesConstraints = desiredValue.getConstraints().copy().withoutAny(DATA_FIELD_PROPERTY).with(DATA_FIELD_PROPERTY, values.iterator().next()); } values = desiredValue.getConstraints().getValues(RESOLUTION_KEY_PROPERTY); if ((values == null) || values.isEmpty()) { if (seriesConstraints == null) { seriesConstraints = desiredValue.getConstraints().copy(); } seriesConstraints.with(RESOLUTION_KEY_PROPERTY, ""); } else if (values.size() > 1) { if (seriesConstraints == null) { seriesConstraints = desiredValue.getConstraints().copy(); } seriesConstraints.withoutAny(RESOLUTION_KEY_PROPERTY).with(RESOLUTION_KEY_PROPERTY, values.iterator().next()); } values = desiredValue.getConstraints().getValues(START_DATE_PROPERTY); if ((values == null) || values.isEmpty()) { if (seriesConstraints == null) { seriesConstraints = desiredValue.getConstraints().copy(); } seriesConstraints.with(START_DATE_PROPERTY, "Null"); } values = desiredValue.getConstraints().getValues(INCLUDE_START_PROPERTY); if ((values == null) || (values.size() != 1)) { if (seriesConstraints == null) { seriesConstraints = desiredValue.getConstraints().copy(); } seriesConstraints.with(INCLUDE_START_PROPERTY, YES_VALUE); } values = desiredValue.getConstraints().getValues(END_DATE_PROPERTY); if ((values == null) || values.isEmpty()) { if (seriesConstraints == null) { seriesConstraints = desiredValue.getConstraints().copy(); } seriesConstraints.with(END_DATE_PROPERTY, "Now"); } values = desiredValue.getConstraints().getValues(INCLUDE_END_PROPERTY); if ((values == null) || (values.size() != 1)) { if (seriesConstraints == null) { seriesConstraints = desiredValue.getConstraints().copy(); } seriesConstraints.with(INCLUDE_END_PROPERTY, YES_VALUE); } if (seriesConstraints != null) { Set<String> propertyValue = constraints.getValues(PROPERTY_ROOT_FINDER_ABSOLUTE_TOLERANCE); if (propertyValue == null) { seriesConstraints.withAny(PROPERTY_ROOT_FINDER_ABSOLUTE_TOLERANCE); } else { seriesConstraints.with(PROPERTY_ROOT_FINDER_ABSOLUTE_TOLERANCE, propertyValue); } propertyValue = constraints.getValues(PROPERTY_ROOT_FINDER_RELATIVE_TOLERANCE); if (propertyValue == null) { seriesConstraints.withAny(PROPERTY_ROOT_FINDER_RELATIVE_TOLERANCE); } else { seriesConstraints.with(PROPERTY_ROOT_FINDER_RELATIVE_TOLERANCE, propertyValue); } propertyValue = constraints.getValues(PROPERTY_ROOT_FINDER_MAX_ITERATIONS); if (propertyValue == null) { seriesConstraints.withAny(PROPERTY_ROOT_FINDER_MAX_ITERATIONS); } else { seriesConstraints.with(PROPERTY_ROOT_FINDER_MAX_ITERATIONS, propertyValue); } propertyValue = constraints.getValues(PROPERTY_DECOMPOSITION); if (propertyValue == null) { seriesConstraints.withAny(PROPERTY_DECOMPOSITION); } else { seriesConstraints.with(PROPERTY_DECOMPOSITION, propertyValue); } propertyValue = constraints.getValues(PROPERTY_USE_FINITE_DIFFERENCE); if (propertyValue == null) { seriesConstraints.withAny(PROPERTY_USE_FINITE_DIFFERENCE); } else { seriesConstraints.with(PROPERTY_USE_FINITE_DIFFERENCE, propertyValue); } return Collections.singleton(new ValueRequirement(YIELD_CURVE_SERIES, target.toSpecification(), seriesConstraints.get())); } final Set<String> curveCalculationConfigNames = constraints.getValues(ValuePropertyNames.CURVE_CALCULATION_CONFIG); if (curveCalculationConfigNames == null || curveCalculationConfigNames.size() != 1) { return null; } final String curveCalculationConfigName = Iterables.getOnlyElement(curveCalculationConfigNames); final MultiCurveCalculationConfig curveCalculationConfig = _curveCalculationConfigSource.getConfig(curveCalculationConfigName); if (curveCalculationConfig == null) { s_logger.error("Could not find curve calculation configuration named {}", curveCalculationConfigName); return null; } if (!curveCalculationConfig.getCalculationMethod().equals(getCalculationMethod())) { return null; } if (!curveCalculationConfig.getTarget().equals(target.toSpecification())) { s_logger.warn("Invalid target for {}, was {} - expected {}", curveCalculationConfigName, target, curveCalculationConfig.getTarget()); return null; } final Set<String> rootFinderAbsoluteTolerance = constraints.getValues(PROPERTY_ROOT_FINDER_ABSOLUTE_TOLERANCE); if (rootFinderAbsoluteTolerance == null || rootFinderAbsoluteTolerance.size() != 1) { return null; } final Set<String> rootFinderRelativeTolerance = constraints.getValues(PROPERTY_ROOT_FINDER_RELATIVE_TOLERANCE); if (rootFinderRelativeTolerance == null || rootFinderRelativeTolerance.size() != 1) { return null; } final Set<String> maxIterations = constraints.getValues(PROPERTY_ROOT_FINDER_MAX_ITERATIONS); if (maxIterations == null || maxIterations.size() != 1) { return null; } final Set<String> decomposition = constraints.getValues(PROPERTY_DECOMPOSITION); if (decomposition == null || decomposition.size() != 1) { return null; } final Set<String> useFiniteDifference = constraints.getValues(PROPERTY_USE_FINITE_DIFFERENCE); if (useFiniteDifference == null || useFiniteDifference.size() != 1) { return null; } final String[] curveNames = curveCalculationConfig.getYieldCurveNames(); final Set<ValueRequirement> requirements = new HashSet<>(); final ComputationTargetSpecification targetSpec = target.toSpecification(); for (final String curveName : curveNames) { final ValueProperties properties = ValueProperties.builder().with(CURVE, curveName).with(CURVE_CALCULATION_CONFIG, curveCalculationConfigName).withOptional(CURVE_CALCULATION_CONFIG) .get(); final ValueProperties curveTSProperties = ValueProperties.builder().with(CURVE, curveName).with(DATA_FIELD_PROPERTY, constraints.getValues(DATA_FIELD_PROPERTY)) .with(RESOLUTION_KEY_PROPERTY, constraints.getValues(RESOLUTION_KEY_PROPERTY)).with(START_DATE_PROPERTY, constraints.getValues(START_DATE_PROPERTY)) .with(INCLUDE_START_PROPERTY, constraints.getValues(INCLUDE_START_PROPERTY)).with(END_DATE_PROPERTY, constraints.getValues(END_DATE_PROPERTY)) .with(INCLUDE_END_PROPERTY, constraints.getValues(INCLUDE_END_PROPERTY)).get(); requirements.add(new ValueRequirement(YIELD_CURVE_HISTORICAL_TIME_SERIES, targetSpec, properties)); requirements.add(new ValueRequirement(YIELD_CURVE_SPEC, targetSpec, properties)); requirements.add(new ValueRequirement(YIELD_CURVE_CONVERSION_HISTORICAL_TIME_SERIES, targetSpec, curveTSProperties)); requirements.add(new ValueRequirement(YIELD_CURVE_HISTORICAL_TIME_SERIES, targetSpec, curveTSProperties)); } if (curveCalculationConfig.getExogenousConfigData() != null) { final LinkedHashMap<String, String[]> exogenousCurveConfigs = curveCalculationConfig.getExogenousConfigData(); for (final Map.Entry<String, String[]> entry : exogenousCurveConfigs.entrySet()) { for (final String exogenousCurveName : entry.getValue()) { final ValueProperties properties = constraints.copy().withoutAny(CURVE_CALCULATION_CONFIG).with(CURVE_CALCULATION_CONFIG, entry.getKey()).withoutAny(CURVE) .with(CURVE, exogenousCurveName).get(); requirements.add(new ValueRequirement(YIELD_CURVE_SERIES, targetSpec, properties)); } } } return requirements; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target, final Map<ValueSpecification, ValueRequirement> inputs) { if (inputs.size() == 1) { final ValueSpecification input = Iterables.getOnlyElement(inputs.entrySet()).getKey(); if (YIELD_CURVE_SERIES.equals(input.getValueName())) { // Use the substituted result return Collections.singleton(input); } } final Set<ValueSpecification> results = new HashSet<>(); final ComputationTargetSpecification targetSpec = target.toSpecification(); String curveCalculationConfigName = null; for (final Map.Entry<ValueSpecification, ValueRequirement> entry : inputs.entrySet()) { final ValueRequirement value = entry.getValue(); if (value.getValueName().equals(YIELD_CURVE_SPEC)) { if (curveCalculationConfigName == null) { curveCalculationConfigName = value.getConstraint(CURVE_CALCULATION_CONFIG); } else { if (!value.getConstraint(CURVE_CALCULATION_CONFIG).equals(curveCalculationConfigName)) { throw new OpenGammaRuntimeException("Had different curve calculation configuration names; should never happen"); } } final String curveName = value.getConstraint(CURVE); final ValueProperties curveProperties = getCurveSeriesProperties(curveCalculationConfigName, curveName); final ValueSpecification spec = new ValueSpecification(YIELD_CURVE_SERIES, targetSpec, curveProperties); results.add(spec); } } if (curveCalculationConfigName == null) { return null; } return results; } /** * Gets the yield curve properties with no values set. * * @return The properties for the curve */ protected abstract ValueProperties getCurveSeriesProperties(); /** * Gets properties for a single yield curve with the curve calculation configuration name and curve. name set. * * @param curveCalculationConfigName The curve calculation configuration name * @param curveName The curve name * @return The properties for the curve */ protected abstract ValueProperties getCurveSeriesProperties(final String curveCalculationConfigName, final String curveName); /** * Gets the curve calculation method. * * @return The curve calculation method */ protected abstract String getCalculationMethod(); /** * Gets the snapshot containing the market data from the function inputs. * * @param inputs The inputs * @param targetSpec The specification of the market data * @param curveName The curve name * @return The market data snapshot * @throws OpenGammaRuntimeException if the snapshot is not present in the inputs */ protected HistoricalTimeSeriesBundle getHistoricalMarketData(final FunctionInputs inputs, final ComputationTargetSpecification targetSpec, final String curveName) { final ValueRequirement marketDataRequirement = new ValueRequirement(YIELD_CURVE_HISTORICAL_TIME_SERIES, targetSpec, ValueProperties.with(CURVE, curveName).get()); final Object marketDataObject = inputs.getValue(marketDataRequirement); if (marketDataObject == null) { throw new OpenGammaRuntimeException("Could not get a value for requirement " + marketDataRequirement); } return (HistoricalTimeSeriesBundle) marketDataObject; } /** * Gets the bundle containing historical fixing from the function inputs. * * @param inputs The inputs * @param targetSpec The specification of the historical data * @param curveName The curve name * @return The bundle * @throws OpenGammaRuntimeException if the bundle is not present in the inputs */ protected HistoricalTimeSeriesBundle getTimeSeriesBundle(final FunctionInputs inputs, final ComputationTargetSpecification targetSpec, final String curveName) { final ValueRequirement timeSeriesRequirement = new ValueRequirement(YIELD_CURVE_CONVERSION_HISTORICAL_TIME_SERIES, targetSpec, ValueProperties.with(CURVE, curveName).get()); final Object timeSeriesObject = inputs.getValue(timeSeriesRequirement); if (timeSeriesObject == null) { throw new OpenGammaRuntimeException("Could not get conversion time series for requirement " + timeSeriesRequirement); } return (HistoricalTimeSeriesBundle) timeSeriesObject; } /** * Gets the interpolated yield curve specifications from the function inputs * * @param inputs The inputs * @param targetSpec The specification of the interpolated yield curve * @param curveName The curve name * @return The specification * @throws OpenGammaRuntimeException if the specification is not present in the inputs */ protected InterpolatedYieldCurveSpecificationWithSecurities getYieldCurveSpecification(final FunctionInputs inputs, final ComputationTargetSpecification targetSpec, final String curveName) { final ValueRequirement specRequirement = new ValueRequirement(YIELD_CURVE_SPEC, targetSpec, ValueProperties.with(CURVE, curveName).get()); final Object specObject = inputs.getValue(specRequirement); if (specObject == null) { return null; } return (InterpolatedYieldCurveSpecificationWithSecurities) specObject; } /** * Gets any known (i.e. exogenous) curves from the function inputs. These curves are held fixed during fitting. * * @param curveCalculationConfig The curve calculation configuration * @param targetSpec The specification of the known curves * @param inputs The inputs * @return A yield curve bundle containing the curves or null if none of the curves are known before fitting * @throws OpenGammaRuntimeException If an exogenous curve is required but is not present in the inputs */ protected YieldCurveBundle getKnownCurves(final MultiCurveCalculationConfig curveCalculationConfig, final ComputationTargetSpecification targetSpec, final FunctionInputs inputs) { YieldCurveBundle knownCurves = null; if (curveCalculationConfig.getExogenousConfigData() != null) { knownCurves = new YieldCurveBundle(); final LinkedHashMap<String, String[]> exogenousCurveNames = curveCalculationConfig.getExogenousConfigData(); for (final Map.Entry<String, String[]> entry : exogenousCurveNames.entrySet()) { for (final String exogenousCurveName : entry.getValue()) { final ValueProperties properties = ValueProperties.builder().with(CURVE, exogenousCurveName).get(); final Object exogenousCurveObject = inputs.getValue(new ValueRequirement(YIELD_CURVE, targetSpec, properties)); if (exogenousCurveObject == null) { throw new OpenGammaRuntimeException("Could not get exogenous curve named " + exogenousCurveName); } final YieldAndDiscountCurve exogenousCurve = (YieldAndDiscountCurve) exogenousCurveObject; knownCurves.setCurve(exogenousCurveName, exogenousCurve); } } } return knownCurves; } protected ConfigDBCurveCalculationConfigSource getCurveCalculationConfigSource() { return _curveCalculationConfigSource; } }