com.opengamma.financial.analytics.model.sensitivities.ExternallyProvidedSensitivitiesYieldCurveNodeSensitivitiesFunction.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.financial.analytics.model.sensitivities.ExternallyProvidedSensitivitiesYieldCurveNodeSensitivitiesFunction.java

Source

/**
 * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.financial.analytics.model.sensitivities;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.Period;

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.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.core.security.Security;
import com.opengamma.core.security.SecuritySource;
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.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.OpenGammaCompilationContext;
import com.opengamma.financial.analytics.ircurve.FixedIncomeStripWithSecurity;
import com.opengamma.financial.analytics.ircurve.InterpolatedYieldCurveSpecificationWithSecurities;
import com.opengamma.financial.analytics.model.YieldCurveNodeSensitivitiesHelper;
import com.opengamma.financial.analytics.timeseries.DateConstraint;
import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils;
import com.opengamma.financial.security.FinancialSecurityUtils;
import com.opengamma.financial.sensitivities.FactorExposureData;
import com.opengamma.financial.sensitivities.FactorType;
import com.opengamma.financial.sensitivities.RawSecurityUtils;
import com.opengamma.financial.sensitivities.SecurityEntryData;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolutionResult;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolver;
import com.opengamma.master.historicaltimeseries.ManageableHistoricalTimeSeries;
import com.opengamma.master.security.RawSecurity;
import com.opengamma.util.money.Currency;
import com.opengamma.util.time.DateUtils;

/**
 *
 */
public class ExternallyProvidedSensitivitiesYieldCurveNodeSensitivitiesFunction
        extends AbstractFunction.NonCompiledInvoker {
    private static final Logger s_logger = LoggerFactory
            .getLogger(ExternallyProvidedSensitivitiesYieldCurveNodeSensitivitiesFunction.class);
    /**
     * The value name calculated by this function.
     */
    public static final String YCNS_REQUIREMENT = ValueRequirementNames.YIELD_CURVE_NODE_SENSITIVITIES;
    private static final CharSequence SWAP_TEXT = "SWAP";
    private static final CharSequence BOND_TEXT = "BOND";
    private HistoricalTimeSeriesResolver _htsResolver;

    @Override
    public void init(final FunctionCompilationContext context) {
        // REVIEW: jim 24-Oct-2012 -- this is a terrible, terrible hack.  Blame Andrew Griffin - he told me to do it.
        _htsResolver = OpenGammaCompilationContext.getHistoricalTimeSeriesResolver(context);
    }

    @Override
    public ComputationTargetType getTargetType() {
        return ComputationTargetType.SECURITY;
    }

    @Override
    public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) {
        if (!(target.getSecurity() instanceof RawSecurity)) {
            return false;
        }
        final RawSecurity security = (RawSecurity) target.getSecurity();
        return security.getSecurityType().equals(SecurityEntryData.EXTERNAL_SENSITIVITIES_SECURITY_TYPE);
    }

    private ValueProperties.Builder createValueProperties(final ComputationTarget target) {
        final Security security = target.getSecurity();
        final String currency = FinancialSecurityUtils.getCurrency(security).getCode();
        final ValueProperties.Builder properties = createValueProperties();
        properties.with(ValuePropertyNames.CURRENCY, currency);
        properties.with(ValuePropertyNames.CURVE_CURRENCY, currency);
        return properties;
    }

    @Override
    public Set<ValueSpecification> getResults(final FunctionCompilationContext context,
            final ComputationTarget target) {
        final ValueProperties.Builder properties = createValueProperties(target);
        properties.withAny(ValuePropertyNames.CURVE);
        properties.withAny(ValuePropertyNames.CURVE_CALCULATION_CONFIG);
        final Set<ValueSpecification> results = Sets.newHashSetWithExpectedSize(2);
        final ComputationTargetSpecification targetSpec = target.toSpecification();
        results.add(new ValueSpecification(YCNS_REQUIREMENT, targetSpec, properties.get()));
        s_logger.debug("getResults(1) = " + results);
        return results;
    }

    @Override
    public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context,
            final ComputationTarget target, final ValueRequirement desiredValue) {
        final Set<String> curves = desiredValue.getConstraints().getValues(ValuePropertyNames.CURVE);
        final Set<String> curveCalcConfigs = desiredValue.getConstraints()
                .getValues(ValuePropertyNames.CURVE_CALCULATION_CONFIG);
        if ((curves == null) || (curves.size() != 1)) {
            s_logger.warn("no curve specified");
            // Can't support an unbound request; an injection function must be used (or declare all as optional and use [PLAT-1771])
            return null;
        }
        if ((curveCalcConfigs == null) || (curveCalcConfigs.size() != 1)) {
            s_logger.warn("no curve config specified");
            return null;
        }
        final String curve = curves.iterator().next();
        final String curveCalcConfig = curveCalcConfigs.iterator().next();
        final Set<ValueRequirement> requirements = Sets.newHashSet();
        requirements.add(getCurveRequirement(target, curve, curveCalcConfig));
        requirements.add(getCurveSpecRequirement(target, curve));
        requirements.addAll(
                getSensitivityRequirements(context.getSecuritySource(), (RawSecurity) target.getSecurity()));
        return requirements;
    }

    @Override
    public Set<ValueSpecification> getResults(final FunctionCompilationContext context,
            final ComputationTarget target, final Map<ValueSpecification, ValueRequirement> inputs) {
        String curveName = null;
        String curveCalculationConfig = null;
        final ComputationTargetSpecification targetSpec = target.toSpecification();
        final Set<ValueSpecification> results = Sets.newHashSetWithExpectedSize(2);
        for (final Map.Entry<ValueSpecification, ValueRequirement> input : inputs.entrySet()) {
            if (ValueRequirementNames.YIELD_CURVE.equals(input.getKey().getValueName())) {
                assert curveName == null;
                assert curveCalculationConfig == null;
                curveName = input.getKey().getProperty(ValuePropertyNames.CURVE);
                curveCalculationConfig = input.getKey().getProperty(ValuePropertyNames.CURVE_CALCULATION_CONFIG);
                assert curveName != null;
                assert curveCalculationConfig != null;
                final ValueProperties.Builder properties = createValueProperties(target);
                properties.with(ValuePropertyNames.CURVE, curveName);
                properties.with(ValuePropertyNames.CURVE_CALCULATION_CONFIG, curveCalculationConfig);
                results.add(new ValueSpecification(YCNS_REQUIREMENT, targetSpec, properties.get()));
            }
        }
        s_logger.debug("getResults(2) returning " + results);
        return results;
    }

    @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 requirement : desiredValues) {
            final ValueProperties constraints = requirement.getConstraints();
            final Set<String> values = constraints.getValues(ValuePropertyNames.CURVE);
            if (values != null) {
                curveName = values.iterator().next();
            }
            final Set<String> curveConfigValues = constraints
                    .getValues(ValuePropertyNames.CURVE_CALCULATION_CONFIG);
            if (curveConfigValues != null) {
                curveCalculationConfig = curveConfigValues.iterator().next();
            }
        }
        assert curveName != null;
        assert curveCalculationConfig != null;
        final RawSecurity security = (RawSecurity) target.getSecurity();
        //final BigDecimal qty = target.getPosition().getQuantity();
        final ValueRequirement curveRequirement = getCurveRequirement(target, curveName, curveCalculationConfig);
        final Object curveObject = inputs.getValue(curveRequirement);
        if (curveObject == null) {
            throw new OpenGammaRuntimeException("Could not get " + curveRequirement);
        }
        Object curveSpecObject = null;
        final ValueRequirement curveSpecRequirement = getCurveSpecRequirement(target, curveName);
        curveSpecObject = inputs.getValue(curveSpecRequirement);
        if (curveSpecObject == null) {
            throw new OpenGammaRuntimeException("Could not get " + curveSpecRequirement);
        }
        final YieldAndDiscountCurve curve = (YieldAndDiscountCurve) curveObject;
        final InterpolatedYieldCurveSpecificationWithSecurities curveSpec = (InterpolatedYieldCurveSpecificationWithSecurities) curveSpecObject;
        final LinkedHashMap<String, YieldAndDiscountCurve> interpolatedCurves = new LinkedHashMap<String, YieldAndDiscountCurve>();
        interpolatedCurves.put(curveName, curve);
        final YieldCurveBundle bundle = new YieldCurveBundle(interpolatedCurves);
        final DoubleMatrix1D sensitivitiesForCurves = getSensitivities(executionContext.getSecuritySource(), inputs,
                security, curveSpec, curve);
        final ValueProperties.Builder properties = createValueProperties(target)
                .with(ValuePropertyNames.CURVE, curveName)
                .with(ValuePropertyNames.CURVE_CALCULATION_CONFIG, curveCalculationConfig);
        final ComputationTargetSpecification targetSpec = target.toSpecification();
        final ValueSpecification resultSpec = new ValueSpecification(YCNS_REQUIREMENT, targetSpec,
                properties.get());
        final Set<ComputedValue> results = YieldCurveNodeSensitivitiesHelper
                .getInstrumentLabelledSensitivitiesForCurve(curveName, bundle, sensitivitiesForCurves, curveSpec,
                        resultSpec);
        //s_logger.debug("execute, returning " + results);
        return results;
    }

    private DoubleMatrix1D getSensitivities(final SecuritySource secSource, final FunctionInputs inputs,
            final RawSecurity rawSecurity, final InterpolatedYieldCurveSpecificationWithSecurities curveSpec,
            final YieldAndDiscountCurve curve) {
        final Collection<FactorExposureData> decodedSensitivities = RawSecurityUtils
                .decodeFactorExposureData(secSource, rawSecurity);
        final double[] entries = new double[curveSpec.getStrips().size()];
        int i = 0;
        for (final FixedIncomeStripWithSecurity strip : curveSpec.getStrips()) {
            final FactorExposureData swapExternalSensitivitiesData = searchForSwapTenorMatch(decodedSensitivities,
                    strip);
            if (swapExternalSensitivitiesData != null) {
                final ComputedValue computedValue = inputs.getComputedValue(
                        getSensitivityRequirement(swapExternalSensitivitiesData.getExposureExternalId()));
                if (computedValue != null) {
                    final ManageableHistoricalTimeSeries mhts = (ManageableHistoricalTimeSeries) computedValue
                            .getValue();
                    final Double value = mhts.getTimeSeries().getLatestValue();
                    entries[i] = -value; //* (qty.doubleValue() ); // we invert here because OpenGamma uses -1bp shift rather than +1.  DV01 function will invert back.
                } else {
                    s_logger.warn("Value was null when getting required input data "
                            + swapExternalSensitivitiesData.getExposureExternalId());
                    entries[i] = 0d;
                }
            } else {
                entries[i] = 0d;
            }
            i++;
        }
        // Quick hack to map in bond data.
        i = 0;
        for (final FixedIncomeStripWithSecurity strip : curveSpec.getStrips()) {
            final FactorExposureData bondExternalSensitivitiesData = searchForBondTenorMatch(decodedSensitivities,
                    strip);
            if (bondExternalSensitivitiesData != null) {
                final ComputedValue computedValue = inputs.getComputedValue(
                        getSensitivityRequirement(bondExternalSensitivitiesData.getExposureExternalId()));
                if (computedValue != null) {
                    final ManageableHistoricalTimeSeries mhts = (ManageableHistoricalTimeSeries) computedValue
                            .getValue();
                    final Double value = mhts.getTimeSeries().getLatestValue();
                    entries[i] -= value; //* (qty.doubleValue() ); // we invert here because OpenGamma uses -1bp shift rather than +1.  DV01 function will invert back.
                } else {
                    s_logger.warn("Value was null when getting required input data "
                            + bondExternalSensitivitiesData.getExposureExternalId());
                }
            }
            i++;
        }
        return new DoubleMatrix1D(entries);
    }

    private FactorExposureData searchForSwapTenorMatch(final Collection<FactorExposureData> exposures,
            final FixedIncomeStripWithSecurity strip) {
        for (final FactorExposureData exposure : exposures) {
            if (exposure.getFactorType().equals(FactorType.YIELD) && exposure.getFactorName().contains(SWAP_TEXT)) {
                if (exposure.getNode() != null && exposure.getNode().length() > 0) {
                    final Period nodePeriod = Period.parse("P" + exposure.getNode());
                    if (strip.getTenor().getPeriod().toTotalMonths() == nodePeriod.toTotalMonths()) {
                        return exposure;
                    }
                }
            }
        }
        return null;
    }

    private FactorExposureData searchForBondTenorMatch(final Collection<FactorExposureData> exposures,
            final FixedIncomeStripWithSecurity strip) {
        for (final FactorExposureData exposure : exposures) {
            if (exposure.getFactorType().equals(FactorType.YIELD) && exposure.getFactorName().contains(BOND_TEXT)) {
                if (exposure.getNode() != null && exposure.getNode().length() > 0) {
                    final Period nodePeriod = Period.parse("P" + exposure.getNode());
                    if (strip.getTenor().getPeriod().toTotalMonths() == nodePeriod.toTotalMonths()) {
                        return exposure;
                    }
                }
            }
        }
        return null;
    }

    @Override
    public String getShortName() {
        return "ExternallyProvidedSensitivitiesYieldCurveNodeSensitivitiesFunction";
    }

    protected Set<ValueRequirement> getSensitivityRequirements(final SecuritySource secSource,
            final RawSecurity rawSecurity) {
        final Set<ValueRequirement> requirements = Sets.newHashSet();
        final Collection<FactorExposureData> decodedSensitivities = RawSecurityUtils
                .decodeFactorExposureData(secSource, rawSecurity);
        for (final FactorExposureData exposureEntry : decodedSensitivities) {
            requirements.add(getSensitivityRequirement(exposureEntry.getExposureExternalId()));
        }
        return requirements;
    }

    protected ValueRequirement getSensitivityRequirement(final ExternalId externalId) {
        final HistoricalTimeSeriesResolutionResult resolutionResult = _htsResolver
                .resolve(ExternalIdBundle.of(externalId), null, null, null, "EXPOSURE", null);
        final ValueRequirement htsRequirement = HistoricalTimeSeriesFunctionUtils.createHTSRequirement(
                resolutionResult, "EXPOSURE", DateConstraint.VALUATION_TIME, true, DateConstraint.VALUATION_TIME,
                true);
        return htsRequirement;
        //return new ValueRequirement();
        //return new ValueRequirement(/*ExternalDataRequirementNames.SENSITIVITY*/"EXPOSURE", ComputationTargetType.PRIMITIVE, UniqueId.of(externalId.getScheme().getName(), externalId.getValue()));
    }

    protected ValueRequirement getCurveRequirement(final ComputationTarget target, final String curveName,
            final String curveCalculationConfig) {
        final Currency currency = FinancialSecurityUtils.getCurrency(target.getSecurity());
        final ValueProperties.Builder properties = ValueProperties.with(ValuePropertyNames.CURVE, curveName);
        properties.with(ValuePropertyNames.CURVE_CALCULATION_CONFIG, curveCalculationConfig);
        return new ValueRequirement(ValueRequirementNames.YIELD_CURVE, ComputationTargetSpecification.of(currency),
                properties.get());
    }

    protected ValueRequirement getCurveSpecRequirement(final ComputationTarget target, final String curveName) {
        final Currency currency = FinancialSecurityUtils.getCurrency(target.getSecurity());
        final ValueProperties.Builder properties = ValueProperties.builder().with(ValuePropertyNames.CURVE,
                curveName);
        return new ValueRequirement(ValueRequirementNames.YIELD_CURVE_SPEC,
                ComputationTargetSpecification.of(currency), properties.get());
    }

}