/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.model.forex.option.black;
import static com.opengamma.financial.analytics.model.forex.option.black.FXOptionBlackFunction.CALL_CURVE;
import static com.opengamma.financial.analytics.model.forex.option.black.FXOptionBlackFunction.CALL_CURVE_CALC_CONFIG;
import static com.opengamma.financial.analytics.model.forex.option.black.FXOptionBlackFunction.PUT_CURVE;
import static com.opengamma.financial.analytics.model.forex.option.black.FXOptionBlackFunction.PUT_CURVE_CALC_CONFIG;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.financial.interestrate.YieldCurveBundle;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.model.option.definition.ForexOptionDataBundle;
import com.opengamma.analytics.financial.model.option.definition.SmileDeltaTermStructureDataBundle;
import com.opengamma.analytics.financial.model.option.definition.YieldCurveWithBlackForexTermStructureBundle;
import com.opengamma.analytics.financial.model.volatility.curve.BlackForexTermStructureParameters;
import com.opengamma.analytics.financial.model.volatility.surface.SmileDeltaTermStructureParametersStrikeInterpolation;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.function.FunctionInputs;
import com.opengamma.engine.target.ComputationTargetType;
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.financial.analytics.model.InstrumentTypeProperties;
import com.opengamma.financial.analytics.model.InterpolatedDataProperties;
import com.opengamma.financial.analytics.model.YieldCurveFunctionUtils;
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.option.FXDigitalOptionSecurity;
import com.opengamma.financial.security.option.NonDeliverableFXDigitalOptionSecurity;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.UnorderedCurrencyPair;
import com.opengamma.util.tuple.Pair;
/**
* Contains utility methods for pricing FX options.
*/
public class FXOptionFunctionUtils {
/**
* Builds the market data bundle for FX options.
* @param now The valuation time
* @param inputs The function inputs
* @param target The computation target
* @param desiredValues The desired values
* @return The FX option market data bundle
* @deprecated The data bundle is deprecated
*/
@Deprecated
public static ForexOptionDataBundle<?> buildMarketBundle(final ZonedDateTime now, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) {
final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor());
final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor());
if (now.isAfter(security.accept(ForexVisitors.getExpiryVisitor()))) {
throw new OpenGammaRuntimeException("FX option " + putCurrency.getCode() + "/" + callCurrency + " has expired");
}
final ValueRequirement desiredValue = desiredValues.iterator().next();
final String putCurveName = desiredValue.getConstraint(PUT_CURVE);
final String callCurveName = desiredValue.getConstraint(CALL_CURVE);
final String putCurveConfig = desiredValue.getConstraint(PUT_CURVE_CALC_CONFIG);
final String callCurveConfig = desiredValue.getConstraint(CALL_CURVE_CALC_CONFIG);
final Object baseQuotePairsObject = inputs.getValue(ValueRequirementNames.CURRENCY_PAIRS);
if (baseQuotePairsObject == null) {
throw new OpenGammaRuntimeException("Could not get base/quote pair data");
}
final CurrencyPairs baseQuotePairs = (CurrencyPairs) baseQuotePairsObject;
final String fullPutCurveName = putCurveName + "_" + putCurrency.getCode();
final String fullCallCurveName = callCurveName + "_" + callCurrency.getCode();
final YieldAndDiscountCurve putFundingCurve = getCurveForCurrency(inputs, putCurrency, putCurveName, putCurveConfig);
final YieldAndDiscountCurve callFundingCurve = getCurveForCurrency(inputs, callCurrency, callCurveName, callCurveConfig);
final YieldAndDiscountCurve[] curves;
final Map<String, Currency> curveCurrency = new HashMap<>();
curveCurrency.put(fullPutCurveName, putCurrency);
curveCurrency.put(fullCallCurveName, callCurrency);
final String[] allCurveNames;
final Currency ccy1;
final Currency ccy2;
final Object spotObject = inputs.getValue(ValueRequirementNames.SPOT_RATE);
if (spotObject == null) {
throw new OpenGammaRuntimeException("Could not get spot requirement");
}
double spot = (Double) spotObject;
final CurrencyPair baseQuotePair = baseQuotePairs.getCurrencyPair(putCurrency, callCurrency);
if (baseQuotePair == null) {
throw new OpenGammaRuntimeException("Could not get base/quote pair for currency pair (" + putCurrency + ", " + callCurrency + ")");
}
if (baseQuotePair.getBase().equals(putCurrency)) { // To get Base/quote in market standard order.
ccy1 = putCurrency;
ccy2 = callCurrency;
curves = new YieldAndDiscountCurve[] {putFundingCurve, callFundingCurve};
allCurveNames = new String[] {fullPutCurveName, fullCallCurveName};
} else {
curves = new YieldAndDiscountCurve[] {callFundingCurve, putFundingCurve};
allCurveNames = new String[] {fullCallCurveName, fullPutCurveName};
ccy1 = callCurrency;
ccy2 = putCurrency;
spot = 1. / spot;
}
final YieldCurveBundle yieldCurves = new YieldCurveBundle(allCurveNames, curves);
final Object volatilitySurfaceObject = inputs.getValue(ValueRequirementNames.STANDARD_VOLATILITY_SURFACE_DATA);
if (volatilitySurfaceObject == null) {
throw new OpenGammaRuntimeException("Could not get volatility surface data");
}
final FXMatrix fxMatrix = new FXMatrix(ccy1, ccy2, spot);
final YieldCurveBundle curvesWithFX = new YieldCurveBundle(fxMatrix, curveCurrency, yieldCurves.getCurvesMap());
final Pair<Currency, Currency> currencyPair = Pair.of(ccy1, ccy2);
if (volatilitySurfaceObject instanceof SmileDeltaTermStructureParametersStrikeInterpolation) {
final SmileDeltaTermStructureParametersStrikeInterpolation smiles = (SmileDeltaTermStructureParametersStrikeInterpolation) volatilitySurfaceObject;
final SmileDeltaTermStructureDataBundle smileBundle = new SmileDeltaTermStructureDataBundle(curvesWithFX, smiles, currencyPair);
return smileBundle;
}
final BlackForexTermStructureParameters termStructure = (BlackForexTermStructureParameters) volatilitySurfaceObject;
final YieldCurveWithBlackForexTermStructureBundle flatData = new YieldCurveWithBlackForexTermStructureBundle(curvesWithFX, termStructure, currencyPair);
return flatData;
}
public static YieldAndDiscountCurve getCurveForCurrency(final FunctionInputs inputs, final Currency currency, final String curveName, final String curveCalculationConfig) {
final ValueRequirement curveRequirement = YieldCurveFunctionUtils.getCurveRequirement(ComputationTargetSpecification.of(currency), curveName, curveCalculationConfig);
final Object curveObject = inputs.getValue(curveRequirement);
if (curveObject == null) {
throw new OpenGammaRuntimeException("Could not get " + curveName + " curve");
}
final YieldAndDiscountCurve curve = (YieldAndDiscountCurve) curveObject;
return curve;
}
public static YieldAndDiscountCurve getCurveForCurrency(final FunctionInputs inputs, final Currency currency) {
final Object curveObject = inputs.getValue(YieldCurveFunctionUtils.getCurveRequirement(ComputationTargetSpecification.of(currency)));
if (curveObject == null) {
throw new OpenGammaRuntimeException("Could not get " + currency + " curve");
}
final YieldAndDiscountCurve curve = (YieldAndDiscountCurve) curveObject;
return curve;
}
public static ValueRequirement getSurfaceRequirement(final String surfaceName, final Currency putCurrency, final Currency callCurrency,
final String interpolatorName, final String leftExtrapolatorName, final String rightExtrapolatorName) {
final ValueProperties surfaceProperties = ValueProperties.builder()
.with(ValuePropertyNames.SURFACE, surfaceName)
.with(InstrumentTypeProperties.PROPERTY_SURFACE_INSTRUMENT_TYPE, InstrumentTypeProperties.FOREX)
.with(InterpolatedDataProperties.X_INTERPOLATOR_NAME, interpolatorName)
.with(InterpolatedDataProperties.LEFT_X_EXTRAPOLATOR_NAME, leftExtrapolatorName)
.with(InterpolatedDataProperties.RIGHT_X_EXTRAPOLATOR_NAME, rightExtrapolatorName)
.get();
final UnorderedCurrencyPair currenciesTarget = UnorderedCurrencyPair.of(putCurrency, callCurrency);
return new ValueRequirement(ValueRequirementNames.STANDARD_VOLATILITY_SURFACE_DATA, ComputationTargetType.UNORDERED_CURRENCY_PAIR.specification(currenciesTarget), surfaceProperties);
}
public static String getResultCurrency(final ComputationTarget target, final CurrencyPair baseQuotePair) {
final FinancialSecurity security = (FinancialSecurity) target.getSecurity();
if (security instanceof FXDigitalOptionSecurity) {
return ((FXDigitalOptionSecurity) target.getSecurity()).getPaymentCurrency().getCode();
}
if (security instanceof NonDeliverableFXDigitalOptionSecurity) {
return ((NonDeliverableFXDigitalOptionSecurity) target.getSecurity()).getPaymentCurrency().getCode();
}
final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor());
final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor());
Currency ccy;
if (baseQuotePair.getBase().equals(putCurrency)) {
ccy = callCurrency;
} else {
ccy = putCurrency;
}
return ccy.getCode();
}
}