/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.analytics.model.black; import static com.opengamma.engine.value.ValuePropertyNames.CURRENCY; import static com.opengamma.engine.value.ValuePropertyNames.CURVE_EXPOSURES; import static com.opengamma.engine.value.ValuePropertyNames.SURFACE; import static com.opengamma.engine.value.ValueRequirementNames.STANDARD_VOLATILITY_SURFACE_DATA; import static com.opengamma.financial.analytics.model.InstrumentTypeProperties.FOREX; import static com.opengamma.financial.analytics.model.InstrumentTypeProperties.PROPERTY_SURFACE_INSTRUMENT_TYPE; import static com.opengamma.financial.analytics.model.InterpolatedDataProperties.LEFT_X_EXTRAPOLATOR_NAME; import static com.opengamma.financial.analytics.model.InterpolatedDataProperties.RIGHT_X_EXTRAPOLATOR_NAME; import static com.opengamma.financial.analytics.model.InterpolatedDataProperties.X_INTERPOLATOR_NAME; import static com.opengamma.financial.analytics.model.curve.CurveCalculationPropertyNamesAndValues.DISCOUNTING; import static com.opengamma.financial.analytics.model.curve.CurveCalculationPropertyNamesAndValues.PROPERTY_CURVE_TYPE; import static com.opengamma.financial.analytics.model.volatility.SmileFittingPropertyNamesAndValues.BLACK; import static com.opengamma.financial.analytics.model.volatility.SmileFittingPropertyNamesAndValues.PROPERTY_VOLATILITY_MODEL; import java.util.Collection; import java.util.Collections; import java.util.Set; import com.google.common.collect.Iterables; import com.opengamma.analytics.financial.forex.method.FXMatrix; import com.opengamma.analytics.financial.instrument.InstrumentDefinition; import com.opengamma.analytics.financial.model.volatility.surface.SmileDeltaTermStructureParametersStrikeInterpolation; import com.opengamma.analytics.financial.provider.description.forex.BlackForexSmileProvider; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderInterface; import com.opengamma.core.convention.ConventionSource; import com.opengamma.core.holiday.HolidaySource; 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.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.ValueProperties; import com.opengamma.engine.value.ValuePropertyNames; import com.opengamma.engine.value.ValueRequirement; import com.opengamma.financial.OpenGammaCompilationContext; import com.opengamma.financial.analytics.conversion.FXVanillaOptionConverter; import com.opengamma.financial.analytics.conversion.FixedIncomeConverterDataProvider; import com.opengamma.financial.analytics.conversion.FutureTradeConverter; import com.opengamma.financial.analytics.conversion.DefaultTradeConverter; import com.opengamma.financial.analytics.model.discounting.DiscountingFunction; import com.opengamma.financial.analytics.model.forex.ForexVisitors; import com.opengamma.financial.convention.ConventionBundleSource; import com.opengamma.financial.currency.CurrencyPair; import com.opengamma.financial.currency.CurrencyPairs; import com.opengamma.financial.currency.CurrencyPairsSource; import com.opengamma.financial.security.FinancialSecurity; import com.opengamma.financial.security.FinancialSecurityVisitor; import com.opengamma.financial.security.FinancialSecurityVisitorAdapter; import com.opengamma.financial.security.option.FXDigitalOptionSecurity; import com.opengamma.financial.security.option.FXOptionSecurity; 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; import com.opengamma.util.tuple.Pairs; /** * Base function for all FX option pricing and risk functions that use a Black surface and curves constructed using the discounting method. */ public abstract class BlackDiscountingFXOptionFunction extends DiscountingFunction { /** * @param valueRequirements The value requirements, not null */ public BlackDiscountingFXOptionFunction(final String... valueRequirements) { super(valueRequirements); } /** * Gets the currency pairs configuration called {@link CurrencyPairs#DEFAULT_CURRENCY_PAIRS} from a {@link CurrencyPairsSource}. * * @param context The compilation context * @return The currency pairs */ protected CurrencyPairs getCurrencyPairs(final FunctionCompilationContext context) { @SuppressWarnings("deprecation") final CurrencyPairsSource currencyPairsSource = OpenGammaCompilationContext.getCurrencyPairsSource(context); return currencyPairsSource.getCurrencyPairs(CurrencyPairs.DEFAULT_CURRENCY_PAIRS); } @Override protected DefaultTradeConverter 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 FXVanillaOptionConverter fxOptionConverter = new FXVanillaOptionConverter(getCurrencyPairs(context)); final FinancialSecurityVisitor<InstrumentDefinition<?>> securityConverter = FinancialSecurityVisitorAdapter.<InstrumentDefinition<?>>builder().fxOptionVisitor(fxOptionConverter) .create(); final FutureTradeConverter futureTradeConverter = new FutureTradeConverter(); return new DefaultTradeConverter(futureTradeConverter, securityConverter); } /** * Base compiled function for all pricing and risk functions that use a Black surface and curves constructed using the discounting method. */ protected abstract class BlackDiscountingCompiledFunction extends DiscountingCompiledFunction { /** * @param tradeToDefinitionConverter Converts targets to definitions, not null * @param definitionToDerivativeConverter Converts definitions to derivatives, not null * @param withCurrency True if the result properties set the {@link ValuePropertyNames#CURRENCY} property. */ protected BlackDiscountingCompiledFunction(final DefaultTradeConverter tradeToDefinitionConverter, final FixedIncomeConverterDataProvider definitionToDerivativeConverter, final boolean withCurrency) { super(tradeToDefinitionConverter, definitionToDerivativeConverter, withCurrency); } @Override public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) { final Security security = target.getTrade().getSecurity(); return security instanceof FXOptionSecurity; } @SuppressWarnings("synthetic-access") @Override protected Collection<ValueProperties.Builder> getResultProperties(final FunctionCompilationContext context, final ComputationTarget target) { final ValueProperties.Builder properties = createValueProperties().with(PROPERTY_CURVE_TYPE, DISCOUNTING).with(PROPERTY_VOLATILITY_MODEL, BLACK).withAny(X_INTERPOLATOR_NAME) .withAny(LEFT_X_EXTRAPOLATOR_NAME).withAny(RIGHT_X_EXTRAPOLATOR_NAME).withAny(SURFACE).withAny(CURVE_EXPOSURES); if (isWithCurrency()) { final FinancialSecurity security = (FinancialSecurity) target.getTrade().getSecurity(); final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor()); final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor()); final CurrencyPairs baseQuotePairs = getCurrencyPairs(context); final CurrencyPair baseQuotePair = baseQuotePairs.getCurrencyPair(putCurrency, callCurrency); final String currency = getResultCurrency(target, baseQuotePair); properties.with(CURRENCY, currency); return Collections.singleton(properties); } return Collections.singleton(properties); } @Override public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) { final Set<ValueRequirement> requirements = super.getRequirements(context, target, desiredValue); if (requirements == null) { return null; } final ValueProperties constraints = desiredValue.getConstraints(); final Set<String> interpolatorNames = constraints.getValues(X_INTERPOLATOR_NAME); final Set<String> leftExtrapolatorNames = constraints.getValues(LEFT_X_EXTRAPOLATOR_NAME); final Set<String> rightExtrapolatorNames = constraints.getValues(RIGHT_X_EXTRAPOLATOR_NAME); final FinancialSecurity security = (FinancialSecurity) target.getTrade().getSecurity(); final Set<String> surface = constraints.getValues(SURFACE); final String interpolatorName = Iterables.getOnlyElement(interpolatorNames); final String leftExtrapolatorName = Iterables.getOnlyElement(leftExtrapolatorNames); final String rightExtrapolatorName = Iterables.getOnlyElement(rightExtrapolatorNames); final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor()); final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor()); final ValueProperties surfaceProperties = ValueProperties.builder().with(SURFACE, surface).with(PROPERTY_SURFACE_INSTRUMENT_TYPE, FOREX).with(X_INTERPOLATOR_NAME, interpolatorName) .with(LEFT_X_EXTRAPOLATOR_NAME, leftExtrapolatorName).with(RIGHT_X_EXTRAPOLATOR_NAME, rightExtrapolatorName).get(); final UnorderedCurrencyPair currenciesTarget = UnorderedCurrencyPair.of(putCurrency, callCurrency); final ValueRequirement surfaceRequirement = new ValueRequirement(STANDARD_VOLATILITY_SURFACE_DATA, ComputationTargetType.UNORDERED_CURRENCY_PAIR.specification(currenciesTarget), surfaceProperties); requirements.add(surfaceRequirement); return requirements; } @Override protected boolean requirementsSet(final ValueProperties constraints) { final Set<String> surfaceNames = constraints.getValues(SURFACE); if (surfaceNames == null) { return false; } final Set<String> interpolatorNames = constraints.getValues(X_INTERPOLATOR_NAME); if (interpolatorNames == null || interpolatorNames.size() != 1) { return false; } final Set<String> leftExtrapolatorNames = constraints.getValues(LEFT_X_EXTRAPOLATOR_NAME); if (leftExtrapolatorNames == null || leftExtrapolatorNames.size() != 1) { return false; } final Set<String> rightExtrapolatorNames = constraints.getValues(RIGHT_X_EXTRAPOLATOR_NAME); if (rightExtrapolatorNames == null || rightExtrapolatorNames.size() != 1) { return false; } return super.requirementsSet(constraints); } /** * Gets the Black surface and curve data. * * @param executionContext The execution context, not null * @param inputs The function inputs, not null * @param target The computation target, not null * @param fxMatrix The FX matrix, not null * @return The Black surface and curve data */ protected BlackForexSmileProvider getBlackSurface(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final FXMatrix fxMatrix) { final FXOptionSecurity security = (FXOptionSecurity) target.getTrade().getSecurity(); final MulticurveProviderInterface data = getMergedProviders(inputs, fxMatrix); final SmileDeltaTermStructureParametersStrikeInterpolation volatilitySurface = (SmileDeltaTermStructureParametersStrikeInterpolation) inputs.getValue(STANDARD_VOLATILITY_SURFACE_DATA); final Pair<Currency, Currency> currencyPair = Pairs.of(security.getPutCurrency(), security.getCallCurrency()); final BlackForexSmileProvider blackData = new BlackForexSmileProvider(data, volatilitySurface, currencyPair); return blackData; } /** * Gets the currency code of the result. * * @param target The computation target * @param baseQuotePair The base/quote pair for the currencies in the security * @return The result currency code. */ protected String getResultCurrency(final ComputationTarget target, final CurrencyPair baseQuotePair) { final FinancialSecurity security = (FinancialSecurity) target.getTrade().getSecurity(); if (security instanceof FXDigitalOptionSecurity) { return ((FXDigitalOptionSecurity) target.getSecurity()).getPaymentCurrency().getCode(); } else if (security instanceof NonDeliverableFXDigitalOptionSecurity) { return ((NonDeliverableFXDigitalOptionSecurity) target.getSecurity()).getPaymentCurrency().getCode(); } final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor()); final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor()); if (baseQuotePair.getBase().equals(putCurrency)) { return callCurrency.getCode(); } return putCurrency.getCode(); } } }