/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.model.sabr;
import static com.opengamma.engine.value.SurfaceAndCubePropertyNames.PROPERTY_CUBE_DEFINITION;
import static com.opengamma.engine.value.SurfaceAndCubePropertyNames.PROPERTY_CUBE_SPECIFICATION;
import static com.opengamma.engine.value.SurfaceAndCubePropertyNames.PROPERTY_SURFACE_DEFINITION;
import static com.opengamma.engine.value.SurfaceAndCubePropertyNames.PROPERTY_SURFACE_SPECIFICATION;
import static com.opengamma.engine.value.ValuePropertyNames.CALCULATION_METHOD;
import static com.opengamma.engine.value.ValuePropertyNames.CURRENCY;
import static com.opengamma.engine.value.ValuePropertyNames.CURVE_EXPOSURES;
import static com.opengamma.engine.value.ValueRequirementNames.SABR_SURFACES;
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.PROPERTY_VOLATILITY_MODEL;
import static com.opengamma.financial.analytics.model.volatility.SmileFittingPropertyNamesAndValues.SABR;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.financial.instrument.InstrumentDefinition;
import com.opengamma.analytics.financial.instrument.index.GeneratorAttributeIR;
import com.opengamma.analytics.financial.instrument.index.GeneratorInstrument;
import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedIbor;
import com.opengamma.analytics.financial.model.option.definition.SABRInterestRateParameters;
import com.opengamma.analytics.financial.model.volatility.smile.function.VolatilityFunctionFactory;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.SABRSwaptionProvider;
import com.opengamma.analytics.financial.provider.description.interestrate.SABRSwaptionProviderDiscount;
import com.opengamma.analytics.math.surface.InterpolatedDoublesSurface;
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.ComputationTargetSpecification;
import com.opengamma.engine.function.FunctionCompilationContext;
import com.opengamma.engine.function.FunctionExecutionContext;
import com.opengamma.engine.function.FunctionInputs;
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.OpenGammaCompilationContext;
import com.opengamma.financial.OpenGammaExecutionContext;
import com.opengamma.financial.analytics.conversion.FixedIncomeConverterDataProvider;
import com.opengamma.financial.analytics.conversion.FutureTradeConverter;
import com.opengamma.financial.analytics.conversion.InterestRateSwapSecurityConverter;
import com.opengamma.financial.analytics.conversion.SwapSecurityConverter;
import com.opengamma.financial.analytics.conversion.SwaptionSecurityConverter;
import com.opengamma.financial.analytics.conversion.DefaultTradeConverter;
import com.opengamma.financial.analytics.model.discounting.DiscountingFunction;
import com.opengamma.financial.analytics.model.swaption.SwaptionUtils;
import com.opengamma.financial.analytics.volatility.fittedresults.SABRFittedSurfaces;
import com.opengamma.financial.convention.ConventionBundleSource;
import com.opengamma.financial.convention.daycount.DayCount;
import com.opengamma.financial.security.FinancialSecurityUtils;
import com.opengamma.financial.security.FinancialSecurityVisitor;
import com.opengamma.financial.security.FinancialSecurityVisitorAdapter;
import com.opengamma.financial.security.option.SwaptionSecurity;
/**
* Base function for all pricing and risk functions that use SABR parameter surfaces and curves constructed using the discounting method.
*/
public abstract class SABRDiscountingFunction extends DiscountingFunction {
/**
* @param valueRequirements The value requirements, not null
*/
public SABRDiscountingFunction(final String... valueRequirements) {
super(valueRequirements);
}
@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 SwapSecurityConverter swapConverter = new SwapSecurityConverter(securitySource, holidaySource, conventionSource, regionSource);
final InterestRateSwapSecurityConverter irsConverter = new InterestRateSwapSecurityConverter(holidaySource, conventionSource, securitySource);
final SwaptionSecurityConverter swaptionConverter = new SwaptionSecurityConverter(swapConverter, irsConverter);
final FinancialSecurityVisitor<InstrumentDefinition<?>> securityConverter = FinancialSecurityVisitorAdapter.<InstrumentDefinition<?>>builder().swaptionVisitor(swaptionConverter)
.create();
final FutureTradeConverter futureTradeConverter = new FutureTradeConverter();
return new DefaultTradeConverter(futureTradeConverter, securityConverter);
}
/**
* Base compiled function for all pricing and risk functions that use SABR parameter surfaces and curves constructed using the discounting method.
*/
protected abstract class SABRDiscountingCompiledFunction 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 SABRDiscountingCompiledFunction(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 SwaptionSecurity;
}
@SuppressWarnings("synthetic-access")
@Override
protected Collection<ValueProperties.Builder> getResultProperties(final FunctionCompilationContext compilationContext, final ComputationTarget target) {
final ValueProperties.Builder properties = createValueProperties()
.with(PROPERTY_CURVE_TYPE, DISCOUNTING)
.with(PROPERTY_VOLATILITY_MODEL, SABR)
.withAny(PROPERTY_CUBE_DEFINITION)
.withAny(PROPERTY_CUBE_SPECIFICATION)
.withAny(PROPERTY_SURFACE_DEFINITION)
.withAny(PROPERTY_SURFACE_SPECIFICATION)
.with(CALCULATION_METHOD, getCalculationMethod())
.withAny(CURVE_EXPOSURES);
if (isWithCurrency()) {
final Security security = target.getTrade().getSecurity();
final String currency = FinancialSecurityUtils.getCurrency(security).getCode();
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> cubeDefinition = constraints.getValues(PROPERTY_CUBE_DEFINITION);
final Set<String> cubeSpecification = constraints.getValues(PROPERTY_CUBE_SPECIFICATION);
final Set<String> surfaceDefinition = constraints.getValues(PROPERTY_SURFACE_DEFINITION);
final Set<String> surfaceSpecification = constraints.getValues(PROPERTY_SURFACE_SPECIFICATION);
final ValueProperties properties = ValueProperties.builder().with(PROPERTY_CUBE_DEFINITION, cubeDefinition)
.with(PROPERTY_CUBE_SPECIFICATION, cubeSpecification)
.with(PROPERTY_SURFACE_DEFINITION, surfaceDefinition)
.with(PROPERTY_SURFACE_SPECIFICATION, surfaceSpecification)
.with(PROPERTY_VOLATILITY_MODEL, SABR).get();
final ValueRequirement surfacesRequirement = new ValueRequirement(ValueRequirementNames.SABR_SURFACES, ComputationTargetSpecification.NULL, properties);
requirements.add(surfacesRequirement);
return requirements;
}
@Override
protected boolean requirementsSet(final ValueProperties constraints) {
final Set<String> cubeDefinitionNames = constraints.getValues(PROPERTY_CUBE_DEFINITION);
if (cubeDefinitionNames == null) {
return false;
}
final Set<String> cubeSpecificationNames = constraints.getValues(PROPERTY_CUBE_SPECIFICATION);
if (cubeSpecificationNames == null) {
return false;
}
final Set<String> surfaceDefinitionNames = constraints.getValues(PROPERTY_SURFACE_DEFINITION);
if (surfaceDefinitionNames == null) {
return false;
}
final Set<String> surfaceSpecificationNames = constraints.getValues(PROPERTY_SURFACE_SPECIFICATION);
if (surfaceSpecificationNames == null) {
return false;
}
return super.requirementsSet(constraints);
}
/**
* Gets the calculation method.
*
* @return The calculation method
*/
protected abstract String getCalculationMethod();
protected SABRSwaptionProvider getSABRSurfaces(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final FXMatrix fxMatrix,
final DayCount dayCount) {
final SecuritySource securitySource = OpenGammaExecutionContext.getSecuritySource(executionContext);
final SwaptionSecurity security = (SwaptionSecurity) target.getTrade().getSecurity();
final InstrumentDefinition<?> definition = getDefinitionFromTarget(target);
final SABRFittedSurfaces surfaces = (SABRFittedSurfaces) inputs.getValue(SABR_SURFACES);
final InterpolatedDoublesSurface alphaSurface = surfaces.getAlphaSurface();
final InterpolatedDoublesSurface betaSurface = surfaces.getBetaSurface();
final InterpolatedDoublesSurface nuSurface = surfaces.getNuSurface();
final InterpolatedDoublesSurface rhoSurface = surfaces.getRhoSurface();
final SABRInterestRateParameters modelParameters = new SABRInterestRateParameters(alphaSurface, betaSurface, rhoSurface, nuSurface, VolatilityFunctionFactory.HAGAN_FORMULA);
final MulticurveProviderDiscount curves = getMergedProviders(inputs, fxMatrix);
final GeneratorInstrument<GeneratorAttributeIR> generatorSwap = SwaptionUtils.getSwapGenerator(security, definition, securitySource);
// TODO: [PLAT-6237]
if (!(generatorSwap instanceof GeneratorSwapFixedIbor)) {
throw new OpenGammaRuntimeException("Cannot handle swap generators of type " + generatorSwap.getClass());
}
return new SABRSwaptionProviderDiscount(curves, modelParameters, (GeneratorSwapFixedIbor) generatorSwap);
}
}
}