* @param black The market (all discounting and forward curves should be of the type YieldCurve with InterpolatedDoublesCurve.
* @return The parameter sensitivity.
*/
public MultipleCurrencyParameterSensitivity calculateSensitivity(final InstrumentDerivative instrument, final BlackSwaptionFlatProviderDiscount black) {
MultipleCurrencyParameterSensitivity result = new MultipleCurrencyParameterSensitivity();
final MultipleCurrencyAmount pvInit = instrument.accept(_valueCalculator, black);
final int nbCcy = pvInit.size();
final List<Currency> ccyList = new ArrayList<>();
for (int loopccy = 0; loopccy < nbCcy; loopccy++) {
ccyList.add(pvInit.getCurrencyAmounts()[loopccy].getCurrency());
}
// Discounting
final Set<Currency> ccyDiscounting = black.getMulticurveProvider().getCurrencies();
for (final Currency ccy : ccyDiscounting) {
final YieldAndDiscountCurve curve = black.getCurve(ccy);
ArgumentChecker.isTrue(curve instanceof YieldCurve, "Curve should be a YieldCurve");
final YieldCurve curveYield = (YieldCurve) curve;
ArgumentChecker.isTrue(curveYield.getCurve() instanceof InterpolatedDoublesCurve, "Yield curve should be based on InterpolatedDoublesCurve");
final InterpolatedDoublesCurve curveInt = (InterpolatedDoublesCurve) curveYield.getCurve();
final int nbNodePoint = curveInt.getXDataAsPrimitive().length;
final double[][] sensitivity = new double[nbCcy][nbNodePoint];
for (int loopnode = 0; loopnode < nbNodePoint; loopnode++) {
final double[] yieldBumpedPlus = curveInt.getYDataAsPrimitive().clone();
yieldBumpedPlus[loopnode] += _shift;
final YieldAndDiscountCurve dscBumpedPlus = new YieldCurve(curveInt.getName(), new InterpolatedDoublesCurve(curveInt.getXDataAsPrimitive(), yieldBumpedPlus, curveInt.getInterpolator(), true));
final BlackSwaptionFlatProviderDiscount marketDscBumpedPlus = new BlackSwaptionFlatProviderDiscount(black.getMulticurveProvider().withDiscountFactor(ccy, dscBumpedPlus),
black.getBlackParameters());
final MultipleCurrencyAmount pvBumpedPlus = instrument.accept(_valueCalculator, marketDscBumpedPlus);
final double[] yieldBumpedMinus = curveInt.getYDataAsPrimitive().clone();
yieldBumpedMinus[loopnode] -= _shift;
final YieldAndDiscountCurve dscBumpedMinus = new YieldCurve(curveInt.getName(),
new InterpolatedDoublesCurve(curveInt.getXDataAsPrimitive(), yieldBumpedMinus, curveInt.getInterpolator(), true));
final BlackSwaptionFlatProviderDiscount marketDscBumpedMinus = new BlackSwaptionFlatProviderDiscount(black.getMulticurveProvider().withDiscountFactor(ccy, dscBumpedMinus),
black.getBlackParameters());
final MultipleCurrencyAmount pvBumpedMinus = instrument.accept(_valueCalculator, marketDscBumpedMinus);
final MultipleCurrencyAmount pvDiff = pvBumpedPlus.plus(pvBumpedMinus.multipliedBy(-1.0));
for (int loopccypv = 0; loopccypv < nbCcy; loopccypv++) {
sensitivity[loopccypv][loopnode] = pvDiff.getAmount(ccyList.get(loopccypv)) / (2 * _shift);
}
}
final String name = black.getMulticurveProvider().getName(ccy);
for (int loopccypv = 0; loopccypv < nbCcy; loopccypv++) {
result = result.plus(new ObjectsPair<>(name, ccyList.get(loopccypv)), new DoubleMatrix1D(sensitivity[loopccypv]));
}
}
// Forward ON
final Set<IndexON> indexON = black.getMulticurveProvider().getIndexesON();
for (final IndexON index : indexON) {
final YieldAndDiscountCurve curve = black.getCurve(index);
ArgumentChecker.isTrue(curve instanceof YieldCurve, "Curve should be a YieldCurve");
final YieldCurve curveYield = (YieldCurve) curve;
ArgumentChecker.isTrue(curveYield.getCurve() instanceof InterpolatedDoublesCurve, "Yield curve should be based on InterpolatedDoublesCurve");
final InterpolatedDoublesCurve curveInt = (InterpolatedDoublesCurve) curveYield.getCurve();
final int nbNodePoint = curveInt.getXDataAsPrimitive().length;
final double[][] sensitivity = new double[nbCcy][nbNodePoint];
for (int loopnode = 0; loopnode < nbNodePoint; loopnode++) {
final double[] yieldBumpedPlus = curveInt.getYDataAsPrimitive().clone();
yieldBumpedPlus[loopnode] += _shift;
final YieldAndDiscountCurve dscBumpedPlus = new YieldCurve(curveInt.getName(), new InterpolatedDoublesCurve(curveInt.getXDataAsPrimitive(), yieldBumpedPlus, curveInt.getInterpolator(), true));
final BlackSwaptionFlatProviderDiscount marketFwdBumpedPlus = new BlackSwaptionFlatProviderDiscount(black.getMulticurveProvider().withForward(index, dscBumpedPlus),
black.getBlackParameters());
final MultipleCurrencyAmount pvBumpedPlus = instrument.accept(_valueCalculator, marketFwdBumpedPlus);
final double[] yieldBumpedMinus = curveInt.getYDataAsPrimitive().clone();
yieldBumpedMinus[loopnode] -= _shift;
final YieldAndDiscountCurve dscBumpedMinus = new YieldCurve(curveInt.getName(),
new InterpolatedDoublesCurve(curveInt.getXDataAsPrimitive(), yieldBumpedMinus, curveInt.getInterpolator(), true));
final BlackSwaptionFlatProviderDiscount marketFwdBumpedMinus = new BlackSwaptionFlatProviderDiscount(black.getMulticurveProvider().withForward(index, dscBumpedMinus),
black.getBlackParameters());
final MultipleCurrencyAmount pvBumpedMinus = instrument.accept(_valueCalculator, marketFwdBumpedMinus);
final MultipleCurrencyAmount pvDiff = pvBumpedPlus.plus(pvBumpedMinus.multipliedBy(-1.0));
for (int loopccypv = 0; loopccypv < nbCcy; loopccypv++) {
sensitivity[loopccypv][loopnode] = pvDiff.getAmount(ccyList.get(loopccypv)) / (2 * _shift);
}
}
final String name = black.getMulticurveProvider().getName(index);
for (int loopccypv = 0; loopccypv < nbCcy; loopccypv++) {
result = result.plus(new ObjectsPair<>(name, ccyList.get(loopccypv)), new DoubleMatrix1D(sensitivity[loopccypv]));
}
}
// Forward Ibor
final Set<IborIndex> indexForward = black.getMulticurveProvider().getIndexesIbor();
for (final IborIndex index : indexForward) {
final YieldAndDiscountCurve curve = black.getCurve(index);
ArgumentChecker.isTrue(curve instanceof YieldCurve, "Curve should be a YieldCurve");
final YieldCurve curveYield = (YieldCurve) curve;
ArgumentChecker.isTrue(curveYield.getCurve() instanceof InterpolatedDoublesCurve, "Yield curve should be based on InterpolatedDoublesCurve");
final InterpolatedDoublesCurve curveInt = (InterpolatedDoublesCurve) curveYield.getCurve();
final int nbNodePoint = curveInt.getXDataAsPrimitive().length;
final double[][] sensitivity = new double[nbCcy][nbNodePoint];
for (int loopnode = 0; loopnode < nbNodePoint; loopnode++) {
final double[] yieldBumpedPlus = curveInt.getYDataAsPrimitive().clone();
yieldBumpedPlus[loopnode] += _shift;
final YieldAndDiscountCurve dscBumpedPlus = new YieldCurve(curveInt.getName(), new InterpolatedDoublesCurve(curveInt.getXDataAsPrimitive(), yieldBumpedPlus, curveInt.getInterpolator(), true));
final BlackSwaptionFlatProviderDiscount marketFwdBumpedPlus = new BlackSwaptionFlatProviderDiscount(black.getMulticurveProvider().withForward(index, dscBumpedPlus),
black.getBlackParameters());
final MultipleCurrencyAmount pvBumpedPlus = instrument.accept(_valueCalculator, marketFwdBumpedPlus);
final double[] yieldBumpedMinus = curveInt.getYDataAsPrimitive().clone();
yieldBumpedMinus[loopnode] -= _shift;
final YieldAndDiscountCurve dscBumpedMinus = new YieldCurve(curveInt.getName(),
new InterpolatedDoublesCurve(curveInt.getXDataAsPrimitive(), yieldBumpedMinus, curveInt.getInterpolator(), true));
final BlackSwaptionFlatProviderDiscount marketFwdBumpedMinus = new BlackSwaptionFlatProviderDiscount(black.getMulticurveProvider().withForward(index, dscBumpedMinus),
black.getBlackParameters());
final MultipleCurrencyAmount pvBumpedMinus = instrument.accept(_valueCalculator, marketFwdBumpedMinus);
final MultipleCurrencyAmount pvDiff = pvBumpedPlus.plus(pvBumpedMinus.multipliedBy(-1.0));
for (int loopccypv = 0; loopccypv < nbCcy; loopccypv++) {
sensitivity[loopccypv][loopnode] = pvDiff.getAmount(ccyList.get(loopccypv)) / (2 * _shift);
}
}
final String name = black.getMulticurveProvider().getName(index);
for (int loopccypv = 0; loopccypv < nbCcy; loopccypv++) {
result = result.plus(new ObjectsPair<>(name, ccyList.get(loopccypv)), new DoubleMatrix1D(sensitivity[loopccypv]));