/**
  * @param date The valuation date, not null
  * @param indexFixingTS The index fixing time series, not null
  * @param settlementDate The settlement date, not null
  * @param yieldCurveNames The yield curve names, not null, must have at least two entries
  * @return The security
  * @deprecated Use the version that does not take curve names
  */
 @Deprecated
 public BondIborSecurity toDerivative(
     final ZonedDateTime date,
     final DoubleTimeSeries<ZonedDateTime> indexFixingTS,
     final ZonedDateTime settlementDate,
     final String... yieldCurveNames) {
   // Implementation note: First yield curve used for coupon and notional (credit), the second for
   // risk free settlement.
   ArgumentChecker.notNull(date, "date");
   ArgumentChecker.notNull(indexFixingTS, "fixing time series");
   ArgumentChecker.notNull(settlementDate, "settlement date");
   ArgumentChecker.notNull(yieldCurveNames, "yield curve names");
   ArgumentChecker.isTrue(yieldCurveNames.length > 1, "at least two curves required");
   final String creditCurveName = yieldCurveNames[0];
   final String riskFreeCurveName = yieldCurveNames[1];
   double settlementTime;
   if (settlementDate.isBefore(date)) {
     settlementTime = 0.0;
   } else {
     settlementTime = TimeCalculator.getTimeBetween(date, settlementDate);
   }
   final AnnuityPaymentFixed nominal =
       (AnnuityPaymentFixed) getNominal().toDerivative(date, creditCurveName);
   final Annuity<Coupon> coupon =
       (Annuity<Coupon>) getCoupons().toDerivative(date, indexFixingTS, yieldCurveNames);
   return new BondIborSecurity(
       nominal.trimBefore(settlementTime),
       coupon.trimBefore(settlementTime),
       settlementTime,
       riskFreeCurveName);
 }
 @Test
 /** Test the present value. */
 public void presentValueExplicit() {
   final MultipleCurrencyAmount pv = METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
   final double timeToExpiry = SWAPTION_LONG_PAYER.getTimeToExpiry();
   final AnnuityPaymentFixed cfe =
       CFEC.visitSwap(SWAPTION_LONG_PAYER.getUnderlyingSwap(), MULTICURVES);
   final int numberOfPayments = cfe.getNumberOfPayments();
   final double alpha[] = new double[numberOfPayments];
   final double disccf[] = new double[numberOfPayments];
   for (int loopcf = 0; loopcf < numberOfPayments; loopcf++) {
     alpha[loopcf] =
         MODEL.alpha(
             HW_PARAMETERS,
             0.0,
             timeToExpiry,
             timeToExpiry,
             cfe.getNthPayment(loopcf).getPaymentTime());
     disccf[loopcf] =
         MULTICURVES.getDiscountFactor(EUR, cfe.getNthPayment(loopcf).getPaymentTime())
             * cfe.getNthPayment(loopcf).getAmount();
   }
   final double kappa = MODEL.kappa(disccf, alpha);
   double pvExpected = 0.0;
   for (int loopcf = 0; loopcf < numberOfPayments; loopcf++) {
     pvExpected += disccf[loopcf] * NORMAL.getCDF(-kappa - alpha[loopcf]);
   }
   assertEquals(
       "Swaption physical - Hull-White - present value", pvExpected, pv.getAmount(EUR), 1E-2);
   final MultipleCurrencyAmount pv2 =
       METHOD_HW.presentValue(SWAPTION_LONG_PAYER, cfe, HW_MULTICURVES);
   assertEquals("Swaption physical - Hull-White - present value", pv, pv2);
 }
 @Override
 public DecisionSchedule visitSwaptionCashFixedIbor(
     final SwaptionCashFixedIbor swaption, final MulticurveProviderInterface multicurves) {
   final double[] decisionTime = new double[] {swaption.getTimeToExpiry()};
   final AnnuityPaymentFixed cfeIbor =
       swaption.getUnderlyingSwap().getSecondLeg().accept(CFEC, multicurves);
   final int nbCfeIbor = cfeIbor.getNumberOfPayments();
   final int nbCpnFixed = swaption.getUnderlyingSwap().getFixedLeg().getNumberOfPayments();
   final double[][] impactTime = new double[1][nbCpnFixed + nbCfeIbor];
   final double[][] impactAmount = new double[1][nbCpnFixed + nbCfeIbor];
   // Fixed leg
   for (int loopcf = 0; loopcf < nbCpnFixed; loopcf++) {
     impactTime[0][loopcf] =
         swaption.getUnderlyingSwap().getFixedLeg().getNthPayment(loopcf).getPaymentTime();
     impactAmount[0][loopcf] =
         swaption.getUnderlyingSwap().getFixedLeg().getNthPayment(loopcf).getPaymentYearFraction()
             * swaption.getUnderlyingSwap().getFixedLeg().getNthPayment(loopcf).getNotional();
   }
   // Ibor leg
   for (int loopcf = 0; loopcf < nbCfeIbor; loopcf++) {
     impactTime[0][nbCpnFixed + loopcf] = cfeIbor.getNthPayment(loopcf).getPaymentTime();
     impactAmount[0][nbCpnFixed + loopcf] = cfeIbor.getNthPayment(loopcf).getAmount();
   }
   final DecisionSchedule decision = new DecisionSchedule(decisionTime, impactTime, impactAmount);
   return decision;
 }
 /**
  * @param date The valuation date, not null
  * @param indexFixingTS The index fixing time series, not null
  * @param settlementDate The settlement date, not null
  * @return The security
  */
 public BondIborSecurity toDerivative(
     final ZonedDateTime date,
     final DoubleTimeSeries<ZonedDateTime> indexFixingTS,
     final ZonedDateTime settlementDate) {
   ArgumentChecker.notNull(date, "date");
   ArgumentChecker.notNull(indexFixingTS, "fixing time series");
   ArgumentChecker.notNull(settlementDate, "settlement date");
   double settlementTime;
   if (settlementDate.isBefore(date)) {
     settlementTime = 0.0;
   } else {
     settlementTime = TimeCalculator.getTimeBetween(date, settlementDate);
   }
   final AnnuityPaymentFixed nominal = (AnnuityPaymentFixed) getNominal().toDerivative(date);
   final Annuity<Coupon> coupon = (Annuity<Coupon>) getCoupons().toDerivative(date, indexFixingTS);
   return new BondIborSecurity(
       nominal.trimBefore(settlementTime), coupon.trimBefore(settlementTime), settlementTime);
 }
 /**
  * Computes the present value of the Physical delivery swaption.
  *
  * @param swaption The swaption.
  * @param hwData The Hull-White parameters and the curves.
  * @return The present value.
  */
 public CurrencyAmount presentValue(
     final SwaptionPhysicalFixedIbor swaption,
     final HullWhiteOneFactorPiecewiseConstantDataBundle hwData) {
   Validate.notNull(swaption);
   Validate.notNull(hwData);
   final double expiryTime = swaption.getTimeToExpiry();
   final AnnuityPaymentFixed cfe = swaption.getUnderlyingSwap().accept(CFEC, hwData);
   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(
             hwData.getHullWhiteParameter(),
             0.0,
             expiryTime,
             expiryTime,
             cfe.getNthPayment(loopcf).getPaymentTime());
     df[loopcf] =
         hwData
             .getCurve(cfe.getDiscountCurve())
             .getDiscountFactor(cfe.getNthPayment(loopcf).getPaymentTime());
     discountedCashFlow[loopcf] = df[loopcf] * cfe.getNthPayment(loopcf).getAmount();
   }
   // Integration
   final SwaptionIntegrant integrant = new SwaptionIntegrant(discountedCashFlow, alpha);
   final double limit = 10.0;
   final double absoluteTolerance = 1.0E-2;
   final double relativeTolerance = 1.0E-6;
   final RungeKuttaIntegrator1D integrator =
       new RungeKuttaIntegrator1D(absoluteTolerance, relativeTolerance, NB_INTEGRATION);
   double pv = 0.0;
   try {
     pv =
         1.0
             / Math.sqrt(2.0 * Math.PI)
             * integrator.integrate(integrant, -limit, limit)
             * (swaption.isLong() ? 1.0 : -1.0);
   } catch (final Exception e) {
     throw new RuntimeException(e);
   }
   return CurrencyAmount.of(swaption.getCurrency(), pv);
 }
 @Override
 public DecisionSchedule visitSwaptionPhysicalFixedIbor(
     final SwaptionPhysicalFixedIbor swaption, final MulticurveProviderInterface multicurves) {
   final double[] decisionTime = new double[] {swaption.getTimeToExpiry()};
   final AnnuityPaymentFixed cfe = swaption.getUnderlyingSwap().accept(CFEC, multicurves);
   final double[][] impactTime = new double[1][cfe.getNumberOfPayments()];
   final double[][] impactAmount = new double[1][cfe.getNumberOfPayments()];
   for (int loopcf = 0; loopcf < cfe.getNumberOfPayments(); loopcf++) {
     impactTime[0][loopcf] = cfe.getNthPayment(loopcf).getPaymentTime();
     impactAmount[0][loopcf] = cfe.getNthPayment(loopcf).getAmount();
   }
   final DecisionSchedule decision = new DecisionSchedule(decisionTime, impactTime, impactAmount);
   return decision;
 }
 @Override
 public DecisionSchedule visitAnnuityCouponIborRatchet(
     final AnnuityCouponIborRatchet annuity, final MulticurveProviderInterface multicurves) {
   final int nbCpn = annuity.getNumberOfPayments();
   final double[] decisionTime = new double[nbCpn];
   final double[][] impactTime = new double[nbCpn][];
   final double[][] impactAmount = new double[nbCpn][];
   for (int loopcpn = 0; loopcpn < nbCpn; loopcpn++) {
     final AnnuityPaymentFixed cfe = annuity.getNthPayment(loopcpn).accept(CFEC, multicurves);
     decisionTime[loopcpn] =
         annuity.isFixed()[loopcpn]
             ? 0.0
             : ((CouponFloating) annuity.getNthPayment(loopcpn)).getFixingTime();
     impactTime[loopcpn] = new double[cfe.getNumberOfPayments()];
     impactAmount[loopcpn] = new double[cfe.getNumberOfPayments()];
     for (int loopcf = 0; loopcf < cfe.getNumberOfPayments(); loopcf++) {
       impactTime[loopcpn][loopcf] = cfe.getNthPayment(loopcf).getPaymentTime();
       impactAmount[loopcpn][loopcf] = cfe.getNthPayment(loopcf).getAmount();
     }
   }
   final DecisionSchedule decision = new DecisionSchedule(decisionTime, impactTime, impactAmount);
   return decision;
 }
 /**
  * Computes the present value of the Physical delivery swaption through approximation..
  *
  * @param swaption The swaption.
  * @param cfe The swaption cash flow equiovalent.
  * @param g2Data The G2++ parameters and the curves.
  * @return The present value.
  */
 public CurrencyAmount presentValue(
     final SwaptionPhysicalFixedIbor swaption,
     final AnnuityPaymentFixed cfe,
     final G2ppPiecewiseConstantDataBundle g2Data) {
   YieldAndDiscountCurve dsc =
       g2Data.getCurve(swaption.getUnderlyingSwap().getFixedLeg().getDiscountCurve());
   int nbCf = cfe.getNumberOfPayments();
   double[] cfa = new double[nbCf];
   double[] t = new double[nbCf];
   for (int loopcf = 0; loopcf < nbCf; loopcf++) {
     cfa[loopcf] =
         -Math.signum(cfe.getNthPayment(0).getAmount()) * cfe.getNthPayment(loopcf).getAmount();
     t[loopcf] = cfe.getNthPayment(loopcf).getPaymentTime();
   }
   double rhog2pp = g2Data.getG2ppParameter().getCorrelation();
   double[][] ht0 = MODEL_G2PP.volatilityMaturityPart(g2Data.getG2ppParameter(), t[0], t);
   double[] dfswap = new double[nbCf];
   double[] p0 = new double[nbCf];
   double[] cP = new double[nbCf];
   for (int loopcf = 0; loopcf < nbCf; loopcf++) {
     dfswap[loopcf] = dsc.getDiscountFactor(t[loopcf]);
     p0[loopcf] = dfswap[loopcf] / dfswap[0];
     cP[loopcf] = cfa[loopcf] * p0[loopcf];
   }
   double k = -cfa[0];
   double b0 = 0.0;
   for (int loopcf = 1; loopcf < nbCf; loopcf++) {
     b0 += cP[loopcf];
   }
   double[] alpha0 = new double[nbCf - 1];
   double[] beta0 = new double[2];
   for (int loopcf = 0; loopcf < nbCf - 1; loopcf++) {
     alpha0[loopcf] = cfa[loopcf + 1] * p0[loopcf + 1] / b0;
     beta0[0] += alpha0[loopcf] * ht0[0][loopcf + 1];
     beta0[1] += alpha0[loopcf] * ht0[1][loopcf + 1];
   }
   double[][] gamma = MODEL_G2PP.gamma(g2Data.getG2ppParameter(), 0, swaption.getTimeToExpiry());
   double[] tau = new double[nbCf];
   for (int loopcf = 0; loopcf < nbCf; loopcf++) {
     tau[loopcf] =
         gamma[0][0] * ht0[0][loopcf] * ht0[0][loopcf]
             + gamma[1][1] * ht0[1][loopcf] * ht0[1][loopcf]
             + 2 * rhog2pp * gamma[0][1] * ht0[0][loopcf] * ht0[1][loopcf];
   }
   double xbarnum = 0.0;
   double xbarde = 0.0;
   for (int loopcf = 0; loopcf < nbCf; loopcf++) {
     xbarnum += cP[loopcf] - cP[loopcf] * tau[loopcf] * tau[loopcf] / 2.0;
     xbarde += cP[loopcf] * tau[loopcf];
   }
   double xbar = xbarnum / xbarde;
   double[] pK = new double[nbCf];
   for (int loopcf = 0; loopcf < nbCf; loopcf++) {
     pK[loopcf] = p0[loopcf] * (1.0 - tau[loopcf] * xbar - tau[loopcf] * tau[loopcf] / 2.0);
   }
   double[] alphaK = new double[nbCf - 1];
   double[] betaK = new double[2];
   for (int loopcf = 0; loopcf < nbCf - 1; loopcf++) {
     alphaK[loopcf] = cfa[loopcf + 1] * pK[loopcf + 1] / k;
     betaK[0] += alphaK[loopcf] * ht0[0][loopcf + 1];
     betaK[1] += alphaK[loopcf] * ht0[1][loopcf + 1];
   }
   double[] betaBar = new double[] {(beta0[0] + betaK[0]) / 2.0, (beta0[1] + betaK[1]) / 2.0};
   double sigmaBar2 =
       gamma[0][0] * betaBar[0] * betaBar[0]
           + gamma[1][1] * betaBar[1] * betaBar[1]
           + 2 * rhog2pp * gamma[0][1] * betaBar[0] * betaBar[1];
   double sigmaBar = Math.sqrt(sigmaBar2);
   EuropeanVanillaOption option = new EuropeanVanillaOption(k, 1, !swaption.isCall());
   final BlackPriceFunction blackFunction = new BlackPriceFunction();
   final BlackFunctionData dataBlack = new BlackFunctionData(b0, dfswap[0], sigmaBar);
   final Function1D<BlackFunctionData, Double> func = blackFunction.getPriceFunction(option);
   final double price = func.evaluate(dataBlack) * (swaption.isLong() ? 1.0 : -1.0);
   return CurrencyAmount.of(swaption.getCurrency(), price);
 }