/*
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.ircurve;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.function.FunctionCompilationContext;
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.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
* Defines static helpers for yield curve functions.
*/
public final class YieldCurveFunction {
private static final Logger s_logger = LoggerFactory.getLogger(YieldCurveFunction.class);
/**
* Identifies the name of the forward curve used for a value. A value dependent on just one
* curve should use the default "CURVE" name and not this prefixed name.
* @deprecated This is used in old yield curve code - do not use
*/
@Deprecated
public static final String PROPERTY_FORWARD_CURVE = "Forward" + ValuePropertyNames.CURVE;
/**
* Identifies the name of the funding curve used for a value. A value dependent on just one
* curve should use the default "CURVE" name and not this prefixed name.
* @deprecated This is used in old yield curve code - do not use
*/
@Deprecated
public static final String PROPERTY_FUNDING_CURVE = "Funding" + ValuePropertyNames.CURVE;
/**
* Identifies the interpolator to be used
*/
public static final String PROPERTY_INTERPOLATOR = "Interpolator";
/**
* Identifies the left extrapolator to be used
*/
public static final String PROPERTY_LEFT_EXTRAPOLATOR = "LeftExtrapolator";
/**
* Identifies the right extrapolator to be used
*/
public static final String PROPERTY_RIGHT_EXTRAPOLATOR = "RightExtrapolator";
private YieldCurveFunction() {
}
// TODO: these should be somewhere else
public static String getPropertyValue(final String propertyName, final ValueRequirement requirement) {
final Set<String> curveNames = requirement.getConstraints().getValues(propertyName);
if ((curveNames == null) || (curveNames.size() != 1)) {
return null;
} else {
return curveNames.iterator().next();
}
}
// TODO: these should be somewhere else
public static String getPropertyValue(final String propertyName, final FunctionCompilationContext context, final ValueRequirement requirement) {
s_logger.debug("propertyName={} requirement={}", propertyName, requirement);
final Set<String> curveNames = requirement.getConstraints().getValues(propertyName);
final Set<String> defaultCurves;
switch ((curveNames != null) ? curveNames.size() : 0) {
case 0:
// Handles both the wildcard case and the unspecified case
s_logger.debug("wildcard or unspecified requirement");
defaultCurves = context.getViewCalculationConfiguration().getDefaultProperties().getValues(propertyName);
if (defaultCurves == null) {
s_logger.info("No default {} defined", propertyName);
throw new IllegalStateException("No default " + propertyName + " defined");
} else if (defaultCurves.size() != 1) {
s_logger.info("Invalid default {} - {}", propertyName, defaultCurves);
throw new IllegalStateException("Invalid default " + propertyName + " - " + defaultCurves);
} else {
final String value = defaultCurves.iterator().next();
s_logger.info("Default {} is {}", propertyName, value);
return value;
}
case 1:
final String value = curveNames.iterator().next();
s_logger.info("Value for {} is {}", propertyName, value);
return value;
default:
defaultCurves = context.getViewCalculationConfiguration().getDefaultProperties().getValues(propertyName);
String foundCurve = null;
for (final String curveName : curveNames) {
if (defaultCurves.contains(curveName)) {
if (foundCurve == null) {
foundCurve = curveName;
} else {
s_logger.info("Default {} contains more than one of {}", propertyName, curveNames);
throw new IllegalStateException("Both " + curveName + " and " + foundCurve + " declared as default " + propertyName);
}
}
}
if (foundCurve != null) {
s_logger.info("Default {} is {}", propertyName, foundCurve);
return foundCurve;
} else {
s_logger.info("None of {} declared as defaults for {}", curveNames, propertyName);
throw new IllegalStateException("Can't select " + propertyName + " from " + curveNames + " - none declared as default");
}
}
}
/**
* Returns the curve name specified as a requirement constraint, null if there is no constraint
* or a wildcard.
*
* @param requirement the requirement
* @return the curve name, may be null
*/
public static String getCurveName(final ValueRequirement requirement) {
return getPropertyValue(ValuePropertyNames.CURVE, requirement);
}
/**
* Returns the curve name specified as a requirement constraint or the view's default curve name if there is
* no constraint or a wildcard.
*
* @param context the function compilation context
* @param requirement the requirement
* @return the curve name, not null
*/
public static String getCurveName(final FunctionCompilationContext context, final ValueRequirement requirement) {
return getPropertyValue(ValuePropertyNames.CURVE, context, requirement);
}
public static String getForwardCurveName(final ValueRequirement requirement) {
return getPropertyValue(PROPERTY_FORWARD_CURVE, requirement);
}
public static String getForwardCurveName(final FunctionCompilationContext context, final ValueRequirement requirement) {
return getPropertyValue(PROPERTY_FORWARD_CURVE, context, requirement);
}
public static String getFundingCurveName(final ValueRequirement requirement) {
return getPropertyValue(PROPERTY_FUNDING_CURVE, requirement);
}
public static String getFundingCurveName(final FunctionCompilationContext context, final ValueRequirement requirement) {
return getPropertyValue(PROPERTY_FUNDING_CURVE, context, requirement);
}
public static ValueRequirement getCurveRequirement(final Currency currency, final String curveName, final String advisoryForward, final String advisoryFunding) {
final ValueProperties.Builder props = ValueProperties.with(ValuePropertyNames.CURVE, curveName);
if (advisoryForward != null) {
props.with(PROPERTY_FORWARD_CURVE, advisoryForward).withOptional(PROPERTY_FORWARD_CURVE);
}
if (advisoryFunding != null) {
props.with(PROPERTY_FUNDING_CURVE, advisoryFunding).withOptional(PROPERTY_FUNDING_CURVE);
}
return new ValueRequirement(ValueRequirementNames.YIELD_CURVE, ComputationTargetSpecification.of(currency), props.get());
}
public static ValueRequirement getCurveRequirement(final Currency currency, final String curveName, final String advisoryForward, final String advisoryFunding, final String calculationMethod) {
final ValueProperties.Builder props = ValueProperties.with(ValuePropertyNames.CURVE, curveName);
if (advisoryForward != null) {
props.with(PROPERTY_FORWARD_CURVE, advisoryForward).withOptional(PROPERTY_FORWARD_CURVE);
}
if (advisoryFunding != null) {
props.with(PROPERTY_FUNDING_CURVE, advisoryFunding).withOptional(PROPERTY_FUNDING_CURVE);
}
props.with(ValuePropertyNames.CURVE_CALCULATION_METHOD, calculationMethod);
return new ValueRequirement(ValueRequirementNames.YIELD_CURVE, ComputationTargetSpecification.of(currency), props.get());
}
public static ValueRequirement getJacobianRequirement(final Currency currency, final String forwardCurveName, final String fundingCurveName) {
return new ValueRequirement(ValueRequirementNames.YIELD_CURVE_JACOBIAN, ComputationTargetSpecification.of(currency),
ValueProperties.with(YieldCurveFunction.PROPERTY_FORWARD_CURVE, forwardCurveName)
.with(YieldCurveFunction.PROPERTY_FUNDING_CURVE, fundingCurveName)
.get());
}
public static ValueRequirement getJacobianRequirement(final Currency currency, final String forwardCurveName, final String fundingCurveName, final String calculationMethod) {
return new ValueRequirement(ValueRequirementNames.YIELD_CURVE_JACOBIAN, ComputationTargetSpecification.of(currency),
ValueProperties.with(YieldCurveFunction.PROPERTY_FORWARD_CURVE, forwardCurveName)
.with(YieldCurveFunction.PROPERTY_FUNDING_CURVE, fundingCurveName)
.with(ValuePropertyNames.CURVE_CALCULATION_METHOD, calculationMethod)
.get());
}
public static ValueRequirement getCouponSensitivityRequirement(final Currency currency, final String forwardCurveName, final String fundingCurveName) {
return new ValueRequirement(ValueRequirementNames.PRESENT_VALUE_COUPON_SENSITIVITY, ComputationTargetSpecification.of(currency),
ValueProperties.builder()
.with(YieldCurveFunction.PROPERTY_FORWARD_CURVE, forwardCurveName)
.with(YieldCurveFunction.PROPERTY_FUNDING_CURVE, fundingCurveName).get());
}
public static ValueRequirement getCouponSensitivityRequirement(final Currency currency) {
return new ValueRequirement(ValueRequirementNames.PRESENT_VALUE_COUPON_SENSITIVITY, ComputationTargetSpecification.of(currency),
ValueProperties.withAny(YieldCurveFunction.PROPERTY_FORWARD_CURVE)
.withAny(YieldCurveFunction.PROPERTY_FUNDING_CURVE)
.get());
}
public static ValueRequirement getJacobianRequirement(final Currency currency, final String calculationMethod) {
return new ValueRequirement(ValueRequirementNames.YIELD_CURVE_JACOBIAN, ComputationTargetSpecification.of(currency),
ValueProperties.withAny(YieldCurveFunction.PROPERTY_FORWARD_CURVE)
.withAny(YieldCurveFunction.PROPERTY_FUNDING_CURVE)
.with(ValuePropertyNames.CURVE_CALCULATION_METHOD, calculationMethod)
.get());
}
public static Pair<String, String> getDesiredValueCurveNames(final Set<ValueRequirement> desiredValues) {
String forwardCurveName = null;
String fundingCurveName = null;
for (final ValueRequirement desiredValue : desiredValues) {
if (forwardCurveName == null) {
final String curveName = getForwardCurveName(desiredValue);
if (curveName != null) {
forwardCurveName = curveName;
if (fundingCurveName != null) {
break;
}
}
}
if (fundingCurveName == null) {
final String curveName = getFundingCurveName(desiredValue);
if (curveName != null) {
fundingCurveName = curveName;
if (forwardCurveName != null) {
break;
}
}
}
}
ArgumentChecker.notNull(fundingCurveName, "fundingCurveName");
ArgumentChecker.notNull(forwardCurveName, "forwardCurveName");
return Pairs.of(forwardCurveName, fundingCurveName);
}
public static Pair<String, String> getDesiredValueCurveNames(final FunctionCompilationContext context, final ValueRequirement desiredValue) {
final String desiredCurveName = getCurveName(context, desiredValue);
String forwardCurveName = getForwardCurveName(desiredValue);
String fundingCurveName = getFundingCurveName(desiredValue);
if (forwardCurveName == null) {
if (fundingCurveName == null) {
forwardCurveName = desiredCurveName;
fundingCurveName = desiredCurveName;
} else {
throw new IllegalArgumentException("forwardCurveName");
}
} else {
if (fundingCurveName == null) {
throw new IllegalArgumentException("fundingCurveName");
} else {
if (!desiredCurveName.equals(forwardCurveName) && !desiredCurveName.equals(fundingCurveName)) {
//TODO put a Jira in about this stupidity
throw new IllegalArgumentException("curveName " + desiredCurveName + " not one of forwardCurveName=" + forwardCurveName + " or fundingCurveName=" + fundingCurveName);
}
}
}
return Pairs.of(forwardCurveName, fundingCurveName);
}
public static Pair<String, String> getInputCurveNames(final Map<ValueSpecification, ValueRequirement> inputs) {
String forwardCurveName = null;
String fundingCurveName = null;
for (final Map.Entry<ValueSpecification, ValueRequirement> input : inputs.entrySet()) {
if (ValueRequirementNames.YIELD_CURVE.equals(input.getKey().getValueName())) {
final String curveName = input.getKey().getProperty(ValuePropertyNames.CURVE);
if (curveName.equals(input.getValue().getConstraint(PROPERTY_FORWARD_CURVE))) {
s_logger.debug("Using {} from advisory forward", curveName);
forwardCurveName = curveName;
} else if (curveName.equals(input.getValue().getConstraint(PROPERTY_FUNDING_CURVE))) {
s_logger.debug("Using {} from advisory funding", curveName);
fundingCurveName = curveName;
} else {
if ((forwardCurveName == null) && (fundingCurveName == null)) {
s_logger.debug("Using {} for both curve names", curveName);
forwardCurveName = curveName;
fundingCurveName = curveName;
} else {
throw new IllegalArgumentException("Curves already set - inputs=" + inputs);
}
}
}
}
ArgumentChecker.notNull(fundingCurveName, "fundingCurveName");
ArgumentChecker.notNull(forwardCurveName, "forwardCurveName");
return Pairs.of(forwardCurveName, fundingCurveName);
}
}