/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.analytics.model.forex.forward; import java.util.Map; import java.util.Set; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.core.security.Security; 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.ValuePropertyNames; import com.opengamma.engine.value.ValueRequirement; import com.opengamma.engine.value.ValueRequirementNames; import com.opengamma.engine.value.ValueSpecification; import com.opengamma.financial.analytics.CurrencyLabelledMatrix1D; import com.opengamma.financial.analytics.model.CalculationPropertyNamesAndValues; import com.opengamma.financial.analytics.model.forex.ForexVisitors; import com.opengamma.financial.currency.CurrencyMatrixSpotSourcingFunction; import com.opengamma.financial.security.FinancialSecurity; import com.opengamma.financial.security.FinancialSecurityTypes; import com.opengamma.financial.security.swap.SwapSecurity; import com.opengamma.util.async.AsynchronousExecution; import com.opengamma.util.money.Currency; /** * Calculates Present Value on FX Forward instruments. * * @deprecated Deprecated */ @Deprecated public class FXForwardPresentValueFunction extends AbstractFunction.NonCompiledInvoker { private static final ComputationTargetType TYPE = FinancialSecurityTypes.FX_FORWARD_SECURITY.or(FinancialSecurityTypes.NON_DELIVERABLE_FX_FORWARD_SECURITY).or(FinancialSecurityTypes.SWAP_SECURITY); @Override public ComputationTargetType getTargetType() { return TYPE; } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { final Security sec = target.getSecurity(); if (sec instanceof SwapSecurity) { // Can only apply to cross currency swaps final FinancialSecurity security = (FinancialSecurity) target.getSecurity(); try { final Currency payCurrency = getPayCurrency(security); if (payCurrency == null) { return false; } final Currency receiveCurrency = getReceiveCurrency(security); if (receiveCurrency == null) { return false; } if (payCurrency.equals(receiveCurrency)) { return false; } } catch (final UnsupportedOperationException e) { return false; } } return true; } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { return ImmutableSet.of(new ValueSpecification(ValueRequirementNames.PRESENT_VALUE, 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> calculationMethod = constraints.getValues(ValuePropertyNames.CALCULATION_METHOD); if (calculationMethod != null && calculationMethod.size() == 1) { if (!CalculationPropertyNamesAndValues.DISCOUNTING.equals(Iterables.getOnlyElement(calculationMethod))) { return null; } } final ValueRequirement fxPvRequirement = new ValueRequirement(ValueRequirementNames.FX_PRESENT_VALUE, target.toSpecification(), constraints.copy().withoutAny(ValuePropertyNames.CURRENCY).get()); final FinancialSecurity security = (FinancialSecurity) target.getSecurity(); final Currency payCurrency = getPayCurrency(security); final Currency receiveCurrency = getReceiveCurrency(security); final ValueRequirement spotRateRequirement = CurrencyMatrixSpotSourcingFunction.getConversionRequirement(payCurrency, receiveCurrency); return ImmutableSet.of(fxPvRequirement, spotRateRequirement); } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target, final Map<ValueSpecification, ValueRequirement> inputs) { ValueProperties properties = null; for (final Map.Entry<ValueSpecification, ValueRequirement> entry : inputs.entrySet()) { if (entry.getKey().getValueName().equals(ValueRequirementNames.FX_PRESENT_VALUE)) { properties = entry.getKey().getProperties(); break; } } if (properties == null) { return null; } final Currency currency = getPayCurrency((FinancialSecurity) target.getSecurity()); return ImmutableSet.of(new ValueSpecification(ValueRequirementNames.PRESENT_VALUE, target.toSpecification(), getResultProperties(currency, properties.copy()))); } @Override public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) throws AsynchronousExecution { final FinancialSecurity security = (FinancialSecurity) target.getSecurity(); final Currency payCurrency = getPayCurrency(security); final Currency receiveCurrency = getReceiveCurrency(security); final ComputedValue input = inputs.getComputedValue(ValueRequirementNames.FX_PRESENT_VALUE); final ValueSpecification inputSpec = input.getSpecification(); final CurrencyLabelledMatrix1D fxPresentValue = (CurrencyLabelledMatrix1D) input.getValue(); if (fxPresentValue.size() != 2) { throw new OpenGammaRuntimeException("Expected " + ValueRequirementNames.FX_PRESENT_VALUE + " input to contain 2 currency values, but found " + fxPresentValue.size()); } int payIndex = -1; int receiveIndex = -1; for (int i = 0; i < 2; i++) { final Currency currency = fxPresentValue.getKeys()[i]; if (payCurrency.equals(currency)) { payIndex = i; } else if (receiveCurrency.equals(currency)) { receiveIndex = i; } else { throw new OpenGammaRuntimeException(ValueRequirementNames.FX_PRESENT_VALUE + " contains unexpected currency " + currency + ". Expected " + payCurrency + " or " + receiveCurrency + "."); } } final double payValue = fxPresentValue.getValues()[payIndex]; final double receiveValue = fxPresentValue.getValues()[receiveIndex]; final double spot = (Double) inputs.getValue(ValueRequirementNames.SPOT_RATE); final double pv = payValue + spot * receiveValue; return ImmutableSet.of(new ComputedValue(getResultSpec(target, inputSpec.getProperties().copy()), pv)); } /** * @param target The target * @param fxPresentValueProperties The properties of the FX present value input * @return The result specification */ protected ValueSpecification getResultSpec(final ComputationTarget target, final ValueProperties.Builder fxPresentValueProperties) { final Currency currency = getPayCurrency((FinancialSecurity) target.getSecurity()); return new ValueSpecification(ValueRequirementNames.PRESENT_VALUE, target.toSpecification(), getResultProperties(currency, fxPresentValueProperties)); } /** * @param currency The currency of the result * @param fxPresentValueProperties The properties of the FX present value input * @return The result properties */ protected ValueProperties getResultProperties(final Currency currency, final ValueProperties.Builder fxPresentValueProperties) { return fxPresentValueProperties.withoutAny(ValuePropertyNames.FUNCTION) .with(ValuePropertyNames.FUNCTION, getUniqueId()) .with(ValuePropertyNames.CURRENCY, currency.getCode()) .get(); } /** * Gets the pay currency of the security. * * @param security The security * @return The pay currency */ protected Currency getPayCurrency(final FinancialSecurity security) { return security.accept(ForexVisitors.getPayCurrencyVisitor()); } /** * Gets the receive currency of the security. * * @param security The security * @return The receive currency */ protected Currency getReceiveCurrency(final FinancialSecurity security) { return security.accept(ForexVisitors.getReceiveCurrencyVisitor()); } }