alphaFixed[loopcf] = MODEL.alpha(parameters, 0.0, expiryTime, expiryTime, swaption.getUnderlyingSwap().getFixedLeg().getNthPayment(loopcf).getPaymentTime());
dfFixed[loopcf] = multicurves.getDiscountFactor(ccy, swaption.getUnderlyingSwap().getFixedLeg().getNthPayment(loopcf).getPaymentTime());
discountedCashFlowFixed[loopcf] = dfFixed[loopcf] * swaption.getUnderlyingSwap().getFixedLeg().getNthPayment(loopcf).getPaymentYearFraction()
* swaption.getUnderlyingSwap().getFixedLeg().getNthPayment(loopcf).getNotional();
}
final AnnuityPaymentFixed cfeIbor = swaption.getUnderlyingSwap().getSecondLeg().accept(CFEC, multicurves);
final double[] alphaIbor = new double[cfeIbor.getNumberOfPayments()];
final double[] dfIbor = new double[cfeIbor.getNumberOfPayments()];
final double[] discountedCashFlowIbor = new double[cfeIbor.getNumberOfPayments()];
for (int loopcf = 0; loopcf < cfeIbor.getNumberOfPayments(); loopcf++) {
alphaIbor[loopcf] = MODEL.alpha(parameters, 0.0, expiryTime, expiryTime, cfeIbor.getNthPayment(loopcf).getPaymentTime());
dfIbor[loopcf] = multicurves.getDiscountFactor(ccy, cfeIbor.getNthPayment(loopcf).getPaymentTime());
discountedCashFlowIbor[loopcf] = dfIbor[loopcf] * cfeIbor.getNthPayment(loopcf).getAmount();
}
final AnnuityPaymentFixed cfe = swaption.getUnderlyingSwap().accept(CFEC, multicurves);
final double[] alpha = new double[cfe.getNumberOfPayments()];
final double[] df = new double[cfe.getNumberOfPayments()];
final double[] discountedCashFlow = new double[cfe.getNumberOfPayments()];
for (int loopcf = 0; loopcf < cfe.getNumberOfPayments(); loopcf++) {
alpha[loopcf] = MODEL.alpha(parameters, 0.0, expiryTime, expiryTime, cfe.getNthPayment(loopcf).getPaymentTime());
df[loopcf] = multicurves.getDiscountFactor(ccy, cfe.getNthPayment(loopcf).getPaymentTime());
discountedCashFlow[loopcf] = df[loopcf] * cfe.getNthPayment(loopcf).getAmount();
}
final double kappa = MODEL.kappa(discountedCashFlow, alpha);
final int nbFixedPaymentYear = (int) Math.round(1.0 / swaption.getUnderlyingSwap().getFixedLeg().getNthPayment(0).getPaymentYearFraction());
final double[] derivativesRate = new double[3];
final double[] derivativesAnnuity = new double[3];
final double x0 = 0.0; // (swaption.getUnderlyingSwap().getFixedLeg().isPayer()) ? Math.max(kappa, 0) : Math.min(kappa, 0);
final double rate = swapRate(x0, discountedCashFlowFixed, alphaFixed, discountedCashFlowIbor, alphaIbor, derivativesRate);
final double annuity = annuityCash(rate, nbFixedPaymentYear, swaption.getUnderlyingSwap().getFixedLeg().getNumberOfPayments(), derivativesAnnuity);
final double[] u = new double[4];
u[0] = annuity * (swaption.getStrike() - rate);
u[1] = (swaption.getStrike() - rate) * derivativesAnnuity[0] * derivativesRate[0] - derivativesRate[0] * annuity;
u[2] = (swaption.getStrike() - rate) * (derivativesAnnuity[0] * derivativesRate[1] + derivativesAnnuity[1] * derivativesRate[0] * derivativesRate[0]) - 2 * derivativesAnnuity[0]
* derivativesRate[0] * derivativesRate[0] - annuity * derivativesRate[1];
u[3] = (-3 * derivativesRate[0] * (derivativesAnnuity[0] * derivativesRate[1] + derivativesAnnuity[1] * derivativesRate[0] * derivativesRate[0]))
- (2 * derivativesAnnuity[0] * derivativesRate[0] * derivativesRate[1])
+ ((swaption.getStrike() - rate) * (derivativesAnnuity[0] * derivativesRate[2] + 3 * derivativesAnnuity[1] * derivativesRate[0] * derivativesRate[1] + derivativesAnnuity[2]
* derivativesRate[0] * derivativesRate[0] * derivativesRate[0])) - (rate * derivativesRate[2]);
final double kappatilde = kappa + alphaIbor[0];
final double alpha0tilde = alphaIbor[0] + x0;
double ncdf;
final double npdf = NORMAL.getPDF(kappatilde);
if (!swaption.getUnderlyingSwap().getFixedLeg().isPayer()) {
ncdf = NORMAL.getCDF(kappatilde);
} else {
ncdf = NORMAL.getCDF(-kappatilde);
}
final double notional = Math.abs(swaption.getUnderlyingSwap().getFixedLeg().getNthPayment(0).getNotional());
// Backward sweep
final double pvTotalBar = 1.0;
final double pvBar = notional * dfIbor[0] * (swaption.isLong() ? 1.0 : -1.0) * pvTotalBar;
double alpha0tildeBar = 0.0;
double kappatildeBar = 0.0;
final double[] uBar = new double[4];
if (!swaption.getUnderlyingSwap().getFixedLeg().isPayer()) {
alpha0tildeBar = ((-u[1] - u[3] * (3 * alpha0tilde * alpha0tilde + 3.0) / 6.0) * ncdf + (u[2] + u[3] * (-6.0 * alpha0tilde + 3.0 * kappatilde) / 6.0) * npdf) * pvBar;
kappatildeBar = ((u[0] - u[1] * alpha0tilde + u[2] * (1 + alpha[0] * alpha[0]) / 2.0 - u[3] * (alpha0tilde * alpha0tilde * alpha0tilde + 3.0 * alpha0tilde) / 6.0) * npdf
+ (-u[2] / 2.0 + u[3] * (3.0 * alpha0tilde - 2.0 * kappatilde) / 6.0) * npdf + (-u[1] - u[2] * (-2.0 * alpha0tilde + kappatilde) / 2.0 + u[3]
* (-3 * alpha0tilde * alpha0tilde + 3.0 * kappatilde * alpha0tilde - kappatilde * kappatilde - 2.0) / 6.0)
* npdf * -kappatilde)
* pvBar;
uBar[0] = ncdf * pvBar;
uBar[1] = (-alpha0tilde * ncdf - npdf) * pvBar;
uBar[2] = ((1 + alpha[0] * alpha[0]) / 2.0 * ncdf - (-2.0 * alpha0tilde + kappatilde) / 2.0 * npdf) * pvBar;
uBar[3] = (-(alpha0tilde * alpha0tilde * alpha0tilde + 3.0 * alpha0tilde) / 6.0 * ncdf + (-3 * alpha0tilde * alpha0tilde + 3.0 * kappatilde * alpha0tilde - kappatilde * kappatilde - 2.0) / 6.0
* npdf)
* pvBar;
} else {
alpha0tildeBar = (-(-u[1] - u[3] * (3 * alpha0tilde * alpha0tilde + 3.0) / 6.0) * ncdf + (u[2] + u[3] * (-6.0 * alpha0tilde + 3.0 * kappatilde) / 6.0) * npdf) * pvBar;
kappatildeBar = ((u[0] - u[1] * alpha0tilde + u[2] * (1 + alpha[0] * alpha[0]) / 2.0 - u[3] * (alpha0tilde * alpha0tilde * alpha0tilde + 3.0 * alpha0tilde) / 6.0) * npdf
+ (-u[2] / 2.0 + u[3] * (3.0 * alpha0tilde - 2 * kappatilde) / 6.0) * npdf + (-u[1] - u[2] * (-2.0 * alpha0tilde + kappatilde) / 2.0 + u[3]
* (-3 * alpha0tilde * alpha0tilde + 3.0 * kappatilde * alpha0tilde - kappatilde * kappatilde - 2.0) / 6.0)
* npdf * -kappatilde)
* pvBar;
uBar[0] = -ncdf * pvBar;
uBar[1] = (+alpha0tilde * ncdf - npdf) * pvBar;
uBar[2] = (-(1 + alpha[0] * alpha[0]) / 2.0 * ncdf - (-2.0 * alpha0tilde + kappatilde) / 2.0 * npdf) * pvBar;
uBar[3] = ((alpha0tilde * alpha0tilde * alpha0tilde + 3.0 * alpha0tilde) / 6.0 * ncdf + (-3 * alpha0tilde * alpha0tilde + 3.0 * kappatilde * alpha0tilde - kappatilde * kappatilde - 2.0) / 6.0
* npdf)
* pvBar;
}
final double annuityBar = (swaption.getStrike() - rate) * uBar[0] - derivativesRate[0] * uBar[1] + -derivativesRate[1] * uBar[2];
final double[] derivativesAnnuityBar = new double[3];
derivativesAnnuityBar[0] = (swaption.getStrike() - rate) * derivativesRate[0] * uBar[1] + ((swaption.getStrike() - rate) * derivativesRate[1] - 2.0 * derivativesRate[0] * derivativesRate[0])
* uBar[2] + (-3 * derivativesRate[0] * derivativesRate[1] - 2 * derivativesRate[0] * derivativesRate[1] + (swaption.getStrike() - rate) * derivativesRate[2]) * uBar[3];
derivativesAnnuityBar[1] = (swaption.getStrike() - rate) * derivativesRate[0] * derivativesRate[0] * uBar[2]
+ (-3 * derivativesRate[0] * derivativesRate[0] * derivativesRate[0] + (swaption.getStrike() - rate) * 3 * derivativesRate[0] * derivativesRate[1]) * uBar[3];
derivativesAnnuityBar[2] = (swaption.getStrike() - rate) * derivativesRate[0] * derivativesRate[0] * derivativesRate[0] * uBar[3];
final double rateBar = (derivativesAnnuity[1] * derivativesAnnuityBar[0])
+ (derivativesAnnuity[2] * derivativesAnnuityBar[1])
+ (derivativesAnnuity[0] * annuityBar)
- (annuity * uBar[0])
- (derivativesAnnuity[0] * derivativesRate[0] * uBar[1])
- ((derivativesAnnuity[0] * derivativesRate[1] + derivativesAnnuity[1] * derivativesRate[0] * derivativesRate[0]) * uBar[2])
- (((derivativesAnnuity[0] * derivativesRate[2] + 3 * derivativesAnnuity[1] * derivativesRate[0] * derivativesRate[1] + derivativesAnnuity[2] * derivativesRate[0] * derivativesRate[0]
* derivativesRate[0]) + derivativesRate[2]) * uBar[3]);
final double[] derivativesRateBar = new double[3];
derivativesRateBar[0] = ((swaption.getStrike() - rate) * derivativesAnnuity[0] - annuity)
* uBar[1]
+ ((swaption.getStrike() - rate) * (2.0 * derivativesAnnuity[1] * derivativesRate[0]) - 4 * derivativesAnnuity[0] * derivativesRate[0])
* uBar[2]
+ (-3 * (derivativesAnnuity[0] * derivativesRate[1] + 3.0 * derivativesAnnuity[1] * derivativesRate[0] * derivativesRate[0]) - 2 * derivativesAnnuity[0] * derivativesRate[1] + (swaption
.getStrike() - rate) * (3 * derivativesAnnuity[1] * derivativesRate[1] + derivativesAnnuity[2] * 3.0 * derivativesRate[0] * derivativesRate[0])) * uBar[3];
derivativesRateBar[1] = ((swaption.getStrike() - rate) * (derivativesAnnuity[0]) - annuity) * uBar[2]
+ (-3 * derivativesRate[0] * (derivativesAnnuity[0]) - 2 * derivativesAnnuity[0] * derivativesRate[0] + (swaption.getStrike() - rate) * (3 * derivativesAnnuity[1] * derivativesRate[0]))
* uBar[3];
derivativesRateBar[2] = ((swaption.getStrike() - rate) * derivativesAnnuity[0] - rate) * uBar[3];
// double kappaBar = 0.0;
final double[] alphaFixedBar = new double[nbFixed];
final double[] alphaIborBar = new double[cfeIbor.getNumberOfPayments()];
swapRateAdjointAlpha(x0, discountedCashFlowFixed, alphaFixed, discountedCashFlowIbor, alphaIbor, rateBar, derivativesRateBar, derivativesRate, alphaFixedBar, alphaIborBar);
alphaIborBar[0] += kappatildeBar + alpha0tildeBar;
final double[] pvsensi = new double[parameters.getVolatility().length];
final double[] partialDerivatives = new double[parameters.getVolatility().length];
for (int loopcf = 0; loopcf < nbFixed; loopcf++) {
MODEL.alpha(parameters, 0.0, expiryTime, expiryTime, swaption.getUnderlyingSwap().getFixedLeg().getNthPayment(loopcf).getPaymentTime(), partialDerivatives);
for (int loopsigma = 0; loopsigma < parameters.getVolatility().length; loopsigma++) {
pvsensi[loopsigma] += alphaFixedBar[loopcf] * partialDerivatives[loopsigma];
}
}
for (int loopcf = 0; loopcf < cfe.getNumberOfPayments(); loopcf++) {
MODEL.alpha(parameters, 0.0, expiryTime, expiryTime, cfeIbor.getNthPayment(loopcf).getPaymentTime(), partialDerivatives);
for (int loopsigma = 0; loopsigma < parameters.getVolatility().length; loopsigma++) {
pvsensi[loopsigma] += alphaIborBar[loopcf] * partialDerivatives[loopsigma];
}
}