/**
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.equity;
import java.util.Map;
import com.opengamma.analytics.financial.equity.StaticReplicationDataBundle;
import com.opengamma.analytics.financial.model.interestrate.curve.ForwardCurve;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository;
import com.opengamma.analytics.financial.model.volatility.surface.BlackVolatilitySurfaceStrike;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.math.interpolation.GridInterpolator2D;
import com.opengamma.analytics.math.surface.DoublesSurface;
import com.opengamma.analytics.math.surface.InterpolatedDoublesSurface;
import com.opengamma.financial.security.option.EquityIndexOptionSecurity;
import com.opengamma.financial.security.option.OptionType;
import com.opengamma.sesame.DiscountingMulticurveCombinerFn;
import com.opengamma.sesame.Environment;
import com.opengamma.sesame.ForwardCurveFn;
import com.opengamma.sesame.GridInterpolator2DFn;
import com.opengamma.sesame.MulticurveBundle;
import com.opengamma.sesame.marketdata.SurfaceId;
import com.opengamma.sesame.trade.EquityIndexOptionTrade;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.result.FailureStatus;
import com.opengamma.util.result.Result;
/**
* {@link StaticReplicationDataBundleFn } implementation to return instances of
* {@link StaticReplicationDataBundle} with {@link BlackVolatilitySurfaceStrike}.
*/
public class StrikeDataFromPriceBundleFn implements StaticReplicationDataBundleFn {
private final DiscountingMulticurveCombinerFn _multicurveCombinerFn;
private final ForwardCurveFn _forwardCurveFn;
private final GridInterpolator2DFn _interpolatorFn;
/**
* Constructors a black volatility provider function for bond future options.
* @param discountingMulticurveCombinerFn the discounting multicurve combiner function, not null.
* @param forwardCurveFn the function to provide the forward curve, not null.
* @param interpolatorFn the interpolator to use when constructing the surface
*/
public StrikeDataFromPriceBundleFn(DiscountingMulticurveCombinerFn discountingMulticurveCombinerFn,
ForwardCurveFn forwardCurveFn,
GridInterpolator2DFn interpolatorFn) {
_interpolatorFn = ArgumentChecker.notNull(interpolatorFn, "interpolator");
_multicurveCombinerFn = ArgumentChecker.notNull(discountingMulticurveCombinerFn, "discountingMulticurveCombinerFn");
_forwardCurveFn = ArgumentChecker.notNull(forwardCurveFn, "forwardCurveFn");
}
@Override
public Result<StaticReplicationDataBundle> getEquityIndexDataProvider(Environment env,
EquityIndexOptionTrade tradeWrapper) {
EquityIndexOptionSecurity security = tradeWrapper.getSecurity();
Result<MulticurveBundle> bundleResult = _multicurveCombinerFn.getMulticurveBundle(env, tradeWrapper);
String volId = security.getOptionType() + "_" + security.getUnderlyingId().getValue();
Result<DoublesSurface> surfaceResult =
env.getMarketDataBundle().get(SurfaceId.of(volId), DoublesSurface.class);
Result<ForwardCurve> forwardResult = _forwardCurveFn.getEquityIndexForwardCurve(env, tradeWrapper);
Result<GridInterpolator2D> interpolatorResult = _interpolatorFn.createGridInterpolator2DFn(env);
if (Result.allSuccessful(bundleResult, surfaceResult, forwardResult, interpolatorResult)) {
boolean isCall = security.getOptionType().equals(OptionType.CALL);
MulticurveProviderDiscount multicurve = bundleResult.getValue().getMulticurveProvider();
DoublesSurface rawSurface = surfaceResult.getValue();
ForwardCurve forwardCurve = forwardResult.getValue();
Map<Currency, YieldAndDiscountCurve> discountingCurves = multicurve.getDiscountingCurves();
YieldAndDiscountCurve discountCurve = discountingCurves.get(security.getCurrency());
Double[] priceData = rawSurface.getZData();
Double[] timeData = rawSurface.getXData();
Double[] strikeData = rawSurface.getYData();
Double[] volData = new Double[priceData.length];
for (int i = 0; i < priceData.length; i++) {
double timeToExpiry = timeData[i];
double optionPrice = priceData[i];
double forwardOptionPrice = optionPrice / discountCurve.getDiscountFactor(timeToExpiry);
double forward = forwardCurve.getForward(timeToExpiry);
try {
volData[i] = BlackFormulaRepository.impliedVolatility(forwardOptionPrice,
forward,
strikeData[i],
timeToExpiry,
isCall);
} catch (Exception e) {
return Result.failure(FailureStatus.INVALID_INPUT, e,
"Error constructing surface {} for price {} and strike {} at maturity {}. {}",
volId, optionPrice, strikeData[i], timeToExpiry, e.getMessage());
}
}
InterpolatedDoublesSurface surface = InterpolatedDoublesSurface.from(timeData,
strikeData,
volData,
interpolatorResult.getValue());
BlackVolatilitySurfaceStrike blackVolSurface = new BlackVolatilitySurfaceStrike(surface);
StaticReplicationDataBundle bundle = new StaticReplicationDataBundle(blackVolSurface,
discountCurve,
forwardCurve);
return Result.success(bundle);
} else {
return Result.failure(bundleResult, surfaceResult, forwardResult, interpolatorResult);
}
}
}