Package com.opengamma.financial.analytics.model.fx

Source Code of com.opengamma.financial.analytics.model.fx.FXForwardPointsFunction

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

import static com.opengamma.engine.value.ValuePropertyNames.CURRENCY;
import static com.opengamma.engine.value.ValuePropertyNames.CURVE;
import static com.opengamma.engine.value.ValuePropertyNames.CURVE_CONSTRUCTION_CONFIG;
import static com.opengamma.engine.value.ValuePropertyNames.CURVE_EXPOSURES;
import static com.opengamma.engine.value.ValuePropertyNames.FORWARD_CURVE_NAME;
import static com.opengamma.engine.value.ValueRequirementNames.CURRENCY_PAIRS;
import static com.opengamma.engine.value.ValueRequirementNames.CURVE_BUNDLE;
import static com.opengamma.engine.value.ValueRequirementNames.CURVE_DEFINITION;
import static com.opengamma.engine.value.ValueRequirementNames.CURVE_MARKET_DATA;
import static com.opengamma.engine.value.ValueRequirementNames.CURVE_SPECIFICATION;
import static com.opengamma.engine.value.ValueRequirementNames.FX_MATRIX;
import static com.opengamma.engine.value.ValueRequirementNames.JACOBIAN_BUNDLE;
import static com.opengamma.financial.analytics.model.CalculationPropertyNamesAndValues.FORWARD_POINTS;
import static com.opengamma.financial.analytics.model.curve.CurveCalculationPropertyNamesAndValues.PROPERTY_CURVE_TYPE;
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.Clock;
import org.threeten.bp.ZonedDateTime;

import com.google.common.collect.Iterables;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.financial.forex.derivative.Forex;
import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.financial.instrument.InstrumentDefinition;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivative;
import com.opengamma.analytics.financial.provider.curve.CurveBuildingBlockBundle;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.ProviderUtils;
import com.opengamma.analytics.math.curve.DoublesCurve;
import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve;
import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory;
import com.opengamma.analytics.math.interpolation.Interpolator1D;
import com.opengamma.analytics.math.interpolation.Interpolator1DFactory;
import com.opengamma.core.config.ConfigSource;
import com.opengamma.core.holiday.HolidaySource;
import com.opengamma.core.marketdatasnapshot.SnapshotDataBundle;
import com.opengamma.core.region.RegionSource;
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.conversion.FXForwardSecurityConverter;
import com.opengamma.financial.analytics.conversion.FixedIncomeConverterDataProvider;
import com.opengamma.financial.analytics.conversion.FutureTradeConverter;
import com.opengamma.financial.analytics.conversion.NonDeliverableFXForwardSecurityConverter;
import com.opengamma.financial.analytics.conversion.TradeConverter;
import com.opengamma.financial.analytics.curve.ConfigDBCurveConstructionConfigurationSource;
import com.opengamma.financial.analytics.curve.CurveConstructionConfiguration;
import com.opengamma.financial.analytics.curve.CurveDefinition;
import com.opengamma.financial.analytics.curve.CurveSpecification;
import com.opengamma.financial.analytics.curve.CurveUtils;
import com.opengamma.financial.analytics.curve.InterpolatedCurveDefinition;
import com.opengamma.financial.analytics.curve.exposure.ConfigDBInstrumentExposuresProvider;
import com.opengamma.financial.analytics.ircurve.strips.CurveNode;
import com.opengamma.financial.analytics.ircurve.strips.CurveNodeWithIdentifier;
import com.opengamma.financial.analytics.ircurve.strips.FXForwardNode;
import com.opengamma.financial.analytics.model.forex.ForexVisitors;
import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesBundle;
import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils;
import com.opengamma.financial.convention.ConventionBundleSource;
import com.opengamma.financial.convention.ConventionSource;
import com.opengamma.financial.currency.CurrencyPair;
import com.opengamma.financial.currency.CurrencyPairs;
import com.opengamma.financial.security.FinancialSecurity;
import com.opengamma.financial.security.FinancialSecurityUtils;
import com.opengamma.financial.security.FinancialSecurityVisitor;
import com.opengamma.financial.security.FinancialSecurityVisitorAdapter;
import com.opengamma.financial.security.fx.FXForwardSecurity;
import com.opengamma.financial.security.fx.NonDeliverableFXForwardSecurity;
import com.opengamma.master.historicaltimeseries.HistoricalTimeSeriesResolver;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.async.AsynchronousExecution;
import com.opengamma.util.money.Currency;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.time.Tenor;

/**
*
*/
public abstract class FXForwardPointsFunction extends AbstractFunction {
  /** The logger */
  private static final Logger s_logger = LoggerFactory.getLogger(FXForwardPointsFunction.class);
  /** The value requirements */
  private final String[] _valueRequirements;

  /**
   * @param valueRequirements The value requirement names, not null
   */
  public FXForwardPointsFunction(final String... valueRequirements) {
    ArgumentChecker.notNull(valueRequirements, "value requirements");
    _valueRequirements = valueRequirements;
  }

  /**
   * Constructs an object capable of converting from {@link ComputationTarget} to {@link InstrumentDefinition}.
   * @param context The compilation context, not null
   * @return The converter
   */
  protected TradeConverter getTargetToDefinitionConverter(final FunctionCompilationContext context) {
    final SecuritySource securitySource = OpenGammaCompilationContext.getSecuritySource(context);
    final HolidaySource holidaySource = OpenGammaCompilationContext.getHolidaySource(context);
    final RegionSource regionSource = OpenGammaCompilationContext.getRegionSource(context);
    final ConventionBundleSource conventionBundleSource = OpenGammaCompilationContext.getConventionBundleSource(context);
    final ConventionSource conventionSource = OpenGammaCompilationContext.getConventionSource(context);
    final FXForwardSecurityConverter fxForwardSecurityConverter = new FXForwardSecurityConverter();
    final NonDeliverableFXForwardSecurityConverter nonDeliverableFXForwardSecurityConverter = new NonDeliverableFXForwardSecurityConverter();
    final FinancialSecurityVisitor<InstrumentDefinition<?>> securityConverter = FinancialSecurityVisitorAdapter.<InstrumentDefinition<?>>builder()
        .fxForwardVisitor(fxForwardSecurityConverter)
        .nonDeliverableFxForwardVisitor(nonDeliverableFXForwardSecurityConverter)
        .create();
    final FutureTradeConverter futureTradeConverter = new FutureTradeConverter(securitySource, holidaySource, conventionSource, conventionBundleSource,
        regionSource);
    return new TradeConverter(futureTradeConverter, securityConverter);
  }

  /**
   * Constructs an object capable of converting from {@link InstrumentDefinition} to {@link InstrumentDerivative}.
   * @param context The compilation context, not null
   * @return The converter
   */
  protected FixedIncomeConverterDataProvider getDefinitionToDerivativeConverter(final FunctionCompilationContext context) {
    final ConventionBundleSource conventionBundleSource = OpenGammaCompilationContext.getConventionBundleSource(context);
    final HistoricalTimeSeriesResolver timeSeriesResolver = OpenGammaCompilationContext.getHistoricalTimeSeriesResolver(context);
    return new FixedIncomeConverterDataProvider(conventionBundleSource, timeSeriesResolver);
  }

  /**
   * Base compiled function for all FX forward points pricing and risk functions.
   */
  public abstract class FXForwardPointsCompiledFunction extends AbstractInvokingCompiledFunction {
    /** Converts targets to definitions */
    private final TradeConverter _tradeToDefinitionConverter;
    /** Converts definitions to derivatives */
    private final FixedIncomeConverterDataProvider _definitionToDerivativeConverter;
    /** Indicates whether the results set {@link ValuePropertyNames#CURRENCY} */
    private final boolean _withCurrency;

    /**
     * @param tradeToDefinitionConverter Converts trades to definitions, not null
     * @param definitionToDerivativeConverter Converts definitions to derivatives, not null
     * @param withCurrency True if this function sets {@link ValuePropertyNames#CURRENCY}
     */
    protected FXForwardPointsCompiledFunction(final TradeConverter tradeToDefinitionConverter,
        final FixedIncomeConverterDataProvider definitionToDerivativeConverter, final boolean withCurrency) {
      ArgumentChecker.notNull(tradeToDefinitionConverter, "target to definition converter");
      ArgumentChecker.notNull(definitionToDerivativeConverter, "definition to derivative converter");
      _tradeToDefinitionConverter = tradeToDefinitionConverter;
      _definitionToDerivativeConverter = definitionToDerivativeConverter;
      _withCurrency = withCurrency;
    }

    @Override
    public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target,
        final Set<ValueRequirement> desiredValues) throws AsynchronousExecution {
      final Clock snapshotClock = executionContext.getValuationClock();
      final ZonedDateTime now = ZonedDateTime.now(snapshotClock);
      final HistoricalTimeSeriesBundle timeSeries = HistoricalTimeSeriesFunctionUtils.getHistoricalTimeSeriesInputs(executionContext, inputs);
      final InstrumentDefinition<?> definition = getDefinitionFromTarget(target);
      final Forex forex = getForex(target, now, timeSeries, definition);
      final FXMatrix fxMatrix = new FXMatrix();
      final CurrencyPairs pairs = (CurrencyPairs) inputs.getValue(CURRENCY_PAIRS);
      final Currency currency1 = forex.getCurrency1();
      final Currency currency2 = forex.getCurrency2();
      if (pairs.getCurrencyPair(currency1, currency2).getBase().equals(currency1)) {
        final double spotRate = (Double) inputs.getValue(new ValueRequirement(ValueRequirementNames.SPOT_RATE,
            CurrencyPair.TYPE.specification(CurrencyPair.of(currency2, currency1))));
        fxMatrix.addCurrency(currency1, currency2, spotRate);
      } else {
        final double spotRate = (Double) inputs.getValue(new ValueRequirement(ValueRequirementNames.SPOT_RATE,
            CurrencyPair.TYPE.specification(CurrencyPair.of(currency2, currency1))));
        fxMatrix.addCurrency(currency2, currency1, 1 / spotRate);
      }
      return getValues(inputs, target, desiredValues, forex, fxMatrix, now);
    }

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

    @Override
    public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) {
      final Security security = target.getTrade().getSecurity();
      return security instanceof FXForwardSecurity ||
          security instanceof NonDeliverableFXForwardSecurity;
    }

    @Override
    public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) {
      final ValueProperties properties = getResultProperties(target).get();
      final Set<ValueSpecification> results = new HashSet<>();
      for (final String valueRequirement : _valueRequirements) {
        results.add(new ValueSpecification(valueRequirement, target.toSpecification(), properties));
      }
      return results;
    }

    @Override
    public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) {
      final ValueProperties constraints = desiredValue.getConstraints();
      final Set<String> curveExposureConfigs = constraints.getValues(CURVE_EXPOSURES);
      if (curveExposureConfigs == null) {
        return null;
      }
      final Set<String> fxForwardCurveNames = constraints.getValues(FORWARD_CURVE_NAME);
      if (fxForwardCurveNames == null || fxForwardCurveNames.size() != 1) {
        return null;
      }
      try {
        final FinancialSecurity security = (FinancialSecurity) target.getTrade().getSecurity();
        final ConfigSource configSource = OpenGammaCompilationContext.getConfigSource(context);
        final SecuritySource securitySource = OpenGammaCompilationContext.getSecuritySource(context);
        final ConfigDBInstrumentExposuresProvider exposureSource = new ConfigDBInstrumentExposuresProvider(configSource, securitySource);
        final ConfigDBCurveConstructionConfigurationSource constructionConfigurationSource = new ConfigDBCurveConstructionConfigurationSource(configSource);
        final Set<ValueRequirement> requirements = new HashSet<>();
        for (final String curveExposureConfig : curveExposureConfigs) {
          final Set<String> curveConstructionConfigurationNames = exposureSource.getCurveConstructionConfigurationsForConfig(curveExposureConfig, security);
          for (final String curveConstructionConfigurationName : curveConstructionConfigurationNames) {
            final ValueProperties properties = ValueProperties.with(CURVE_CONSTRUCTION_CONFIG, curveConstructionConfigurationName).get();
            requirements.add(new ValueRequirement(CURVE_BUNDLE, ComputationTargetSpecification.NULL, properties));
            requirements.add(new ValueRequirement(JACOBIAN_BUNDLE, ComputationTargetSpecification.NULL, properties));
            final CurveConstructionConfiguration curveConstructionConfiguration = constructionConfigurationSource.getCurveConstructionConfiguration(curveConstructionConfigurationName);
            final String[] curveNames = CurveUtils.getCurveNamesForConstructionConfiguration(curveConstructionConfiguration);
            for (final String curveName : curveNames) {
              final ValueProperties curveProperties = ValueProperties.builder()
                  .with(CURVE, curveName)
                  .get();
              requirements.add(new ValueRequirement(CURVE_DEFINITION, ComputationTargetSpecification.NULL, curveProperties));
              requirements.add(new ValueRequirement(FX_MATRIX, ComputationTargetSpecification.NULL, properties));
            }
          }
        }
        final Collection<Currency> currencies = FinancialSecurityUtils.getCurrencies(security, securitySource);
        if (currencies.size() > 1) {
          final Iterator<Currency> iter = currencies.iterator();
          final Currency initialCurrency = iter.next();
          while (iter.hasNext()) {
            requirements.add(new ValueRequirement(ValueRequirementNames.SPOT_RATE, CurrencyPair.TYPE.specification(CurrencyPair.of(iter.next(), initialCurrency))));
          }
        }
        final InstrumentDefinition<?> definition = getDefinitionFromTarget(target);
        final Set<ValueRequirement> timeSeriesRequirements = getConversionTimeSeriesRequirements(context, target, definition);
        if (timeSeriesRequirements == null) {
          return null;
        }
        requirements.addAll(timeSeriesRequirements);
        final String fxForwardCurveName = Iterables.getOnlyElement(fxForwardCurveNames);
        final ValueProperties fxForwardCurveProperties = ValueProperties.builder().with(CURVE, fxForwardCurveName).get();
        final ValueRequirement fxForwardCurveDefinition = new ValueRequirement(CURVE_DEFINITION, ComputationTargetSpecification.NULL,
            fxForwardCurveProperties);
        final ValueRequirement fxForwardCurveSpecification = new ValueRequirement(CURVE_SPECIFICATION, ComputationTargetSpecification.NULL,
            fxForwardCurveProperties);
        final ValueRequirement fxForwardCurveDataRequirement = new ValueRequirement(CURVE_MARKET_DATA, ComputationTargetSpecification.NULL,
            fxForwardCurveProperties);
        final ValueRequirement currencyPairsRequirement = new ValueRequirement(CURRENCY_PAIRS, ComputationTargetSpecification.NULL, ValueProperties.none());
        requirements.add(fxForwardCurveDataRequirement);
        requirements.add(fxForwardCurveDefinition);
        requirements.add(fxForwardCurveSpecification);
        requirements.add(currencyPairsRequirement);
        return requirements;
      } catch (final Exception e) {
        s_logger.error(e.getMessage());
        return null;
      }
    }

    protected ValueProperties.Builder getResultProperties(final ComputationTarget target) {
      final ValueProperties.Builder properties = createValueProperties()
          .withAny(CURVE_EXPOSURES)
          .withAny(FORWARD_CURVE_NAME)
          .with(PROPERTY_CURVE_TYPE, FORWARD_POINTS);
      if (_withCurrency) {
        properties.with(CURRENCY, ((FinancialSecurity) target.getTrade().getSecurity()).accept(ForexVisitors.getReceiveCurrencyVisitor()).getCode());
      }
      return properties;
    }

    /**
     * Gets an {@link InstrumentDefinition} given a target.
     * @param target The target, not null
     * @return An instrument definition
     */
    protected InstrumentDefinition<?> getDefinitionFromTarget(final ComputationTarget target) {
      return _tradeToDefinitionConverter.convert(target.getTrade());
    }

    /**
     * Gets a conversion time-series for an instrument definition. If no time-series are required,
     * returns an empty set.
     * @param context The compilation context, not null
     * @param target The target, not null
     * @param definition The definition, not null
     * @return A set of time-series requirements
     */
    protected Set<ValueRequirement> getConversionTimeSeriesRequirements(final FunctionCompilationContext context, final ComputationTarget target,
        final InstrumentDefinition<?> definition) {
      return _definitionToDerivativeConverter.getConversionTimeSeriesRequirements(target.getTrade().getSecurity(), definition);
    }

    /**
     * Gets an {@link InstrumentDerivative}.
     * @param target The target, not null
     * @param now The valuation time, not null
     * @param timeSeries The conversion time series bundle, not null but may be empty
     * @param definition The definition, not null
     * @return The instrument derivative
     */
    protected Forex getForex(final ComputationTarget target, final ZonedDateTime now, final HistoricalTimeSeriesBundle timeSeries,
        final InstrumentDefinition<?> definition) {
      return (Forex) _definitionToDerivativeConverter.convert(target.getTrade().getSecurity(), definition, now, timeSeries);
    }

    /**
     * Calculates the result.
     * @param inputs The inputs, not null
     * @param target The target, not null
     * @param desiredValues The desired values for this function, not null
     * @param forex The forex trade, not null
     * @param fxMatrix The FX matrix, not null
     * @param now The valuation time, not null
     * @return The results
     */
    protected abstract Set<ComputedValue> getValues(FunctionInputs inputs, ComputationTarget target, Set<ValueRequirement> desiredValues,
        Forex forex, FXMatrix fxMatrix, ZonedDateTime now);

    protected MulticurveProviderDiscount getMergedProviders(final FunctionInputs inputs, final FXMatrix matrix) {
      final Collection<MulticurveProviderDiscount> providers = new HashSet<>();
      for (final ComputedValue input : inputs.getAllValues()) {
        final String valueName = input.getSpecification().getValueName();
        if (CURVE_BUNDLE.equals(valueName)) {
          providers.add((MulticurveProviderDiscount) input.getValue());
        }
      }
      final MulticurveProviderDiscount result = ProviderUtils.mergeDiscountingProviders(providers);
      return ProviderUtils.mergeDiscountingProviders(result, matrix);
    }

    protected CurveBuildingBlockBundle getMergedCurveBuildingBlocks(final FunctionInputs inputs) {
      final CurveBuildingBlockBundle result = new CurveBuildingBlockBundle();
      for (final ComputedValue input : inputs.getAllValues()) {
        final String valueName = input.getSpecification().getValueName();
        if (valueName.equals(JACOBIAN_BUNDLE)) {
          result.addAll((CurveBuildingBlockBundle) input.getValue());
        }
      }
      return result;
    }

    protected DoublesCurve getForwardPoints(final FunctionInputs inputs, final String fxForwardCurveName,
        final ZonedDateTime now) {
      final ValueProperties curveProperties = ValueProperties.with(CURVE, fxForwardCurveName).get();
      final ValueRequirement definitionRequirement = new ValueRequirement(CURVE_DEFINITION, ComputationTargetSpecification.NULL, curveProperties);
      final CurveDefinition definition = (CurveDefinition) inputs.getValue(definitionRequirement);
      if (definition == null) {
        throw new OpenGammaRuntimeException("Could not get definition for " + fxForwardCurveName);
      }
      final String interpolatorName, leftExtrapolatorName, rightExtrapolatorName;
      if (definition instanceof InterpolatedCurveDefinition) {
        final InterpolatedCurveDefinition interpolatedDefinition = (InterpolatedCurveDefinition) definition;
        interpolatorName = interpolatedDefinition.getInterpolatorName();
        if (interpolatedDefinition.getLeftExtrapolatorName() != null) {
          leftExtrapolatorName = interpolatedDefinition.getLeftExtrapolatorName();
          rightExtrapolatorName = interpolatedDefinition.getRightExtrapolatorName();
        } else {
          leftExtrapolatorName = Interpolator1DFactory.LINEAR_EXTRAPOLATOR;
          rightExtrapolatorName = Interpolator1DFactory.LINEAR_EXTRAPOLATOR;
        }
      } else {
        interpolatorName = Interpolator1DFactory.LINEAR;
        leftExtrapolatorName = Interpolator1DFactory.LINEAR_EXTRAPOLATOR;
        rightExtrapolatorName = Interpolator1DFactory.LINEAR_EXTRAPOLATOR;
      }
      final CurveSpecification specification = (CurveSpecification) inputs.getValue(CURVE_SPECIFICATION);
      final SnapshotDataBundle data = (SnapshotDataBundle) inputs.getValue(CURVE_MARKET_DATA);
      final DoubleArrayList tList = new DoubleArrayList();
      final DoubleArrayList fxList = new DoubleArrayList();
      for (final CurveNodeWithIdentifier nodeWithId : specification.getNodes()) {
        final CurveNode node = nodeWithId.getCurveNode();
        if (!(node instanceof FXForwardNode)) {
          throw new OpenGammaRuntimeException("Unexpected node " + nodeWithId + " found");
        }
        final Double fxForward = data.getDataPoint(nodeWithId.getIdentifier());
        if (fxForward == null) {
          throw new OpenGammaRuntimeException("Could not get FX forward rate for " + node);
        }
        final Tenor tenor = node.getResolvedMaturity();
        tList.add(DateUtils.getDifferenceInYears(now, now.plus(tenor.getPeriod())));
        fxList.add(fxForward);
      }
      final Interpolator1D interpolator = CombinedInterpolatorExtrapolatorFactory.getInterpolator(interpolatorName,
          leftExtrapolatorName, rightExtrapolatorName);
      return InterpolatedDoublesCurve.from(tList.toDoubleArray(), fxList.toDoubleArray(), interpolator);
    }
  }
}
TOP

Related Classes of com.opengamma.financial.analytics.model.fx.FXForwardPointsFunction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.