ComplexNumber[] res = new ComplexNumber[6];
res[0] = heston.getFunction(t).evaluate(z);
//bump kappa
final double kappa = heston.getKappa();
HestonCharacteristicExponent hestonT = heston.withKappa(kappa + eps);
ComplexNumber up = hestonT.getFunction(t).evaluate(z);
if (kappa > eps) {
hestonT = heston.withKappa(kappa - eps);
ComplexNumber down = hestonT.getFunction(t).evaluate(z);
res[1] = divide(subtract(up, down), 2 * eps);
} else {
hestonT = heston.withKappa(kappa + 2 * eps);
ComplexNumber up2 = hestonT.getFunction(t).evaluate(z);
res[1] = add(multiply(-1.5 / eps, res[0]), multiply(2 / eps, up), multiply(-0.5 / eps, up2));
}
//bump theta
final double theta = heston.getTheta();
hestonT = heston.withTheta(theta + eps);
up = hestonT.getFunction(t).evaluate(z);
if (theta > eps) {
hestonT = heston.withTheta(theta - eps);
ComplexNumber down = hestonT.getFunction(t).evaluate(z);
res[2] = divide(subtract(up, down), 2 * eps);
} else {
hestonT = heston.withTheta(theta + 2 * eps);
ComplexNumber up2 = hestonT.getFunction(t).evaluate(z);
res[2] = add(multiply(-1.5 / eps, res[0]), multiply(2 / eps, up), multiply(-0.5 / eps, up2));
}
//bump vol0
final double vol0 = heston.getVol0();
hestonT = heston.withVol0(vol0 + eps);
up = hestonT.getFunction(t).evaluate(z);
if (vol0 > eps) {
hestonT = heston.withVol0(vol0 - eps);
ComplexNumber down = hestonT.getFunction(t).evaluate(z);
res[3] = divide(subtract(up, down), 2 * eps);
} else {
hestonT = heston.withVol0(vol0 + 2 * eps);
ComplexNumber up2 = hestonT.getFunction(t).evaluate(z);
res[3] = add(multiply(-1.5 / eps, res[0]), multiply(2 / eps, up), multiply(-0.5 / eps, up2));
}
//bump omega
final double omega = heston.getOmega();
hestonT = heston.withOmega(omega + eps);
up = hestonT.getFunction(t).evaluate(z);
if (omega > eps) {
hestonT = heston.withOmega(omega - eps);
ComplexNumber down = hestonT.getFunction(t).evaluate(z);
res[4] = divide(subtract(up, down), 2 * eps);
} else {
hestonT = heston.withOmega(omega + 2 * eps);
ComplexNumber up2 = hestonT.getFunction(t).evaluate(z);
res[4] = add(multiply(-1.5 / eps, res[0]), multiply(2 / eps, up), multiply(-0.5 / eps, up2));
}
//bump rho
final double rho = heston.getRho();
if (rho + 1 < eps) {
hestonT = heston.withRho(rho + eps);
up = hestonT.getFunction(t).evaluate(z);
hestonT = heston.withRho(rho + 2 * eps);
ComplexNumber up2 = hestonT.getFunction(t).evaluate(z);
res[5] = add(multiply(-1.5 / eps, res[0]), multiply(2 / eps, up), multiply(-0.5 / eps, up2));
} else if (1 - rho < eps) {
hestonT = heston.withRho(rho - eps);
ComplexNumber down = hestonT.getFunction(t).evaluate(z);
hestonT = heston.withRho(rho - 2 * eps);
ComplexNumber down2 = hestonT.getFunction(t).evaluate(z);
res[5] = add(multiply(0.5 / eps, down2), multiply(-2 / eps, down), multiply(1.5 / eps, res[0]));
} else {
hestonT = heston.withRho(rho + eps);
up = hestonT.getFunction(t).evaluate(z);
hestonT = heston.withRho(rho - eps);
ComplexNumber down = hestonT.getFunction(t).evaluate(z);
res[5] = divide(subtract(up, down), 2 * eps);
}
return res;
}