Package com.opengamma.analytics.financial.interestrate.swaption.provider

Source Code of com.opengamma.analytics.financial.interestrate.swaption.provider.SwaptionPhysicalFixedIborSABRLMMExactMethod

/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.swaption.provider;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.opengamma.analytics.financial.interestrate.PresentValueSABRSensitivityDataBundle;
import com.opengamma.analytics.financial.interestrate.swaption.derivative.SwaptionPhysicalFixedIbor;
import com.opengamma.analytics.financial.interestrate.swaption.method.SwaptionPhysicalFixedIborBasketMethod;
import com.opengamma.analytics.financial.model.interestrate.definition.LiborMarketModelDisplacedDiffusionParameters;
import com.opengamma.analytics.financial.provider.calculator.sabrswaption.PresentValueCurveSensitivitySABRSwaptionCalculator;
import com.opengamma.analytics.financial.provider.calculator.sabrswaption.PresentValueSABRSensitivitySABRSwaptionCalculator;
import com.opengamma.analytics.financial.provider.calculator.sabrswaption.PresentValueSABRSwaptionCalculator;
import com.opengamma.analytics.financial.provider.description.interestrate.LiborMarketModelDisplacedDiffusionProvider;
import com.opengamma.analytics.financial.provider.description.interestrate.LiborMarketModelDisplacedDiffusionProviderInterface;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderInterface;
import com.opengamma.analytics.financial.provider.description.interestrate.SABRSwaptionProviderInterface;
import com.opengamma.analytics.financial.provider.method.SuccessiveRootFinderLMMDDCalibrationEngine;
import com.opengamma.analytics.financial.provider.method.SuccessiveRootFinderLMMDDCalibrationObjective;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyMulticurveSensitivity;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.matrix.CommonsMatrixAlgebra;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.CurrencyAmount;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.tuple.DoublesPair;

/**
* Method to computes the present value and sensitivities of physical delivery European swaptions with a Libor Market Model calibrated exactly to SABR prices.
* The LMM displacements and volatility weights are hard coded.
*/
public class SwaptionPhysicalFixedIborSABRLMMExactMethod {

  /**
   * The default mean reversion parameter for the model.
   */
  private static final double DEFAULT_MEAN_REVERSION = 0.01;
  /**
   * The default common displacement parameter for all rates in the model.
   */
  private static final double DEFAULT_DISPLACEMENT = 0.10;
  /**
   * The default parameter to create the weight on the different model volatilities.
   */
  private static final double DEFAULT_ANGLE = Math.PI / 2;
  // TODO: Create a way to pass the model parameters to the method.
  /**
   * The SABR method used for European swaptions with physical delivery.
   */
  private static final PresentValueSABRSwaptionCalculator PVSSC = PresentValueSABRSwaptionCalculator.getInstance();
  private static final PresentValueCurveSensitivitySABRSwaptionCalculator PVCSSSC = PresentValueCurveSensitivitySABRSwaptionCalculator.getInstance();
  private static final PresentValueSABRSensitivitySABRSwaptionCalculator PVSSSSC = PresentValueSABRSensitivitySABRSwaptionCalculator.getInstance();
  /**
   * The LMM method used for European swaptions with physical delivery.
   */
  private static final SwaptionPhysicalFixedIborLMMDDMethod METHOD_SWAPTION_LMM = SwaptionPhysicalFixedIborLMMDDMethod.getInstance();
  /**
   * The method used to create the calibration basket.
   */
  private static final SwaptionPhysicalFixedIborBasketMethod METHOD_BASKET = SwaptionPhysicalFixedIborBasketMethod.getInstance();

  /**
   * The method calibrates a LMM on a set of vanilla swaption priced with SABR. The set of vanilla swaptions is given by the CalibrationType.
   * The original swaption is priced with the calibrated LMM.
   * This should not be used for vanilla swaptions (the price is equal to the SABR price with a longer computation type and some approximation).
   * This is useful for non-standard swaptions like amortized swaptions.
   * @param swaption The swaption.
   * @param sabrData The SABR data.
   * @return The present value.
   */
  public MultipleCurrencyAmount presentValue(final SwaptionPhysicalFixedIbor swaption, final SABRSwaptionProviderInterface sabrData) {
    ArgumentChecker.notNull(swaption, "Swaption");
    ArgumentChecker.notNull(sabrData, "SABR swaption provider");
    final Currency ccy = swaption.getCurrency();
    final MulticurveProviderInterface multicurves = sabrData.getMulticurveProvider();
    //TODO: Create a way to chose the LMM base parameters (displacement, mean reversion, volatility).
    final LiborMarketModelDisplacedDiffusionParameters lmmParameters = LiborMarketModelDisplacedDiffusionParameters.from(swaption, DEFAULT_DISPLACEMENT, DEFAULT_MEAN_REVERSION, new VolatilityLMMAngle(
        DEFAULT_ANGLE, DEFAULT_DISPLACEMENT));
    final SuccessiveRootFinderLMMDDCalibrationObjective objective = new SuccessiveRootFinderLMMDDCalibrationObjective(lmmParameters, ccy);
    final SuccessiveRootFinderLMMDDCalibrationEngine<SABRSwaptionProviderInterface> calibrationEngine = new SuccessiveRootFinderLMMDDCalibrationEngine<>(objective);
    final SwaptionPhysicalFixedIbor[] swaptionCalibration = METHOD_BASKET.calibrationBasketFixedLegPeriod(swaption);
    calibrationEngine.addInstrument(swaptionCalibration, PVSSC);
    calibrationEngine.calibrate(sabrData);
    final LiborMarketModelDisplacedDiffusionProviderInterface lmm = new LiborMarketModelDisplacedDiffusionProvider(multicurves, lmmParameters, ccy);
    return MultipleCurrencyAmount.of(swaption.getCurrency(), METHOD_SWAPTION_LMM.presentValue(swaption, lmm).getAmount(ccy));
  }

  /**
   * The method calibrates a LMM on a set of vanilla swaption priced with SABR. The set of vanilla swaptions is given by the CalibrationType.
   * The SABR parameters sensitivities of the original swaption are calculated with LMM re-calibration.
   * @param swaption The swaption.
   * @param sabrData The SABR data.
   * @return The present value SABR parameters sensitivity.
   */
  public PresentValueSABRSensitivityDataBundle presentValueSABRSensitivity(final SwaptionPhysicalFixedIbor swaption, final SABRSwaptionProviderInterface sabrData) {
    ArgumentChecker.notNull(swaption, "Swaption");
    ArgumentChecker.notNull(sabrData, "SABR swaption provider");
    final Currency ccy = swaption.getCurrency();
    final MulticurveProviderInterface multicurves = sabrData.getMulticurveProvider();
    //TODO: Create a way to chose the LMM base parameters (displacement, mean reversion, volatility).
    final LiborMarketModelDisplacedDiffusionParameters lmmParameters = LiborMarketModelDisplacedDiffusionParameters.from(swaption, DEFAULT_DISPLACEMENT, DEFAULT_MEAN_REVERSION, new VolatilityLMMAngle(
        DEFAULT_ANGLE, DEFAULT_DISPLACEMENT));
    final SuccessiveRootFinderLMMDDCalibrationObjective objective = new SuccessiveRootFinderLMMDDCalibrationObjective(lmmParameters, ccy);
    final SuccessiveRootFinderLMMDDCalibrationEngine<SABRSwaptionProviderInterface> calibrationEngine = new SuccessiveRootFinderLMMDDCalibrationEngine<>(objective);
    final SwaptionPhysicalFixedIbor[] swaptionCalibration = METHOD_BASKET.calibrationBasketFixedLegPeriod(swaption);
    calibrationEngine.addInstrument(swaptionCalibration, PVSSC);
    calibrationEngine.calibrate(sabrData);
    final LiborMarketModelDisplacedDiffusionProviderInterface lmm = new LiborMarketModelDisplacedDiffusionProvider(multicurves, lmmParameters, ccy);
    // Risks
    final int nbCal = swaptionCalibration.length;
    final int nbFact = lmmParameters.getNbFactor();
    final List<Integer> instrumentIndex = calibrationEngine.getInstrumentIndex();
    final double[] dPvAmdLambda = new double[nbCal];
    final double[][][] dPvCaldGamma = new double[nbCal][][];
    final double[][] dPvCaldLambda = new double[nbCal][nbCal];
    final PresentValueSABRSensitivityDataBundle[] dPvCaldSABR = new PresentValueSABRSensitivityDataBundle[nbCal];
    final double[][] dPvAmdGamma = METHOD_SWAPTION_LMM.presentValueLMMSensitivity(swaption, lmm);
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      dPvCaldGamma[loopcal] = METHOD_SWAPTION_LMM.presentValueLMMSensitivity(swaptionCalibration[loopcal], lmm);
    }
    // Multiplicative-factor sensitivity
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      for (int loopperiod = instrumentIndex.get(loopcal); loopperiod < instrumentIndex.get(loopcal + 1); loopperiod++) {
        for (int loopfact = 0; loopfact < nbFact; loopfact++) {
          dPvAmdLambda[loopcal] += dPvAmdGamma[loopperiod][loopfact] * lmmParameters.getVolatility()[loopperiod][loopfact];
        }
      }
    }
    for (int loopcal1 = 0; loopcal1 < nbCal; loopcal1++) {
      for (int loopcal2 = 0; loopcal2 < nbCal; loopcal2++) {
        for (int loopperiod = instrumentIndex.get(loopcal2); loopperiod < instrumentIndex.get(loopcal2 + 1); loopperiod++) {
          for (int loopfact = 0; loopfact < nbFact; loopfact++) {
            dPvCaldLambda[loopcal1][loopcal2] += dPvCaldGamma[loopcal1][loopperiod][loopfact] * lmmParameters.getVolatility()[loopperiod][loopfact];
          }
        }
      }
    }
    final CommonsMatrixAlgebra matrix = new CommonsMatrixAlgebra();
    final DoubleMatrix2D dPvCaldLambdaMatrix = new DoubleMatrix2D(dPvCaldLambda);
    final DoubleMatrix2D dPvCaldLambdaMatrixInverse = matrix.getInverse(dPvCaldLambdaMatrix);
    // SABR sensitivity
    final double[][] dPvCaldAlpha = new double[nbCal][nbCal];
    final double[][] dPvCaldRho = new double[nbCal][nbCal];
    final double[][] dPvCaldNu = new double[nbCal][nbCal];
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      dPvCaldSABR[loopcal] = swaptionCalibration[loopcal].accept(PVSSSSC, sabrData);
      final Set<DoublesPair> keySet = dPvCaldSABR[loopcal].getAlpha().getMap().keySet();
      final DoublesPair[] keys = keySet.toArray(new DoublesPair[keySet.size()]);
      dPvCaldAlpha[loopcal][loopcal] = dPvCaldSABR[loopcal].getAlpha().getMap().get(keys[0]);
      dPvCaldRho[loopcal][loopcal] = dPvCaldSABR[loopcal].getRho().getMap().get(keys[0]);
      dPvCaldNu[loopcal][loopcal] = dPvCaldSABR[loopcal].getNu().getMap().get(keys[0]);
    }
    final DoubleMatrix1D dPvAmdLambdaMatrix = new DoubleMatrix1D(dPvAmdLambda);
    final DoubleMatrix2D dPvCaldAlphaMatrix = new DoubleMatrix2D(dPvCaldAlpha);
    final DoubleMatrix2D dLambdadAlphaMatrix = (DoubleMatrix2D) matrix.multiply(dPvCaldLambdaMatrixInverse, dPvCaldAlphaMatrix);
    final DoubleMatrix2D dPvAmdAlphaMatrix = (DoubleMatrix2D) matrix.multiply(matrix.getTranspose(dLambdadAlphaMatrix), dPvAmdLambdaMatrix);
    final DoubleMatrix2D dPvCaldRhoMatrix = new DoubleMatrix2D(dPvCaldRho);
    final DoubleMatrix2D dLambdadRhoMatrix = (DoubleMatrix2D) matrix.multiply(dPvCaldLambdaMatrixInverse, dPvCaldRhoMatrix);
    final DoubleMatrix2D dPvAmdRhoMatrix = (DoubleMatrix2D) matrix.multiply(matrix.getTranspose(dLambdadRhoMatrix), dPvAmdLambdaMatrix);
    final DoubleMatrix2D dPvCaldNuMatrix = new DoubleMatrix2D(dPvCaldNu);
    final DoubleMatrix2D dLambdadNuMatrix = (DoubleMatrix2D) matrix.multiply(dPvCaldLambdaMatrixInverse, dPvCaldNuMatrix);
    final DoubleMatrix2D dPvAmdNuMatrix = (DoubleMatrix2D) matrix.multiply(matrix.getTranspose(dLambdadNuMatrix), dPvAmdLambdaMatrix);
    final double[] dPvAmdAlpha = matrix.getTranspose(dPvAmdAlphaMatrix).getData()[0];
    final double[] dPvAmdRho = matrix.getTranspose(dPvAmdRhoMatrix).getData()[0];
    final double[] dPvAmdNu = matrix.getTranspose(dPvAmdNuMatrix).getData()[0];
    // Storage in PresentValueSABRSensitivityDataBundle
    final PresentValueSABRSensitivityDataBundle sensi = new PresentValueSABRSensitivityDataBundle();
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      final DoublesPair expiryMaturity = new DoublesPair(swaptionCalibration[loopcal].getTimeToExpiry(), swaptionCalibration[loopcal].getMaturityTime());
      sensi.addAlpha(expiryMaturity, dPvAmdAlpha[loopcal]);
      sensi.addRho(expiryMaturity, dPvAmdRho[loopcal]);
      sensi.addNu(expiryMaturity, dPvAmdNu[loopcal]);
    }
    return sensi;
  }

  /**
   * The method calibrates a LMM on a set of vanilla swaption priced with SABR. The set of vanilla swaptions is given by the CalibrationType.
   * The curve sensitivities of the original swaption are calculated with LMM re-calibration.
   * @param swaption The swaption.
   * @param sabrData The SABR data.
   * @return The present value curve sensitivities.
   */
  public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final SwaptionPhysicalFixedIbor swaption, final SABRSwaptionProviderInterface sabrData) {
    ArgumentChecker.notNull(swaption, "Swaption");
    ArgumentChecker.notNull(sabrData, "SABR swaption provider");
    final Currency ccy = swaption.getCurrency();
    final MulticurveProviderInterface multicurves = sabrData.getMulticurveProvider();
    //TODO: Create a way to chose the LMM base parameters (displacement, mean reversion, volatility).
    final LiborMarketModelDisplacedDiffusionParameters lmmParameters = LiborMarketModelDisplacedDiffusionParameters.from(swaption, DEFAULT_DISPLACEMENT, DEFAULT_MEAN_REVERSION, new VolatilityLMMAngle(
        DEFAULT_ANGLE, DEFAULT_DISPLACEMENT));
    final SuccessiveRootFinderLMMDDCalibrationObjective objective = new SuccessiveRootFinderLMMDDCalibrationObjective(lmmParameters, ccy);
    final SuccessiveRootFinderLMMDDCalibrationEngine<SABRSwaptionProviderInterface> calibrationEngine = new SuccessiveRootFinderLMMDDCalibrationEngine<>(objective);
    final SwaptionPhysicalFixedIbor[] swaptionCalibration = METHOD_BASKET.calibrationBasketFixedLegPeriod(swaption);
    calibrationEngine.addInstrument(swaptionCalibration, PVSSC);
    calibrationEngine.calibrate(sabrData);
    final LiborMarketModelDisplacedDiffusionProviderInterface lmm = new LiborMarketModelDisplacedDiffusionProvider(multicurves, lmmParameters, ccy);
    // Risks
    final int nbCal = swaptionCalibration.length;
    final int nbFact = lmmParameters.getNbFactor();
    final List<Integer> instrumentIndex = calibrationEngine.getInstrumentIndex();
    final double[] dPvAmdLambda = new double[nbCal];
    final double[][][] dPvCaldGamma = new double[nbCal][][];
    final double[][] dPvCaldLambda = new double[nbCal][nbCal];
    MultipleCurrencyMulticurveSensitivity pvcsCal = METHOD_SWAPTION_LMM.presentValueCurveSensitivity(swaption, lmm);
    pvcsCal = pvcsCal.cleaned();
    final double[][] dPvAmdGamma = METHOD_SWAPTION_LMM.presentValueLMMSensitivity(swaption, lmm);
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      dPvCaldGamma[loopcal] = METHOD_SWAPTION_LMM.presentValueLMMSensitivity(swaptionCalibration[loopcal], lmm);
    }
    // Multiplicative-factor sensitivity
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      for (int loopperiod = instrumentIndex.get(loopcal); loopperiod < instrumentIndex.get(loopcal + 1); loopperiod++) {
        for (int loopfact = 0; loopfact < nbFact; loopfact++) {
          dPvAmdLambda[loopcal] += dPvAmdGamma[loopperiod][loopfact] * lmmParameters.getVolatility()[loopperiod][loopfact];
        }
      }
    }
    for (int loopcal1 = 0; loopcal1 < nbCal; loopcal1++) {
      for (int loopcal2 = 0; loopcal2 < nbCal; loopcal2++) {
        for (int loopperiod = instrumentIndex.get(loopcal2); loopperiod < instrumentIndex.get(loopcal2 + 1); loopperiod++) {
          for (int loopfact = 0; loopfact < nbFact; loopfact++) {
            dPvCaldLambda[loopcal1][loopcal2] += dPvCaldGamma[loopcal1][loopperiod][loopfact] * lmmParameters.getVolatility()[loopperiod][loopfact];
          }
        }
      }
    }
    final MultipleCurrencyMulticurveSensitivity[] pvcsCalBase = new MultipleCurrencyMulticurveSensitivity[nbCal];
    final MultipleCurrencyMulticurveSensitivity[] pvcsCalCal = new MultipleCurrencyMulticurveSensitivity[nbCal];
    final MultipleCurrencyMulticurveSensitivity[] pvcsCalDiff = new MultipleCurrencyMulticurveSensitivity[nbCal];
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      pvcsCalBase[loopcal] = swaptionCalibration[loopcal].accept(PVCSSSC, sabrData);
      pvcsCalBase[loopcal] = pvcsCalBase[loopcal].cleaned();
      pvcsCalCal[loopcal] = METHOD_SWAPTION_LMM.presentValueCurveSensitivity(swaptionCalibration[loopcal], lmm);
      pvcsCalCal[loopcal] = pvcsCalCal[loopcal].cleaned();
      pvcsCalDiff[loopcal] = pvcsCalBase[loopcal].plus(pvcsCalCal[loopcal].multipliedBy(-1));
      pvcsCalDiff[loopcal] = pvcsCalDiff[loopcal].cleaned();
    }
    final CommonsMatrixAlgebra matrix = new CommonsMatrixAlgebra();
    final DoubleMatrix2D dPvCaldLambdaMatrix = new DoubleMatrix2D(dPvCaldLambda);
    final DoubleMatrix2D dPvCaldLambdaMatrixInverse = matrix.getInverse(dPvCaldLambdaMatrix);
    // Curve sensitivity
    final MultipleCurrencyMulticurveSensitivity[] dLambdadC = new MultipleCurrencyMulticurveSensitivity[nbCal];
    for (int loopcal1 = 0; loopcal1 < nbCal; loopcal1++) {
      dLambdadC[loopcal1] = new MultipleCurrencyMulticurveSensitivity();
      for (int loopcal2 = 0; loopcal2 <= loopcal1; loopcal2++) {
        dLambdadC[loopcal1] = dLambdadC[loopcal1].plus(pvcsCalDiff[loopcal2].multipliedBy(dPvCaldLambdaMatrixInverse.getEntry(loopcal1, loopcal2)));
      }
    }
    MultipleCurrencyMulticurveSensitivity pvcsAdjust = new MultipleCurrencyMulticurveSensitivity();
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      pvcsAdjust = pvcsAdjust.plus(dLambdadC[loopcal].multipliedBy(dPvAmdLambda[loopcal]));
    }
    pvcsAdjust = pvcsAdjust.cleaned();
    MultipleCurrencyMulticurveSensitivity pvcsTot = pvcsCal.plus(pvcsAdjust);
    pvcsTot = pvcsTot.cleaned();
    return pvcsTot;
  }

  private static final class VolatilityLMMAngle extends Function1D<Double, Double[]> {
    /**
     * The angle between the factors: factor 1 weight is cos(angle*t/20) and factor 2 weight is sin(angle*t/20).
     * For the angle = 0, there is only one factor. For angle = pi/2, the 0Y rate is independent of the 20Y rate.
     */
    private final double _angle;
    private final double _displacement;

    public VolatilityLMMAngle(final double angle, final double displacement) {
      _angle = angle;
      _displacement = displacement;
    }

    @Override
    public Double[] evaluate(final Double x) {
      final Double[] result = new Double[2];
      result[0] = 0.01 / (_displacement + 0.05) * Math.cos(x / 20.0 * _angle);
      result[1] = 0.01 / (_displacement + 0.05) * Math.sin(x / 20.0 * _angle);
      // Implementation note: the initial value are chosen to have a 20% Black vol at 5% rate level.
      return result;
    }
  }

  /**
   * The method calibrates a LMM on a set of vanilla swaption priced with SABR. The set of vanilla swaptions is given by the CalibrationType.
   * The curve and SABR sensitivities of the original swaption are calculated with LMM re-calibration.
   * Used mainly for performance test purposes as the output is hybrid list.
   * @param swaption The swaption.
   * @param sabrData The SABR data.
   * @return The results (returned as a list of objects) [0] the present value, [1] the present curve sensitivity, [2] the present value SABR sensitivity.
   */
  public List<Object> presentValueCurveSABRSensitivity(final SwaptionPhysicalFixedIbor swaption, final SABRSwaptionProviderInterface sabrData) {
    ArgumentChecker.notNull(swaption, "Swaption");
    ArgumentChecker.notNull(sabrData, "SABR swaption provider");
    final Currency ccy = swaption.getCurrency();
    final MulticurveProviderInterface multicurves = sabrData.getMulticurveProvider();
    //TODO: Create a way to chose the LMM base parameters (displacement, mean reversion, volatility).
    final LiborMarketModelDisplacedDiffusionParameters lmmParameters = LiborMarketModelDisplacedDiffusionParameters.from(swaption, DEFAULT_DISPLACEMENT, DEFAULT_MEAN_REVERSION, new VolatilityLMMAngle(
        DEFAULT_ANGLE, DEFAULT_DISPLACEMENT));
    final SuccessiveRootFinderLMMDDCalibrationObjective objective = new SuccessiveRootFinderLMMDDCalibrationObjective(lmmParameters, ccy);
    final SuccessiveRootFinderLMMDDCalibrationEngine<SABRSwaptionProviderInterface> calibrationEngine = new SuccessiveRootFinderLMMDDCalibrationEngine<>(objective);
    final SwaptionPhysicalFixedIbor[] swaptionCalibration = METHOD_BASKET.calibrationBasketFixedLegPeriod(swaption);
    calibrationEngine.addInstrument(swaptionCalibration, PVSSC);
    calibrationEngine.calibrate(sabrData);
    final LiborMarketModelDisplacedDiffusionProviderInterface lmm = new LiborMarketModelDisplacedDiffusionProvider(multicurves, lmmParameters, ccy);
    // Risks
    final int nbCal = swaptionCalibration.length;
    final int nbFact = lmmParameters.getNbFactor();
    final List<Integer> instrumentIndex = calibrationEngine.getInstrumentIndex();
    final double[] dPvAmdLambda = new double[nbCal];
    final double[][][] dPvCaldGamma = new double[nbCal][][];
    final double[][] dPvCaldLambda = new double[nbCal][nbCal];
    final PresentValueSABRSensitivityDataBundle[] dPvCaldSABR = new PresentValueSABRSensitivityDataBundle[nbCal];
    MultipleCurrencyMulticurveSensitivity pvcsCal = METHOD_SWAPTION_LMM.presentValueCurveSensitivity(swaption, lmm);
    pvcsCal = pvcsCal.cleaned();
    final double[][] dPvAmdGamma = METHOD_SWAPTION_LMM.presentValueLMMSensitivity(swaption, lmm);
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      dPvCaldGamma[loopcal] = METHOD_SWAPTION_LMM.presentValueLMMSensitivity(swaptionCalibration[loopcal], lmm);
    }
    // Multiplicative-factor sensitivity
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      for (int loopperiod = instrumentIndex.get(loopcal); loopperiod < instrumentIndex.get(loopcal + 1); loopperiod++) {
        for (int loopfact = 0; loopfact < nbFact; loopfact++) {
          dPvAmdLambda[loopcal] += dPvAmdGamma[loopperiod][loopfact] * lmmParameters.getVolatility()[loopperiod][loopfact];
        }
      }
    }
    for (int loopcal1 = 0; loopcal1 < nbCal; loopcal1++) {
      for (int loopcal2 = 0; loopcal2 < nbCal; loopcal2++) {
        for (int loopperiod = instrumentIndex.get(loopcal2); loopperiod < instrumentIndex.get(loopcal2 + 1); loopperiod++) {
          for (int loopfact = 0; loopfact < nbFact; loopfact++) {
            dPvCaldLambda[loopcal1][loopcal2] += dPvCaldGamma[loopcal1][loopperiod][loopfact] * lmmParameters.getVolatility()[loopperiod][loopfact];
          }
        }
      }
    }
    final MultipleCurrencyMulticurveSensitivity[] pvcsCalBase = new MultipleCurrencyMulticurveSensitivity[nbCal];
    final MultipleCurrencyMulticurveSensitivity[] pvcsCalCal = new MultipleCurrencyMulticurveSensitivity[nbCal];
    final MultipleCurrencyMulticurveSensitivity[] pvcsCalDiff = new MultipleCurrencyMulticurveSensitivity[nbCal];
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      pvcsCalBase[loopcal] = swaptionCalibration[loopcal].accept(PVCSSSC, sabrData);
      pvcsCalBase[loopcal] = pvcsCalBase[loopcal].cleaned();
      pvcsCalCal[loopcal] = METHOD_SWAPTION_LMM.presentValueCurveSensitivity(swaptionCalibration[loopcal], lmm);
      pvcsCalCal[loopcal] = pvcsCalCal[loopcal].cleaned();
      pvcsCalDiff[loopcal] = pvcsCalBase[loopcal].plus(pvcsCalCal[loopcal].multipliedBy(-1));
      pvcsCalDiff[loopcal] = pvcsCalDiff[loopcal].cleaned();
    }
    final CommonsMatrixAlgebra matrix = new CommonsMatrixAlgebra();
    final DoubleMatrix2D dPvCaldLambdaMatrix = new DoubleMatrix2D(dPvCaldLambda);
    final DoubleMatrix2D dPvCaldLambdaMatrixInverse = matrix.getInverse(dPvCaldLambdaMatrix);
    // SABR sensitivity
    final double[][] dPvCaldAlpha = new double[nbCal][nbCal];
    final double[][] dPvCaldRho = new double[nbCal][nbCal];
    final double[][] dPvCaldNu = new double[nbCal][nbCal];
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      dPvCaldSABR[loopcal] = swaptionCalibration[loopcal].accept(PVSSSSC, sabrData);
      final Set<DoublesPair> keySet = dPvCaldSABR[loopcal].getAlpha().getMap().keySet();
      final DoublesPair[] keys = keySet.toArray(new DoublesPair[keySet.size()]);
      dPvCaldAlpha[loopcal][loopcal] = dPvCaldSABR[loopcal].getAlpha().getMap().get(keys[0]);
      dPvCaldRho[loopcal][loopcal] = dPvCaldSABR[loopcal].getRho().getMap().get(keys[0]);
      dPvCaldNu[loopcal][loopcal] = dPvCaldSABR[loopcal].getNu().getMap().get(keys[0]);
    }
    final DoubleMatrix1D dPvAmdLambdaMatrix = new DoubleMatrix1D(dPvAmdLambda);
    final DoubleMatrix2D dPvCaldAlphaMatrix = new DoubleMatrix2D(dPvCaldAlpha);
    final DoubleMatrix2D dLambdadAlphaMatrix = (DoubleMatrix2D) matrix.multiply(dPvCaldLambdaMatrixInverse, dPvCaldAlphaMatrix);
    final DoubleMatrix2D dPvAmdAlphaMatrix = (DoubleMatrix2D) matrix.multiply(matrix.getTranspose(dLambdadAlphaMatrix), dPvAmdLambdaMatrix);
    final DoubleMatrix2D dPvCaldRhoMatrix = new DoubleMatrix2D(dPvCaldRho);
    final DoubleMatrix2D dLambdadRhoMatrix = (DoubleMatrix2D) matrix.multiply(dPvCaldLambdaMatrixInverse, dPvCaldRhoMatrix);
    final DoubleMatrix2D dPvAmdRhoMatrix = (DoubleMatrix2D) matrix.multiply(matrix.getTranspose(dLambdadRhoMatrix), dPvAmdLambdaMatrix);
    final DoubleMatrix2D dPvCaldNuMatrix = new DoubleMatrix2D(dPvCaldNu);
    final DoubleMatrix2D dLambdadNuMatrix = (DoubleMatrix2D) matrix.multiply(dPvCaldLambdaMatrixInverse, dPvCaldNuMatrix);
    final DoubleMatrix2D dPvAmdNuMatrix = (DoubleMatrix2D) matrix.multiply(matrix.getTranspose(dLambdadNuMatrix), dPvAmdLambdaMatrix);
    final double[] dPvAmdAlpha = matrix.getTranspose(dPvAmdAlphaMatrix).getData()[0];
    final double[] dPvAmdRho = matrix.getTranspose(dPvAmdRhoMatrix).getData()[0];
    final double[] dPvAmdNu = matrix.getTranspose(dPvAmdNuMatrix).getData()[0];
    // Storage in PresentValueSABRSensitivityDataBundle
    final PresentValueSABRSensitivityDataBundle pvss = new PresentValueSABRSensitivityDataBundle();
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      final DoublesPair expiryMaturity = new DoublesPair(swaptionCalibration[loopcal].getTimeToExpiry(), swaptionCalibration[loopcal].getMaturityTime());
      pvss.addAlpha(expiryMaturity, dPvAmdAlpha[loopcal]);
      pvss.addRho(expiryMaturity, dPvAmdRho[loopcal]);
      pvss.addNu(expiryMaturity, dPvAmdNu[loopcal]);
    }
    // Curve sensitivity
    final MultipleCurrencyMulticurveSensitivity[] dLambdadC = new MultipleCurrencyMulticurveSensitivity[nbCal];
    for (int loopcal1 = 0; loopcal1 < nbCal; loopcal1++) {
      dLambdadC[loopcal1] = new MultipleCurrencyMulticurveSensitivity();
      for (int loopcal2 = 0; loopcal2 <= loopcal1; loopcal2++) {
        dLambdadC[loopcal1] = dLambdadC[loopcal1].plus(pvcsCalDiff[loopcal2].multipliedBy(dPvCaldLambdaMatrixInverse.getEntry(loopcal1, loopcal2)));
      }
    }
    MultipleCurrencyMulticurveSensitivity pvcs = new MultipleCurrencyMulticurveSensitivity();
    for (int loopcal = 0; loopcal < nbCal; loopcal++) {
      pvcs = pvcs.plus(dLambdadC[loopcal].multipliedBy(dPvAmdLambda[loopcal]));
    }
    pvcs = pvcs.plus(pvcsCal);
    pvcs = pvcs.cleaned();
    final List<Object> results = new ArrayList<>();
    results.add(CurrencyAmount.of(swaption.getCurrency(), METHOD_SWAPTION_LMM.presentValue(swaption, lmm).getAmount(ccy)));
    results.add(pvcs);
    results.add(pvss);
    return results;
  }

}
TOP

Related Classes of com.opengamma.analytics.financial.interestrate.swaption.provider.SwaptionPhysicalFixedIborSABRLMMExactMethod

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.