/** * 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_EXPOSURES; import static com.opengamma.engine.value.ValuePropertyNames.FORWARD_CURVE_NAME; import static com.opengamma.engine.value.ValuePropertyNames.PROPERTY_PNL_CONTRIBUTIONS; import static com.opengamma.engine.value.ValuePropertyNames.SAMPLING_FUNCTION; import static com.opengamma.engine.value.ValuePropertyNames.SCHEDULE_CALCULATOR; import static com.opengamma.engine.value.ValuePropertyNames.TRANSFORMATION_METHOD; import static com.opengamma.engine.value.ValueRequirementNames.CURRENCY_PAIRS; import static com.opengamma.engine.value.ValueRequirementNames.FX_CURRENCY_EXPOSURE; import static com.opengamma.engine.value.ValueRequirementNames.PNL_SERIES; import static com.opengamma.engine.value.ValueRequirementNames.RETURN_SERIES; import static com.opengamma.financial.analytics.model.CalculationPropertyNamesAndValues.FORWARD_POINTS; import static com.opengamma.financial.analytics.model.curve.CurveCalculationPropertyNamesAndValues.PROPERTY_CURVE_TYPE; import static com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils.END_DATE_PROPERTY; import static com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils.INCLUDE_END_PROPERTY; import static com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils.INCLUDE_START_PROPERTY; import static com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils.START_DATE_PROPERTY; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import com.google.common.collect.Iterables; import com.opengamma.core.position.Position; import com.opengamma.core.position.Trade; import com.opengamma.core.security.Security; 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.ValueRequirement; import com.opengamma.engine.value.ValueRequirementNames; import com.opengamma.engine.value.ValueSpecification; import com.opengamma.financial.OpenGammaCompilationContext; import com.opengamma.financial.analytics.model.forex.ForexVisitors; import com.opengamma.financial.currency.CurrencyPair; import com.opengamma.financial.currency.CurrencyPairs; import com.opengamma.financial.security.FinancialSecurity; import com.opengamma.financial.security.fx.FXForwardSecurity; import com.opengamma.financial.security.fx.NonDeliverableFXForwardSecurity; import com.opengamma.timeseries.date.localdate.LocalDateDoubleTimeSeries; import com.opengamma.util.async.AsynchronousExecution; import com.opengamma.util.money.Currency; import com.opengamma.util.money.MultipleCurrencyAmount; import com.opengamma.util.money.UnorderedCurrencyPair; /** * */ public class FXForwardPointsCurrencyExposurePnLFunction extends AbstractFunction.NonCompiledInvoker { @Override public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) throws AsynchronousExecution { final Position position = target.getPosition(); final ValueRequirement desiredValue = Iterables.getOnlyElement(desiredValues); final FXForwardSecurity security = (FXForwardSecurity) position.getSecurity(); final MultipleCurrencyAmount mca = (MultipleCurrencyAmount) inputs.getValue(FX_CURRENCY_EXPOSURE); final Currency payCurrency = security.getPayCurrency(); final Currency receiveCurrency = security.getReceiveCurrency(); final CurrencyPairs currencyPairs = (CurrencyPairs) inputs.getValue(CURRENCY_PAIRS); final CurrencyPair currencyPair = currencyPairs.getCurrencyPair(payCurrency, receiveCurrency); final Currency currencyNonBase = currencyPair.getCounter(); // The non-base currency final double exposure = mca.getAmount(currencyNonBase); final LocalDateDoubleTimeSeries fxSpotReturnSeries = (LocalDateDoubleTimeSeries) inputs.getValue(RETURN_SERIES); final LocalDateDoubleTimeSeries pnlSeries = fxSpotReturnSeries.multiply(position.getQuantity().doubleValue() * exposure); // The P/L time series is in the base currency final ValueSpecification spec = new ValueSpecification(ValueRequirementNames.PNL_SERIES, target.toSpecification(), desiredValue.getConstraints()); return Collections.singleton(new ComputedValue(spec, pnlSeries)); } @Override public ComputationTargetType getTargetType() { return ComputationTargetType.POSITION; } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { final Security security = target.getPosition().getSecurity(); return security instanceof FXForwardSecurity || security instanceof NonDeliverableFXForwardSecurity; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { final ValueProperties properties = createValueProperties() .withAny(START_DATE_PROPERTY) .withAny(END_DATE_PROPERTY) .withAny(INCLUDE_START_PROPERTY) .withAny(INCLUDE_END_PROPERTY) .withAny(TRANSFORMATION_METHOD) .withAny(SCHEDULE_CALCULATOR) .withAny(SAMPLING_FUNCTION) .withAny(CURVE_EXPOSURES) .withAny(FORWARD_CURVE_NAME) .with(PROPERTY_CURVE_TYPE, FORWARD_POINTS) .with(PROPERTY_PNL_CONTRIBUTIONS, FX_CURRENCY_EXPOSURE) .withAny(CURRENCY) .get(); return Collections.singleton(new ValueSpecification(PNL_SERIES, target.toSpecification(), properties)); } @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 || curveExposureConfigs.size() != 1) { return null; } final Set<String> fxForwardCurveNames = constraints.getValues(FORWARD_CURVE_NAME); if (fxForwardCurveNames == null || fxForwardCurveNames.size() != 1) { return null; } final Set<String> includeStarts = constraints.getValues(INCLUDE_START_PROPERTY); if (includeStarts != null && includeStarts.size() != 1) { return null; } final Set<String> includeEnds = constraints.getValues(INCLUDE_END_PROPERTY); if (includeEnds != null && includeEnds.size() != 1) { return null; } final Set<String> startDates = constraints.getValues(START_DATE_PROPERTY); if (startDates != null && startDates.size() != 1) { return null; } final Set<String> endDates = constraints.getValues(END_DATE_PROPERTY); if (endDates != null && endDates.size() != 1) { return null; } final Set<String> samplingFunctions = constraints.getValues(SAMPLING_FUNCTION); if (samplingFunctions == null || samplingFunctions.size() != 1) { return null; } final Set<String> scheduleMethods = constraints.getValues(SCHEDULE_CALCULATOR); if (scheduleMethods == null || scheduleMethods.size() != 1) { return null; } final Set<String> transformationMethods = constraints.getValues(TRANSFORMATION_METHOD); if (transformationMethods == null || transformationMethods.size() != 1) { return null; } final String curveExposureConfig = Iterables.getOnlyElement(curveExposureConfigs); final String fxForwardCurveName = Iterables.getOnlyElement(fxForwardCurveNames); final ValueProperties properties = ValueProperties.builder() .with(CURVE_EXPOSURES, curveExposureConfig) .with(FORWARD_CURVE_NAME, fxForwardCurveName) .with(PROPERTY_CURVE_TYPE, FORWARD_POINTS) .get(); final FinancialSecurity security = (FinancialSecurity) target.getPosition().getSecurity(); final Currency payCurrency = security.accept(ForexVisitors.getPayCurrencyVisitor()); final Currency receiveCurrency = security.accept(ForexVisitors.getReceiveCurrencyVisitor()); final ComputationTargetSpecification fxSpotReturnSeriesSpec = ComputationTargetType.UNORDERED_CURRENCY_PAIR.specification(UnorderedCurrencyPair.of(payCurrency, receiveCurrency)); final Set<ValueRequirement> requirements = new HashSet<>(); final ValueProperties returnSeriesProperties = ValueProperties.builder() .with(SCHEDULE_CALCULATOR, scheduleMethods) .with(SAMPLING_FUNCTION, samplingFunctions) .with(INCLUDE_START_PROPERTY, includeStarts) .with(INCLUDE_END_PROPERTY, includeEnds) .with(START_DATE_PROPERTY, startDates) .with(END_DATE_PROPERTY, endDates) .with(TRANSFORMATION_METHOD, transformationMethods) .get(); requirements.add(new ValueRequirement(RETURN_SERIES, fxSpotReturnSeriesSpec, returnSeriesProperties)); final Trade trade = Iterables.getOnlyElement(target.getPosition().getTrades()); requirements.add(new ValueRequirement(FX_CURRENCY_EXPOSURE, ComputationTargetSpecification.of(trade), properties)); requirements.add(new ValueRequirement(CURRENCY_PAIRS, ComputationTargetSpecification.NULL, ValueProperties.none())); return requirements; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target, final Map<ValueSpecification, ValueRequirement> inputs) { String includeStart = null; String includeEnd = null; String startDate = null; String endDate = null; String transformationMethod = null; String scheduleCalculator = null; String samplingFunction = null; String curveExposures = null; String forwardCurveName = null; for (final Map.Entry<ValueSpecification, ValueRequirement> entry : inputs.entrySet()) { final String valueName = entry.getValue().getValueName(); final ValueRequirement requirement = entry.getValue(); if (valueName.equals(RETURN_SERIES)) { includeStart = requirement.getConstraint(INCLUDE_START_PROPERTY); includeEnd = requirement.getConstraint(INCLUDE_END_PROPERTY); startDate = requirement.getConstraint(START_DATE_PROPERTY); endDate = requirement.getConstraint(END_DATE_PROPERTY); transformationMethod = requirement.getConstraint(TRANSFORMATION_METHOD); scheduleCalculator = requirement.getConstraint(SCHEDULE_CALCULATOR); samplingFunction = requirement.getConstraint(SAMPLING_FUNCTION); } else if (valueName.equals(FX_CURRENCY_EXPOSURE)) { curveExposures = requirement.getConstraint(CURVE_EXPOSURES); forwardCurveName = requirement.getConstraint(FORWARD_CURVE_NAME); } } if (includeStart == null || curveExposures == null) { return null; } //TODO how should this be done? final CurrencyPairs pairs = OpenGammaCompilationContext.getCurrencyPairsSource(context).getCurrencyPairs(CurrencyPairs.DEFAULT_CURRENCY_PAIRS); final FinancialSecurity security = (FinancialSecurity) target.getPosition().getSecurity(); final Currency payCurrency = security.accept(ForexVisitors.getPayCurrencyVisitor()); final Currency receiveCurrency = security.accept(ForexVisitors.getReceiveCurrencyVisitor()); final CurrencyPair currencyPair = pairs.getCurrencyPair(payCurrency, receiveCurrency); final Currency currencyBase = currencyPair.getBase(); final ValueProperties properties = createValueProperties() .with(INCLUDE_START_PROPERTY, includeStart) .with(INCLUDE_END_PROPERTY, includeEnd) .with(START_DATE_PROPERTY, startDate) .with(END_DATE_PROPERTY, endDate) .with(TRANSFORMATION_METHOD, transformationMethod) .with(SCHEDULE_CALCULATOR, scheduleCalculator) .with(SAMPLING_FUNCTION, samplingFunction) .with(CURVE_EXPOSURES, curveExposures) .with(FORWARD_CURVE_NAME, forwardCurveName) .with(PROPERTY_CURVE_TYPE, FORWARD_POINTS) .with(PROPERTY_PNL_CONTRIBUTIONS, FX_CURRENCY_EXPOSURE) .with(CURRENCY, currencyBase.getCode()) .get(); return Collections.singleton(new ValueSpecification(PNL_SERIES, target.toSpecification(), properties)); } }