/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.analytics.model.credit; import static com.opengamma.engine.value.ValuePropertyNames.FUNCTION; import static com.opengamma.financial.analytics.model.credit.CreditInstrumentPropertyNamesAndValues.ADDITIVE_SPREAD_CURVE_SHIFT; import static com.opengamma.financial.analytics.model.credit.CreditInstrumentPropertyNamesAndValues.MULTIPLICATIVE_SPREAD_CURVE_SHIFT; import static com.opengamma.financial.analytics.model.credit.CreditInstrumentPropertyNamesAndValues.PROPERTY_SPREAD_CURVE_SHIFT; import static com.opengamma.financial.analytics.model.credit.CreditInstrumentPropertyNamesAndValues.PROPERTY_SPREAD_CURVE_SHIFT_TYPE; import java.util.Collections; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Iterables; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.analytics.math.curve.NodalObjectsCurve; import com.opengamma.engine.ComputationTarget; 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.ValueRequirement; import com.opengamma.engine.value.ValueRequirementNames; import com.opengamma.engine.value.ValueSpecification; import com.opengamma.util.async.AsynchronousExecution; import com.opengamma.util.time.Tenor; /** * */ public class ISDACreditSpreadCurveShiftFunction extends AbstractFunction.NonCompiledInvoker { private static final Logger s_logger = LoggerFactory.getLogger(ISDACreditSpreadCurveFunction.class); private static final String PREFIX = "Shifted "; @Override public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) throws AsynchronousExecution { final ValueRequirement desiredValue = Iterables.getOnlyElement(desiredValues); final ValueSpecification input = Iterables.getOnlyElement(inputs.getAllValues()).getSpecification(); final Object creditSpreadCurveObject = inputs.getValue(ValueRequirementNames.CREDIT_SPREAD_CURVE); if (creditSpreadCurveObject == null) { throw new OpenGammaRuntimeException("Could not get credit spread curve"); } @SuppressWarnings("unchecked") final NodalObjectsCurve<Tenor, Double> creditSpreadCurve = (NodalObjectsCurve<Tenor, Double>) creditSpreadCurveObject; final String shiftProperty = desiredValue.getConstraint(PROPERTY_SPREAD_CURVE_SHIFT); final String shiftTypeProperty = desiredValue.getConstraint(PROPERTY_SPREAD_CURVE_SHIFT_TYPE); final double shift = Double.parseDouble(shiftProperty); final Tenor[] xs = creditSpreadCurve.getXData(); final Double[] ys = creditSpreadCurve.getYData(); final Double[] shiftedYs = new Double[ys.length]; switch (shiftTypeProperty) { case ADDITIVE_SPREAD_CURVE_SHIFT: for (int i = 0; i < ys.length; i++) { shiftedYs[i] = ys[i] + shift; } break; case MULTIPLICATIVE_SPREAD_CURVE_SHIFT: for (int i = 0; i < ys.length; i++) { shiftedYs[i] = ys[i] * (1 + shift / 100.); } break; default: throw new OpenGammaRuntimeException("Spread curve shift type not recognised" + shiftTypeProperty); } final String name = PREFIX + creditSpreadCurve.getName(); final NodalObjectsCurve<Tenor, Double> shiftedCurve = NodalObjectsCurve.from(xs, shiftedYs, name); final ValueProperties properties = createValueProperties(input) .with(PROPERTY_SPREAD_CURVE_SHIFT, shiftProperty) .with(PROPERTY_SPREAD_CURVE_SHIFT_TYPE, shiftTypeProperty) .get(); return Collections.singleton(new ComputedValue(new ValueSpecification(input.getValueName(), input.getTargetSpecification(), properties), shiftedCurve)); } @Override public ComputationTargetType getTargetType() { return ComputationTargetType.NULL; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { return Collections.singleton(new ValueSpecification(ValueRequirementNames.CREDIT_SPREAD_CURVE, target.toSpecification(), ValueProperties.all())); } @Override public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) { final ValueProperties constraints = desiredValue.getConstraints(); final Set<String> shifts = constraints.getValues(PROPERTY_SPREAD_CURVE_SHIFT); if (shifts == null || shifts.isEmpty()) { return null; } final Set<String> shiftTypes = constraints.getValues(PROPERTY_SPREAD_CURVE_SHIFT_TYPE); if (shiftTypes == null || shiftTypes.isEmpty()) { return null; } final String shiftType = Iterables.getOnlyElement(shiftTypes); if (!(shiftType.equals(ADDITIVE_SPREAD_CURVE_SHIFT) || shiftType.equals(MULTIPLICATIVE_SPREAD_CURVE_SHIFT))) { s_logger.error("Spread curve shift type {} not recognised", shiftType); return null; } final ValueProperties properties = constraints.copy() .withoutAny(PROPERTY_SPREAD_CURVE_SHIFT) .withoutAny(PROPERTY_SPREAD_CURVE_SHIFT_TYPE) .get(); return Collections.singleton(new ValueRequirement(desiredValue.getValueName(), target.toSpecification(), properties)); } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target, final Map<ValueSpecification, ValueRequirement> inputs) { final ValueSpecification input = Iterables.getOnlyElement(inputs.keySet()); final ValueProperties properties = createValueProperties(input) .withAny(PROPERTY_SPREAD_CURVE_SHIFT) .withAny(PROPERTY_SPREAD_CURVE_SHIFT_TYPE) .get(); return Collections.singleton(new ValueSpecification(input.getValueName(), input.getTargetSpecification(), properties)); } private ValueProperties.Builder createValueProperties(final ValueSpecification input) { return input.getProperties().copy().withoutAny(FUNCTION).with(FUNCTION, getUniqueId()); } }