final Date volRefDate = process.blackVolatility().currentLink().referenceDate();
final double /* @Time */t = voldc.yearFraction(volRefDate, A.exercise.lastDate());
final double /* @Rate */riskFreeRate = -Math.log(process.riskFreeRate().currentLink().discount(A.exercise.lastDate())) / t;
final Date rateRefDate = process.riskFreeRate().currentLink().referenceDate();
final PoissonDistribution p = new PoissonDistribution(lambda * t);
final Handle<? extends Quote> stateVariable = process.stateVariable();
final Handle<YieldTermStructure> dividendTS = process.dividendYield();
final RelinkableHandle<YieldTermStructure> riskFreeTS =
new RelinkableHandle<YieldTermStructure>(process.riskFreeRate().currentLink());
final RelinkableHandle<BlackVolTermStructure> volTS =
new RelinkableHandle<BlackVolTermStructure>(process.blackVolatility().currentLink());
final GeneralizedBlackScholesProcess bsProcess =
new GeneralizedBlackScholesProcess(stateVariable, dividendTS, riskFreeTS, volTS);
final AnalyticEuropeanEngine baseEngine = new AnalyticEuropeanEngine(bsProcess);
final VanillaOption.ArgumentsImpl baseArguments = (VanillaOption.ArgumentsImpl) baseEngine.getArguments();
baseArguments.payoff = A.payoff;
baseArguments.exercise = A.exercise;
baseArguments.validate();
final VanillaOption.ResultsImpl baseResults = (VanillaOption.ResultsImpl) baseEngine.getResults();
R.value = 0.0;
greeks.delta = 0.0;
greeks.gamma = 0.0;
greeks.theta = 0.0;
greeks.vega = 0.0;
greeks.rho = 0.0;
greeks.dividendRho = 0.0;
double /* @Real */ r, v, weight, lastContribution = 1.0;
double /* @Real */ theta_correction;
int i;
for (i = 0; lastContribution > relativeAccuracy && i < maxIterations || i < (int)(lambda*t); i++) {
// constant vol/rate assumption. It should be relaxed
v = Math.sqrt((variance + i * jumpSquareVol) / t);
r = riskFreeRate - process.jumpIntensity().currentLink().value() * k + i * muPlusHalfSquareVol / t;
riskFreeTS.linkTo(new FlatForward(rateRefDate, r, voldc));
volTS.linkTo(new BlackConstantVol(rateRefDate, volcal, v, voldc));
baseArguments.validate();
baseEngine.calculate();
weight = p.op(i);
R.value += weight * baseResults.value;
greeks.delta += weight * baseResults.greeks().delta;
greeks.gamma += weight * baseResults.greeks().gamma;
greeks.vega += weight * (Math.sqrt(variance / t) / v) * baseResults.greeks().vega;
// theta modified
theta_correction = baseResults.greeks().vega * ((i * jumpSquareVol) / (2.0 * v * t * t)) + baseResults.greeks().rho * i
* muPlusHalfSquareVol / (t * t);
greeks.theta += weight * (baseResults.greeks().theta + theta_correction + lambda * baseResults.value);
if (i != 0) {
greeks.theta -= (p.op(i-1) * lambda * baseResults.value);
}
// end theta calculation
greeks.rho += weight * baseResults.greeks().rho;
greeks.dividendRho += weight * baseResults.greeks().dividendRho;