/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.model.volatility.surface;
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.financial.model.option.definition.SmileDeltaParameters;
import com.opengamma.analytics.financial.model.volatility.surface.SmileDeltaTermStructureParametersStrikeInterpolation;
import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory;
import com.opengamma.analytics.math.interpolation.Interpolator1D;
import com.opengamma.core.marketdatasnapshot.VolatilitySurfaceData;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.function.FunctionExecutionContext;
import com.opengamma.engine.function.FunctionInputs;
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.model.InstrumentTypeProperties;
import com.opengamma.financial.analytics.model.InterpolatedDataProperties;
import com.opengamma.financial.analytics.volatility.surface.VolatilitySurfaceShiftFunction;
import com.opengamma.util.time.Tenor;
/**
*
*/
public abstract class ForexPutCallDeltaVolatilitySurfaceFunction extends ForexVolatilitySurfaceFunction {
/** The logger */
private static final Logger s_logger = LoggerFactory.getLogger(ForexPutCallDeltaVolatilitySurfaceFunction.class);
@Override
public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) {
final ValueRequirement desiredValue = desiredValues.iterator().next();
final String surfaceName = desiredValue.getConstraint(ValuePropertyNames.SURFACE);
final String interpolatorName = desiredValue.getConstraint(InterpolatedDataProperties.X_INTERPOLATOR_NAME);
final String leftExtrapolatorName = desiredValue.getConstraint(InterpolatedDataProperties.LEFT_X_EXTRAPOLATOR_NAME);
final String rightExtrapolatorName = desiredValue.getConstraint(InterpolatedDataProperties.RIGHT_X_EXTRAPOLATOR_NAME);
final ValueRequirement surfaceRequirement = getDataRequirement(surfaceName, target);
final Object volatilitySurfaceObject = inputs.getValue(surfaceRequirement);
if (volatilitySurfaceObject == null) {
throw new OpenGammaRuntimeException("Could not get " + surfaceRequirement);
}
// In some circumstances, we will get Object arrays for xs and ys, so need to cope with that.
@SuppressWarnings("unchecked")
final VolatilitySurfaceData<Object, Object> fxVolatilitySurface = (VolatilitySurfaceData<Object, Object>) volatilitySurfaceObject;
final Object[] tenorsObjs = fxVolatilitySurface.getXs();
final Tenor[] tenors = new Tenor[tenorsObjs.length];
System.arraycopy(tenorsObjs, 0, tenors, 0, tenors.length);
final Object[] deltaValueObjs = fxVolatilitySurface.getYs();
final Double[] deltaValues = new Double[deltaValueObjs.length];
System.arraycopy(deltaValueObjs, 0, deltaValues, 0, deltaValueObjs.length);
Arrays.sort(tenors);
Arrays.sort(deltaValues);
final int nPoints = tenors.length;
final SmileDeltaParameters[] smile = new SmileDeltaParameters[nPoints];
final int nSmileValues = deltaValues.length;
final Set<String> shifts = desiredValues.iterator().next().getConstraints().getValues(VolatilitySurfaceShiftFunction.SHIFT);
final double shiftMultiplier;
if ((shifts != null) && (shifts.size() == 1)) {
final String shift = shifts.iterator().next();
shiftMultiplier = 1 + Double.parseDouble(shift);
} else {
shiftMultiplier = 1;
}
for (int i = 0; i < tenors.length; i++) {
final Tenor tenor = tenors[i];
final double t = getTime(tenor);
final DoubleArrayList deltas = new DoubleArrayList();
final DoubleArrayList volatilities = new DoubleArrayList();
for (int j = 0; j < nSmileValues; j++) {
final Double delta = deltaValues[j];
if (delta != null) {
Double volatility = fxVolatilitySurface.getVolatility((Object) tenor, (Object) delta);
if (volatility != null) {
volatility *= shiftMultiplier;
if (delta < 50) {
deltas.add(getTransformedDelta(delta));
}
volatilities.add(volatility);
}
} else {
s_logger.info("Had a null value for tenor number " + j);
}
}
smile[i] = new SmileDeltaParameters(t, deltas.toDoubleArray(), volatilities.toDoubleArray());
}
final Interpolator1D interpolator = CombinedInterpolatorExtrapolatorFactory.getInterpolator(interpolatorName, leftExtrapolatorName, rightExtrapolatorName);
final SmileDeltaTermStructureParametersStrikeInterpolation smiles = new SmileDeltaTermStructureParametersStrikeInterpolation(smile, interpolator);
final ValueProperties.Builder resultProperties = createValueProperties()
.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);
if (shifts != null) {
resultProperties.with(VolatilitySurfaceShiftFunction.SHIFT, shifts);
}
return Collections.singleton(new ComputedValue(new ValueSpecification(ValueRequirementNames.STANDARD_VOLATILITY_SURFACE_DATA, target.toSpecification(),
resultProperties.get()), smiles));
}
/**
* Transforms the delta for this surface type into that expected by the analytics library.
* @param delta The delta
* @return The transformed delta.
*/
protected abstract double getTransformedDelta(double delta);
}