public override void calculate()
{
Utils.QL_REQUIRE(process_.x0() > 0.0, () => "negative or null underlying given");
StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;
Utils.QL_REQUIRE(payoff != null, () => "non-striked payoff given");
Exercise exercise = arguments_.exercise;
double t = process_.riskFreeRate().link.dayCounter().yearFraction(process_.riskFreeRate().link.referenceDate(),
exercise.lastDate());
double a = model_.link.parameters()[0];
double sigma = model_.link.parameters()[1];
double eta = process_.blackVolatility().link.blackVol(exercise.lastDate(), payoff.strike());
double varianceOffset;
if (a * t > Math.Pow(Const.QL_EPSILON, 0.25))
{
double v = sigma * sigma / (a * a) * (t + 2 / a * Math.Exp(-a * t) - 1 / (2 * a) * Math.Exp(-2 * a * t) - 3 / (2 * a));
double mu = 2 * rho_ * sigma * eta / a * (t - 1 / a * (1 - Math.Exp(-a * t)));
varianceOffset = v + mu;
}
else
{
// low-a algebraic limit
double v = sigma * sigma * t * t * t * (1 / 3.0 - 0.25 * a * t + 7 / 60.0 * a * a * t * t);
double mu = rho_ * sigma * eta * t * t * (1 - a * t / 3.0 + a * a * t * t / 12.0);
varianceOffset = v + mu;
}
Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(
new ShiftedBlackVolTermStructure(varianceOffset, process_.blackVolatility()));
GeneralizedBlackScholesProcess adjProcess =
new GeneralizedBlackScholesProcess(process_.stateVariable(),
process_.dividendYield(),
process_.riskFreeRate(),
volTS);
AnalyticEuropeanEngine bsmEngine = new AnalyticEuropeanEngine(adjProcess);
VanillaOption option = new VanillaOption(payoff, exercise);
option.setupArguments(bsmEngine.getArguments());
bsmEngine.calculate();
results_ = bsmEngine.getResults() as OneAssetOption.Results;
}