final double b = data.getCostOfCarry();
final double lambda = data.getHalfLife();
final double sigmaLR = data.getLongRunVolatility();
final double volOfSigma = data.getVolatilityOfVolatility();
final double rho = data.getCorrelation();
final StandardOptionDataBundle bsmData = new StandardOptionDataBundle(data);
final OptionDefinition call = definition.isCall() ? definition : new EuropeanVanillaOptionDefinition(k, definition.getExpiry(), true);
final double beta = -Math.log(2) / lambda;
final double alpha = -beta * sigmaLR * sigmaLR;
final double delta = beta * t;
final double eDelta = Math.exp(delta);
final boolean betaIsZero = CompareUtils.closeEquals(beta, 0, ZERO);
final double variance = sigma * sigma;
final double meanVariance = getMeanVariance(betaIsZero, variance, alpha, t, beta, eDelta, delta);
final double df = getDF(r, b, t);
final double sDf = s * df;
final double d1 = getD(s, k, b, meanVariance, t);
final double d2 = d1 - Math.sqrt(meanVariance * t);
final double nD1 = NORMAL.getPDF(d1);
final double f0 = BSM.getPricingFunction(call).evaluate(bsmData.withVolatilitySurface(new VolatilitySurface(ConstantDoublesSurface.from(Math.sqrt(meanVariance)))));
final double f1 = getF1(betaIsZero, variance, rho, alpha, t, beta, delta, eDelta, sDf, nD1, d2, meanVariance);
final double f2 = getF2(betaIsZero, variance, rho, alpha, t, beta, delta, eDelta, sDf, nD1, d1, d2, meanVariance);
final double callPrice = f0 + f1 * volOfSigma + f2 * volOfSigma * volOfSigma;
if (!definition.isCall()) {
return callPrice - s * df + k * Math.exp(-r * t);