/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.financial.analytics.model.volatility.local.deprecated; import static com.opengamma.engine.value.ValuePropertyNames.CURVE; import static com.opengamma.engine.value.ValuePropertyNames.SURFACE; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_H; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_MAX_MONEYNESS; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_PDE_DIRECTION; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_SPACE_GRID_BUNCHING; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_SPACE_STEPS; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_SURFACE_TYPE; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_THETA; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_TIME_GRID_BUNCHING; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_TIME_STEPS; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_X_AXIS; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_Y_AXIS; import static com.opengamma.financial.analytics.model.volatility.local.deprecated.LocalVolatilityPDEValuePropertyNames.PROPERTY_Y_AXIS_TYPE; import java.util.Collections; import java.util.Map; import java.util.Set; import org.threeten.bp.Clock; import org.threeten.bp.ZonedDateTime; import com.google.common.collect.Sets; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.analytics.financial.model.interestrate.curve.ForwardCurve; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption; import com.opengamma.analytics.financial.model.volatility.local.DupireLocalVolatilityCalculator; import com.opengamma.analytics.financial.model.volatility.local.LocalVolatilityForwardPDEGreekCalculator1; import com.opengamma.analytics.financial.model.volatility.local.LocalVolatilitySurface; import com.opengamma.analytics.financial.model.volatility.smile.fitting.interpolation.GeneralSmileInterpolator; import com.opengamma.analytics.financial.model.volatility.smile.fitting.interpolation.SmileInterpolatorSpline; import com.opengamma.analytics.financial.model.volatility.smile.fitting.sabr.SmileSurfaceDataBundle; import com.opengamma.analytics.financial.model.volatility.surface.Moneyness; import com.opengamma.analytics.financial.model.volatility.surface.VolatilitySurfaceInterpolator; 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.ComputationTargetReference; 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.OpenGammaExecutionContext; import com.opengamma.financial.analytics.model.InstrumentTypeProperties; import com.opengamma.financial.analytics.model.curve.forward.ForwardCurveValuePropertyNames; import com.opengamma.financial.currency.CurrencyPair; import com.opengamma.financial.currency.CurrencyPairs; import com.opengamma.financial.security.FinancialSecurity; import com.opengamma.financial.security.option.FXOptionSecurity; /** * @deprecated Deprecated */ @Deprecated public abstract class LocalVolatilityPDEGridFunction extends AbstractFunction.NonCompiledInvoker { private final String _instrumentType; public LocalVolatilityPDEGridFunction(final String instrumentType) { _instrumentType = instrumentType; } @Override public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) { final Clock snapshotClock = executionContext.getValuationClock(); final ZonedDateTime now = ZonedDateTime.now(snapshotClock); final ValueRequirement desiredValue = desiredValues.iterator().next(); final String surfaceName = desiredValue.getConstraint(SURFACE); final String surfaceType = desiredValue.getConstraint(PROPERTY_SURFACE_TYPE); final boolean moneynessSurface = LocalVolatilityPDEUtils.isMoneynessSurface(surfaceType); if (!moneynessSurface) { throw new OpenGammaRuntimeException("Cannot handle surface type other than moneyness; asked for strike"); } final String xAxis = desiredValue.getConstraint(PROPERTY_X_AXIS); final boolean useLogTime = LocalVolatilityPDEUtils.useLogTime(xAxis); final String yAxis = desiredValue.getConstraint(PROPERTY_Y_AXIS); final boolean useIntegratedVariance = LocalVolatilityPDEUtils.useIntegratedVariance(yAxis); final String yAxisType = desiredValue.getConstraint(PROPERTY_Y_AXIS_TYPE); final boolean useLogValue = LocalVolatilityPDEUtils.useLogValue(yAxisType); final String forwardCurveCalculationMethod = desiredValue.getConstraint(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD); final String forwardCurveName = desiredValue.getConstraint(CURVE); final String hName = desiredValue.getConstraint(PROPERTY_H); final double h = Double.parseDouble(hName); final String thetaName = desiredValue.getConstraint(PROPERTY_THETA); final double theta = Double.parseDouble(thetaName); final String timeStepsName = desiredValue.getConstraint(PROPERTY_TIME_STEPS); final int timeSteps = Integer.parseInt(timeStepsName); final String spaceStepsName = desiredValue.getConstraint(PROPERTY_SPACE_STEPS); final int spaceSteps = Integer.parseInt(spaceStepsName); final String timeGridBunchingName = desiredValue.getConstraint(PROPERTY_TIME_GRID_BUNCHING); final double timeGridBunching = Double.parseDouble(timeGridBunchingName); final String spaceGridBunchingName = desiredValue.getConstraint(PROPERTY_SPACE_GRID_BUNCHING); final double spaceGridBunching = Double.parseDouble(spaceGridBunchingName); final String pdeDirection = desiredValue.getConstraint(PROPERTY_PDE_DIRECTION); if (!(pdeDirection.equals(LocalVolatilityPDEValuePropertyNames.FORWARD_PDE))) { throw new OpenGammaRuntimeException("Can only use forward PDE; should never ask for this direction: " + pdeDirection); } final DupireLocalVolatilityCalculator localVolatilityCalculator = new DupireLocalVolatilityCalculator(h); //TODO R White testing using spline rather than SABR - this should be an option final GeneralSmileInterpolator smileInterpolator = new SmileInterpolatorSpline(); final VolatilitySurfaceInterpolator surfaceFitter = new VolatilitySurfaceInterpolator(smileInterpolator, useLogTime, useIntegratedVariance, useLogValue); //final PiecewiseSABRSurfaceFitter1<?> surfaceFitter = new MoneynessPiecewiseSABRSurfaceFitter(useLogTime, useIntegratedVariance, useLogValue); //TODO get rid of hardcoded maxProxydelta = 1.5 final LocalVolatilityForwardPDEGreekCalculator1<?> calculator = new LocalVolatilityForwardPDEGreekCalculator1<Moneyness>(theta, timeSteps, spaceSteps, timeGridBunching, spaceGridBunching, /*(MoneynessPiecewiseSABRSurfaceFitter)*/surfaceFitter, localVolatilityCalculator, 1.5); final ValueSpecification spec = new ValueSpecification(desiredValue.getValueName(), target.toSpecification(), desiredValue.getConstraints()); final FinancialSecurity security = (FinancialSecurity) target.getSecurity(); final ComputationTargetReference id = getTargetForUnderlyings(target); final ValueRequirement surfaceRequirement = getVolatilitySurfaceRequirement(surfaceName, surfaceType, xAxis, yAxis, yAxisType, hName, forwardCurveCalculationMethod, forwardCurveName, id); final Object localVolatilitySurfaceObject = inputs.getValue(surfaceRequirement); if (localVolatilitySurfaceObject == null) { throw new OpenGammaRuntimeException("Local volatility surface was null"); } final LocalVolatilitySurface<?> localVolatilitySurface = (LocalVolatilitySurface<?>) localVolatilitySurfaceObject; final ValueRequirement forwardCurveRequirement = getForwardCurveRequirement(forwardCurveCalculationMethod, forwardCurveName, id); final Object forwardCurveObject = inputs.getValue(forwardCurveRequirement); if (forwardCurveObject == null) { throw new OpenGammaRuntimeException("Forward curve was null"); } final ForwardCurve forwardCurve = (ForwardCurve) forwardCurveObject; final ValueRequirement volDataRequirement = getUnderlyingVolatilityDataRequirement(surfaceName, id); final SmileSurfaceDataBundle data = getData(inputs, volDataRequirement, forwardCurveRequirement); final FXOptionSecurity fxOption = (FXOptionSecurity) security; final CurrencyPairs currencyPairs = OpenGammaExecutionContext.getCurrencyPairsSource(executionContext).getCurrencyPairs(CurrencyPairs.DEFAULT_CURRENCY_PAIRS); final CurrencyPair currencyPair = currencyPairs.getCurrencyPair(fxOption.getPutCurrency(), fxOption.getCallCurrency()); final EuropeanVanillaOption option = getOption(security, now, currencyPair); return Collections.singleton(new ComputedValue(spec, getResult(calculator, localVolatilitySurface, forwardCurve, data, option))); } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) { final ValueProperties properties = createValueProperties() .with(ValuePropertyNames.CALCULATION_METHOD, LocalVolatilityPDEValuePropertyNames.LOCAL_VOLATILITY_METHOD) .with(InstrumentTypeProperties.PROPERTY_SURFACE_INSTRUMENT_TYPE, _instrumentType) .withAny(SURFACE) .withAny(PROPERTY_SURFACE_TYPE) .withAny(PROPERTY_X_AXIS) .withAny(PROPERTY_Y_AXIS) .withAny(PROPERTY_Y_AXIS_TYPE) .withAny(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD) .withAny(CURVE) .withAny(PROPERTY_THETA) .withAny(PROPERTY_TIME_STEPS) .withAny(PROPERTY_SPACE_STEPS) .withAny(PROPERTY_TIME_GRID_BUNCHING) .withAny(PROPERTY_SPACE_GRID_BUNCHING) .withAny(PROPERTY_MAX_MONEYNESS) .withAny(PROPERTY_H) .withAny(PROPERTY_PDE_DIRECTION).get(); return Collections.singleton(new ValueSpecification(getResultName(), 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> surfaceNames = constraints.getValues(SURFACE); if (surfaceNames == null || surfaceNames.size() != 1) { return null; } final Set<String> surfaceTypeNames = constraints.getValues(PROPERTY_SURFACE_TYPE); if (surfaceTypeNames == null || surfaceTypeNames.size() != 1) { return null; } final Set<String> xAxisNames = constraints.getValues(PROPERTY_X_AXIS); if (xAxisNames == null || xAxisNames.size() != 1) { return null; } final Set<String> yAxisNames = constraints.getValues(PROPERTY_Y_AXIS); if (yAxisNames == null || yAxisNames.size() != 1) { return null; } final Set<String> yAxisTypeNames = constraints.getValues(PROPERTY_Y_AXIS_TYPE); if (yAxisTypeNames == null || yAxisTypeNames.size() != 1) { return null; } final Set<String> forwardCurveCalculationMethodNames = constraints.getValues(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD); if (forwardCurveCalculationMethodNames == null || forwardCurveCalculationMethodNames.size() != 1) { return null; } final Set<String> hNames = constraints.getValues(PROPERTY_H); if (hNames == null || hNames.size() != 1) { return null; } final Set<String> forwardCurveNames = constraints.getValues(CURVE); if (forwardCurveNames == null || forwardCurveNames.size() != 1) { return null; } final String surfaceType = surfaceTypeNames.iterator().next(); final String xAxis = xAxisNames.iterator().next(); final String yAxis = yAxisNames.iterator().next(); final String yAxisType = yAxisTypeNames.iterator().next(); final String forwardCurveCalculationMethod = forwardCurveCalculationMethodNames.iterator().next(); final String h = hNames.iterator().next(); final String forwardCurveName = forwardCurveNames.iterator().next(); final String surfaceName = surfaceNames.iterator().next(); final ComputationTargetReference id = getTargetForUnderlyings(target); final ValueRequirement volDataRequirement = getUnderlyingVolatilityDataRequirement(surfaceName, id); return Sets.newHashSet(getVolatilitySurfaceRequirement(surfaceName, surfaceType, xAxis, yAxis, yAxisType, h, forwardCurveCalculationMethod, forwardCurveName, id), getForwardCurveRequirement(forwardCurveCalculationMethod, forwardCurveName, id), volDataRequirement); } @Override public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target, final Map<ValueSpecification, ValueRequirement> inputs) { String surfaceName = null; String surfaceType = null; String xAxis = null; String yAxis = null; String yAxisType = null; String forwardCurveCalculationMethod = null; String forwardCurveName = null; String h = null; for (final Map.Entry<ValueSpecification, ValueRequirement> input : inputs.entrySet()) { final ValueProperties constraints = input.getValue().getConstraints(); if (input.getValue().getValueName().equals(ValueRequirementNames.FORWARD_CURVE)) { if (constraints.getValues(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD) != null) { final Set<String> forwardCurveCalculationMethodNames = constraints.getValues(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD); if (forwardCurveCalculationMethodNames == null || forwardCurveCalculationMethodNames.size() != 1) { throw new OpenGammaRuntimeException("Missing or non-unique forward curve calculation method name"); } forwardCurveCalculationMethod = forwardCurveCalculationMethodNames.iterator().next(); } if (constraints.getValues(CURVE) != null) { final Set<String> forwardCurveNames = constraints.getValues(CURVE); if (forwardCurveNames == null || forwardCurveNames.size() != 1) { throw new OpenGammaRuntimeException("Missing or non-unique forward curve name"); } forwardCurveName = forwardCurveNames.iterator().next(); } } else if (input.getValue().getValueName().equals(ValueRequirementNames.LOCAL_VOLATILITY_SURFACE)) { if (constraints.getValues(SURFACE) != null) { final Set<String> surfaceNames = constraints.getValues(SURFACE); if (surfaceNames == null || surfaceNames.size() != 1) { throw new OpenGammaRuntimeException("Missing or non-unique surface name"); } surfaceName = surfaceNames.iterator().next(); } if (constraints.getValues(PROPERTY_SURFACE_TYPE) != null) { final Set<String> surfaceTypeNames = constraints.getValues(PROPERTY_SURFACE_TYPE); if (surfaceTypeNames == null || surfaceTypeNames.size() != 1) { throw new OpenGammaRuntimeException("Missing or non-unique surface type name"); } surfaceType = surfaceTypeNames.iterator().next(); } if (constraints.getValues(PROPERTY_X_AXIS) != null) { final Set<String> xAxisNames = constraints.getValues(PROPERTY_X_AXIS); if (xAxisNames == null || xAxisNames.size() != 1) { throw new OpenGammaRuntimeException("Missing or non-unique x-axis property name"); } xAxis = xAxisNames.iterator().next(); } if (constraints.getValues(PROPERTY_Y_AXIS) != null) { final Set<String> yAxisNames = constraints.getValues(PROPERTY_Y_AXIS); if (yAxisNames == null || yAxisNames.size() != 1) { throw new OpenGammaRuntimeException("Missing or non-unique y-axis property name"); } yAxis = yAxisNames.iterator().next(); } if (constraints.getValues(PROPERTY_Y_AXIS_TYPE) != null) { final Set<String> yAxisTypeNames = constraints.getValues(PROPERTY_Y_AXIS_TYPE); if (yAxisTypeNames == null || yAxisTypeNames.size() != 1) { throw new OpenGammaRuntimeException("Missing or non-unique y-axis type property name"); } yAxisType = yAxisTypeNames.iterator().next(); } if (constraints.getValues(PROPERTY_H) != null) { final Set<String> hNames = constraints.getValues(PROPERTY_H); if (hNames == null || hNames.size() != 1) { throw new OpenGammaRuntimeException("Missing or non-unique h name"); } h = hNames.iterator().next(); } } } assert surfaceName != null; assert surfaceType != null; assert xAxis != null; assert yAxis != null; assert yAxisType != null; assert forwardCurveCalculationMethod != null; assert h != null; assert forwardCurveName != null; return Collections.singleton(getResultSpec(target, surfaceName, surfaceType, xAxis, yAxis, yAxisType, forwardCurveCalculationMethod, h, forwardCurveName)); } protected abstract ComputationTargetReference getTargetForUnderlyings(final ComputationTarget target); protected abstract EuropeanVanillaOption getOption(final FinancialSecurity security, final ZonedDateTime date, final CurrencyPair currencyPair); //TODO shouldn't need to do this - write a fudge builder for the data bundle and have it as an input protected abstract SmileSurfaceDataBundle getData(final FunctionInputs inputs, final ValueRequirement volDataRequirement, final ValueRequirement forwardCurveRequirement); protected abstract Object getResult(final LocalVolatilityForwardPDEGreekCalculator1<?> calculator, final LocalVolatilitySurface<?> localVolatilitySurface, final ForwardCurve forwardCurve, final SmileSurfaceDataBundle data, final EuropeanVanillaOption option); protected abstract String getResultName(); protected abstract ValueRequirement getUnderlyingVolatilityDataRequirement(final String surfaceName, final ComputationTargetReference id); private ValueRequirement getVolatilitySurfaceRequirement(final String surfaceName, final String surfaceType, final String xAxis, final String yAxis, final String yAxisType, final String h, final String forwardCurveCalculationMethod, final String forwardCurveName, final ComputationTargetReference target) { final ValueProperties properties = ValueProperties.builder() .with(InstrumentTypeProperties.PROPERTY_SURFACE_INSTRUMENT_TYPE, _instrumentType) .with(SURFACE, surfaceName) .with(PROPERTY_SURFACE_TYPE, surfaceType) .with(PROPERTY_X_AXIS, xAxis) .with(PROPERTY_Y_AXIS, yAxis) .with(PROPERTY_Y_AXIS_TYPE, yAxisType) .with(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD, forwardCurveCalculationMethod) .with(CURVE, forwardCurveName) .with(PROPERTY_H, h).get(); return new ValueRequirement(ValueRequirementNames.LOCAL_VOLATILITY_SURFACE, target, properties); } private ValueRequirement getForwardCurveRequirement(final String calculationMethod, final String forwardCurveName, final ComputationTargetReference target) { final ValueProperties properties = ValueProperties.builder() .with(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD, calculationMethod) .with(CURVE, forwardCurveName).get(); return new ValueRequirement(ValueRequirementNames.FORWARD_CURVE, target, properties); } private ValueProperties getResultProperties(final String surfaceName, final String surfaceType, final String xAxis, final String yAxis, final String yAxisType, final String forwardCurveCalculationMethod, final String h, final String forwardCurveName) { return createValueProperties() .with(ValuePropertyNames.CALCULATION_METHOD, LocalVolatilityPDEValuePropertyNames.LOCAL_VOLATILITY_METHOD) .with(InstrumentTypeProperties.PROPERTY_SURFACE_INSTRUMENT_TYPE, _instrumentType) .with(ValuePropertyNames.SURFACE, surfaceName) .with(PROPERTY_SURFACE_TYPE, surfaceType) .with(PROPERTY_X_AXIS, xAxis) .with(PROPERTY_Y_AXIS, yAxis) .with(PROPERTY_Y_AXIS_TYPE, yAxisType) .with(ForwardCurveValuePropertyNames.PROPERTY_FORWARD_CURVE_CALCULATION_METHOD, forwardCurveCalculationMethod) .with(CURVE, forwardCurveName) .withAny(PROPERTY_THETA) .withAny(PROPERTY_TIME_STEPS) .withAny(PROPERTY_SPACE_STEPS) .withAny(PROPERTY_TIME_GRID_BUNCHING) .withAny(PROPERTY_SPACE_GRID_BUNCHING) .withAny(PROPERTY_MAX_MONEYNESS) .with(PROPERTY_H, h) .withAny(PROPERTY_PDE_DIRECTION).get(); } private ValueSpecification getResultSpec(final ComputationTarget target, final String definitionName, final String surfaceType, final String xAxis, final String yAxis, final String yAxisType, final String forwardCurveCalculationMethod, final String h, final String forwardCurveName) { final ValueProperties properties = getResultProperties(definitionName, surfaceType, xAxis, yAxis, yAxisType, forwardCurveCalculationMethod, h, forwardCurveName); return new ValueSpecification(getResultName(), target.toSpecification(), properties); } }