/** * 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 java.util.HashSet; import java.util.Set; import org.threeten.bp.Instant; import org.threeten.bp.LocalTime; import org.threeten.bp.ZoneOffset; import org.threeten.bp.ZonedDateTime; import com.google.common.collect.Sets; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.analytics.financial.model.interestrate.curve.DiscountCurve; import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve; import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve; import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve; import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory; import com.opengamma.analytics.math.interpolation.Interpolator1D; import com.opengamma.core.marketdatasnapshot.SnapshotDataBundle; import com.opengamma.engine.ComputationTarget; import com.opengamma.engine.ComputationTargetSpecification; import com.opengamma.engine.function.AbstractFunction; import com.opengamma.engine.function.CompiledFunctionDefinition; 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.analytics.curve.InterpolatedCurveSpecification; import com.opengamma.financial.analytics.ircurve.strips.ContinuouslyCompoundedRateNode; import com.opengamma.financial.analytics.ircurve.strips.CurveNodeWithIdentifier; import com.opengamma.financial.analytics.ircurve.strips.DiscountFactorNode; import com.opengamma.financial.analytics.model.InterpolatedDataProperties; import com.opengamma.util.time.DateUtils; import com.opengamma.util.time.Tenor; /** * */ public class InterpolatedYieldCurveFunction extends AbstractFunction { @Override public CompiledFunctionDefinition compile(final FunctionCompilationContext compilationContext, final Instant atInstant) { final ZonedDateTime atZDT = ZonedDateTime.ofInstant(atInstant, ZoneOffset.UTC); return new AbstractInvokingCompiledFunction(atZDT.with(LocalTime.MIDNIGHT), atZDT.plusDays(1).with(LocalTime.MIDNIGHT).minusNanos(1000000)) { @SuppressWarnings("synthetic-access") @Override public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) { String curveName = null; String curveCalculationConfig = null; for (final ValueRequirement desiredValue : desiredValues) { if (desiredValue.getValueName().equals(ValueRequirementNames.YIELD_CURVE)) { curveName = desiredValue.getConstraint(ValuePropertyNames.CURVE); curveCalculationConfig = desiredValue.getConstraint(ValuePropertyNames.CURVE_CALCULATION_CONFIG); break; } } final Object specificationObject = inputs.getValue(ValueRequirementNames.CURVE_SPECIFICATION); if (specificationObject == null) { throw new OpenGammaRuntimeException("Could not get curve specification"); } if (!(specificationObject instanceof InterpolatedCurveSpecification)) { throw new OpenGammaRuntimeException("Curve specification was not an InterpolatedCurveSpecification"); } final Object dataObject = inputs.getValue(ValueRequirementNames.CURVE_MARKET_DATA); if (dataObject == null) { throw new OpenGammaRuntimeException("Could not get yield curve data"); } final InterpolatedCurveSpecification specification = (InterpolatedCurveSpecification) specificationObject; final SnapshotDataBundle marketData = (SnapshotDataBundle) dataObject; final int n = marketData.size(); final double[] times = new double[n]; final double[] yields = new double[n]; final double[][] jacobian = new double[n][n]; Boolean isYield = null; int i = 0; for (final CurveNodeWithIdentifier node : specification.getNodes()) { if (node.getCurveNode() instanceof ContinuouslyCompoundedRateNode) { if (i == 0) { isYield = true; } else { if (!isYield) { throw new OpenGammaRuntimeException("Was expecting only continuously-compounded rate nodes; have " + node.getCurveNode()); } } } else if (node.getCurveNode() instanceof DiscountFactorNode) { if (i == 0) { isYield = false; } else { if (isYield) { throw new OpenGammaRuntimeException("Was expecting only discount factor nodes; have " + node.getCurveNode()); } } } else { throw new OpenGammaRuntimeException("Can only handle discount factor or continuously-compounded rate nodes; have " + node.getCurveNode()); } //TODO add check to make sure it's only discounting or rate curve nodes final Double marketValue = marketData.getDataPoint(node.getIdentifier()); final Tenor maturity = node.getCurveNode().getResolvedMaturity(); if (marketValue == null) { throw new OpenGammaRuntimeException("Could not get market data for " + node); } times[i] = DateUtils.estimatedDuration(maturity.getPeriod()).toDays() / 365.0; //TODO check if this is correct yields[i] = marketValue; jacobian[i][i] = 1; i++; } final String interpolatorName = specification.getInterpolatorName(); final String rightExtrapolatorName = specification.getRightExtrapolatorName(); final String leftExtrapolatorName = specification.getLeftExtrapolatorName(); final Interpolator1D interpolator = CombinedInterpolatorExtrapolatorFactory.getInterpolator(interpolatorName, leftExtrapolatorName, rightExtrapolatorName); final InterpolatedDoublesCurve curve = InterpolatedDoublesCurve.from(times, yields, interpolator, curveName); final ValueProperties curveProperties = createValueProperties() .with(ValuePropertyNames.CURVE, curveName) .with(ValuePropertyNames.CURVE_CALCULATION_CONFIG, curveCalculationConfig) .with(ValuePropertyNames.CURVE_CALCULATION_METHOD, InterpolatedDataProperties.CALCULATION_METHOD_NAME).get(); final ValueProperties jacobianProperties = createValueProperties() .with(ValuePropertyNames.CURVE_CALCULATION_CONFIG, curveCalculationConfig) .with(ValuePropertyNames.CURVE_CALCULATION_METHOD, InterpolatedDataProperties.CALCULATION_METHOD_NAME).get(); final ValueSpecification curveSpec = new ValueSpecification(ValueRequirementNames.YIELD_CURVE, target.toSpecification(), curveProperties); final ValueSpecification jacobianSpec = new ValueSpecification(ValueRequirementNames.YIELD_CURVE_JACOBIAN, target.toSpecification(), jacobianProperties); final YieldAndDiscountCurve yieldCurve = isYield ? YieldCurve.from(curve) : DiscountCurve.from(curve); return Sets.newHashSet(new ComputedValue(curveSpec, yieldCurve), new ComputedValue(jacobianSpec, jacobian)); } //TODO should eventually be NULL? @Override public ComputationTargetType getTargetType() { return ComputationTargetType.CURRENCY; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { final ValueProperties curveProperties = createValueProperties() .withAny(ValuePropertyNames.CURVE) .withAny(ValuePropertyNames.CURVE_CALCULATION_CONFIG) .with(ValuePropertyNames.CURVE_CALCULATION_METHOD, InterpolatedDataProperties.CALCULATION_METHOD_NAME) .get(); final ValueProperties jacobianProperties = createValueProperties() .withAny(ValuePropertyNames.CURVE_CALCULATION_CONFIG) .with(ValuePropertyNames.CURVE_CALCULATION_METHOD, InterpolatedDataProperties.CALCULATION_METHOD_NAME) .get(); final ValueSpecification curveSpec = new ValueSpecification(ValueRequirementNames.YIELD_CURVE, target.toSpecification(), curveProperties); final ValueSpecification jacobianSpec = new ValueSpecification(ValueRequirementNames.YIELD_CURVE_JACOBIAN, target.toSpecification(), jacobianProperties); return Sets.newHashSet(curveSpec, jacobianSpec); } @Override public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) { final ValueProperties constraints = desiredValue.getConstraints(); final String curveName = constraints.getStrictValue(ValuePropertyNames.CURVE); if (curveName == null) { return null; } final Set<ValueRequirement> requirements = new HashSet<>(); final ValueProperties properties = ValueProperties.builder() .with(ValuePropertyNames.CURVE, curveName).get(); requirements.add(new ValueRequirement(ValueRequirementNames.CURVE_MARKET_DATA, ComputationTargetSpecification.NULL, properties)); requirements.add(new ValueRequirement(ValueRequirementNames.CURVE_SPECIFICATION, ComputationTargetSpecification.NULL, properties)); return requirements; } }; } }