return _externalBeta;
}
@Override
protected DoubleMatrix1D getGlobalStart(final double forward, final double[] strikes, final double expiry, final double[] impliedVols) {
final RandomEngine random = getRandom();
final DoubleMatrix1D fitP = getPolynomialFit(forward, strikes, impliedVols);
final double a = fitP.getEntry(0);
final double b = fitP.getEntry(1);
final double c = fitP.getEntry(2);
double alpha, beta, rho, nu;
//TODO make better use of the polynomial fit information
if (_externalBeta) {
beta = _beta;
} else {
beta = random.nextDouble();
}
if (a <= 0.0) { //negative ATM vol - can get this if fit points are far from ATM
double sum = 0;
final int n = strikes.length;
for (int i = 0; i < n; i++) {
sum += impliedVols[i];
}
final double approxAlpha = sum / n * Math.pow(forward, 1 - beta);
alpha = (random.nextDouble() + 0.5) * approxAlpha;
rho = random.nextDouble() - 0.5;
nu = 0.5 * random.nextDouble() + 0.1;
return new DoubleMatrix1D(alpha, beta, rho, nu);
}
if (Math.abs(b) < 1e-3 && Math.abs(c) < 1e-3) { //almost flat smile
if (_externalBeta && _beta != 1.0) {
s_logger.warn("Smile almost flat. Cannot use beta = ", +_beta + " so extenal value ignored, and beta = 1.0 used");
}
return new DoubleMatrix1D(a, 1.0, 0.0, Math.max(0.0, 4 * c));
}
final double approxAlpha = a * Math.pow(forward, 1 - beta);
alpha = (random.nextDouble() + 0.5) * approxAlpha;
rho = random.nextDouble() - 0.5;
nu = (random.nextDouble() + 0.5) * Math.max(0.0, 4 * c);
return new DoubleMatrix1D(alpha, beta, rho, nu);
}