cpnCap[loopcpn][looppath] = cpn.getCapCoefficients()[0] * cpnRate[loopcpn - 1][looppath] + cpn.getCapCoefficients()[1] * ibor[loopcpn][looppath] + cpn.getCapCoefficients()[2];
cpnRate[loopcpn][looppath] = Math.min(Math.max(cpnFloor[loopcpn][looppath], cpnMain[loopcpn][looppath]), cpnCap[loopcpn][looppath]);
annuityPathValue[looppath] += cpnRate[loopcpn][looppath] * cpn.getPaymentYearFraction() * cpn.getNotional() * pathDiscountFactors[looppath][loopcpn][1];
}
} else {
final CouponIborGearing cpn = (CouponIborGearing) annuity.getNthPayment(loopcpn);
for (int looppath = 0; looppath < nbPath; looppath++) {
ibor[loopcpn][looppath] = (-impactAmount[0][0] * pathDiscountFactors[looppath][0][0] / (impactAmount[0][1] * pathDiscountFactors[looppath][0][1]) - 1.0) / cpn.getFixingAccrualFactor();
cpnRate[loopcpn][looppath] = cpn.getFactor() * ibor[loopcpn][looppath] + cpn.getSpread();
annuityPathValue[looppath] += cpnRate[loopcpn][looppath] * cpn.getPaymentYearFraction() * cpn.getNotional() * pathDiscountFactors[looppath][loopcpn][1];
}
}
}
}
for (int looppath = 0; looppath < nbPath; looppath++) {
price += annuityPathValue[looppath];
}
price = price / nbPath;
// Backward sweep
final double priceBar = 1.0;
final double[] annuityPathValueBar = new double[nbPath];
for (int looppath = 0; looppath < nbPath; looppath++) {
annuityPathValueBar[looppath] = 1.0 / nbPath * priceBar;
}
final double[][] impactAmountBar = new double[nbCpn][];
final double[][] cpnRateBar = new double[nbCpn][nbPath];
final double[][] iborBar = new double[nbCpn][nbPath];
final double[][] cpnMainBar = new double[nbCpn][nbPath];
final double[][] cpnFloorBar = new double[nbCpn][nbPath];
final double[][] cpnCapBar = new double[nbCpn][nbPath];
final Double[][][] pathDiscountFactorsBar = new Double[nbPath][nbCpn][];
for (int loopcpn = nbCpn - 1; loopcpn >= 0; loopcpn--) {
impactAmountBar[loopcpn] = new double[impactAmount[loopcpn].length];
for (int looppath = 0; looppath < nbPath; looppath++) {
pathDiscountFactorsBar[looppath][loopcpn] = new Double[impactAmount[loopcpn].length];
}
if (annuity.isFixed()[loopcpn]) { // Coupon already fixed: only one cash flow
for (int looppath = 0; looppath < nbPath; looppath++) {
impactAmountBar[loopcpn][0] += pathDiscountFactors[looppath][loopcpn][0] * annuityPathValueBar[looppath];
pathDiscountFactorsBar[looppath][loopcpn][0] = impactAmount[loopcpn][0] * annuityPathValueBar[looppath];
}
} else {
if (annuity.getNthPayment(loopcpn) instanceof CouponIborRatchet) {
final CouponIborRatchet cpn = (CouponIborRatchet) annuity.getNthPayment(loopcpn);
for (int looppath = 0; looppath < nbPath; looppath++) {
cpnRateBar[loopcpn][looppath] += cpn.getPaymentYearFraction() * cpn.getNotional() * pathDiscountFactors[looppath][loopcpn][1] * annuityPathValueBar[looppath];
cpnCapBar[loopcpn][looppath] = (cpnCap[loopcpn][looppath] < Math.max(cpnFloor[loopcpn][looppath], cpnMain[loopcpn][looppath]) ? 1.0 : 0.0) * cpnRateBar[loopcpn][looppath];
cpnFloorBar[loopcpn][looppath] = (cpnCap[loopcpn][looppath] >= Math.max(cpnFloor[loopcpn][looppath], cpnMain[loopcpn][looppath]) ? 1.0 : 0.0)
* (cpnFloor[loopcpn][looppath] > cpnMain[loopcpn][looppath] ? 1.0 : 0.0) * cpnRateBar[loopcpn][looppath];
cpnMainBar[loopcpn][looppath] = (cpnCap[loopcpn][looppath] >= Math.max(cpnFloor[loopcpn][looppath], cpnMain[loopcpn][looppath]) ? 1.0 : 0.0)
* (cpnFloor[loopcpn][looppath] <= cpnMain[loopcpn][looppath] ? 1.0 : 0.0) * cpnRateBar[loopcpn][looppath];
cpnRateBar[loopcpn - 1][looppath] += cpn.getCapCoefficients()[0] * cpnCapBar[loopcpn][looppath] + cpn.getFloorCoefficients()[0] * cpnFloorBar[loopcpn][looppath]
+ cpn.getMainCoefficients()[0] * cpnMainBar[loopcpn][looppath];
iborBar[loopcpn][looppath] = cpn.getMainCoefficients()[1] * cpnMainBar[loopcpn][looppath] + cpn.getFloorCoefficients()[1] * cpnFloorBar[loopcpn][looppath] + cpn.getCapCoefficients()[1]
* cpnCapBar[loopcpn][looppath];
impactAmountBar[loopcpn][0] += -pathDiscountFactors[looppath][loopcpn][0] / (impactAmount[loopcpn][1] * pathDiscountFactors[looppath][loopcpn][1]) / cpn.getFixingAccrualFactor()
* iborBar[loopcpn][looppath];
impactAmountBar[loopcpn][1] += impactAmount[loopcpn][0] * pathDiscountFactors[looppath][loopcpn][0] / pathDiscountFactors[looppath][loopcpn][1]
/ (impactAmount[loopcpn][1] * impactAmount[loopcpn][1]) / cpn.getFixingAccrualFactor() * iborBar[loopcpn][looppath];
pathDiscountFactorsBar[looppath][loopcpn][1] = cpnRate[loopcpn][looppath] * cpn.getPaymentYearFraction() * cpn.getNotional() * annuityPathValueBar[looppath];
pathDiscountFactorsBar[looppath][loopcpn][0] = -impactAmount[loopcpn][0] / (impactAmount[loopcpn][1] * pathDiscountFactors[looppath][loopcpn][1]) / cpn.getFixingAccrualFactor()
* iborBar[loopcpn][looppath];
pathDiscountFactorsBar[looppath][loopcpn][1] += impactAmount[loopcpn][0] * pathDiscountFactors[looppath][loopcpn][0] / impactAmount[loopcpn][1]
/ (pathDiscountFactors[looppath][loopcpn][1] * pathDiscountFactors[looppath][loopcpn][1]) / cpn.getFixingAccrualFactor() * iborBar[loopcpn][looppath];
}
} else {
final CouponIborGearing cpn = (CouponIborGearing) annuity.getNthPayment(loopcpn);
for (int looppath = 0; looppath < nbPath; looppath++) {
cpnRateBar[loopcpn][looppath] += cpn.getPaymentYearFraction() * cpn.getNotional() * pathDiscountFactors[looppath][loopcpn][1] * annuityPathValueBar[looppath];
iborBar[loopcpn][looppath] = cpn.getFactor() * cpnRateBar[loopcpn][looppath];
impactAmountBar[0][0] += -pathDiscountFactors[looppath][0][0] / (impactAmount[0][1] * pathDiscountFactors[looppath][0][1]) / cpn.getFixingAccrualFactor() * iborBar[loopcpn][looppath];
impactAmountBar[0][1] += impactAmount[0][0] * pathDiscountFactors[looppath][0][0] / pathDiscountFactors[looppath][0][1] / (impactAmount[0][1] * impactAmount[0][1])
/ cpn.getFixingAccrualFactor() * iborBar[loopcpn][looppath];
pathDiscountFactorsBar[looppath][loopcpn][1] = cpnRate[loopcpn][looppath] * cpn.getPaymentYearFraction() * cpn.getNotional() * annuityPathValueBar[looppath];
pathDiscountFactorsBar[looppath][0][0] = -impactAmount[0][0] / (impactAmount[0][1] * pathDiscountFactors[looppath][0][1]) / cpn.getFixingAccrualFactor() * iborBar[loopcpn][looppath];
pathDiscountFactorsBar[looppath][0][1] += impactAmount[0][0] * pathDiscountFactors[looppath][0][0] / impactAmount[0][1]
/ (pathDiscountFactors[looppath][0][1] * pathDiscountFactors[looppath][0][1]) / cpn.getFixingAccrualFactor() * iborBar[loopcpn][looppath];
}
}
}
}
mcResults.setImpactAmountDerivative(impactAmountBar);