/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.sesame.function.scenarios.curvedata; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import com.opengamma.financial.analytics.curve.CurveSpecification; import com.opengamma.financial.analytics.ircurve.strips.CurveNodeWithIdentifier; import com.opengamma.financial.analytics.ircurve.strips.RateFutureNode; import com.opengamma.id.ExternalId; import com.opengamma.id.ExternalIdBundle; import com.opengamma.sesame.function.scenarios.ScenarioArgument; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.result.FailureStatus; import com.opengamma.util.result.Result; import com.opengamma.util.time.Tenor; /** * Shifts to apply to the points in a curve, specified by the tenors of the points to which they apply. * * @deprecated use the new scenario framework */ @Deprecated public abstract class CurveDataPointShifts implements ScenarioArgument<CurveDataPointShifts, CurveDataPointShiftsDecorator> { /** Curves are only shifted if they match this matcher. */ private final CurveSpecificationMatcher _matcher; /** Shift amounts keyed by tenor of the point to which they apply. */ private final Map<Tenor, Double> _shifts; @Override public Class<CurveDataPointShiftsDecorator> getFunctionType() { return CurveDataPointShiftsDecorator.class; } protected CurveDataPointShifts(CurveSpecificationMatcher matcher, List<PointShift> shifts) { ArgumentChecker.notNull(shifts, "shifts"); _matcher = ArgumentChecker.notNull(matcher, "matcher"); _shifts = new HashMap<>(shifts.size()); for (PointShift shift : shifts) { _shifts.put(shift._tenor, shift._shiftAmount); } } /** * Returns a new map of values containing the data in the input map with shifts applied. * Shifts are only applied if the curve specification matches the matcher. * * @param curveSpec specification of the curve * @param values market data of the curve's points, keyed by identifier * @return the shifted values */ public Result<Map<ExternalIdBundle, Double>> apply(CurveSpecification curveSpec, Map<ExternalIdBundle, Double> values) { if (!_matcher.matches(curveSpec)) { return Result.success(values); } // populate the results with the value. if there is no shift defined for a point the original value will be used Map<ExternalIdBundle, Double> results = new HashMap<>(values); ExternalIdMap<Double> valueMap = new ExternalIdMap<>(values); Map<Tenor, CurveNodeWithIdentifier> tenorNodeMap = createNodeMap(curveSpec); List<Result<?>> failures = new ArrayList<>(); for (Map.Entry<Tenor, Double> entry : _shifts.entrySet()) { Tenor tenor = entry.getKey(); Double shiftAmount = entry.getValue(); double shiftedValue; CurveNodeWithIdentifier node = tenorNodeMap.get(tenor); if (node == null) { failures.add(Result.failure(FailureStatus.MISSING_DATA, "No curve point found with tenor {}", tenor)); } else { ExternalId nodeId = node.getIdentifier(); Double value = valueMap.get(nodeId); // futures are quoted the other way round, i.e. (1 - value) if (node.getCurveNode() instanceof RateFutureNode) { shiftedValue = 1 - shift(1 - value, shiftAmount); } else { shiftedValue = shift(value, shiftAmount); } results.put(valueMap.getBundle(nodeId), shiftedValue); } } if (failures.isEmpty()) { return Result.success(results); } else { return Result.failure(failures); } } /** * Applies a shift to a value. * * @param normalizedValue the value to shift * @param shiftAmount the amount to shift by * @return the shifted amount */ protected abstract double shift(double normalizedValue, double shiftAmount); private static Map<Tenor, CurveNodeWithIdentifier> createNodeMap(CurveSpecification curveSpec) { Set<CurveNodeWithIdentifier> nodes = curveSpec.getNodes(); Map<Tenor, CurveNodeWithIdentifier> nodeMap = new HashMap<>(nodes.size()); for (CurveNodeWithIdentifier node : nodes) { nodeMap.put(node.getCurveNode().getResolvedMaturity(), node); } return nodeMap; } /** * Creates a shift that adds an absolute amount to each market data point in the curve. * * @param matcher for deciding whether a curve should be shifted * @param shifts the shifts to apply to the curve points * @return an instance to perform the shift */ public static CurveDataPointShifts absolute(CurveSpecificationMatcher matcher, PointShift... shifts) { return new Absolute(matcher, Arrays.asList(shifts)); } /** * Creates a shift that adds an absolute amount to each market data point in the curve. * * @param matcher for deciding whether a curve should be shifted * @param shifts the shifts to apply to the curve points * @return an instance to perform the shift */ public static CurveDataPointShifts absolute(CurveSpecificationMatcher matcher, List<PointShift> shifts) { return new Absolute(matcher, shifts); } /** * Creates a shift that adds a relative amount to each market data point in the curve. * A shift of 0.1 (+10%) scales the point value by 1.1, a shift of -0.2 (-20%) scales the point value by 0.8. * * @param matcher for deciding whether a curve should be shifted * @param shifts the shifts to apply to the curve points * @return an instance to perform the shift */ public static CurveDataPointShifts relative(CurveSpecificationMatcher matcher, PointShift... shifts) { return new Relative(matcher, Arrays.asList(shifts)); } /** * Creates a shift that adds a relative amount to each market data point in the curve. * A shift of 0.1 (+10%) scales the point value by 1.1, a shift of -0.2 (-20%) scales the point value by 0.8. * * @param matcher for deciding whether a curve should be shifted * @param shifts the shifts to apply to the curve points * @return an instance to perform the shift */ public static CurveDataPointShifts relative(CurveSpecificationMatcher matcher, List<PointShift> shifts) { return new Relative(matcher, shifts); } /** * A shift amount and the tenor of the point to which it should be applied. */ public static final class PointShift { private final Tenor _tenor; private final double _shiftAmount; private PointShift(Tenor tenor, double shiftAmount) { _tenor = ArgumentChecker.notNull(tenor, "tenor"); _shiftAmount = shiftAmount; } /** * Creates a shift. * * @param tenor the tenor of the point to which the shift should be applied * @param shiftAmount the amount to shift by * @return the shift */ public static PointShift of(Tenor tenor, double shiftAmount) { return new PointShift(tenor, shiftAmount); } } /** * Adds an absolute amount to the point's value. */ private static final class Absolute extends CurveDataPointShifts { public Absolute(CurveSpecificationMatcher matcher, List<PointShift> shifts) { super(matcher, shifts); } @Override protected double shift(double normalizedValue, double shiftAmount) { return normalizedValue + shiftAmount; } } /** * Scales the point's value. */ private static final class Relative extends CurveDataPointShifts { public Relative(CurveSpecificationMatcher matcher, List<PointShift> shifts) { super(matcher, shifts); } @Override protected double shift(double normalizedValue, double shiftAmount) { return normalizedValue * (1 + shiftAmount); } } }