@Test(enabled = false)
 /** Analyzes the shape of the forward curve. */
 public void forwardAnalysis() {
   final MulticurveProviderInterface marketDsc =
       CURVES_PAR_SPREAD_MQ_WITHOUT_TODAY_BLOCK.get(0).getFirst();
   final int jump = 1;
   final int startIndex = 0;
   final int nbDate = 2750;
   ZonedDateTime startDate =
       ScheduleCalculator.getAdjustedDate(NOW, AUDBB3M.getSpotLag() + startIndex * jump, SYD);
   final double[] rateDsc = new double[nbDate];
   final double[] startTime = new double[nbDate];
   try {
     final FileWriter writer = new FileWriter("fwd-dsc.csv");
     for (int loopdate = 0; loopdate < nbDate; loopdate++) {
       startTime[loopdate] = TimeCalculator.getTimeBetween(NOW, startDate);
       final ZonedDateTime endDate = ScheduleCalculator.getAdjustedDate(startDate, AUDBB3M, SYD);
       final double endTime = TimeCalculator.getTimeBetween(NOW, endDate);
       final double accrualFactor = AUDBB3M.getDayCount().getDayCountFraction(startDate, endDate);
       rateDsc[loopdate] =
           marketDsc.getForwardRate(AUDBB3M, startTime[loopdate], endTime, accrualFactor);
       startDate = ScheduleCalculator.getAdjustedDate(startDate, jump, SYD);
       writer.append(0.0 + "," + startTime[loopdate] + "," + rateDsc[loopdate] + "\n");
     }
     writer.flush();
     writer.close();
   } catch (final IOException e) {
     e.printStackTrace();
   }
 }
 /**
  * Compute the end date of a period from the start date, a period and a Ibor index. The index is
  * used for the conventions.
  *
  * @param startDate The period start date.
  * @param tenor The period tenor.
  * @param index The Ibor index.
  * @param calendar The holiday calendar.
  * @return The end date.
  */
 public static ZonedDateTime getAdjustedDate(
     final ZonedDateTime startDate,
     final Period tenor,
     final IborIndex index,
     final Calendar calendar) {
   ArgumentChecker.notNull(index, "Index");
   return getAdjustedDate(
       startDate, tenor, index.getBusinessDayConvention(), calendar, index.isEndOfMonth());
 }
 /**
  * Fixed coupon bond builder from standard financial details. The accrual dates are unadjusted;
  * the payment dates are adjusted according to the business day convention.
  *
  * @param maturityDate The maturity date.
  * @param firstAccrualDate The first accrual date (bond start date).
  * @param index The coupon Ibor index.
  * @param settlementDays Standard number of days between trade date and trade settlement. Used for
  *     clean price and yield computation.
  * @param dayCount The coupon day count convention.
  * @param businessDay The business day convention for the payments.
  * @param isEOM The end-of-month flag.
  * @param issuer The issuer name.
  * @param calendar The holiday calendar for the ibor leg.
  * @return The fixed coupon bond.
  */
 public static BondIborSecurityDefinition from(
     final ZonedDateTime maturityDate,
     final ZonedDateTime firstAccrualDate,
     final IborIndex index,
     final int settlementDays,
     final DayCount dayCount,
     final BusinessDayConvention businessDay,
     final boolean isEOM,
     final String issuer,
     final Calendar calendar) {
   ArgumentChecker.notNull(maturityDate, "Maturity date");
   ArgumentChecker.notNull(firstAccrualDate, "First accrual date");
   ArgumentChecker.notNull(index, "Ibor index");
   ArgumentChecker.notNull(dayCount, "Day count");
   ArgumentChecker.notNull(businessDay, "Business day convention");
   final AnnuityCouponIborDefinition coupon =
       AnnuityCouponIborDefinition.fromAccrualUnadjusted(
           firstAccrualDate, maturityDate, DEFAULT_NOTIONAL, index, false, calendar);
   final PaymentFixedDefinition[] nominalPayment =
       new PaymentFixedDefinition[] {
         new PaymentFixedDefinition(
             index.getCurrency(), businessDay.adjustDate(calendar, maturityDate), DEFAULT_NOTIONAL)
       };
   final AnnuityPaymentFixedDefinition nominal =
       new AnnuityPaymentFixedDefinition(nominalPayment, calendar);
   return new BondIborSecurityDefinition(
       nominal, coupon, DEFAULT_EX_COUPON_DAYS, settlementDays, calendar, dayCount, issuer);
 }
 /**
  * Constructor from all the details.
  *
  * @param currency The payment currency.
  * @param paymentTime Time (in years) up to the payment.
  * @param discountingCurveName Name of the funding curve.
  * @param paymentYearFraction The year fraction (or accrual factor) for the coupon payment.
  * @param notional Coupon notional.
  * @param fixingTime Time (in years) up to fixing.
  * @param index Ibor-like index on which the coupon fixes. The index currency should be the same
  *     as the index currency.
  * @param fixingPeriodStartTime The fixing period start time (in years).
  * @param fixingPeriodEndTime The fixing period end time (in years).
  * @param fixingAccrualFactor The fixing period accrual factor (or year fraction) in the fixing
  *     convention.
  * @param spread The spread paid above the Ibor rate.
  * @param factor The gearing (multiplicative) factor applied to the Ibor rate.
  * @param forwardCurveName The forward curve name used in to estimate the fixing index.
  */
 public CouponIborGearing(
     Currency currency,
     double paymentTime,
     String discountingCurveName,
     double paymentYearFraction,
     double notional,
     double fixingTime,
     IborIndex index,
     double fixingPeriodStartTime,
     double fixingPeriodEndTime,
     double fixingAccrualFactor,
     double spread,
     double factor,
     String forwardCurveName) {
   super(currency, paymentTime, discountingCurveName, paymentYearFraction, notional, fixingTime);
   Validate.notNull(index, "Index");
   Validate.notNull(forwardCurveName, "Forward curve");
   Validate.isTrue(currency.equals(index.getCurrency()));
   this._index = index;
   this._fixingPeriodStartTime = fixingPeriodStartTime;
   this._fixingPeriodEndTime = fixingPeriodEndTime;
   this._fixingAccrualFactor = fixingAccrualFactor;
   this._spread = spread;
   this._factor = factor;
   this._forwardCurveName = forwardCurveName;
   _spreadAmount = getNotional() * getPaymentYearFraction() * spread;
 }
 /**
  * Constructor of a Ibor-like floating coupon from the coupon details and the Ibor index. The
  * payment currency is the index currency.
  *
  * @param currency The coupn currency.
  * @param paymentDate The coupon payment date.
  * @param accrualStartDate The start date of the accrual period.
  * @param accrualEndDate The end date of the accrual period.
  * @param paymentAccrualFactor The accrual factor of the accrual period.
  * @param notional The coupon notional.
  * @param fixingDate The coupon fixing date.
  * @param fixingPeriodStartDate The start date of the fixing period.
  * @param fixingPeriodEndDate The end date of the fixing period.
  * @param fixingPeriodAccrualFactor The accrual factor (or year fraction) associated to the fixing
  *     period in the Index day count convention.
  * @param index The coupon Ibor index. Should of the same currency as the payment.
  * @param calendar The holiday calendar for the ibor index.
  */
 public CouponIborDefinition(
     final Currency currency,
     final ZonedDateTime paymentDate,
     final ZonedDateTime accrualStartDate,
     final ZonedDateTime accrualEndDate,
     final double paymentAccrualFactor,
     final double notional,
     final ZonedDateTime fixingDate,
     final ZonedDateTime fixingPeriodStartDate,
     final ZonedDateTime fixingPeriodEndDate,
     final double fixingPeriodAccrualFactor,
     final IborIndex index,
     final Calendar calendar) {
   super(
       currency,
       paymentDate,
       accrualStartDate,
       accrualEndDate,
       paymentAccrualFactor,
       notional,
       fixingDate);
   ArgumentChecker.notNull(index, "index");
   ArgumentChecker.notNull(calendar, "calendar");
   ArgumentChecker.isTrue(
       currency.equals(index.getCurrency()), "index currency different from payment currency");
   _fixingPeriodStartDate = fixingPeriodStartDate;
   _fixingPeriodEndDate = fixingPeriodEndDate;
   _fixingPeriodAccrualFactor = fixingPeriodAccrualFactor;
   _index = index;
   _calendar = calendar;
 }
 static {
   for (int loopsub = 0; loopsub < NB_SUB_PERIOD; loopsub++) {
     FIXING_ACCRUAL_FACTORS[loopsub] =
         USDLIBOR1M
             .getDayCount()
             .getDayCountFraction(ACCRUAL_START_DATES[loopsub], FIXING_PERIOD_END_DATES[loopsub]);
   }
 }
 /**
  * Compute a schedule of adjusted dates from a start date, total tenor and a Ibor index.
  *
  * @param startDate The start date.
  * @param tenorTotal The total tenor.
  * @param stubShort In case the the periods do not fit exactly between start and end date, is the
  *     remaining interval shorter (true) or longer (false) than the requested period.
  * @param fromEnd The dates in the schedule can be computed from the end date (true) or from the
  *     start date (false).
  * @param index The related ibor index. The period tenor, business day convention, calendar and
  *     EOM rule of the index are used.
  * @param calendar The holiday calendar.
  * @return The adjusted dates schedule (not including the start date).
  */
 public static ZonedDateTime[] getAdjustedDateSchedule(
     final ZonedDateTime startDate,
     final Period tenorTotal,
     final boolean stubShort,
     final boolean fromEnd,
     final IborIndex index,
     final Calendar calendar) {
   return getAdjustedDateSchedule(
       startDate,
       tenorTotal,
       index.getTenor(),
       stubShort,
       fromEnd,
       index.getBusinessDayConvention(),
       calendar,
       index.isEndOfMonth());
 }
 @Override
 public String toString() {
   String result = "IRFuture Security: " + _name;
   result += " - Index: " + _iborIndex.getName();
   result += " - Start fixing: " + _fixingPeriodStartTime;
   result += " - End fixing: " + _fixingPeriodEndTime;
   result += " - Notional: " + _notional;
   return result;
 }
 @Test
 public void presentValueMarketDiscount() {
   final MultipleCurrencyAmount pvComputed = METHOD_CPN_IBOR.presentValue(CPN_IBOR, MULTICURVES);
   final double forward =
       MULTICURVES.getForwardRate(
           EURIBOR3M,
           CPN_IBOR.getFixingPeriodStartTime(),
           CPN_IBOR.getFixingPeriodEndTime(),
           CPN_IBOR.getFixingAccrualFactor());
   final double df =
       MULTICURVES.getDiscountFactor(EURIBOR3M.getCurrency(), CPN_IBOR.getPaymentTime());
   final double pvExpected = NOTIONAL * ACCRUAL_FACTOR * forward * df;
   assertEquals(
       "CouponIborDiscountingMarketMethod: present value",
       pvExpected,
       pvComputed.getAmount(EURIBOR3M.getCurrency()),
       TOLERANCE_PV);
 }
 /**
  * Builder of a coupon from the accrual dates and the index. The fixing dates are calculated using
  * the index. The payment date is the end accrual date.
  *
  * @param accrualStartDate Start date of the accrual period.
  * @param accrualEndDate End date of the accrual period.
  * @param accrualFactor The accrual factor of the accrual period.
  * @param notional The coupon notional.
  * @param index The coupon Ibor index. Should of the same currency as the payment.
  * @param calendar The holiday calendar for the ibor index.
  * @return The coupon.
  */
 public static CouponIborDefinition from(
     final ZonedDateTime accrualStartDate,
     final ZonedDateTime accrualEndDate,
     final double accrualFactor,
     final double notional,
     final IborIndex index,
     final Calendar calendar) {
   final ZonedDateTime fixingDate =
       ScheduleCalculator.getAdjustedDate(accrualStartDate, -index.getSpotLag(), calendar);
   return new CouponIborDefinition(
       index.getCurrency(),
       accrualEndDate,
       accrualStartDate,
       accrualEndDate,
       accrualFactor,
       notional,
       fixingDate,
       index,
       calendar);
 }
 @Test
 /** Tests the present value for curves with seasonal adjustment. */
 public void presentValueSeasonality() {
   MarketBundle marketSeason = MarketDataSets.createMarket2(PRICING_DATE);
   int tenorYear = 5;
   double notional = 100000000;
   ZonedDateTime settleDate =
       ScheduleCalculator.getAdjustedDate(PRICING_DATE, USDLIBOR3M.getSpotLag(), CALENDAR_USD);
   ZonedDateTime paymentDate =
       ScheduleCalculator.getAdjustedDate(
           settleDate,
           Period.ofYears(tenorYear),
           BUSINESS_DAY,
           CALENDAR_USD,
           USDLIBOR3M.isEndOfMonth());
   double weightSettle =
       1.0
           - (settleDate.getDayOfMonth() - 1.0)
               / settleDate.getMonthOfYear().getLastDayOfMonth(settleDate.isLeapYear());
   double indexStart = weightSettle * 225.964 + (1 - weightSettle) * 225.722;
   CouponInflationZeroCouponInterpolationDefinition zeroCouponUsdDefinition =
       CouponInflationZeroCouponInterpolationDefinition.from(
           settleDate, paymentDate, notional, PRICE_INDEX_US, indexStart, MONTH_LAG, false);
   CouponInflationZeroCouponInterpolation zeroCouponUsd =
       zeroCouponUsdDefinition.toDerivative(PRICING_DATE, "not used");
   CurrencyAmount pvInflation = METHOD.presentValue(zeroCouponUsd, marketSeason);
   double df =
       MARKET
           .getCurve(zeroCouponUsd.getCurrency())
           .getDiscountFactor(zeroCouponUsd.getPaymentTime());
   double indexMonth0 =
       marketSeason.getCurve(PRICE_INDEX_US).getPriceIndex(zeroCouponUsd.getReferenceEndTime()[0]);
   double indexMonth1 =
       marketSeason.getCurve(PRICE_INDEX_US).getPriceIndex(zeroCouponUsd.getReferenceEndTime()[1]);
   double finalIndex =
       zeroCouponUsdDefinition.getWeight() * indexMonth0
           + (1 - zeroCouponUsdDefinition.getWeight()) * indexMonth1;
   double pvExpected = (finalIndex / indexStart - 1) * df * notional;
   assertEquals(
       "PV in market with seasonal adjustment", pvExpected, pvInflation.getAmount(), 1E-2);
 }
 @Override
 public int hashCode() {
   final int prime = 31;
   int result = super.hashCode();
   result = prime * result + _fixingPeriodEndDate.hashCode();
   result = prime * result + _fixingPeriodStartDate.hashCode();
   long temp;
   temp = Double.doubleToLongBits(_fixingPeriodAccrualFactor);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   result = prime * result + _index.hashCode();
   return result;
 }
 /**
  * Builder of Ibor-like coupon from the fixing date and the index. The payment and accrual dates
  * are the one of the fixing period.
  *
  * @param notional Coupon notional.
  * @param fixingDate The coupon fixing date.
  * @param index The coupon Ibor index.
  * @param calendar The holiday calendar for the ibor index.
  * @return The Ibor coupon.
  */
 public static CouponIborDefinition from(
     final double notional,
     final ZonedDateTime fixingDate,
     final IborIndex index,
     final Calendar calendar) {
   ArgumentChecker.notNull(fixingDate, "fixing date");
   ArgumentChecker.notNull(index, "index");
   final ZonedDateTime fixingPeriodStartDate =
       ScheduleCalculator.getAdjustedDate(fixingDate, index.getSpotLag(), calendar);
   final ZonedDateTime fixingPeriodEndDate =
       ScheduleCalculator.getAdjustedDate(
           fixingPeriodStartDate,
           index.getTenor(),
           index.getBusinessDayConvention(),
           calendar,
           index.isEndOfMonth());
   final double fixingPeriodAccrualFactor =
       index
           .getDayCount()
           .getDayCountFraction(fixingPeriodStartDate, fixingPeriodEndDate, calendar);
   return new CouponIborDefinition(
       index.getCurrency(),
       fixingPeriodEndDate,
       fixingPeriodStartDate,
       fixingPeriodEndDate,
       fixingPeriodAccrualFactor,
       notional,
       fixingDate,
       index,
       calendar);
 }
 @Override
 protected void buildMessage(
     final FudgeSerializer serializer, final MutableFudgeMsg message, final IborIndex object) {
   message.add(SPOT_LAG_FIELD, object.getSpotLag());
   message.add(DAY_COUNT_FIELD, object.getDayCount().getConventionName());
   message.add(
       BUSINESS_DAY_CONVENTION_FIELD, object.getBusinessDayConvention().getConventionName());
   message.add(EOM_FIELD, object.isEndOfMonth());
   message.add(TENOR_FIELD, object.getTenor().toString());
   message.add(NAME_FIELD, object.getName());
   message.add(CURRENCY_FIELD, object.getCurrency().getCode());
 }
 static {
   ACCRUAL_START_DATES[0] = START_DATE;
   for (int loopsub = 1; loopsub < NB_SUB_PERIOD; loopsub++) {
     ACCRUAL_START_DATES[loopsub] = ACCRUAL_END_DATES[loopsub - 1];
   }
   double af = 0.0;
   for (int loopsub = 0; loopsub < NB_SUB_PERIOD; loopsub++) {
     PAYMENT_ACCRUAL_FACTORS[loopsub] =
         USDLIBOR1M
             .getDayCount()
             .getDayCountFraction(ACCRUAL_START_DATES[loopsub], ACCRUAL_END_DATES[loopsub]);
     af += PAYMENT_ACCRUAL_FACTORS[loopsub];
   }
   PAYMENT_ACCRUAL_FACTOR = af;
 }
 static {
   LEGS_DEFINITION[0] =
       AnnuityDefinitionBuilder.couponFixed(
           EUR,
           SETTLEMENT_DATE,
           MATURITY_DATE,
           EUR1YEURIBOR6M.getFixedLegPeriod(),
           TARGET,
           EUR1YEURIBOR6M.getFixedLegDayCount(),
           EUR1YEURIBOR6M.getBusinessDayConvention(),
           EUR1YEURIBOR6M.isEndOfMonth(),
           NOTIONAL,
           SPREAD,
           IS_PAYER_SPREAD,
           STUB,
           0);
   LEGS_DEFINITION[1] =
       AnnuityDefinitionBuilder.couponIbor(
           SETTLEMENT_DATE,
           MATURITY_DATE,
           EURIBOR3M.getTenor(),
           NOTIONAL,
           EURIBOR3M,
           IS_PAYER_SPREAD,
           EURIBOR3M.getDayCount(),
           EURIBOR3M.getBusinessDayConvention(),
           EURIBOR3M.isEndOfMonth(),
           TARGET,
           STUB,
           0);
   LEGS_DEFINITION[2] =
       AnnuityDefinitionBuilder.couponIbor(
           SETTLEMENT_DATE,
           MATURITY_DATE,
           EURIBOR6M.getTenor(),
           NOTIONAL,
           EURIBOR6M,
           !IS_PAYER_SPREAD,
           EURIBOR6M.getDayCount(),
           EURIBOR6M.getBusinessDayConvention(),
           EURIBOR6M.isEndOfMonth(),
           TARGET,
           STUB,
           0);
 }
 /**
  * Swap with spread builder from the all the details on the fixed and ibor leg. The currency is
  * the currency of the Ibor index.
  *
  * @param settlementDate The settlement date.
  * @param maturityDate The swap maturity date.
  * @param fixedLegPeriod The payment period for the fixed leg.
  * @param fixedLegDayCount The fixed leg day count.
  * @param fixedLegBusinessDayConvention The fixed leg business day convention.
  * @param fixedLegEOM The fixed leg end-of-month rule application.
  * @param fixedLegNotional The fixed leg notional.
  * @param fixedLegRate The fixed leg rate.
  * @param iborLegPeriod The Ibor leg payment period.
  * @param iborLegDayCount The Ibor leg day count convention.
  * @param iborLegBusinessDayConvention The Ibor leg business day convention.
  * @param iborLegEOM The Ibor leg end-of-month.
  * @param iborLegNotional The Ibor leg notional.
  * @param iborIndex The Ibor index.
  * @param iborLegSpread The Ibor leg spread.
  * @param isPayer The payer flag for the fixed leg.
  * @param calendar The holiday calendar of the ibor leg.
  * @return The swap.
  */
 public static SwapFixedIborSpreadDefinition from(
     final ZonedDateTime settlementDate,
     final ZonedDateTime maturityDate,
     final Period fixedLegPeriod,
     final DayCount fixedLegDayCount,
     final BusinessDayConvention fixedLegBusinessDayConvention,
     final boolean fixedLegEOM,
     final double fixedLegNotional,
     final double fixedLegRate,
     final Period iborLegPeriod,
     final DayCount iborLegDayCount,
     final BusinessDayConvention iborLegBusinessDayConvention,
     final boolean iborLegEOM,
     final double iborLegNotional,
     final IborIndex iborIndex,
     final double iborLegSpread,
     final boolean isPayer,
     final Calendar calendar) {
   ArgumentChecker.notNull(iborIndex, "Ibor index");
   final AnnuityCouponFixedDefinition fixedLeg =
       AnnuityCouponFixedDefinition.from(
           iborIndex.getCurrency(),
           settlementDate,
           maturityDate,
           fixedLegPeriod,
           calendar,
           fixedLegDayCount,
           fixedLegBusinessDayConvention,
           fixedLegEOM,
           fixedLegNotional,
           fixedLegRate,
           isPayer);
   final AnnuityCouponIborSpreadDefinition iborLeg =
       AnnuityCouponIborSpreadDefinition.from(
           settlementDate,
           maturityDate,
           iborLegPeriod,
           iborLegNotional,
           iborIndex,
           !isPayer,
           iborLegBusinessDayConvention,
           iborLegEOM,
           iborLegDayCount,
           iborLegSpread,
           calendar);
   return new SwapFixedIborSpreadDefinition(fixedLeg, iborLeg);
 }
 /**
  * Builder of Ibor-like coupon from an underlying coupon, the fixing date and the index. The
  * fixing period dates are deduced from the index and the fixing date.
  *
  * @param coupon Underlying coupon.
  * @param fixingDate The coupon fixing date.
  * @param index The coupon Ibor index.
  * @param calendar The holiday calendar for the ibor index.
  * @return The Ibor coupon.
  */
 public static CouponIborDefinition from(
     final CouponDefinition coupon,
     final ZonedDateTime fixingDate,
     final IborIndex index,
     final Calendar calendar) {
   ArgumentChecker.notNull(coupon, "coupon");
   ArgumentChecker.notNull(fixingDate, "fixing date");
   ArgumentChecker.notNull(index, "index");
   return new CouponIborDefinition(
       index.getCurrency(),
       coupon.getPaymentDate(),
       coupon.getAccrualStartDate(),
       coupon.getAccrualEndDate(),
       coupon.getPaymentYearFraction(),
       coupon.getNotional(),
       fixingDate,
       index,
       calendar);
 }
 /**
  * Constructor of a Ibor-like floating coupon from the coupon details and the Ibor index. The
  * payment currency is the index currency.
  *
  * @param paymentDate Coupon payment date.
  * @param accrualStartDate Start date of the accrual period.
  * @param accrualEndDate End date of the accrual period.
  * @param accrualFactor Accrual factor of the accrual period.
  * @param notional Coupon notional.
  * @param fixingDate The coupon fixing date.
  * @param index The coupon Ibor index.
  * @param calendar The holiday calendar for the ibor index.
  * @return The Ibor coupon.
  */
 public static CouponIborDefinition from(
     final ZonedDateTime paymentDate,
     final ZonedDateTime accrualStartDate,
     final ZonedDateTime accrualEndDate,
     final double accrualFactor,
     final double notional,
     final ZonedDateTime fixingDate,
     final IborIndex index,
     final Calendar calendar) {
   ArgumentChecker.notNull(index, "index");
   return new CouponIborDefinition(
       index.getCurrency(),
       paymentDate,
       accrualStartDate,
       accrualEndDate,
       accrualFactor,
       notional,
       fixingDate,
       index,
       calendar);
 }
 @Override
 public int hashCode() {
   final int prime = 31;
   int result = super.hashCode();
   long temp;
   temp = Double.doubleToLongBits(_factor);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   temp = Double.doubleToLongBits(_fixingAccrualFactor);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   temp = Double.doubleToLongBits(_fixingPeriodEndTime);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   temp = Double.doubleToLongBits(_fixingPeriodStartTime);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   result = prime * result + _forwardCurveName.hashCode();
   result = prime * result + _index.hashCode();
   temp = Double.doubleToLongBits(_spread);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   temp = Double.doubleToLongBits(_spreadAmount);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   return result;
 }
 @Override
 public int hashCode() {
   final int prime = 31;
   int result = 1;
   long temp;
   temp = Double.doubleToLongBits(_fixingPeriodAccrualFactor);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   temp = Double.doubleToLongBits(_fixingPeriodEndTime);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   temp = Double.doubleToLongBits(_fixingPeriodStartTime);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   result = prime * result + (_forwardCurveName == null ? 0 : _forwardCurveName.hashCode());
   result =
       prime * result + (_discountingCurveName == null ? 0 : _discountingCurveName.hashCode());
   result = prime * result + _iborIndex.hashCode();
   temp = Double.doubleToLongBits(_lastTradingTime);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   result = prime * result + _name.hashCode();
   temp = Double.doubleToLongBits(_notional);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   temp = Double.doubleToLongBits(_paymentAccrualFactor);
   result = prime * result + (int) (temp ^ (temp >>> 32));
   return result;
 }
 /**
  * Constructor of a Ibor-like floating coupon from the coupon details and the Ibor index. The
  * payment currency is the index currency. The fixing dates and accrual factors are inferred from
  * the index.
  *
  * @param currency The coupon currency.
  * @param paymentDate The coupon payment date.
  * @param accrualStartDate The start date of the accrual period.
  * @param accrualEndDate The end date of the accrual period.
  * @param paymentAccrualFactor The accrual factor of the accrual period.
  * @param notional The coupon notional.
  * @param fixingDate The coupon fixing date.
  * @param index The coupon Ibor index. Should of the same currency as the payment.
  * @param calendar The holiday calendar for the ibor index.
  */
 public CouponIborDefinition(
     final Currency currency,
     final ZonedDateTime paymentDate,
     final ZonedDateTime accrualStartDate,
     final ZonedDateTime accrualEndDate,
     final double paymentAccrualFactor,
     final double notional,
     final ZonedDateTime fixingDate,
     final IborIndex index,
     final Calendar calendar) {
   super(
       currency,
       paymentDate,
       accrualStartDate,
       accrualEndDate,
       paymentAccrualFactor,
       notional,
       fixingDate);
   ArgumentChecker.notNull(index, "index");
   ArgumentChecker.notNull(calendar, "calendar");
   ArgumentChecker.isTrue(
       currency.equals(index.getCurrency()), "index currency different from payment currency");
   _index = index;
   _fixingPeriodStartDate =
       ScheduleCalculator.getAdjustedDate(fixingDate, _index.getSpotLag(), calendar);
   _fixingPeriodEndDate =
       ScheduleCalculator.getAdjustedDate(
           _fixingPeriodStartDate,
           index.getTenor(),
           index.getBusinessDayConvention(),
           calendar,
           index.isEndOfMonth());
   _fixingPeriodAccrualFactor =
       index
           .getDayCount()
           .getDayCountFraction(_fixingPeriodStartDate, _fixingPeriodEndDate, calendar);
   _calendar = calendar;
 }
/**
 * Tests for the methods related to interest rate securities pricing with Hull-White model convexity
 * adjustment.
 */
@Test(groups = TestGroup.UNIT)
public class InterestRateFutureSecurityHullWhiteMethodTest {

  private static final MulticurveProviderDiscount MULTICURVES =
      MulticurveProviderDiscountDataSets.createMulticurveEurUsd();
  private static final IborIndex[] INDEX_LIST =
      MulticurveProviderDiscountDataSets.getIndexesIborMulticurveEurUsd();
  private static final IborIndex EURIBOR3M = INDEX_LIST[0];
  private static final Currency EUR = EURIBOR3M.getCurrency();
  private static final Calendar CALENDAR = MulticurveProviderDiscountDataSets.getEURCalendar();
  // Future
  private static final ZonedDateTime SPOT_LAST_TRADING_DATE = DateUtils.getUTCDate(2012, 9, 19);
  private static final ZonedDateTime LAST_TRADING_DATE =
      ScheduleCalculator.getAdjustedDate(SPOT_LAST_TRADING_DATE, -EURIBOR3M.getSpotLag(), CALENDAR);
  private static final double NOTIONAL = 1000000.0; // 1m
  private static final double FUTURE_FACTOR = 0.25;
  private static final String NAME = "ERU2";

  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 5, 12);
  private static final InterestRateFutureSecurityDefinition ERU2_DEFINITION =
      new InterestRateFutureSecurityDefinition(
          LAST_TRADING_DATE, EURIBOR3M, NOTIONAL, FUTURE_FACTOR, NAME, CALENDAR);

  private static final InterestRateFutureSecurity ERU2 =
      ERU2_DEFINITION.toDerivative(REFERENCE_DATE);

  private static final double MEAN_REVERSION = 0.01;
  private static final double[] VOLATILITY = new double[] {0.01, 0.011, 0.012, 0.013, 0.014};
  private static final double[] VOLATILITY_TIME = new double[] {0.5, 1.0, 2.0, 5.0};
  private static final HullWhiteOneFactorPiecewiseConstantParameters MODEL_PARAMETERS =
      new HullWhiteOneFactorPiecewiseConstantParameters(
          MEAN_REVERSION, VOLATILITY, VOLATILITY_TIME);

  private static final HullWhiteOneFactorProviderDiscount HW_MULTICURVES =
      new HullWhiteOneFactorProviderDiscount(MULTICURVES, MODEL_PARAMETERS, EUR);
  private static final HullWhiteOneFactorPiecewiseConstantInterestRateModel MODEL =
      new HullWhiteOneFactorPiecewiseConstantInterestRateModel();

  private static final InterestRateFutureSecurityHullWhiteMethod METHOD_IRFUT_HW =
      InterestRateFutureSecurityHullWhiteMethod.getInstance();

  private static final MarketQuoteHullWhiteCalculator MQHWC =
      MarketQuoteHullWhiteCalculator.getInstance();
  private static final MarketQuoteCurveSensitivityHullWhiteCalculator MQCSHWC =
      MarketQuoteCurveSensitivityHullWhiteCalculator.getInstance();
  private static final ConvexityAdjustmentHullWhiteCalculator CAHWC =
      ConvexityAdjustmentHullWhiteCalculator.getInstance();
  private static final ParRateHullWhiteCalculator PRHWC = ParRateHullWhiteCalculator.getInstance();

  private static final double SHIFT_FD = 1.0E-6;
  private static final SimpleParameterSensitivityParameterCalculator<
          HullWhiteOneFactorProviderInterface>
      SPSHWC = new SimpleParameterSensitivityParameterCalculator<>(MQCSHWC);
  private static final SimpleParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator
      SPSHWC_FD =
          new SimpleParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator(MQHWC, SHIFT_FD);

  private static final double TOLERANCE_PRICE = 1.0E-10;
  private static final double TOLERANCE_PRICE_DELTA = 1.0E-8;

  @Test
  /** Test the price computed from the curves and HW parameters. */
  public void price() {
    final double price = METHOD_IRFUT_HW.price(ERU2, HW_MULTICURVES);
    final double forward =
        MULTICURVES.getSimplyCompoundForwardRate(
            EURIBOR3M,
            ERU2.getFixingPeriodStartTime(),
            ERU2.getFixingPeriodEndTime(),
            ERU2.getFixingPeriodAccrualFactor());
    final double factor =
        MODEL.futuresConvexityFactor(
            MODEL_PARAMETERS,
            ERU2.getTradingLastTime(),
            ERU2.getFixingPeriodStartTime(),
            ERU2.getFixingPeriodEndTime());
    final double expectedPrice =
        1.0 - factor * forward + (1 - factor) / ERU2.getFixingPeriodAccrualFactor();
    assertEquals(
        "InterestRateFutureSecurityHullWhiteProviderMethod: price",
        expectedPrice,
        price,
        TOLERANCE_PRICE);
  }

  @Test
  /** Test the par rate computed from the curves and HW parameters. Par rate = 1-price. */
  public void parRate() {
    final double price = METHOD_IRFUT_HW.price(ERU2, HW_MULTICURVES);
    final double parRateExpected = 1.0d - price;
    final double parRateComputed = METHOD_IRFUT_HW.parRate(ERU2, HW_MULTICURVES);
    assertEquals(
        "InterestRateFutureSecurityHullWhiteProviderMethod: parRate",
        parRateExpected,
        parRateComputed,
        TOLERANCE_PRICE);
  }

  @Test
  /** Test the par rate computed from the method and the calculator. */
  public void parRateMethodVsCalculator() {
    final double parRateMethod = METHOD_IRFUT_HW.parRate(ERU2, HW_MULTICURVES);
    final double parRateCalculator = ERU2.accept(PRHWC, HW_MULTICURVES);
    assertEquals(
        "InterestRateFutureSecurityHullWhiteProviderMethod: parRate",
        parRateMethod,
        parRateCalculator,
        TOLERANCE_PRICE);
  }

  @Test
  /** Test the price as "MarketQuote" */
  public void marketQuote() {
    final double priceMethod = METHOD_IRFUT_HW.price(ERU2, HW_MULTICURVES);
    final double marketQuote = ERU2.accept(MQHWC, HW_MULTICURVES);
    assertEquals(
        "InterestRateFutureSecurityHullWhiteProviderMethod: price",
        priceMethod,
        marketQuote,
        TOLERANCE_PRICE);
  }

  @Test
  /** Test the convexity adjustment */
  public void convexityAdjustment() {
    final double price = METHOD_IRFUT_HW.price(ERU2, HW_MULTICURVES);
    final double forward =
        MULTICURVES.getSimplyCompoundForwardRate(
            EURIBOR3M,
            ERU2.getFixingPeriodStartTime(),
            ERU2.getFixingPeriodEndTime(),
            ERU2.getFixingPeriodAccrualFactor());
    final double convexityAdjustment = METHOD_IRFUT_HW.convexityAdjustment(ERU2, HW_MULTICURVES);
    assertEquals(
        "InterestRateFutureSecurityHullWhiteProviderMethod: convexity adjustment",
        price - (1.0d - forward),
        convexityAdjustment,
        TOLERANCE_PRICE);
    final double caCalculator = ERU2.accept(CAHWC, HW_MULTICURVES);
    assertEquals(
        "DeliverableSwapFuturesSecurityDefinition: convexity adjustment",
        caCalculator,
        convexityAdjustment,
        TOLERANCE_PRICE);
  }

  @Test
  /** Test the price curve sensitivity versus a finite difference computation. */
  public void priceCurveSensitivity() {
    final SimpleParameterSensitivity pcsExact =
        SPSHWC.calculateSensitivity(ERU2, HW_MULTICURVES, MULTICURVES.getAllNames());
    final SimpleParameterSensitivity pcsFD = SPSHWC_FD.calculateSensitivity(ERU2, HW_MULTICURVES);
    AssertSensitivityObjects.assertEquals(
        "DeliverableSwapFuturesSecurityHullWhiteMethod: priceCurveSensitivity",
        pcsExact,
        pcsFD,
        TOLERANCE_PRICE_DELTA);
  }
}
/** Tests the interest rate future option with margin transaction description. */
@Test
public class InterestRateFutureOptionPremiumTransactionDefinitionTest {

  private static final HolidayCalendar CALENDAR = HolidayCalendars.SAT_SUN;
  private static final IborIndex IBOR_INDEX = IndexIborMaster.getInstance().getIndex("EURIBOR3M");

  // Future option mid-curve 1Y
  private static final ZonedDateTime SPOT_LAST_TRADING_DATE = DateUtils.getUTCDate(2012, 9, 19);
  private static final ZonedDateTime LAST_TRADING_DATE =
      ScheduleCalculator.getAdjustedDate(
          SPOT_LAST_TRADING_DATE, -IBOR_INDEX.getSpotLag(), CALENDAR);
  private static final double NOTIONAL = 1000000.0; // 1m
  private static final double FUTURE_FACTOR = 0.25;
  private static final String NAME = "ERU2";
  private static final double STRIKE = 0.9895;
  private static final InterestRateFutureSecurityDefinition ERU2 =
      new InterestRateFutureSecurityDefinition(
          LAST_TRADING_DATE, IBOR_INDEX, NOTIONAL, FUTURE_FACTOR, NAME, CALENDAR);
  private static final ZonedDateTime EXPIRATION_DATE = DateUtils.getUTCDate(2011, 9, 16);
  private static final boolean IS_CALL = true;
  private static final InterestRateFutureOptionPremiumSecurityDefinition OPTION_EDU2 =
      new InterestRateFutureOptionPremiumSecurityDefinition(ERU2, EXPIRATION_DATE, STRIKE, IS_CALL);
  // Transaction
  private static final int QUANTITY = -123;
  private static final ZonedDateTime PREMIUM_DATE = DateUtils.getUTCDate(2011, 5, 12);
  private static final double TRADE_PRICE = 0.0050;
  private static final InterestRateFutureOptionPremiumTransactionDefinition OPTION_TRANSACTION =
      new InterestRateFutureOptionPremiumTransactionDefinition(
          OPTION_EDU2, QUANTITY, PREMIUM_DATE, TRADE_PRICE);
  // Derivative
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2010, 8, 18);
  private static final String DISCOUNTING_CURVE_NAME = "Funding";
  private static final String FORWARD_CURVE_NAME = "Forward";
  private static final String[] CURVES = {DISCOUNTING_CURVE_NAME, FORWARD_CURVE_NAME};

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullUnderlying() {
    new InterestRateFutureOptionPremiumTransactionDefinition(
        null, QUANTITY, PREMIUM_DATE, TRADE_PRICE);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullTradeDate() {
    new InterestRateFutureOptionPremiumTransactionDefinition(
        OPTION_EDU2, QUANTITY, null, TRADE_PRICE);
  }

  @Test
  /** Tests the class getters. */
  public void getter() {
    assertEquals(OPTION_EDU2, OPTION_TRANSACTION.getUnderlyingOption());
    assertEquals(QUANTITY, OPTION_TRANSACTION.getQuantity());
    assertEquals(PREMIUM_DATE, OPTION_TRANSACTION.getPremium().getPaymentDate());
    assertEquals(TRADE_PRICE, OPTION_TRANSACTION.getTradePrice());
  }

  @Test
  /** Tests the equal and hashCode methods. */
  public void equalHash() {
    final InterestRateFutureOptionPremiumTransactionDefinition other =
        new InterestRateFutureOptionPremiumTransactionDefinition(
            OPTION_EDU2, QUANTITY, PREMIUM_DATE, TRADE_PRICE);
    assertTrue(OPTION_TRANSACTION.equals(other));
    assertTrue(OPTION_TRANSACTION.hashCode() == other.hashCode());
    InterestRateFutureOptionPremiumTransactionDefinition modifidOption;
    modifidOption =
        new InterestRateFutureOptionPremiumTransactionDefinition(
            OPTION_EDU2, QUANTITY + 1, PREMIUM_DATE, TRADE_PRICE);
    assertFalse(OPTION_TRANSACTION.equals(modifidOption));
    modifidOption =
        new InterestRateFutureOptionPremiumTransactionDefinition(
            OPTION_EDU2, QUANTITY, LAST_TRADING_DATE, TRADE_PRICE);
    assertFalse(OPTION_TRANSACTION.equals(modifidOption));
    modifidOption =
        new InterestRateFutureOptionPremiumTransactionDefinition(
            OPTION_EDU2, QUANTITY, PREMIUM_DATE, TRADE_PRICE - 0.00001);
    assertFalse(OPTION_TRANSACTION.equals(modifidOption));
  }

  @Test
  /** Tests the toDerivative method when the reference date is before the premium settlement. */
  public void toDerivativeBeforeSettlement() {
    final InterestRateFutureOptionPremiumTransaction transactionConverted =
        OPTION_TRANSACTION.toDerivative(REFERENCE_DATE);
    final InterestRateFutureOptionPremiumSecurity security =
        OPTION_EDU2.toDerivative(REFERENCE_DATE);
    final double premiumTime = TimeCalculator.getTimeBetween(REFERENCE_DATE, PREMIUM_DATE);
    final InterestRateFutureOptionPremiumTransaction transaction =
        new InterestRateFutureOptionPremiumTransaction(
            security, QUANTITY, premiumTime, TRADE_PRICE);
    assertEquals("Option on future: to derivative", transaction, transactionConverted);
  }

  @Test
  /** Tests the toDerivative method when the reference date is on the premium settlement. */
  public void toDerivativeOnSettlement() {
    final ZonedDateTime referenceDate = PREMIUM_DATE;
    final InterestRateFutureOptionPremiumTransaction transactionConverted =
        OPTION_TRANSACTION.toDerivative(referenceDate);
    final InterestRateFutureOptionPremiumSecurity security =
        OPTION_EDU2.toDerivative(referenceDate);
    final double premiumTime = 0.0;
    final InterestRateFutureOptionPremiumTransaction transaction =
        new InterestRateFutureOptionPremiumTransaction(
            security, QUANTITY, premiumTime, TRADE_PRICE);
    assertEquals("Option on future: to derivative", transaction, transactionConverted);
  }

  @Test
  /** Tests the toDerivative method when the reference date is after the premium settlement. */
  public void toDerivativeAfterSettlement() {
    final ZonedDateTime referenceDate = PREMIUM_DATE.plusDays(1);
    final InterestRateFutureOptionPremiumTransaction transactionConverted =
        OPTION_TRANSACTION.toDerivative(referenceDate);
    final InterestRateFutureOptionPremiumSecurity security =
        OPTION_EDU2.toDerivative(referenceDate);
    final double premiumTime = 0.0;
    final double price = 0.0; // The payment is in the past and is represented by a 0 payment today.
    final InterestRateFutureOptionPremiumTransaction transaction =
        new InterestRateFutureOptionPremiumTransaction(security, QUANTITY, premiumTime, price);
    assertEquals("Option on future: to derivative", transaction, transactionConverted);
  }
}
/** Tests related to the pricing of physical delivery swaption in Hull-White one factor model. */
public class SwaptionPhysicalFixedIborHullWhiteMethodTest {

  private static final MulticurveProviderDiscount MULTICURVES =
      MulticurveProviderDiscountDataSets.createMulticurveEurUsd();
  private static final IborIndex EURIBOR6M =
      MulticurveProviderDiscountDataSets.getIndexesIborMulticurveEurUsd()[1];

  private static final Currency EUR = EURIBOR6M.getCurrency();
  private static final Calendar CALENDAR = MulticurveProviderDiscountDataSets.getEURCalendar();

  private static final HullWhiteOneFactorPiecewiseConstantParameters HW_PARAMETERS =
      HullWhiteDataSets.createHullWhiteParameters();
  private static final HullWhiteOneFactorProviderDiscount HW_MULTICURVES =
      new HullWhiteOneFactorProviderDiscount(MULTICURVES, HW_PARAMETERS, EUR);

  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 7, 7);
  // Swaption 5Yx5Y
  private static final int SPOT_LAG = EURIBOR6M.getSpotLag();
  private static final int SWAP_TENOR_YEAR = 5;
  private static final Period SWAP_TENOR = Period.ofYears(SWAP_TENOR_YEAR);
  private static final GeneratorSwapFixedIbor EUR1YEURIBOR6M =
      GeneratorSwapFixedIborMaster.getInstance().getGenerator("EUR1YEURIBOR6M", CALENDAR);
  private static final ZonedDateTime EXPIRY_DATE = DateUtils.getUTCDate(2016, 7, 7);
  private static final boolean IS_LONG = true;
  private static final ZonedDateTime SETTLEMENT_DATE =
      ScheduleCalculator.getAdjustedDate(EXPIRY_DATE, SPOT_LAG, CALENDAR);
  private static final double NOTIONAL = 100000000; // 100m
  private static final double RATE = 0.0175;
  private static final boolean FIXED_IS_PAYER = true;
  private static final SwapFixedIborDefinition SWAP_PAYER_DEFINITION =
      SwapFixedIborDefinition.from(
          SETTLEMENT_DATE, SWAP_TENOR, EUR1YEURIBOR6M, NOTIONAL, RATE, FIXED_IS_PAYER);
  private static final SwapFixedIborDefinition SWAP_RECEIVER_DEFINITION =
      SwapFixedIborDefinition.from(
          SETTLEMENT_DATE, SWAP_TENOR, EUR1YEURIBOR6M, NOTIONAL, RATE, !FIXED_IS_PAYER);

  private static final SwaptionPhysicalFixedIborDefinition SWAPTION_LONG_PAYER_DEFINITION =
      SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, SWAP_PAYER_DEFINITION, IS_LONG);
  private static final SwaptionPhysicalFixedIborDefinition SWAPTION_LONG_RECEIVER_DEFINITION =
      SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, SWAP_RECEIVER_DEFINITION, IS_LONG);
  private static final SwaptionPhysicalFixedIborDefinition SWAPTION_SHORT_PAYER_DEFINITION =
      SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, SWAP_PAYER_DEFINITION, !IS_LONG);
  private static final SwaptionPhysicalFixedIborDefinition SWAPTION_SHORT_RECEIVER_DEFINITION =
      SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, SWAP_RECEIVER_DEFINITION, !IS_LONG);

  private static final SwapFixedCoupon<Coupon> SWAP_RECEIVER =
      SWAP_RECEIVER_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final SwaptionPhysicalFixedIbor SWAPTION_LONG_PAYER =
      SWAPTION_LONG_PAYER_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final SwaptionPhysicalFixedIbor SWAPTION_LONG_RECEIVER =
      SWAPTION_LONG_RECEIVER_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final SwaptionPhysicalFixedIbor SWAPTION_SHORT_PAYER =
      SWAPTION_SHORT_PAYER_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final SwaptionPhysicalFixedIbor SWAPTION_SHORT_RECEIVER =
      SWAPTION_SHORT_RECEIVER_DEFINITION.toDerivative(REFERENCE_DATE);

  // Calculator
  private static final SwaptionPhysicalFixedIborHullWhiteMethod METHOD_HW =
      SwaptionPhysicalFixedIborHullWhiteMethod.getInstance();
  private static final SwapFixedCouponDiscountingMethod METHOD_SWAP =
      SwapFixedCouponDiscountingMethod.getInstance();

  private static final CashFlowEquivalentCalculator CFEC =
      CashFlowEquivalentCalculator.getInstance();
  private static final ParRateDiscountingCalculator PRDC =
      ParRateDiscountingCalculator.getInstance();
  private static final PresentValueDiscountingCalculator PVDC =
      PresentValueDiscountingCalculator.getInstance();
  private static final PresentValueCurveSensitivityDiscountingCalculator PVCSDC =
      PresentValueCurveSensitivityDiscountingCalculator.getInstance();
  private static final PresentValueHullWhiteCalculator PVHWC =
      PresentValueHullWhiteCalculator.getInstance();
  private static final PresentValueCurveSensitivityHullWhiteCalculator PVCSHWC =
      PresentValueCurveSensitivityHullWhiteCalculator.getInstance();

  private static final double SHIFT = 1.0E-6;
  private static final ParameterSensitivityParameterCalculator<HullWhiteOneFactorProviderInterface>
      PS_HW_C = new ParameterSensitivityParameterCalculator<>(PVCSHWC);
  private static final ParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator PS_HW_FDC =
      new ParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator(PVHWC, SHIFT);

  private static final SwaptionPhysicalFixedIborHullWhiteNumericalIntegrationMethod
      METHOD_HW_INTEGRATION =
          SwaptionPhysicalFixedIborHullWhiteNumericalIntegrationMethod.getInstance();
  private static final SwaptionPhysicalFixedIborHullWhiteApproximationMethod
      METHOD_HW_APPROXIMATION = SwaptionPhysicalFixedIborHullWhiteApproximationMethod.getInstance();
  private static final int NB_PATH = 12500;
  private static final HullWhiteMonteCarloMethod METHOD_HW_MONTECARLO =
      new HullWhiteMonteCarloMethod(new NormalRandomNumberGenerator(0.0, 1.0), NB_PATH);

  private static final HullWhiteOneFactorPiecewiseConstantInterestRateModel MODEL =
      new HullWhiteOneFactorPiecewiseConstantInterestRateModel();
  private static final ProbabilityDistribution<Double> NORMAL = new NormalDistribution(0, 1);

  private static final double TOLERANCE_PV = 1.0E-2;
  private static final double TOLERANCE_PV_DELTA =
      1.0E+0; // Testing note: Sensitivity is for a movement of 1. 1E+2 = 1 cent for a 1 bp move.

  @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);
  }

  @Test
  /** Tests long/short parity. */
  public void longShortParityExplicit() {
    final MultipleCurrencyAmount pvLong =
        METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final MultipleCurrencyAmount pvShort =
        METHOD_HW.presentValue(SWAPTION_SHORT_PAYER, HW_MULTICURVES);
    assertEquals(
        "Swaption physical - Hull-White - present value - long/short parity",
        pvLong.getAmount(EUR),
        -pvShort.getAmount(EUR),
        TOLERANCE_PV);
  }

  @Test
  /** Tests payer/receiver/swap parity. */
  public void payerReceiverParityExplicit() {
    final MultipleCurrencyAmount pvReceiverLong =
        METHOD_HW.presentValue(SWAPTION_LONG_RECEIVER, HW_MULTICURVES);
    final MultipleCurrencyAmount pvPayerShort =
        METHOD_HW.presentValue(SWAPTION_SHORT_PAYER, HW_MULTICURVES);
    final MultipleCurrencyAmount pvSwap = SWAP_RECEIVER.accept(PVDC, MULTICURVES);
    assertEquals(
        "Swaption physical - Hull-White - present value - payer/receiver/swap parity",
        pvReceiverLong.getAmount(EUR) + pvPayerShort.getAmount(EUR),
        pvSwap.getAmount(EUR),
        TOLERANCE_PV);
  }

  @Test
  /** Tests the method against the present value calculator. */
  public void presentValueMethodVsCalculator() {
    final MultipleCurrencyAmount pvMethod =
        METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final MultipleCurrencyAmount pvCalculator = SWAPTION_LONG_PAYER.accept(PVHWC, HW_MULTICURVES);
    assertEquals(
        "SwaptionPhysicalFixedIborSABRMethod: present value : method and calculator",
        pvMethod,
        pvCalculator);
  }

  @Test
  /** Compare explicit formula with numerical integration. */
  public void presentValueNumericalIntegration() {
    final MultipleCurrencyAmount pvPayerLongExplicit =
        METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final MultipleCurrencyAmount pvPayerLongIntegration =
        METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    assertEquals(
        "Swaption physical - Hull-White - present value - explicit/numerical integration",
        pvPayerLongExplicit.getAmount(EUR),
        pvPayerLongIntegration.getAmount(EUR),
        TOLERANCE_PV);
    final MultipleCurrencyAmount pvPayerShortExplicit =
        METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final MultipleCurrencyAmount pvPayerShortIntegration =
        METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    assertEquals(
        "Swaption physical - Hull-White - present value - explicit/numerical integration",
        pvPayerShortExplicit.getAmount(EUR),
        pvPayerShortIntegration.getAmount(EUR),
        TOLERANCE_PV);
    final MultipleCurrencyAmount pvReceiverLongExplicit =
        METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final MultipleCurrencyAmount pvReceiverLongIntegration =
        METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    assertEquals(
        "Swaption physical - Hull-White - present value - explicit/numerical integration",
        pvReceiverLongExplicit.getAmount(EUR),
        pvReceiverLongIntegration.getAmount(EUR),
        TOLERANCE_PV);
    final MultipleCurrencyAmount pvReceiverShortExplicit =
        METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final MultipleCurrencyAmount pvReceiverShortIntegration =
        METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    assertEquals(
        "Swaption physical - Hull-White - present value - explicit/numerical integration",
        pvReceiverShortExplicit.getAmount(EUR),
        pvReceiverShortIntegration.getAmount(EUR),
        TOLERANCE_PV);
  }

  @Test
  /** Compare explicit formula with approximated formula. */
  public void presentValueApproximation() {
    final BlackImpliedVolatilityFormula implied = new BlackImpliedVolatilityFormula();
    final double forward =
        SWAPTION_LONG_PAYER
            .getUnderlyingSwap()
            .accept(ParRateDiscountingCalculator.getInstance(), MULTICURVES);
    final double pvbp =
        METHOD_SWAP.presentValueBasisPoint(SWAPTION_LONG_PAYER.getUnderlyingSwap(), MULTICURVES);
    final MultipleCurrencyAmount pvPayerLongExplicit =
        METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final MultipleCurrencyAmount pvPayerLongApproximation =
        METHOD_HW_APPROXIMATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final BlackFunctionData data = new BlackFunctionData(forward, pvbp, 0.20);
    final double volExplicit =
        implied.getImpliedVolatility(data, SWAPTION_LONG_PAYER, pvPayerLongExplicit.getAmount(EUR));
    final double volApprox =
        implied.getImpliedVolatility(
            data, SWAPTION_LONG_PAYER, pvPayerLongApproximation.getAmount(EUR));
    assertEquals(
        "Swaption physical - Hull-White - present value - explicit/approximation",
        pvPayerLongExplicit.getAmount(EUR),
        pvPayerLongApproximation.getAmount(EUR),
        5.0E+2);
    assertEquals(
        "Swaption physical - Hull-White - present value - explicit/approximation",
        volExplicit,
        volApprox,
        2.5E-4); // 0.025%
    final MultipleCurrencyAmount pvReceiverLongExplicit =
        METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final MultipleCurrencyAmount pvReceiverLongApproximation =
        METHOD_HW_APPROXIMATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    assertEquals(
        "Swaption physical - Hull-White - present value - explicit/numerical integration",
        pvReceiverLongExplicit.getAmount(EUR),
        pvReceiverLongApproximation.getAmount(EUR),
        5.0E+2);
  }

  @Test
  /** Approximation analysis. */
  public void presentValueApproximationAnalysis() {
    final NormalImpliedVolatilityFormula implied = new NormalImpliedVolatilityFormula();
    final int nbStrike = 20;
    final double[] pvExplicit = new double[nbStrike + 1];
    final double[] pvApproximation = new double[nbStrike + 1];
    final double[] strike = new double[nbStrike + 1];
    final double[] volExplicit = new double[nbStrike + 1];
    final double[] volApprox = new double[nbStrike + 1];
    final double strikeRange = 0.010;
    final SwapFixedCoupon<Coupon> swap = SWAP_PAYER_DEFINITION.toDerivative(REFERENCE_DATE);
    final double forward = swap.accept(PRDC, MULTICURVES);
    final double pvbp = METHOD_SWAP.presentValueBasisPoint(swap, MULTICURVES);
    for (int loopstrike = 0; loopstrike <= nbStrike; loopstrike++) {
      strike[loopstrike] =
          forward
              - strikeRange
              + 3
                  * strikeRange
                  * loopstrike
                  / nbStrike; // From forward-strikeRange to forward+2*strikeRange
      final SwapFixedIborDefinition swapDefinition =
          SwapFixedIborDefinition.from(
              SETTLEMENT_DATE,
              SWAP_TENOR,
              EUR1YEURIBOR6M,
              NOTIONAL,
              strike[loopstrike],
              FIXED_IS_PAYER);
      final SwaptionPhysicalFixedIborDefinition swaptionDefinition =
          SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, swapDefinition, IS_LONG);
      final SwaptionPhysicalFixedIbor swaption = swaptionDefinition.toDerivative(REFERENCE_DATE);
      pvExplicit[loopstrike] = METHOD_HW.presentValue(swaption, HW_MULTICURVES).getAmount(EUR);
      pvApproximation[loopstrike] =
          METHOD_HW_APPROXIMATION.presentValue(swaption, HW_MULTICURVES).getAmount(EUR);
      final NormalFunctionData data = new NormalFunctionData(forward, pvbp, 0.01);
      volExplicit[loopstrike] =
          implied.getImpliedVolatility(data, swaption, pvExplicit[loopstrike]);
      volApprox[loopstrike] =
          implied.getImpliedVolatility(data, swaption, pvApproximation[loopstrike]);
      assertEquals(
          "Swaption physical - Hull-White - implied volatility - explicit/approximation",
          volExplicit[loopstrike],
          volApprox[loopstrike],
          1.0E-3); // 0.10%
    }
  }

  @Test(enabled = true)
  /** Compare explicit formula with Monte-Carlo and long/short and payer/receiver parities. */
  public void presentValueMonteCarlo() {
    HullWhiteMonteCarloMethod methodMC;
    methodMC =
        new HullWhiteMonteCarloMethod(
            new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH);
    // Seed fixed to the DEFAULT_SEED for testing purposes.
    final MultipleCurrencyAmount pvPayerLongExplicit =
        METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final MultipleCurrencyAmount pvPayerLongMC =
        methodMC.presentValue(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES);
    assertEquals(
        "Swaption physical - Hull-White - Monte Carlo",
        pvPayerLongExplicit.getAmount(EUR),
        pvPayerLongMC.getAmount(EUR),
        1.0E+4);
    final double pvMCPreviousRun = 4221400.891;
    assertEquals(
        "Swaption physical - Hull-White - Monte Carlo",
        pvMCPreviousRun,
        pvPayerLongMC.getAmount(EUR),
        TOLERANCE_PV);
    methodMC =
        new HullWhiteMonteCarloMethod(
            new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH);
    final MultipleCurrencyAmount pvPayerShortMC =
        methodMC.presentValue(SWAPTION_SHORT_PAYER, EUR, HW_MULTICURVES);
    assertEquals(
        "Swaption physical - Hull-White - Monte Carlo",
        -pvPayerLongMC.getAmount(EUR),
        pvPayerShortMC.getAmount(EUR),
        TOLERANCE_PV);
    final MultipleCurrencyAmount pvReceiverLongMC =
        methodMC.presentValue(SWAPTION_LONG_RECEIVER, EUR, HW_MULTICURVES);
    final MultipleCurrencyAmount pvSwap = SWAP_RECEIVER.accept(PVDC, MULTICURVES);
    assertEquals(
        "Swaption physical - Hull-White - Monte Carlo - payer/receiver/swap parity",
        pvReceiverLongMC.getAmount(EUR) + pvPayerShortMC.getAmount(EUR),
        pvSwap.getAmount(EUR),
        1.0E+5);
  }

  @Test
  /** Tests the Hull-White parameters sensitivity for the explicit formula. */
  public void presentValueHullWhiteSensitivityExplicit() {
    final double[] hwSensitivity =
        METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final int nbVolatility = HW_PARAMETERS.getVolatility().length;
    final double shiftVol = 1.0E-6;
    final double[] volatilityBumped = new double[nbVolatility];
    System.arraycopy(HW_PARAMETERS.getVolatility(), 0, volatilityBumped, 0, nbVolatility);
    final double[] volatilityTime = new double[nbVolatility - 1];
    System.arraycopy(HW_PARAMETERS.getVolatilityTime(), 1, volatilityTime, 0, nbVolatility - 1);
    final double[] pvBumpedPlus = new double[nbVolatility];
    final double[] pvBumpedMinus = new double[nbVolatility];
    final HullWhiteOneFactorPiecewiseConstantParameters parametersBumped =
        new HullWhiteOneFactorPiecewiseConstantParameters(
            HW_PARAMETERS.getMeanReversion(), volatilityBumped, volatilityTime);
    final HullWhiteOneFactorProviderDiscount bundleBumped =
        new HullWhiteOneFactorProviderDiscount(MULTICURVES, parametersBumped, EUR);
    for (int loopvol = 0; loopvol < nbVolatility; loopvol++) {
      volatilityBumped[loopvol] += shiftVol;
      parametersBumped.setVolatility(volatilityBumped);
      pvBumpedPlus[loopvol] =
          METHOD_HW.presentValue(SWAPTION_LONG_PAYER, bundleBumped).getAmount(EUR);
      volatilityBumped[loopvol] -= 2 * shiftVol;
      parametersBumped.setVolatility(volatilityBumped);
      pvBumpedMinus[loopvol] =
          METHOD_HW.presentValue(SWAPTION_LONG_PAYER, bundleBumped).getAmount(EUR);
      assertEquals(
          "Swaption - Hull-White sensitivity adjoint: derivative "
              + loopvol
              + " - difference:"
              + ((pvBumpedPlus[loopvol] - pvBumpedMinus[loopvol]) / (2 * shiftVol)
                  - hwSensitivity[loopvol]),
          (pvBumpedPlus[loopvol] - pvBumpedMinus[loopvol]) / (2 * shiftVol),
          hwSensitivity[loopvol],
          TOLERANCE_PV_DELTA);
      volatilityBumped[loopvol] = HW_PARAMETERS.getVolatility()[loopvol];
    }
  }

  @Test
  /** Tests long/short parity. */
  public void presentValueHullWhiteSensitivitylongShortParityExplicit() {
    final double[] pvhwsLong =
        METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final double[] pvhwsShort =
        METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_SHORT_PAYER, HW_MULTICURVES);
    for (int loophw = 0; loophw < pvhwsLong.length; loophw++) {
      assertEquals(
          "Swaption physical - Hull-White - presentValueHullWhiteSensitivity - long/short parity",
          pvhwsLong[loophw],
          -pvhwsShort[loophw],
          TOLERANCE_PV_DELTA);
    }
  }

  @Test
  /** Tests payer/receiver/swap parity. */
  public void presentValueHullWhiteSensitivitypayerReceiverParityExplicit() {
    final double[] pvhwsReceiverLong =
        METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_RECEIVER, HW_MULTICURVES);
    final double[] pvhwsPayerShort =
        METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_SHORT_PAYER, HW_MULTICURVES);
    for (int loophw = 0; loophw < pvhwsReceiverLong.length; loophw++) {
      assertEquals(
          "Swaption physical - Hull-White - present value - payer/receiver/swap parity",
          0,
          pvhwsReceiverLong[loophw] + pvhwsPayerShort[loophw],
          TOLERANCE_PV_DELTA);
    }
  }

  @Test
  /** Tests present value curve sensitivity when the valuation date is on trade date. */
  public void presentValueCurveSensitivity() {
    final MultipleCurrencyParameterSensitivity pvpsExact =
        PS_HW_C.calculateSensitivity(
            SWAPTION_SHORT_RECEIVER,
            HW_MULTICURVES,
            HW_MULTICURVES.getMulticurveProvider().getAllNames());
    final MultipleCurrencyParameterSensitivity pvpsFD =
        PS_HW_FDC.calculateSensitivity(SWAPTION_SHORT_RECEIVER, HW_MULTICURVES);
    AssertSensivityObjects.assertEquals(
        "SwaptionPhysicalFixedIborSABRMethod: presentValueCurveSensitivity ",
        pvpsExact,
        pvpsFD,
        TOLERANCE_PV_DELTA);
  }

  @Test(enabled = false)
  /** Tests present value curve sensitivity when the valuation date is on trade date. */
  public void presentValueCurveSensitivityStability() {
    // 5Yx5Y
    final MultipleCurrencyParameterSensitivity pvpsExact =
        PS_HW_C.calculateSensitivity(
            SWAPTION_SHORT_RECEIVER,
            HW_MULTICURVES,
            HW_MULTICURVES.getMulticurveProvider().getAllNames());
    final double derivativeExact = pvpsExact.totalSensitivity(MULTICURVES.getFxRates(), EUR);
    final double startingShift = 1.0E-4;
    final double ratio = Math.sqrt(2.0);
    final int nbShift = 55;
    final double[] eps = new double[nbShift + 1];
    final double[] derivative_FD = new double[nbShift];
    final double[] diff = new double[nbShift];
    eps[0] = startingShift;
    for (int loopshift = 0; loopshift < nbShift; loopshift++) {
      final ParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator fdShift =
          new ParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator(PVHWC, eps[loopshift]);
      final MultipleCurrencyParameterSensitivity pvpsFD =
          fdShift.calculateSensitivity(SWAPTION_SHORT_RECEIVER, HW_MULTICURVES);
      derivative_FD[loopshift] = pvpsFD.totalSensitivity(MULTICURVES.getFxRates(), EUR);
      diff[loopshift] = derivative_FD[loopshift] - derivativeExact;
      eps[loopshift + 1] = eps[loopshift] / ratio;
    }
    // 1Mx5Y
    final Period expirationPeriod =
        Period.ofDays(
            1); // Period.ofDays(1); Period.ofDays(7); Period.ofMonths(1); Period.ofYears(1);
    // Period.ofYears(10);
    final ZonedDateTime expiryDateExp =
        ScheduleCalculator.getAdjustedDate(REFERENCE_DATE, expirationPeriod, EURIBOR6M, CALENDAR);
    final ZonedDateTime settlementDateExp =
        ScheduleCalculator.getAdjustedDate(expiryDateExp, SPOT_LAG, CALENDAR);
    final double ATM = 0.0151; //  1W: 1.52% - 1M: 1.52% - 1Y: 1.51% - 10Y: 1.51%
    final SwapFixedIborDefinition swapExpx5YDefinition =
        SwapFixedIborDefinition.from(
            settlementDateExp, SWAP_TENOR, EUR1YEURIBOR6M, NOTIONAL, ATM, !FIXED_IS_PAYER);
    final SwaptionPhysicalFixedIborDefinition swaptionExpx5YDefinition =
        SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, swapExpx5YDefinition, !IS_LONG);
    final SwaptionPhysicalFixedIbor swaptionExpx5Y =
        swaptionExpx5YDefinition.toDerivative(REFERENCE_DATE);
    //    final double forward = swaptionExpx5Y.getUnderlyingSwap().accept(PRDC, MULTICURVES);
    final MultipleCurrencyParameterSensitivity pvpsExactExp =
        PS_HW_C.calculateSensitivity(
            swaptionExpx5Y, HW_MULTICURVES, HW_MULTICURVES.getMulticurveProvider().getAllNames());
    final double derivativeExactExp = pvpsExactExp.totalSensitivity(MULTICURVES.getFxRates(), EUR);
    final double[] derivative_FDExp = new double[nbShift];
    final double[] diffExp = new double[nbShift];
    for (int loopshift = 0; loopshift < nbShift; loopshift++) {
      final ParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator fdShift =
          new ParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator(PVHWC, eps[loopshift]);
      final MultipleCurrencyParameterSensitivity pvpsFD =
          fdShift.calculateSensitivity(swaptionExpx5Y, HW_MULTICURVES);
      derivative_FDExp[loopshift] = pvpsFD.totalSensitivity(MULTICURVES.getFxRates(), EUR);
      diffExp[loopshift] = derivative_FDExp[loopshift] - derivativeExactExp;
    }
    //    int t = 0;
    //    t++;
  }

  @Test
  /** Tests long/short parity. */
  public void presentValueCurveSensitivityLongShortParityExplicit() {
    final MultipleCurrencyMulticurveSensitivity pvhwsLong =
        METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    final MultipleCurrencyMulticurveSensitivity pvhwsShort =
        METHOD_HW.presentValueCurveSensitivity(SWAPTION_SHORT_PAYER, HW_MULTICURVES);
    AssertSensivityObjects.assertEquals(
        "Swaption physical - Hull-White - presentValueCurveSensitivity - long/short parity",
        pvhwsLong,
        pvhwsShort.multipliedBy(-1.0),
        TOLERANCE_PV_DELTA);
  }

  @Test
  /** Tests payer/receiver/swap parity. */
  public void presentValueCurveSensitivityPayerReceiverParityExplicit() {
    final MultipleCurrencyMulticurveSensitivity pvhwsReceiverLong =
        METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_RECEIVER, HW_MULTICURVES);
    final MultipleCurrencyMulticurveSensitivity pvhwsPayerShort =
        METHOD_HW.presentValueCurveSensitivity(SWAPTION_SHORT_PAYER, HW_MULTICURVES);
    final MultipleCurrencyMulticurveSensitivity pvSwap = SWAP_RECEIVER.accept(PVCSDC, MULTICURVES);
    AssertSensivityObjects.assertEquals(
        "Swaption physical - Hull-White - presentValueCurveSensitivity - payer/receiver/swap parity",
        pvSwap.cleaned(TOLERANCE_PV_DELTA),
        pvhwsReceiverLong.plus(pvhwsPayerShort).cleaned(TOLERANCE_PV_DELTA),
        TOLERANCE_PV_DELTA);
  }

  @Test
  /** Tests the curve sensitivity in Monte Carlo approach. */
  public void presentValueCurveSensitivityMonteCarlo() {
    final double toleranceDelta = 1.0E+6; // 100 USD by bp
    final MultipleCurrencyMulticurveSensitivity pvcsExplicit =
        METHOD_HW
            .presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES)
            .cleaned(TOLERANCE_PV_DELTA);
    final HullWhiteMonteCarloMethod methodMC =
        new HullWhiteMonteCarloMethod(
            new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH);
    final MultipleCurrencyMulticurveSensitivity pvcsMC =
        methodMC
            .presentValueCurveSensitivity(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES)
            .cleaned(TOLERANCE_PV_DELTA);
    AssertSensivityObjects.assertEquals(
        "Swaption physical - Hull-White - presentValueCurveSensitivity - payer/receiver/swap parity",
        pvcsExplicit,
        pvcsMC,
        toleranceDelta);
  }

  @Test(enabled = false)
  /** Tests of performance. "enabled = false" for the standard testing. */
  public void performance() {
    long startTime, endTime;
    final int nbTest = 1000;
    MultipleCurrencyAmount pvPayerLongExplicit = MultipleCurrencyAmount.of(EUR, 0.0);
    MultipleCurrencyAmount pvPayerLongIntegration = MultipleCurrencyAmount.of(EUR, 0.0);
    MultipleCurrencyAmount pvPayerLongApproximation = MultipleCurrencyAmount.of(EUR, 0.0);
    @SuppressWarnings("unused")
    MultipleCurrencyAmount pvPayerLongMC = MultipleCurrencyAmount.of(EUR, 0.0);
    double[] pvhws =
        METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    MultipleCurrencyMulticurveSensitivity pvcs =
        METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongExplicit = METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest + " pv swaption Hull-White explicit method: " + (endTime - startTime) + " ms");
    // Performance note: HW price: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 380 ms for
    // 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " HW sensitivity swaption Hull-White explicit method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW sensitivity (3): 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon:
    // 430 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvcs = METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " curve sensitivity swaption Hull-White explicit method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: curve sensitivity (40): 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 855 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
      pvcs = METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
      pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " price/delta/vega swaption Hull-White explicit method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: present value/delta/vega: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 1730 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongIntegration =
          METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " swaption Hull-White numerical integration method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW numerical integration: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 1700 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongApproximation =
          METHOD_HW_APPROXIMATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest + " swaption Hull-White approximation method: " + (endTime - startTime) + " ms");
    // Performance note: HW approximation: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 250
    // ms for 10000 swaptions.

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongMC = METHOD_HW_MONTECARLO.presentValue(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " swaption Hull-White Monte Carlo method ("
            + NB_PATH
            + " paths): "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW approximation: 18-Aug-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 9200
    // ms for 1000 swaptions (12500 paths).

    final double difference =
        pvPayerLongExplicit.getAmount(EUR) - pvPayerLongIntegration.getAmount(EUR);
    final double difference2 =
        pvPayerLongExplicit.getAmount(EUR) - pvPayerLongApproximation.getAmount(EUR);
    //      double difference3 = pvPayerLongExplicit.getAmount(CUR) - pvPayerLongMC.getAmount(CUR);
    System.out.println("Difference explicit-integration: " + difference);
    System.out.println("Difference explicit-approximation: " + difference2);
    //      System.out.println("Difference explicit-Monte Carlo: " + difference3);
    System.out.println("Curve sensitivity: " + pvcs.toString());
    System.out.println("HW sensitivity: " + Arrays.toString(pvhws));
  }

  @Test(enabled = false)
  /** Tests of performance. "enabled = false" for the standard testing. */
  public void performanceCurveSensitivity() {
    long startTime, endTime;
    final int nbTest = 25;
    MultipleCurrencyAmount pvMC = MultipleCurrencyAmount.of(EUR, 0.0);
    final MultipleCurrencyMulticurveSensitivity pvcsExplicit =
        METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES);
    MultipleCurrencyMulticurveSensitivity pvcsMC = pvcsExplicit;
    final HullWhiteMonteCarloMethod methodMC =
        new HullWhiteMonteCarloMethod(
            new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH);

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvMC = METHOD_HW_MONTECARLO.presentValue(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " swaption Hull-White Monte Carlo method ("
            + NB_PATH
            + " paths): "
            + (endTime - startTime)
            + " ms / price:"
            + pvMC.toString());
    // Performance note: HW approximation: 03-Dec-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 250
    // ms for 25 swaptions (12500 paths).
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvcsMC = methodMC.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " curve sensitivity swaption Hull-White MC method: ("
            + NB_PATH
            + " paths) "
            + (endTime - startTime)
            + " ms / risk:"
            + pvcsMC.toString());
    // Performance note: curve sensitivity (40): 03-Dec-2012: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 600 ms for 25 swaptions (12500 paths).

  }
}
/** Test the swaps with multiple legs present value and related figures. */
@Test(groups = TestGroup.UNIT)
public class SwapMultilegCalculatorTest {

  private static final MulticurveProviderDiscount MULTICURVES =
      MulticurveProviderDiscountDataSets.createMulticurveEurUsd();

  private static final Calendar TARGET = new MondayToFridayCalendar("TRAGET");
  private static final IndexIborMaster INDEX_MASTER = IndexIborMaster.getInstance();
  private static final IborIndex EURIBOR3M = INDEX_MASTER.getIndex("EURIBOR3M");
  private static final IborIndex EURIBOR6M = INDEX_MASTER.getIndex("EURIBOR6M");
  private static final GeneratorSwapFixedIborMaster SWAP_MASTER =
      GeneratorSwapFixedIborMaster.getInstance();
  private static final GeneratorSwapFixedIbor EUR1YEURIBOR6M =
      SWAP_MASTER.getGenerator("EUR1YEURIBOR6M", TARGET);
  private static final Period ANNUITY_TENOR = Period.ofYears(2);
  private static final Currency EUR = EURIBOR3M.getCurrency();

  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2013, 3, 20);
  private static final ZonedDateTime SETTLEMENT_DATE = DateUtils.getUTCDate(2013, 10, 16);
  private static final double NOTIONAL = 100000000; // 100 m
  private static final double SPREAD = 0.0010; // 10 bps
  private static final StubType STUB = StubType.SHORT_START;

  // Swap represeting a EUR basis swap: 1 spread leg and 2 Euribor leg.
  private static final boolean IS_PAYER_SPREAD = true;
  private static final ZonedDateTime MATURITY_DATE = SETTLEMENT_DATE.plus(ANNUITY_TENOR);
  private static final int NB_LEGS = 3;

  @SuppressWarnings("rawtypes")
  private static final AnnuityDefinition[] LEGS_DEFINITION = new AnnuityDefinition[NB_LEGS];

  static {
    LEGS_DEFINITION[0] =
        AnnuityDefinitionBuilder.couponFixed(
            EUR,
            SETTLEMENT_DATE,
            MATURITY_DATE,
            EUR1YEURIBOR6M.getFixedLegPeriod(),
            TARGET,
            EUR1YEURIBOR6M.getFixedLegDayCount(),
            EUR1YEURIBOR6M.getBusinessDayConvention(),
            EUR1YEURIBOR6M.isEndOfMonth(),
            NOTIONAL,
            SPREAD,
            IS_PAYER_SPREAD,
            STUB,
            0);
    LEGS_DEFINITION[1] =
        AnnuityDefinitionBuilder.couponIbor(
            SETTLEMENT_DATE,
            MATURITY_DATE,
            EURIBOR3M.getTenor(),
            NOTIONAL,
            EURIBOR3M,
            IS_PAYER_SPREAD,
            EURIBOR3M.getDayCount(),
            EURIBOR3M.getBusinessDayConvention(),
            EURIBOR3M.isEndOfMonth(),
            TARGET,
            STUB,
            0);
    LEGS_DEFINITION[2] =
        AnnuityDefinitionBuilder.couponIbor(
            SETTLEMENT_DATE,
            MATURITY_DATE,
            EURIBOR6M.getTenor(),
            NOTIONAL,
            EURIBOR6M,
            !IS_PAYER_SPREAD,
            EURIBOR6M.getDayCount(),
            EURIBOR6M.getBusinessDayConvention(),
            EURIBOR6M.isEndOfMonth(),
            TARGET,
            STUB,
            0);
  }

  @SuppressWarnings("unchecked")
  private static final SwapMultilegDefinition SWAP_MULTI_LEG_DEFINITION =
      new SwapMultilegDefinition(LEGS_DEFINITION);

  private static final SwapMultileg SWAP_MULTI_LEG =
      SWAP_MULTI_LEG_DEFINITION.toDerivative(REFERENCE_DATE);

  private static final PresentValueDiscountingCalculator PVDC =
      PresentValueDiscountingCalculator.getInstance();
  private static final PresentValueCurveSensitivityDiscountingCalculator PVCSDC =
      PresentValueCurveSensitivityDiscountingCalculator.getInstance();
  private static final ParSpreadMarketQuoteDiscountingCalculator PSMQDC =
      ParSpreadMarketQuoteDiscountingCalculator.getInstance();
  private static final ParSpreadMarketQuoteCurveSensitivityDiscountingCalculator PSMQCSDC =
      ParSpreadMarketQuoteCurveSensitivityDiscountingCalculator.getInstance();
  private static final PresentValueMarketQuoteSensitivityDiscountingCalculator PVMQSC =
      PresentValueMarketQuoteSensitivityDiscountingCalculator.getInstance();
  private static final PresentValueMarketQuoteSensitivityCurveSensitivityDiscountingCalculator
      PVMQSCSC =
          PresentValueMarketQuoteSensitivityCurveSensitivityDiscountingCalculator.getInstance();

  private static final double TOLERANCE_PV = 1.0E-2;
  private static final double TOLERANCE_PV_DELTA = 1.0E-2;
  private static final double TOLERANCE_RATE = 1.0E-8;
  private static final double TOLERANCE_RATE_DELTA = 1.0E-8;

  @Test
  public void presentValueDiscountingCalculator() {
    final MultipleCurrencyAmount pvSwap = SWAP_MULTI_LEG.accept(PVDC, MULTICURVES);
    MultipleCurrencyAmount pvLegs = MultipleCurrencyAmount.of(EUR, 0.0);
    for (int loopleg = 0; loopleg < NB_LEGS; loopleg++) {
      pvLegs = pvLegs.plus(SWAP_MULTI_LEG.getLegs()[loopleg].accept(PVDC, MULTICURVES));
    }
    assertEquals(
        "SwapMultileg: presentValueDiscountingCalculator",
        pvSwap.getAmount(EUR),
        pvLegs.getAmount(EUR),
        TOLERANCE_PV);
  }

  @Test
  public void presentValueCurveSensitivityDiscountingCalculator() {
    final MultipleCurrencyMulticurveSensitivity pvcsSwap =
        SWAP_MULTI_LEG.accept(PVCSDC, MULTICURVES);
    MultipleCurrencyMulticurveSensitivity pvcsLegs =
        SWAP_MULTI_LEG.getLegs()[0].accept(PVCSDC, MULTICURVES);
    for (int loopleg = 1; loopleg < NB_LEGS; loopleg++) {
      pvcsLegs = pvcsLegs.plus(SWAP_MULTI_LEG.getLegs()[loopleg].accept(PVCSDC, MULTICURVES));
    }
    AssertSensitivityObjects.assertEquals(
        "SwapMultileg: presentValueCurveSensitivityDiscountingCalculator",
        pvcsLegs,
        pvcsSwap,
        TOLERANCE_PV_DELTA);
  }

  @Test
  public void parSpreadMarketQuoteDiscountingCalculator() {
    final double psmq = SWAP_MULTI_LEG.accept(PSMQDC, MULTICURVES);
    final double pv =
        -MULTICURVES
            .getFxRates()
            .convert(
                SWAP_MULTI_LEG.accept(PVDC, MULTICURVES), SWAP_MULTI_LEG.getLegs()[0].getCurrency())
            .getAmount();
    final double pvbp = SWAP_MULTI_LEG.getLegs()[0].accept(PVMQSC, MULTICURVES);
    assertEquals(
        "SwapMultileg: parSpreadMarketQuoteDiscountingCalculator", psmq, pv / pvbp, TOLERANCE_RATE);
  }

  @Test
  public void parSpreadMarketQuoteCurveSensitivityDiscountingCalculator() {
    final double pv =
        MULTICURVES
            .getFxRates()
            .convert(
                SWAP_MULTI_LEG.accept(PVDC, MULTICURVES), SWAP_MULTI_LEG.getLegs()[0].getCurrency())
            .getAmount();
    final double pvbp = SWAP_MULTI_LEG.getLegs()[0].accept(PVMQSC, MULTICURVES);
    final MulticurveSensitivity pvcs =
        SWAP_MULTI_LEG
            .accept(PVCSDC, MULTICURVES)
            .converted(EUR, MULTICURVES.getFxRates())
            .getSensitivity(EUR);
    final MulticurveSensitivity pvbpcs = SWAP_MULTI_LEG.getLegs()[0].accept(PVMQSCSC, MULTICURVES);
    final MulticurveSensitivity psmqcsExpected =
        pvcs.multipliedBy(-1.0d / pvbp).plus(pvbpcs.multipliedBy(pv / (pvbp * pvbp))).cleaned();
    final MulticurveSensitivity psmqcs = SWAP_MULTI_LEG.accept(PSMQCSDC, MULTICURVES).cleaned();
    AssertSensitivityObjects.assertEquals(
        "SwapMultileg: presentValueCurveSensitivityDiscountingCalculator",
        psmqcs,
        psmqcsExpected,
        TOLERANCE_RATE_DELTA);
  }
}
/**
 * Tests related to the pricing methods for Ibor coupon in the discounting method with data in
 * MarketBundle.
 */
public class CouponIborDiscountingProviderMethodTest {

  private static final MulticurveProviderDiscount MULTICURVES =
      MulticurveProviderDiscountDataSets.createMulticurveEurUsd();
  private static final IborIndex[] IBOR_INDEXES =
      MulticurveProviderDiscountDataSets.getIndexesIborMulticurveEurUsd();
  private static final IborIndex EURIBOR3M = IBOR_INDEXES[0];
  private static final Currency EUR = EURIBOR3M.getCurrency();
  private static final Calendar CALENDAR = MulticurveProviderDiscountDataSets.getEURCalendar();

  private static final DayCount DAY_COUNT_COUPON =
      DayCountFactory.INSTANCE.getDayCount("Actual/365");
  private static final ZonedDateTime ACCRUAL_START_DATE = DateUtils.getUTCDate(2011, 5, 23);
  private static final ZonedDateTime ACCRUAL_END_DATE = DateUtils.getUTCDate(2011, 8, 22);
  private static final double ACCRUAL_FACTOR =
      DAY_COUNT_COUPON.getDayCountFraction(ACCRUAL_START_DATE, ACCRUAL_END_DATE);
  private static final double NOTIONAL = 1000000; // 1m
  private static final CouponIborDefinition CPN_IBOR_DEFINITION =
      CouponIborDefinition.from(
          ACCRUAL_START_DATE, ACCRUAL_END_DATE, ACCRUAL_FACTOR, NOTIONAL, EURIBOR3M, CALENDAR);

  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2010, 12, 27);
  private static final CouponIbor CPN_IBOR =
      (CouponIbor) CPN_IBOR_DEFINITION.toDerivative(REFERENCE_DATE);

  private static final CouponIborDiscountingMethod METHOD_CPN_IBOR =
      CouponIborDiscountingMethod.getInstance();
  private static final PresentValueDiscountingCalculator PVDC =
      PresentValueDiscountingCalculator.getInstance();
  private static final PresentValueCurveSensitivityDiscountingCalculator PVCSDC =
      PresentValueCurveSensitivityDiscountingCalculator.getInstance();

  private static final double TOLERANCE_PV = 1.0E-2;
  private static final double TOLERANCE_PV_DELTA = 1.0E+2;

  @Test
  public void presentValueMarketDiscount() {
    final MultipleCurrencyAmount pvComputed = METHOD_CPN_IBOR.presentValue(CPN_IBOR, MULTICURVES);
    final double forward =
        MULTICURVES.getForwardRate(
            EURIBOR3M,
            CPN_IBOR.getFixingPeriodStartTime(),
            CPN_IBOR.getFixingPeriodEndTime(),
            CPN_IBOR.getFixingAccrualFactor());
    final double df =
        MULTICURVES.getDiscountFactor(EURIBOR3M.getCurrency(), CPN_IBOR.getPaymentTime());
    final double pvExpected = NOTIONAL * ACCRUAL_FACTOR * forward * df;
    assertEquals(
        "CouponIborDiscountingMarketMethod: present value",
        pvExpected,
        pvComputed.getAmount(EURIBOR3M.getCurrency()),
        TOLERANCE_PV);
  }

  @Test
  public void presentValueMethodVsCalculator() {
    final MultipleCurrencyAmount pvMethod = METHOD_CPN_IBOR.presentValue(CPN_IBOR, MULTICURVES);
    final MultipleCurrencyAmount pvCalculator = CPN_IBOR.accept(PVDC, MULTICURVES);
    assertEquals(
        "CouponFixedDiscountingMarketMethod: present value",
        pvMethod.getAmount(EUR),
        pvCalculator.getAmount(EUR),
        TOLERANCE_PV);
  }

  // Testing note: the presentValueMarketSensitivity is tested in
  // ParameterSensitivityProviderCalculatorTest

  @Test
  public void presentValueMarketSensitivityMethodVsCalculator() {
    final MultipleCurrencyMulticurveSensitivity pvcsMethod =
        METHOD_CPN_IBOR.presentValueCurveSensitivity(CPN_IBOR, MULTICURVES);
    final MultipleCurrencyMulticurveSensitivity pvcsCalculator =
        CPN_IBOR.accept(PVCSDC, MULTICURVES);
    AssertSensivityObjects.assertEquals(
        "CouponFixedDiscountingMarketMethod: presentValueMarketSensitivity",
        pvcsMethod,
        pvcsCalculator,
        TOLERANCE_PV_DELTA);
  }
}
public class CouponFixedCompoundingDefinitionTest {

  private static final Calendar NYC = new MondayToFridayCalendar("NYC");
  private static final IndexIborMaster MASTER_IBOR = IndexIborMaster.getInstance();
  private static final IborIndex USDLIBOR1M = MASTER_IBOR.getIndex("USDLIBOR1M");
  private static final Currency CURRENCY = USDLIBOR1M.getCurrency();

  private static final Period TENOR_3M = Period.ofMonths(3);
  private static final ZonedDateTime START_DATE = DateUtils.getUTCDate(2012, 8, 24);
  private static final double NOTIONAL = 123454321;
  private static final double FIXED_RATE = .02;

  private static final ZonedDateTime[] ACCRUAL_END_DATES =
      ScheduleCalculator.getAdjustedDateSchedule(
          START_DATE, TENOR_3M, true, false, USDLIBOR1M, NYC);
  private static final int NB_SUB_PERIOD = ACCRUAL_END_DATES.length;
  private static final ZonedDateTime[] ACCRUAL_START_DATES = new ZonedDateTime[NB_SUB_PERIOD];
  private static final double[] PAYMENT_ACCRUAL_FACTORS = new double[NB_SUB_PERIOD];
  private static final double PAYMENT_ACCRUAL_FACTOR;

  static {
    ACCRUAL_START_DATES[0] = START_DATE;
    for (int loopsub = 1; loopsub < NB_SUB_PERIOD; loopsub++) {
      ACCRUAL_START_DATES[loopsub] = ACCRUAL_END_DATES[loopsub - 1];
    }
    double af = 0.0;
    for (int loopsub = 0; loopsub < NB_SUB_PERIOD; loopsub++) {
      PAYMENT_ACCRUAL_FACTORS[loopsub] =
          USDLIBOR1M
              .getDayCount()
              .getDayCountFraction(ACCRUAL_START_DATES[loopsub], ACCRUAL_END_DATES[loopsub]);
      af += PAYMENT_ACCRUAL_FACTORS[loopsub];
    }
    PAYMENT_ACCRUAL_FACTOR = af;
  }

  private static final ZonedDateTime[] FIXING_DATES =
      ScheduleCalculator.getAdjustedDate(ACCRUAL_START_DATES, -USDLIBOR1M.getSpotLag(), NYC);
  private static final ZonedDateTime[] FIXING_PERIOD_END_DATES =
      ScheduleCalculator.getAdjustedDate(ACCRUAL_START_DATES, USDLIBOR1M, NYC);
  private static final double[] FIXING_ACCRUAL_FACTORS = new double[NB_SUB_PERIOD];

  static {
    for (int loopsub = 0; loopsub < NB_SUB_PERIOD; loopsub++) {
      FIXING_ACCRUAL_FACTORS[loopsub] =
          USDLIBOR1M
              .getDayCount()
              .getDayCountFraction(ACCRUAL_START_DATES[loopsub], FIXING_PERIOD_END_DATES[loopsub]);
    }
  }

  private static final ZonedDateTime PAYMENT_DATE = ACCRUAL_END_DATES[NB_SUB_PERIOD - 1];
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2012, 8, 17);
  private static final double[] FIXING_TIMES =
      TimeCalculator.getTimeBetween(REFERENCE_DATE, FIXING_DATES);
  private static final double[] FIXING_PERIOD_END_TIMES =
      TimeCalculator.getTimeBetween(REFERENCE_DATE, FIXING_PERIOD_END_DATES);
  private static final double[] ACCRUAL_START_TIMES =
      TimeCalculator.getTimeBetween(REFERENCE_DATE, ACCRUAL_START_DATES);
  private static final double[] ACCRUAL_END_TIMES =
      TimeCalculator.getTimeBetween(REFERENCE_DATE, ACCRUAL_END_DATES);
  private static final double PAYMENT_TIME = ACCRUAL_END_TIMES[NB_SUB_PERIOD - 1];
  private static final String DSC_NAME = "Dsc_USD";
  private static final String FWD_NAME = "Forward1M_USD";

  private static final CouponFixedCompoundingDefinition COUPON =
      CouponFixedCompoundingDefinition.from(
          CURRENCY,
          PAYMENT_DATE,
          ACCRUAL_START_DATES[0],
          ACCRUAL_END_DATES[NB_SUB_PERIOD - 1],
          PAYMENT_ACCRUAL_FACTOR,
          NOTIONAL,
          FIXED_RATE,
          ACCRUAL_START_DATES,
          ACCRUAL_END_DATES,
          PAYMENT_ACCRUAL_FACTORS);

  @Test
  /** Tests the getters. */
  public void testGetters() {
    assertEquals(COUPON.getPaymentDate(), PAYMENT_DATE);
    assertEquals(COUPON.getAccrualStartDate(), ACCRUAL_START_DATES[0]);
    assertEquals(COUPON.getAccrualEndDate(), ACCRUAL_END_DATES[NB_SUB_PERIOD - 1]);
    assertEquals(COUPON.getPaymentYearFraction(), PAYMENT_ACCRUAL_FACTOR, 1E-10);
    assertEquals(COUPON.getNotional(), NOTIONAL, 1E-2);
    assertEquals(COUPON.getRate(), FIXED_RATE, 1E-10);
    assertArrayEquals(COUPON.getAccrualStartDates(), ACCRUAL_START_DATES);
    assertArrayEquals(COUPON.getAccrualEndDates(), ACCRUAL_END_DATES);
    assertArrayEquals(COUPON.getPaymentAccrualFactors(), PAYMENT_ACCRUAL_FACTORS, 0);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void nullCurrency() {
    CouponFixedCompoundingDefinition.from(
        null,
        PAYMENT_DATE,
        ACCRUAL_START_DATES[0],
        ACCRUAL_END_DATES[NB_SUB_PERIOD - 1],
        PAYMENT_ACCRUAL_FACTOR,
        NOTIONAL,
        FIXED_RATE,
        ACCRUAL_START_DATES,
        ACCRUAL_END_DATES,
        PAYMENT_ACCRUAL_FACTORS);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullPaymentDate() {
    CouponFixedCompoundingDefinition.from(
        CURRENCY,
        null,
        ACCRUAL_START_DATES[0],
        ACCRUAL_END_DATES[NB_SUB_PERIOD - 1],
        PAYMENT_ACCRUAL_FACTOR,
        NOTIONAL,
        FIXED_RATE,
        ACCRUAL_START_DATES,
        ACCRUAL_END_DATES,
        PAYMENT_ACCRUAL_FACTORS);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNegativePaymentAccrualFactor() {
    CouponFixedCompoundingDefinition.from(
        CURRENCY,
        PAYMENT_DATE,
        ACCRUAL_START_DATES[0],
        ACCRUAL_END_DATES[NB_SUB_PERIOD - 1],
        -PAYMENT_ACCRUAL_FACTOR,
        NOTIONAL,
        FIXED_RATE,
        ACCRUAL_START_DATES,
        ACCRUAL_END_DATES,
        PAYMENT_ACCRUAL_FACTORS);
  }

  @Test
  /** Tests the equal and hash code. */
  public void testEqualHash() {
    assertEquals("CouponIbor: equal-hash", COUPON, COUPON);
    final CouponFixedCompoundingDefinition other =
        CouponFixedCompoundingDefinition.from(
            CURRENCY,
            PAYMENT_DATE,
            ACCRUAL_START_DATES[0],
            ACCRUAL_END_DATES[NB_SUB_PERIOD - 1],
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXED_RATE,
            ACCRUAL_START_DATES,
            ACCRUAL_END_DATES,
            PAYMENT_ACCRUAL_FACTORS);
    assertEquals("CouponFixedCompoundingDefinition: equal-hash", other, COUPON);
    assertEquals(
        "CouponFixedCompoundingDefinition: equal-hash", other.hashCode(), COUPON.hashCode());
    CouponFixedCompoundingDefinition modified;
    modified =
        CouponFixedCompoundingDefinition.from(
            CURRENCY,
            PAYMENT_DATE.plusDays(1),
            ACCRUAL_START_DATES[0],
            ACCRUAL_END_DATES[NB_SUB_PERIOD - 1],
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXED_RATE,
            ACCRUAL_START_DATES,
            ACCRUAL_END_DATES,
            PAYMENT_ACCRUAL_FACTORS);
    assertFalse("CouponIbor: equal-hash", COUPON.equals(modified));
    modified =
        CouponFixedCompoundingDefinition.from(
            CURRENCY,
            PAYMENT_DATE,
            ACCRUAL_START_DATES[0].plusDays(1),
            ACCRUAL_END_DATES[NB_SUB_PERIOD - 1],
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXED_RATE,
            ACCRUAL_START_DATES,
            ACCRUAL_END_DATES,
            PAYMENT_ACCRUAL_FACTORS);
    assertFalse("CouponIbor: equal-hash", COUPON.equals(modified));
    modified =
        CouponFixedCompoundingDefinition.from(
            CURRENCY,
            PAYMENT_DATE,
            ACCRUAL_START_DATES[0],
            ACCRUAL_END_DATES[NB_SUB_PERIOD - 1].plusDays(1),
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXED_RATE,
            ACCRUAL_START_DATES,
            ACCRUAL_END_DATES,
            PAYMENT_ACCRUAL_FACTORS);
    assertFalse("CouponIbor: equal-hash", COUPON.equals(modified));
    modified =
        CouponFixedCompoundingDefinition.from(
            CURRENCY,
            PAYMENT_DATE,
            ACCRUAL_START_DATES[0],
            ACCRUAL_END_DATES[NB_SUB_PERIOD - 1],
            PAYMENT_ACCRUAL_FACTOR + 1,
            NOTIONAL,
            FIXED_RATE,
            ACCRUAL_START_DATES,
            ACCRUAL_END_DATES,
            PAYMENT_ACCRUAL_FACTORS);
    assertFalse("CouponIbor: equal-hash", COUPON.equals(modified));
    modified =
        CouponFixedCompoundingDefinition.from(
            CURRENCY,
            PAYMENT_DATE,
            ACCRUAL_START_DATES[0],
            ACCRUAL_END_DATES[NB_SUB_PERIOD - 1],
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL + 1,
            FIXED_RATE,
            ACCRUAL_START_DATES,
            ACCRUAL_END_DATES,
            PAYMENT_ACCRUAL_FACTORS);
    assertFalse("CouponIbor: equal-hash", COUPON.equals(modified));
    modified =
        CouponFixedCompoundingDefinition.from(
            CURRENCY,
            PAYMENT_DATE,
            ACCRUAL_START_DATES[0],
            ACCRUAL_END_DATES[NB_SUB_PERIOD - 1],
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXED_RATE + 1,
            ACCRUAL_START_DATES,
            ACCRUAL_END_DATES,
            PAYMENT_ACCRUAL_FACTORS);
    assertFalse("CouponIbor: equal-hash", COUPON.equals(modified));
  }
}
/** Tests related to the construction of Ibor coupon. */
public class CouponIborTest {

  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2010, 12, 27);
  private static final Calendar TARGET = new MondayToFridayCalendar("TARGET");
  private static final IndexIborMaster INDEX_IBOR_MASTER = IndexIborMaster.getInstance();
  private static final IborIndex INDEX_EURIBOR3M = INDEX_IBOR_MASTER.getIndex("EURIBOR3M");
  private static final Currency EUR = INDEX_EURIBOR3M.getCurrency();
  // Coupon
  private static final DayCount DAY_COUNT_COUPON =
      DayCountFactory.INSTANCE.getDayCount("Actual/365");
  private static final ZonedDateTime ACCRUAL_START_DATE = DateUtils.getUTCDate(2011, 5, 23);
  private static final ZonedDateTime ACCRUAL_END_DATE = DateUtils.getUTCDate(2011, 8, 22);
  private static final ZonedDateTime PAYMENT_DATE = DateUtils.getUTCDate(2011, 8, 24);
  private static final double ACCRUAL_FACTOR =
      DAY_COUNT_COUPON.getDayCountFraction(ACCRUAL_START_DATE, ACCRUAL_END_DATE);
  private static final double NOTIONAL = 1000000; // 1m
  private static final ZonedDateTime FIXING_DATE =
      ScheduleCalculator.getAdjustedDate(
          ACCRUAL_END_DATE, -INDEX_EURIBOR3M.getSpotLag(), TARGET); // In arrears
  private static final ZonedDateTime FIXING_START_DATE = ACCRUAL_END_DATE;
  private static final ZonedDateTime FIXING_END_DATE =
      ScheduleCalculator.getAdjustedDate(FIXING_START_DATE, INDEX_EURIBOR3M, TARGET);

  private static final double PAYMENT_TIME =
      TimeCalculator.getTimeBetween(REFERENCE_DATE, PAYMENT_DATE);
  private static final double FIXING_TIME =
      TimeCalculator.getTimeBetween(REFERENCE_DATE, FIXING_DATE);
  private static final double FIXING_START_TIME =
      TimeCalculator.getTimeBetween(REFERENCE_DATE, FIXING_START_DATE);
  private static final double FIXING_END_TIME =
      TimeCalculator.getTimeBetween(REFERENCE_DATE, FIXING_END_DATE);
  private static final double FIXING_ACCRUAL_FACTOR =
      INDEX_EURIBOR3M.getDayCount().getDayCountFraction(FIXING_START_DATE, FIXING_END_DATE);

  private static final CouponIbor CPN_IBOR =
      new CouponIbor(
          EUR,
          PAYMENT_TIME,
          ACCRUAL_FACTOR,
          NOTIONAL,
          FIXING_TIME,
          INDEX_EURIBOR3M,
          FIXING_START_TIME,
          FIXING_END_TIME,
          FIXING_ACCRUAL_FACTOR);

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void nullCurrency() {
    new CouponIbor(
        null,
        PAYMENT_TIME,
        ACCRUAL_FACTOR,
        NOTIONAL,
        FIXING_TIME,
        INDEX_EURIBOR3M,
        FIXING_START_TIME,
        FIXING_END_TIME,
        FIXING_ACCRUAL_FACTOR);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void nullIndex() {
    new CouponIbor(
        EUR,
        PAYMENT_TIME,
        ACCRUAL_FACTOR,
        NOTIONAL,
        FIXING_TIME,
        null,
        FIXING_START_TIME,
        FIXING_END_TIME,
        FIXING_ACCRUAL_FACTOR);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void incompatibleCurrency() {
    new CouponIbor(
        Currency.USD,
        PAYMENT_TIME,
        ACCRUAL_FACTOR,
        NOTIONAL,
        FIXING_TIME,
        INDEX_EURIBOR3M,
        FIXING_START_TIME,
        FIXING_END_TIME,
        FIXING_ACCRUAL_FACTOR);
  }

  @Test
  /** Tests the getters. */
  public void getter() {
    assertEquals("CouponIbor: getter", EUR, CPN_IBOR.getCurrency());
    assertEquals("CouponIbor: getter", INDEX_EURIBOR3M, CPN_IBOR.getIndex());
    assertEquals("CouponIbor: getter", FIXING_START_TIME, CPN_IBOR.getFixingPeriodStartTime());
    assertEquals("CouponIbor: getter", FIXING_END_TIME, CPN_IBOR.getFixingPeriodEndTime());
    assertEquals("CouponIbor: getter", FIXING_ACCRUAL_FACTOR, CPN_IBOR.getFixingAccrualFactor());
  }

  @Test
  public void testWithNotional() {
    final double notional = NOTIONAL + 1000;
    final CouponIbor expected =
        new CouponIbor(
            EUR,
            PAYMENT_TIME,
            ACCRUAL_FACTOR,
            notional,
            FIXING_TIME,
            INDEX_EURIBOR3M,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL_FACTOR);
    assertEquals(expected, CPN_IBOR.withNotional(notional));
  }

  @Test
  /** Tests the equal and hash code. */
  public void testEqualHash() {
    assertEquals("CouponIbor: equal-hash", CPN_IBOR, CPN_IBOR);
    final CouponIbor other =
        new CouponIbor(
            EUR,
            PAYMENT_TIME,
            ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            INDEX_EURIBOR3M,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL_FACTOR);
    assertEquals("CouponIbor: equal-hash", other, CPN_IBOR);
    assertEquals("CouponIbor: equal-hash", other.hashCode(), CPN_IBOR.hashCode());
    CouponIbor modified;
    modified =
        new CouponIbor(
            EUR,
            PAYMENT_TIME + 0.1,
            ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            INDEX_EURIBOR3M,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL_FACTOR);
    assertFalse("CouponIbor: equal-hash", CPN_IBOR.equals(modified));
    modified =
        new CouponIbor(
            EUR,
            PAYMENT_TIME,
            ACCRUAL_FACTOR + 0.1,
            NOTIONAL,
            FIXING_TIME,
            INDEX_EURIBOR3M,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL_FACTOR);
    assertFalse("CouponIbor: equal-hash", CPN_IBOR.equals(modified));
    modified =
        new CouponIbor(
            EUR,
            PAYMENT_TIME,
            ACCRUAL_FACTOR,
            NOTIONAL + 1.0,
            FIXING_TIME,
            INDEX_EURIBOR3M,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL_FACTOR);
    assertFalse("CouponIbor: equal-hash", CPN_IBOR.equals(modified));
    modified =
        new CouponIbor(
            EUR,
            PAYMENT_TIME,
            ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME - 0.1,
            INDEX_EURIBOR3M,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL_FACTOR);
    assertFalse("CouponIbor: equal-hash", CPN_IBOR.equals(modified));
    modified =
        new CouponIbor(
            Currency.USD,
            PAYMENT_TIME,
            ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            INDEX_IBOR_MASTER.getIndex("USDLIBOR3M"),
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL_FACTOR);
    assertFalse("CouponIbor: equal-hash", CPN_IBOR.equals(modified));
    modified =
        new CouponIbor(
            EUR,
            PAYMENT_TIME,
            ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            INDEX_EURIBOR3M,
            FIXING_START_TIME + 0.1,
            FIXING_END_TIME,
            FIXING_ACCRUAL_FACTOR);
    assertFalse("CouponIbor: equal-hash", CPN_IBOR.equals(modified));
    modified =
        new CouponIbor(
            EUR,
            PAYMENT_TIME,
            ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            INDEX_EURIBOR3M,
            FIXING_START_TIME,
            FIXING_END_TIME + 0.1,
            FIXING_ACCRUAL_FACTOR);
    assertFalse("CouponIbor: equal-hash", CPN_IBOR.equals(modified));
    modified =
        new CouponIbor(
            EUR,
            PAYMENT_TIME,
            ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            INDEX_EURIBOR3M,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL_FACTOR + 0.1);
    assertFalse("CouponIbor: equal-hash", CPN_IBOR.equals(modified));
  }
}
/**
 * Test class for the replication method for CMS caplet/floorlet using a SABR smile with
 * extrapolation.
 */
@Test
public class CapFloorCMSSABRExtrapolationRightReplicationMethodTest {

  private static final MulticurveProviderDiscount MULTICURVES =
      MulticurveProviderDiscountDataSets.createMulticurveEurUsd();
  private static final IborIndex EURIBOR6M =
      MulticurveProviderDiscountDataSets.getIndexesIborMulticurveEurUsd()[1];
  private static final Currency EUR = EURIBOR6M.getCurrency();
  private static final HolidayCalendar CALENDAR =
      MulticurveProviderDiscountDataSets.getEURCalendar();

  private static final SABRInterestRateParameters SABR_PARAMETER = SABRDataSets.createSABR1();
  private static final GeneratorSwapFixedIbor EUR1YEURIBOR6M =
      GeneratorSwapFixedIborMaster.getInstance().getGenerator("EUR1YEURIBOR6M", CALENDAR);
  private static final SABRSwaptionProviderDiscount SABR_MULTICURVES =
      new SABRSwaptionProviderDiscount(MULTICURVES, SABR_PARAMETER, EUR1YEURIBOR6M);

  // Swap 5Y
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventions.MODIFIED_FOLLOWING;
  private static final boolean IS_EOM = true;
  private static final Period ANNUITY_TENOR = Period.ofYears(5);
  private static final ZonedDateTime SETTLEMENT_DATE = DateUtils.getUTCDate(2020, 4, 28);
  // Fixed leg: Semi-annual bond
  private static final Period FIXED_PAYMENT_PERIOD = Period.ofMonths(6);
  private static final DayCount FIXED_DAY_COUNT = DayCounts.THIRTY_U_360;
  private static final double RATE = 0.0325;
  private static final boolean FIXED_IS_PAYER = true;
  private static final AnnuityCouponFixedDefinition FIXED_ANNUITY =
      AnnuityCouponFixedDefinition.from(
          EUR,
          SETTLEMENT_DATE,
          ANNUITY_TENOR,
          FIXED_PAYMENT_PERIOD,
          CALENDAR,
          FIXED_DAY_COUNT,
          BUSINESS_DAY,
          IS_EOM,
          1.0,
          RATE,
          FIXED_IS_PAYER);
  // Ibor leg: quarterly money
  private static final AnnuityCouponIborDefinition IBOR_ANNUITY =
      AnnuityCouponIborDefinition.from(
          SETTLEMENT_DATE, ANNUITY_TENOR, 1.0, EURIBOR6M, !FIXED_IS_PAYER, CALENDAR);
  // CMS coupon construction
  private static final IndexSwap CMS_INDEX =
      new IndexSwap(FIXED_PAYMENT_PERIOD, FIXED_DAY_COUNT, EURIBOR6M, ANNUITY_TENOR, CALENDAR);
  private static final SwapFixedIborDefinition SWAP_DEFINITION =
      new SwapFixedIborDefinition(FIXED_ANNUITY, IBOR_ANNUITY);
  private static final ZonedDateTime FIXING_DATE =
      ScheduleCalculator.getAdjustedDate(SETTLEMENT_DATE, -EURIBOR6M.getSpotLag(), CALENDAR);
  private static final ZonedDateTime ACCRUAL_START_DATE = SETTLEMENT_DATE; // pre-fixed
  private static final ZonedDateTime ACCRUAL_END_DATE =
      ScheduleCalculator.getAdjustedDate(
          ACCRUAL_START_DATE, FIXED_PAYMENT_PERIOD, BUSINESS_DAY, CALENDAR);
  private static final ZonedDateTime PAYMENT_DATE = ACCRUAL_END_DATE;
  private static final DayCount PAYMENT_DAY_COUNT = DayCounts.ACT_360;
  private static final double ACCRUAL_FACTOR =
      DayCountUtils.yearFraction(PAYMENT_DAY_COUNT, ACCRUAL_START_DATE, ACCRUAL_END_DATE);
  private static final double NOTIONAL = 10000000; // 10m
  private static final CouponCMSDefinition CMS_COUPON_RECEIVER_DEFINITION =
      CouponCMSDefinition.from(
          PAYMENT_DATE,
          ACCRUAL_START_DATE,
          ACCRUAL_END_DATE,
          ACCRUAL_FACTOR,
          NOTIONAL,
          FIXING_DATE,
          SWAP_DEFINITION,
          CMS_INDEX);
  private static final CouponCMSDefinition CMS_COUPON_PAYER_DEFINITION =
      CouponCMSDefinition.from(
          PAYMENT_DATE,
          ACCRUAL_START_DATE,
          ACCRUAL_END_DATE,
          ACCRUAL_FACTOR,
          -NOTIONAL,
          FIXING_DATE,
          SWAP_DEFINITION,
          CMS_INDEX);
  // Cap/Floor construction
  private static final double STRIKE = 0.04;
  private static final boolean IS_CAP = true;
  private static final CapFloorCMSDefinition CMS_CAP_LONG_DEFINITION =
      CapFloorCMSDefinition.from(CMS_COUPON_RECEIVER_DEFINITION, STRIKE, IS_CAP);
  private static final CapFloorCMSDefinition CMS_CAP_SHORT_DEFINITION =
      CapFloorCMSDefinition.from(CMS_COUPON_PAYER_DEFINITION, STRIKE, IS_CAP);
  private static final CapFloorCMSDefinition CMS_CAP_0_DEFINITION =
      CapFloorCMSDefinition.from(CMS_COUPON_RECEIVER_DEFINITION, 0.0, IS_CAP);
  // to derivatives
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2010, 8, 18);

  private static final CouponCMS CMS_COUPON =
      (CouponCMS) CMS_COUPON_RECEIVER_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final CapFloorCMS CMS_CAP_0 =
      (CapFloorCMS) CMS_CAP_0_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final CapFloorCMS CMS_CAP_LONG =
      (CapFloorCMS) CMS_CAP_LONG_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final CapFloorCMS CMS_CAP_SHORT =
      (CapFloorCMS) CMS_CAP_SHORT_DEFINITION.toDerivative(REFERENCE_DATE);
  // Calculators & methods
  private static final CapFloorCMSSABRReplicationMethod METHOD_STANDARD_CAP =
      CapFloorCMSSABRReplicationMethod.getDefaultInstance();
  private static final CouponCMSSABRReplicationMethod METHOD_STANDARD_CPN =
      CouponCMSSABRReplicationMethod.getInstance();
  private static final CouponCMSDiscountingMethod METHOD_DSC_CPN =
      CouponCMSDiscountingMethod.getInstance();

  private static final double CUT_OFF_STRIKE = 0.10;
  private static final double MU = 2.50;
  private static final CapFloorCMSSABRExtrapolationRightReplicationMethod METHOD_EXTRAPOLATION_CAP =
      new CapFloorCMSSABRExtrapolationRightReplicationMethod(CUT_OFF_STRIKE, MU);
  private static final CouponCMSSABRExtrapolationRightReplicationMethod METHOD_EXTRAPOLATION_CPN =
      new CouponCMSSABRExtrapolationRightReplicationMethod(CUT_OFF_STRIKE, MU);
  // Calculators
  private static final PresentValueSABRSwaptionRightExtrapolationCalculator PVSSXC =
      new PresentValueSABRSwaptionRightExtrapolationCalculator(CUT_OFF_STRIKE, MU);
  private static final PresentValueCurveSensitivitySABRSwaptionRightExtrapolationCalculator
      PVCSSSXC =
          new PresentValueCurveSensitivitySABRSwaptionRightExtrapolationCalculator(
              CUT_OFF_STRIKE, MU);
  private static final PresentValueSABRSensitivitySABRSwaptionRightExtrapolationCalculator
      PVSSSSXC =
          new PresentValueSABRSensitivitySABRSwaptionRightExtrapolationCalculator(
              CUT_OFF_STRIKE, MU);

  private static final double SHIFT = 1.0E-6;
  private static final ParameterSensitivityParameterCalculator<SABRSwaptionProviderInterface>
      PS_SS_C = new ParameterSensitivityParameterCalculator<>(PVCSSSXC);
  private static final ParameterSensitivitySABRSwaptionDiscountInterpolatedFDCalculator PS_SS_FDC =
      new ParameterSensitivitySABRSwaptionDiscountInterpolatedFDCalculator(PVSSXC, SHIFT);

  private static final double TOLERANCE_PV = 1.0E-2;
  private static final double TOLERANCE_PV_DELTA = 5.0E+3; // 0.01 currency unit for 1 bp.

  /**
   * Test the present value for a CMS coupon with pricing by replication in the SABR with
   * extrapolation framework. The present value is tested against hard-coded value and cap of strike
   * 0.
   */
  public void presentValue() {
    // CMS cap/floor with strike 0 has the same price as a CMS coupon.
    final double priceCouponStd =
        METHOD_STANDARD_CPN.presentValue(CMS_COUPON, SABR_MULTICURVES).getAmount(EUR).getAmount();
    final double rateCouponStd =
        priceCouponStd
            / (CMS_COUPON.getPaymentYearFraction()
                * CMS_COUPON.getNotional()
                * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime()));
    final double priceCouponExtra =
        METHOD_EXTRAPOLATION_CPN
            .presentValue(CMS_COUPON, SABR_MULTICURVES)
            .getAmount(EUR)
            .getAmount();
    final double rateCouponExtra =
        priceCouponExtra
            / (CMS_COUPON.getPaymentYearFraction()
                * CMS_COUPON.getNotional()
                * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime()));
    final double priceCouponNoAdj =
        METHOD_DSC_CPN.presentValue(CMS_COUPON, MULTICURVES).getAmount(EUR).getAmount();
    final double rateCouponNoAdj =
        priceCouponNoAdj
            / (CMS_COUPON.getPaymentYearFraction()
                * CMS_COUPON.getNotional()
                * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime()));
    assertEquals(
        "Extrapolation: comparison with standard method", rateCouponStd > rateCouponExtra, true);
    assertEquals(
        "Extrapolation: comparison with no convexity adjustment",
        rateCouponExtra > rateCouponNoAdj,
        true);
    final double rateCouponExtraExpected = 0.0189864; // From previous run.
    assertEquals("Extrapolation: hard-coded value", rateCouponExtraExpected, rateCouponExtra, 1E-6);
    final double priceCap0Extra =
        METHOD_EXTRAPOLATION_CAP
            .presentValue(CMS_CAP_0, SABR_MULTICURVES)
            .getAmount(EUR)
            .getAmount();
    assertEquals(
        "Extrapolation: CMS coupon vs Cap 0", priceCouponExtra, priceCap0Extra, TOLERANCE_PV);
  }

  /**
   * Tests the price of CMS coupon and cap/floor using replication in the SABR framework. Method v
   * Calculator.
   */
  public void presentValueMethodVsCalculator() {
    final double pvMethod =
        METHOD_EXTRAPOLATION_CAP
            .presentValue(CMS_CAP_LONG, SABR_MULTICURVES)
            .getAmount(EUR)
            .getAmount();
    final double pvCalculator =
        CMS_CAP_LONG.accept(PVSSXC, SABR_MULTICURVES).getAmount(EUR).getAmount();
    assertEquals(
        "CMS cap/floor SABR: Present value : method vs calculator",
        pvMethod,
        pvCalculator,
        TOLERANCE_PV);
  }

  /**
   * Test the present value for a CMS cap with pricing by replication in the SABR with extrapolation
   * framework. The present value is tested against hard-coded value and a long/short parity is
   * tested.
   */
  public void presentValueReplicationCap() {
    // CMS cap/floor with strike 0 has the same price as a CMS coupon.
    final double priceCapLongStd =
        METHOD_STANDARD_CAP.presentValue(CMS_CAP_LONG, SABR_MULTICURVES).getAmount(EUR).getAmount();
    final double priceCapLongExtra =
        METHOD_EXTRAPOLATION_CAP
            .presentValue(CMS_CAP_LONG, SABR_MULTICURVES)
            .getAmount(EUR)
            .getAmount();
    final double priceCapShortExtra =
        METHOD_EXTRAPOLATION_CAP
            .presentValue(CMS_CAP_SHORT, SABR_MULTICURVES)
            .getAmount(EUR)
            .getAmount();
    assertEquals(
        "CMS cap by replication - Extrapolation: comparison with standard method",
        priceCapLongStd > priceCapLongExtra,
        true);
    final double priceCapExtraExpected = 30696.572; // From previous run.
    assertEquals(
        "CMS cap by replication - Extrapolation: hard-coded value",
        priceCapExtraExpected,
        priceCapLongExtra,
        TOLERANCE_PV);
    assertEquals(
        "CMS cap by replication - Extrapolation: long/short parity",
        -priceCapShortExtra,
        priceCapLongExtra,
        TOLERANCE_PV);
  }

  /**
   * Test the present value rate sensitivity for a CMS cap with pricing by replication in the SABR
   * with extrapolation framework.
   */
  public void presentValueCurveSensitivity() {
    final MultipleCurrencyParameterSensitivity pvpsCapLongExact =
        PS_SS_C.calculateSensitivity(
            CMS_CAP_LONG, SABR_MULTICURVES, SABR_MULTICURVES.getMulticurveProvider().getAllNames());
    final MultipleCurrencyParameterSensitivity pvpsCapLongFD =
        PS_SS_FDC.calculateSensitivity(CMS_CAP_LONG, SABR_MULTICURVES);
    AssertSensitivityObjects.assertEquals(
        "SwaptionPhysicalFixedIborSABRMethod: presentValueCurveSensitivity ",
        pvpsCapLongExact,
        pvpsCapLongFD,
        TOLERANCE_PV_DELTA);
    final MultipleCurrencyParameterSensitivity pvpsCapShortExact =
        PS_SS_C.calculateSensitivity(
            CMS_CAP_SHORT,
            SABR_MULTICURVES,
            SABR_MULTICURVES.getMulticurveProvider().getAllNames());
    final MultipleCurrencyParameterSensitivity pvpsCapShortFD =
        PS_SS_FDC.calculateSensitivity(CMS_CAP_SHORT, SABR_MULTICURVES);
    AssertSensitivityObjects.assertEquals(
        "SwaptionPhysicalFixedIborSABRMethod: presentValueCurveSensitivity ",
        pvpsCapShortExact,
        pvpsCapShortFD,
        TOLERANCE_PV_DELTA);
  }

  /**
   * Test the present value rate sensitivity for a CMS cap with pricing by replication in the SABR
   * with extrapolation framework. Method v Calculator.
   */
  public void presentValueCurveSensitivityMethodVsCalculator() {
    final MultipleCurrencyMulticurveSensitivity pvcsMethod =
        METHOD_EXTRAPOLATION_CAP.presentValueCurveSensitivity(CMS_CAP_LONG, SABR_MULTICURVES);
    final MultipleCurrencyMulticurveSensitivity pvcsCalculator =
        CMS_CAP_LONG.accept(PVCSSSXC, SABR_MULTICURVES);
    AssertSensitivityObjects.assertEquals(
        "CMS cap/floor SABR: Present value : method vs calculator",
        pvcsMethod,
        pvcsCalculator,
        TOLERANCE_PV_DELTA);
  }

  /** Tests the cap present value SABR parameters sensitivity vs finite difference. */
  public void presentValueSABRSensitivity() {
    final double pv =
        METHOD_EXTRAPOLATION_CAP
            .presentValue(CMS_CAP_LONG, SABR_MULTICURVES)
            .getAmount(EUR)
            .getAmount();
    final PresentValueSABRSensitivityDataBundle pvsCapLong =
        METHOD_EXTRAPOLATION_CAP.presentValueSABRSensitivity(CMS_CAP_LONG, SABR_MULTICURVES);
    // SABR sensitivity vs finite difference
    final double shift = 0.0001;
    final double shiftAlpha = 0.00001;
    final double maturity =
        CMS_CAP_LONG
                .getUnderlyingSwap()
                .getFixedLeg()
                .getNthPayment(
                    CMS_CAP_LONG.getUnderlyingSwap().getFixedLeg().getNumberOfPayments() - 1)
                .getPaymentTime()
            - CMS_CAP_LONG.getSettlementTime();
    final DoublesPair expectedExpiryTenor = DoublesPair.of(CMS_CAP_LONG.getFixingTime(), maturity);
    // Alpha sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterAlphaBumped =
        SABRDataSets.createSABR1AlphaBumped(shiftAlpha);
    final SABRSwaptionProviderDiscount sabrBundleAlphaBumped =
        new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterAlphaBumped, EUR1YEURIBOR6M);
    final double pvLongPayerAlphaBumped =
        METHOD_EXTRAPOLATION_CAP
            .presentValue(CMS_CAP_LONG, sabrBundleAlphaBumped)
            .getAmount(EUR)
            .getAmount();
    final double expectedAlphaSensi = (pvLongPayerAlphaBumped - pv) / shiftAlpha;
    assertEquals("Number of alpha sensitivity", pvsCapLong.getAlpha().getMap().keySet().size(), 1);
    assertEquals(
        "Alpha sensitivity expiry/tenor",
        pvsCapLong.getAlpha().getMap().keySet().contains(expectedExpiryTenor),
        true);
    assertEquals(
        "Alpha sensitivity value",
        expectedAlphaSensi,
        pvsCapLong.getAlpha().getMap().get(expectedExpiryTenor),
        TOLERANCE_PV_DELTA);
    // Rho sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterRhoBumped = SABRDataSets.createSABR1RhoBumped();
    final SABRSwaptionProviderDiscount sabrBundleRhoBumped =
        new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterRhoBumped, EUR1YEURIBOR6M);
    final double pvLongPayerRhoBumped =
        METHOD_EXTRAPOLATION_CAP
            .presentValue(CMS_CAP_LONG, sabrBundleRhoBumped)
            .getAmount(EUR)
            .getAmount();
    final double expectedRhoSensi = (pvLongPayerRhoBumped - pv) / shift;
    assertEquals("Number of rho sensitivity", pvsCapLong.getRho().getMap().keySet().size(), 1);
    assertEquals(
        "Rho sensitivity expiry/tenor",
        pvsCapLong.getRho().getMap().keySet().contains(expectedExpiryTenor),
        true);
    assertEquals(
        "Rho sensitivity value",
        expectedRhoSensi,
        pvsCapLong.getRho().getMap().get(expectedExpiryTenor),
        TOLERANCE_PV_DELTA);
    // Alpha sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterNuBumped = SABRDataSets.createSABR1NuBumped();
    final SABRSwaptionProviderDiscount sabrBundleNuBumped =
        new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterNuBumped, EUR1YEURIBOR6M);
    final double pvLongPayerNuBumped =
        METHOD_EXTRAPOLATION_CAP
            .presentValue(CMS_CAP_LONG, sabrBundleNuBumped)
            .getAmount(EUR)
            .getAmount();
    final double expectedNuSensi = (pvLongPayerNuBumped - pv) / shift;
    assertEquals("Number of nu sensitivity", pvsCapLong.getNu().getMap().keySet().size(), 1);
    assertTrue(
        "Nu sensitivity expiry/tenor",
        pvsCapLong.getNu().getMap().keySet().contains(expectedExpiryTenor));
    assertEquals(
        "Nu sensitivity value",
        expectedNuSensi,
        pvsCapLong.getNu().getMap().get(expectedExpiryTenor),
        TOLERANCE_PV_DELTA);
  }

  /** Tests the coupon present value SABR parameters sensitivity vs finite difference. */
  public void presentValueSABRSensitivityCoupon() {
    final double pv =
        METHOD_EXTRAPOLATION_CPN
            .presentValue(CMS_COUPON, SABR_MULTICURVES)
            .getAmount(EUR)
            .getAmount();
    final PresentValueSABRSensitivityDataBundle pvsCpn =
        METHOD_EXTRAPOLATION_CPN.presentValueSABRSensitivity(CMS_COUPON, SABR_MULTICURVES);
    // SABR sensitivity vs finite difference
    final double shift = 0.0001;
    final double shiftAlpha = 0.00001;
    final double maturity =
        CMS_COUPON
                .getUnderlyingSwap()
                .getFixedLeg()
                .getNthPayment(
                    CMS_COUPON.getUnderlyingSwap().getFixedLeg().getNumberOfPayments() - 1)
                .getPaymentTime()
            - CMS_COUPON.getSettlementTime();
    final DoublesPair expectedExpiryTenor = DoublesPair.of(CMS_COUPON.getFixingTime(), maturity);
    // Alpha sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterAlphaBumped =
        SABRDataSets.createSABR1AlphaBumped(shiftAlpha);
    final SABRSwaptionProviderDiscount sabrBundleAlphaBumped =
        new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterAlphaBumped, EUR1YEURIBOR6M);
    final double pvLongPayerAlphaBumped =
        METHOD_EXTRAPOLATION_CPN
            .presentValue(CMS_COUPON, sabrBundleAlphaBumped)
            .getAmount(EUR)
            .getAmount();
    final double expectedAlphaSensi = (pvLongPayerAlphaBumped - pv) / shiftAlpha;
    assertEquals("Number of alpha sensitivity", pvsCpn.getAlpha().getMap().keySet().size(), 1);
    assertEquals(
        "Alpha sensitivity expiry/tenor",
        pvsCpn.getAlpha().getMap().keySet().contains(expectedExpiryTenor),
        true);
    assertEquals(
        "Alpha sensitivity value",
        expectedAlphaSensi,
        pvsCpn.getAlpha().getMap().get(expectedExpiryTenor),
        TOLERANCE_PV_DELTA);
    // Rho sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterRhoBumped = SABRDataSets.createSABR1RhoBumped();
    final SABRSwaptionProviderDiscount sabrBundleRhoBumped =
        new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterRhoBumped, EUR1YEURIBOR6M);
    final double pvLongPayerRhoBumped =
        METHOD_EXTRAPOLATION_CPN
            .presentValue(CMS_COUPON, sabrBundleRhoBumped)
            .getAmount(EUR)
            .getAmount();
    final double expectedRhoSensi = (pvLongPayerRhoBumped - pv) / shift;
    assertEquals("Number of rho sensitivity", pvsCpn.getRho().getMap().keySet().size(), 1);
    assertEquals(
        "Rho sensitivity expiry/tenor",
        pvsCpn.getRho().getMap().keySet().contains(expectedExpiryTenor),
        true);
    assertEquals(
        "Rho sensitivity value",
        expectedRhoSensi,
        pvsCpn.getRho().getMap().get(expectedExpiryTenor),
        TOLERANCE_PV_DELTA);
    // Nu sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterNuBumped = SABRDataSets.createSABR1NuBumped();
    final SABRSwaptionProviderDiscount sabrBundleNuBumped =
        new SABRSwaptionProviderDiscount(MULTICURVES, sabrParameterNuBumped, EUR1YEURIBOR6M);
    final double pvLongPayerNuBumped =
        METHOD_EXTRAPOLATION_CPN
            .presentValue(CMS_COUPON, sabrBundleNuBumped)
            .getAmount(EUR)
            .getAmount();
    final double expectedNuSensi = (pvLongPayerNuBumped - pv) / shift;
    assertEquals("Number of nu sensitivity", pvsCpn.getNu().getMap().keySet().size(), 1);
    assertTrue(
        "Nu sensitivity expiry/tenor",
        pvsCpn.getNu().getMap().keySet().contains(expectedExpiryTenor));
    assertEquals(
        "Nu sensitivity value",
        expectedNuSensi,
        pvsCpn.getNu().getMap().get(expectedExpiryTenor),
        TOLERANCE_PV_DELTA);
  }

  /** Tests the present value SABR parameters sensitivity: Method vs Calculator. */
  public void presentValueSABRSensitivityMethodVsCalculator() {
    final PresentValueSABRSensitivityDataBundle pvssMethod =
        METHOD_EXTRAPOLATION_CAP.presentValueSABRSensitivity(CMS_CAP_LONG, SABR_MULTICURVES);
    final PresentValueSABRSensitivityDataBundle pvssCalculator =
        CMS_CAP_LONG.accept(PVSSSSXC, SABR_MULTICURVES);
    assertEquals(
        "CMS cap/floor SABR: Present value SABR sensitivity: method vs calculator",
        pvssMethod,
        pvssCalculator);
  }

  /** Tests the present value strike sensitivity: Cap. */
  public void presentValueStrikeSensitivityCap() {
    final double[] strikes = new double[] {0.0001, 0.0010, 0.0050, 0.0100, 0.0200, 0.0400, 0.0500};
    final int nbStrikes = strikes.length;
    final double shift = 1.0E-5;
    final double[] errorRelative = new double[nbStrikes];
    for (int loopstrike = 0; loopstrike < nbStrikes; loopstrike++) {
      final CapFloorCMSDefinition cmsCapDefinition =
          CapFloorCMSDefinition.from(CMS_COUPON_RECEIVER_DEFINITION, strikes[loopstrike], IS_CAP);
      final CapFloorCMSDefinition cmsCapShiftUpDefinition =
          CapFloorCMSDefinition.from(
              CMS_COUPON_RECEIVER_DEFINITION, strikes[loopstrike] + shift, IS_CAP);
      final CapFloorCMSDefinition cmsCapShiftDoDefinition =
          CapFloorCMSDefinition.from(
              CMS_COUPON_RECEIVER_DEFINITION, strikes[loopstrike] - shift, IS_CAP);
      final CapFloorCMS cmsCap = (CapFloorCMS) cmsCapDefinition.toDerivative(REFERENCE_DATE);
      final CapFloorCMS cmsCapShiftUp =
          (CapFloorCMS) cmsCapShiftUpDefinition.toDerivative(REFERENCE_DATE);
      final CapFloorCMS cmsCapShiftDo =
          (CapFloorCMS) cmsCapShiftDoDefinition.toDerivative(REFERENCE_DATE);
      final double pvShiftUp =
          METHOD_EXTRAPOLATION_CAP
              .presentValue(cmsCapShiftUp, SABR_MULTICURVES)
              .getAmount(EUR)
              .getAmount();
      final double pvShiftDo =
          METHOD_EXTRAPOLATION_CAP
              .presentValue(cmsCapShiftDo, SABR_MULTICURVES)
              .getAmount(EUR)
              .getAmount();
      final double sensiExpected = (pvShiftUp - pvShiftDo) / (2 * shift);
      final double sensiComputed =
          METHOD_EXTRAPOLATION_CAP.presentValueStrikeSensitivity(cmsCap, SABR_MULTICURVES);
      errorRelative[loopstrike] = (sensiExpected - sensiComputed) / sensiExpected;
      assertEquals(
          "CMS cap/floor SABR: Present value strike sensitivity " + loopstrike,
          0,
          errorRelative[loopstrike],
          5.0E-3);
    }
  }

  /**
   * Tests to estimate the impact of mu on the CMS coupon pricing. "enabled = false" for the
   * standard testing.
   */
  public void testPriceMultiMu() {
    final double[] mu = new double[] {1.10, 1.30, 1.55, 2.25, 3.50, 6.00, 15.0};
    final int nbMu = mu.length;
    final double priceCouponStd =
        METHOD_STANDARD_CPN.presentValue(CMS_COUPON, SABR_MULTICURVES).getAmount(EUR).getAmount();
    @SuppressWarnings("unused")
    final double rateCouponStd =
        priceCouponStd
            / (CMS_COUPON.getPaymentYearFraction()
                * CMS_COUPON.getNotional()
                * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime()));
    final double[] priceCouponExtra = new double[nbMu];
    final double[] rateCouponExtra = new double[nbMu];
    for (int loopmu = 0; loopmu < nbMu; loopmu++) {
      final CouponCMSSABRExtrapolationRightReplicationMethod methodExtrapolation =
          new CouponCMSSABRExtrapolationRightReplicationMethod(CUT_OFF_STRIKE, mu[loopmu]);
      priceCouponExtra[loopmu] =
          methodExtrapolation.presentValue(CMS_COUPON, SABR_MULTICURVES).getAmount(EUR).getAmount();
      rateCouponExtra[loopmu] =
          priceCouponExtra[loopmu]
              / (CMS_COUPON.getPaymentYearFraction()
                  * CMS_COUPON.getNotional()
                  * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime()));
    }
    final double priceCouponNoAdj =
        METHOD_DSC_CPN.presentValue(CMS_COUPON, MULTICURVES).getAmount(EUR).getAmount();
    final double rateCouponNoAdj =
        priceCouponNoAdj
            / (CMS_COUPON.getPaymentYearFraction()
                * CMS_COUPON.getNotional()
                * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime()));
    for (int loopmu = 1; loopmu < nbMu; loopmu++) {
      assertTrue(
          "Extrapolation: comparison with standard method",
          rateCouponExtra[loopmu - 1] > rateCouponExtra[loopmu]);
    }
    assertTrue(
        "Extrapolation: comparison with standard method",
        rateCouponExtra[nbMu - 1] > rateCouponNoAdj);
  }
}