public class BondIborTransactionDefinitionTest {

  // Quarterly Libor6m 2Y
  private static final Currency CUR = Currency.USD;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final DayCount DAY_COUNT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Following");
  private static final boolean IS_EOM = false;
  private static final Period IBOR_TENOR = Period.ofMonths(3);
  private static final DayCount IBOR_DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("30/360");
  private static final int IBOR_SPOT_LAG = 2;
  private static final BusinessDayConvention IBOR_BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IBOR_IS_EOM = false;
  private static final IborIndex IBOR_INDEX =
      new IborIndex(
          CUR, IBOR_TENOR, IBOR_SPOT_LAG, CALENDAR, IBOR_DAY_COUNT, IBOR_BUSINESS_DAY, IBOR_IS_EOM);
  private static final Period BOND_TENOR = Period.ofYears(2);
  private static final int SETTLEMENT_DAYS = 3; // Standard for euro-bonds.
  private static final ZonedDateTime START_ACCRUAL_DATE = DateUtils.getUTCDate(2011, 7, 13);
  private static final ZonedDateTime MATURITY_DATE = START_ACCRUAL_DATE.plus(BOND_TENOR);
  private static final BondIborSecurityDefinition BOND_DESCRIPTION =
      BondIborSecurityDefinition.from(
          MATURITY_DATE,
          START_ACCRUAL_DATE,
          IBOR_INDEX,
          SETTLEMENT_DAYS,
          DAY_COUNT,
          BUSINESS_DAY,
          IS_EOM);
  // Transaction
  private static final double PRICE = 0.90;
  private static final ZonedDateTime SETTLEMENT_DATE = DateUtils.getUTCDate(2011, 8, 18);
  private static final double QUANTITY = 100000000; // 100m
  private static final BondIborTransactionDefinition BOND_TRANSACTION =
      new BondIborTransactionDefinition(BOND_DESCRIPTION, QUANTITY, SETTLEMENT_DATE, PRICE);

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullUnderlying() {
    new BondIborTransactionDefinition(null, QUANTITY, SETTLEMENT_DATE, PRICE);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullSettle() {
    new BondIborTransactionDefinition(BOND_DESCRIPTION, QUANTITY, null, PRICE);
  }

  @Test
  public void testGetters() {
    assertEquals(PRICE, BOND_TRANSACTION.getPrice());
    assertEquals(QUANTITY, BOND_TRANSACTION.getQuantity());
    assertEquals(SETTLEMENT_DATE, BOND_TRANSACTION.getSettlementDate());
    assertEquals(BOND_DESCRIPTION, BOND_TRANSACTION.getUnderlyingBond());
    assertEquals(DateUtils.getUTCDate(2011, 7, 13), BOND_TRANSACTION.getPreviousAccrualDate());
    assertEquals(DateUtils.getUTCDate(2011, 10, 13), BOND_TRANSACTION.getNextAccrualDate());
  }
}
/** Tests related to the discounting method for bond security. */
public class BondSecurityFRDiscountingMethodTest {

  // Calculators
  private static final PresentValueCalculator PVC = PresentValueCalculator.getInstance();
  private static final BondSecurityDiscountingMethod METHOD =
      BondSecurityDiscountingMethod.getInstance();

  private static final double TOLERANCE_PRICE = 1.0E-8;

  private static final String REPO_TYPE = "General collateral";
  private static final Currency EUR = Currency.EUR;
  private static final Calendar TARGET = new MondayToFridayCalendar("TARGET");
  private static final DayCount DAY_COUNT_ACTACTICMA =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ICMA");
  private static final BusinessDayConvention BUSINESS_DAY_FOL =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Following");
  private static final boolean IS_EOM_FIXED = false;

  // To derivatives
  private static final DayCount ACT_ACT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
  private static final String CREDIT_CURVE_NAME = "Credit";
  private static final String REPO_CURVE_NAME = "Repo";
  private static final String FORWARD_CURVE_NAME = "Forward";
  private static final String[] CURVES_NAME = {
    CREDIT_CURVE_NAME, REPO_CURVE_NAME, FORWARD_CURVE_NAME
  };
  private static final YieldCurveBundle CURVES = TestsDataSetsSABR.createCurvesBond1();

  // FRTR 4 1/2 04/25/41 - ISIN:  FR0010773192
  private static final String ISSUER_FR = "FRANCE (GOVT OF)";
  private static final YieldConvention YIELD_CONVENTION_FRANCE =
      SimpleYieldConvention.FRANCE_COMPOUND_METHOD;
  private static final int SETTLEMENT_DAYS_FR = 3;
  private static final Period PAYMENT_TENOR_FR = Period.ofMonths(12);
  //  private static final int COUPON_PER_YEAR_FR = 1;
  private static final ZonedDateTime BOND_START_FR = DateUtils.getUTCDate(2009, 4, 25);
  private static final ZonedDateTime BOND_MATURITY_FR = DateUtils.getUTCDate(2041, 4, 25);
  private static final ZonedDateTime BOND_FIRSTCPN_FR = DateUtils.getUTCDate(2010, 4, 25);
  private static final double RATE_FR = 0.0450;
  private static final BondFixedSecurityDefinition BOND_FR_SECURITY_DEFINITION =
      BondFixedSecurityDefinition.from(
          EUR,
          BOND_START_FR,
          BOND_FIRSTCPN_FR,
          BOND_MATURITY_FR,
          PAYMENT_TENOR_FR,
          RATE_FR,
          SETTLEMENT_DAYS_FR,
          TARGET,
          DAY_COUNT_ACTACTICMA,
          BUSINESS_DAY_FOL,
          YIELD_CONVENTION_FRANCE,
          IS_EOM_FIXED,
          ISSUER_FR);
}
Example #3
0
 /**
  * Constructor.
  *
  * @param calendar A EUR calendar.
  */
 public Euribor6M(Calendar calendar) {
   super(
       Currency.EUR,
       Period.ofMonths(6),
       2,
       calendar,
       DayCountFactory.INSTANCE.getDayCount("Actual/360"),
       BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following"),
       true);
 }
 @Override
 public IborIndex buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) {
   final Currency currency = Currency.of(message.getString(CURRENCY_FIELD));
   final int spotLag = message.getInt(SPOT_LAG_FIELD);
   final DayCount dayCount =
       DayCountFactory.INSTANCE.getDayCount(message.getString(DAY_COUNT_FIELD));
   final BusinessDayConvention businessDayConvention =
       BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention(
           message.getString(BUSINESS_DAY_CONVENTION_FIELD));
   final boolean isEOM = message.getBoolean(EOM_FIELD);
   final Period tenor = Period.parse(message.getString(TENOR_FIELD));
   final String name = message.getString(NAME_FIELD);
   return new IborIndex(currency, tenor, spotLag, dayCount, businessDayConvention, isEOM, name);
 }
public class BondPreviousCloseDirtyPriceFunction extends BondFunction {
  private static final BondCalculator DIRTY_PRICE_CALCULATOR =
      BondCalculatorFactory.getBondCalculator(BondCalculatorFactory.BOND_DIRTY_PRICE);
  private static final BusinessDayConvention PREVIOUS =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Preceding");

  public BondPreviousCloseDirtyPriceFunction() {
    super(MarketDataRequirementNames.MARKET_VALUE);
  }

  @Override
  protected Set<ComputedValue> getComputedValues(
      final FunctionExecutionContext context,
      final Currency currency,
      final Security security,
      final BondDefinition bondDefinition,
      final Object value,
      final ZonedDateTime now,
      final String yieldCurveName) {
    final double cleanPrice = (Double) value;
    final ValueSpecification specification =
        new ValueSpecification(
            new ValueRequirement(ValueRequirementNames.DIRTY_PRICE, security), getUniqueId());
    final HolidaySource holidaySource = OpenGammaExecutionContext.getHolidaySource(context);
    final Calendar calendar = new HolidaySourceCalendarAdapter(holidaySource, currency);
    final ZonedDateTime previousClose = PREVIOUS.adjustDate(calendar, now.minusDays(1));
    final Bond bond = bondDefinition.toDerivative(previousClose, yieldCurveName);
    final double dirtyPrice = DIRTY_PRICE_CALCULATOR.calculate(bond, cleanPrice / 100.0);
    return Sets.newHashSet(new ComputedValue(specification, dirtyPrice * 100.0));
  }

  @Override
  public Set<ValueSpecification> getResults(
      final FunctionCompilationContext context, final ComputationTarget target) {
    if (canApplyTo(context, target)) {
      return Sets.newHashSet(
          new ValueSpecification(
              new ValueRequirement(ValueRequirementNames.DIRTY_PRICE, target.getSecurity()),
              getUniqueId()));
    }
    return null;
  }

  @Override
  public String getShortName() {
    return "BondDirtyPriceFunction";
  }
}
 public static void addBondFutureConvention(final ConventionBundleMaster conventionMaster) {
   Validate.notNull(conventionMaster, "convention master");
   conventionMaster.addConventionBundle(
       ExternalIdBundle.of(
           ExternalId.of(
               InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME,
               "GBP_BOND_FUTURE_DELIVERABLE_CONVENTION")),
       "GBP_BOND_FUTURE_DELIVERABLE_CONVENTION",
       true,
       true,
       7,
       0,
       DayCountFactory.INSTANCE.getDayCount("Actual/365"),
       BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Following"),
       SimpleYieldConvention.MONEY_MARKET);
 }
Example #7
0
  public static synchronized void addFixedIncomeInstrumentConventions(
      final ConventionBundleMaster conventionMaster) {
    Validate.notNull(conventionMaster, "convention master");
    final BusinessDayConvention modified =
        BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
    final BusinessDayConvention following =
        BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Following");
    final DayCount act360 = DayCountFactory.INSTANCE.getDayCount("Actual/360");
    final DayCount act365 = DayCountFactory.INSTANCE.getDayCount("Actual/365");
    final Frequency annual = SimpleFrequencyFactory.INSTANCE.getFrequency(Frequency.ANNUAL_NAME);
    final Frequency semiAnnual =
        SimpleFrequencyFactory.INSTANCE.getFrequency(Frequency.SEMI_ANNUAL_NAME);
    final Frequency quarterly =
        SimpleFrequencyFactory.INSTANCE.getFrequency(Frequency.QUARTERLY_NAME);
    final ExternalId ca = ExternalSchemes.financialRegionId("CA");

    final ConventionBundleMasterUtils utils = new ConventionBundleMasterUtils(conventionMaster);
    // TODO looked at BSYM and the codes seem right but need to check
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD00O/N Index"), simpleNameSecurityId("CAD LIBOR O/N")),
        "CAD LIBOR O/N",
        act360,
        following,
        Period.ofDays(1),
        0,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD00S/N Index"), simpleNameSecurityId("CAD LIBOR S/N")),
        "CAD LIBOR S/N",
        act360,
        following,
        Period.ofDays(1),
        0,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD00T/N Index"), simpleNameSecurityId("CAD LIBOR T/N")),
        "CAD LIBOR T/N",
        act360,
        following,
        Period.ofDays(1),
        0,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0001W Index"), simpleNameSecurityId("CAD LIBOR 1w")),
        "CAD LIBOR 1w",
        act360,
        following,
        Period.ofDays(1),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0002W Index"), simpleNameSecurityId("CAD LIBOR 2w")),
        "CAD LIBOR 2w",
        act360,
        following,
        Period.ofDays(1),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0001M Index"), simpleNameSecurityId("CAD LIBOR 1m")),
        "CAD LIBOR 1m",
        act360,
        following,
        Period.ofMonths(1),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0002M Index"), simpleNameSecurityId("CAD LIBOR 2m")),
        "CAD LIBOR 2m",
        act360,
        following,
        Period.ofMonths(2),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0003M Index"), simpleNameSecurityId("CAD LIBOR 3m")),
        "CAD LIBOR 3m",
        act360,
        following,
        Period.ofMonths(3),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0004M Index"), simpleNameSecurityId("CAD LIBOR 4m")),
        "CAD LIBOR 4m",
        act360,
        following,
        Period.ofMonths(4),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0005M Index"), simpleNameSecurityId("CAD LIBOR 5m")),
        "CAD LIBOR 5m",
        act360,
        following,
        Period.ofMonths(5),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0006M Index"), simpleNameSecurityId("CAD LIBOR 6m")),
        "CAD LIBOR 6m",
        act360,
        following,
        Period.ofMonths(6),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0007M Index"), simpleNameSecurityId("CAD LIBOR 7m")),
        "CAD LIBOR 7m",
        act360,
        following,
        Period.ofMonths(7),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0008M Index"), simpleNameSecurityId("CAD LIBOR 8m")),
        "CAD LIBOR 8m",
        act360,
        following,
        Period.ofMonths(8),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0009M Index"), simpleNameSecurityId("CAD LIBOR 9m")),
        "CAD LIBOR 9m",
        act360,
        following,
        Period.ofMonths(9),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0010M Index"), simpleNameSecurityId("CAD LIBOR 10m")),
        "CAD LIBOR 10m",
        act360,
        following,
        Period.ofMonths(10),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0011M Index"), simpleNameSecurityId("CAD LIBOR 11m")),
        "CAD LIBOR 11m",
        act360,
        following,
        Period.ofMonths(11),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CD0012M Index"), simpleNameSecurityId("CAD LIBOR 12m")),
        "CAD LIBOR 12m",
        act360,
        following,
        Period.ofMonths(12),
        2,
        false,
        ca);

    // TODO need to check that these are right for deposit rates
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDR1T Curncy"), simpleNameSecurityId("CAD DEPOSIT 1d")),
        "CAD DEPOSIT 1d",
        act365,
        following,
        Period.ofDays(1),
        0,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDR2T Curncy"), simpleNameSecurityId("CAD DEPOSIT 2d")),
        "CAD DEPOSIT 2d",
        act365,
        following,
        Period.ofDays(1),
        0,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDR3T Curncy"), simpleNameSecurityId("CAD DEPOSIT 3d")),
        "CAD DEPOSIT 3d",
        act365,
        following,
        Period.ofDays(1),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDR1Z Curncy"), simpleNameSecurityId("CAD DEPOSIT 1w")),
        "CAD DEPOSIT 1w",
        act365,
        following,
        Period.ofDays(7),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDR2Z Curncy"), simpleNameSecurityId("CAD DEPOSIT 2w")),
        "CAD DEPOSIT 2w",
        act365,
        following,
        Period.ofDays(14),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDR3Z Curncy"), simpleNameSecurityId("CAD DEPOSIT 3w")),
        "CAD DEPOSIT 3w",
        act365,
        following,
        Period.ofDays(21),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDRA Curncy"), simpleNameSecurityId("CAD DEPOSIT 1m")),
        "CAD DEPOSIT 1m",
        act365,
        following,
        Period.ofMonths(1),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDRB Curncy"), simpleNameSecurityId("CAD DEPOSIT 2m")),
        "CAD DEPOSIT 2m",
        act365,
        following,
        Period.ofMonths(2),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDRC Curncy"), simpleNameSecurityId("CAD DEPOSIT 3m")),
        "CAD DEPOSIT 3m",
        act365,
        following,
        Period.ofMonths(3),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDRD Curncy"), simpleNameSecurityId("CAD DEPOSIT 4m")),
        "CAD DEPOSIT 4m",
        act365,
        following,
        Period.ofMonths(4),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDRE Curncy"), simpleNameSecurityId("CAD DEPOSIT 5m")),
        "CAD DEPOSIT 5m",
        act365,
        following,
        Period.ofMonths(5),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDRF Curncy"), simpleNameSecurityId("CAD DEPOSIT 6m")),
        "CAD DEPOSIT 6m",
        act365,
        following,
        Period.ofMonths(6),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDRG Curncy"), simpleNameSecurityId("CAD DEPOSIT 7m")),
        "CAD DEPOSIT 7m",
        act365,
        following,
        Period.ofMonths(7),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDRH Curncy"), simpleNameSecurityId("CAD DEPOSIT 8m")),
        "CAD DEPOSIT 8m",
        act365,
        following,
        Period.ofMonths(8),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDRI Curncy"), simpleNameSecurityId("CAD DEPOSIT 9m")),
        "CAD DEPOSIT 9m",
        act365,
        following,
        Period.ofMonths(9),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDRJ Curncy"), simpleNameSecurityId("CAD DEPOSIT 10m")),
        "CAD DEPOSIT 10m",
        act365,
        following,
        Period.ofMonths(10),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDRK Curncy"), simpleNameSecurityId("CAD DEPOSIT 11m")),
        "CAD DEPOSIT 11m",
        act365,
        following,
        Period.ofMonths(11),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDR1 Curncy"), simpleNameSecurityId("CAD DEPOSIT 1y")),
        "CAD DEPOSIT 1y",
        act365,
        following,
        Period.ofYears(1),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDR2 Curncy"), simpleNameSecurityId("CAD DEPOSIT 2y")),
        "CAD DEPOSIT 2y",
        act365,
        following,
        Period.ofYears(2),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDR3 Curncy"), simpleNameSecurityId("CAD DEPOSIT 3y")),
        "CAD DEPOSIT 3y",
        act365,
        following,
        Period.ofYears(3),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDR4 Curncy"), simpleNameSecurityId("CAD DEPOSIT 4y")),
        "CAD DEPOSIT 4y",
        act365,
        following,
        Period.ofYears(4),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDDR5 Curncy"), simpleNameSecurityId("CAD DEPOSIT 5y")),
        "CAD DEPOSIT 5y",
        act365,
        following,
        Period.ofYears(5),
        2,
        false,
        ca);
    // TODO check daycount
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDOR01 Index"),
            bloombergTickerSecurityId("CDOR01 RBC Index"),
            simpleNameSecurityId("CDOR 1m")),
        "CDOR 1m",
        act365,
        following,
        Period.ofMonths(1),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDOR02 Index"),
            bloombergTickerSecurityId("CDOR02 RBC Index"),
            simpleNameSecurityId("CDOR 2m")),
        "CDOR 2m",
        act365,
        following,
        Period.ofMonths(2),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDOR03 Index"),
            bloombergTickerSecurityId("CDOR03 RBC Index"),
            simpleNameSecurityId("CDOR 3m")),
        "CDOR 3m",
        act365,
        following,
        Period.ofMonths(3),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDOR06 Index"),
            bloombergTickerSecurityId("CDOR06 RBC Index"),
            simpleNameSecurityId("CDOR 6m")),
        "CDOR 6m",
        act365,
        following,
        Period.ofMonths(6),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CDOR12 Index"),
            bloombergTickerSecurityId("CDOR12 RBC Index"),
            simpleNameSecurityId("CDOR 12m")),
        "CDOR 12m",
        act365,
        following,
        Period.ofMonths(12),
        2,
        false,
        ca);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("CAONREPO Index"),
            simpleNameSecurityId("RBC OVERNIGHT REPO")),
        "RBC OVERNIGHT REPO",
        act365,
        following,
        Period.ofDays(1),
        0,
        false,
        ca,
        0);

    utils.addConventionBundle(
        ExternalIdBundle.of(simpleNameSecurityId("CAD_SWAP")),
        "CAD_SWAP",
        act365,
        modified,
        semiAnnual,
        0,
        ca,
        act365,
        modified,
        quarterly,
        0,
        simpleNameSecurityId("CDOR 3m"),
        ca,
        true);
    utils.addConventionBundle(
        ExternalIdBundle.of(simpleNameSecurityId("CAD_1Y_SWAP")),
        "CAD_1Y_SWAP",
        act365,
        modified,
        annual,
        0,
        ca,
        act365,
        modified,
        quarterly,
        0,
        simpleNameSecurityId("CDOR 3m"),
        ca,
        true);

    // Overnight Index Swap Convention have additional flag, publicationLag
    final Integer publicationLag = 1;
    utils.addConventionBundle(
        ExternalIdBundle.of(simpleNameSecurityId("CAD_OIS_SWAP")),
        "CAD_OIS_SWAP",
        act365,
        modified,
        annual,
        0,
        ca,
        act365,
        modified,
        annual,
        0,
        simpleNameSecurityId("RBC OVERNIGHT REPO"),
        ca,
        true,
        publicationLag);

    // TODO check the following details - copied from old CAD_FRA
    utils.addConventionBundle(
        ExternalIdBundle.of(simpleNameSecurityId("CAD_3M_FRA")),
        "CAD_3M_FRA",
        act365,
        following,
        quarterly,
        2,
        ca,
        act365,
        following,
        quarterly,
        2,
        simpleNameSecurityId("CDOR 3m"),
        ca,
        false);
    utils.addConventionBundle(
        ExternalIdBundle.of(simpleNameSecurityId("USD_6M_FRA")),
        "USD_6M_FRA",
        act365,
        following,
        semiAnnual,
        2,
        ca,
        act365,
        following,
        semiAnnual,
        2,
        simpleNameSecurityId("CDOR 6m"),
        ca,
        false);
    utils.addConventionBundle(
        ExternalIdBundle.of(simpleNameSecurityId("CAD_FRA")),
        "CAD_FRA",
        act365,
        following,
        quarterly,
        2,
        ca,
        act365,
        following,
        quarterly,
        2,
        simpleNameSecurityId("CDOR 3m"),
        ca,
        false);

    // TODO according to my information:
    // "Floating leg compounded quarterly at CDOR Flat paid semi-annually or annually for 1y"
    // Don't know how we're going to put that in
  }
/** Tests related to the construction of CapFloorCMSSpread. */
public class CapFloorCMSSpreadTest {

  // Swaps
  private static final Currency CUR = Currency.USD;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final ZonedDateTime SETTLEMENT_DATE = DateUtils.getUTCDate(2011, 3, 17);
  private static final Period FIXED_PAYMENT_PERIOD = Period.ofMonths(6);
  private static final DayCount FIXED_DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("30/360");
  private static final boolean FIXED_IS_PAYER = true; // Irrelevant for the underlying
  private static final double RATE = 0.0; // Irrelevant for the underlying
  private static final Period INDEX_TENOR = Period.ofMonths(3);
  private static final int SETTLEMENT_DAYS = 2;
  private static final DayCount DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final IborIndex IBOR_INDEX =
      new IborIndex(CUR, INDEX_TENOR, SETTLEMENT_DAYS, CALENDAR, DAY_COUNT, BUSINESS_DAY, IS_EOM);
  // Swap 10Y
  private static final Period ANNUITY_TENOR_1 = Period.ofYears(10);
  private static final IndexSwap CMS_INDEX_1 =
      new IndexSwap(FIXED_PAYMENT_PERIOD, FIXED_DAY_COUNT, IBOR_INDEX, ANNUITY_TENOR_1);
  private static final SwapFixedIborDefinition SWAP_DEFINITION_1 =
      SwapFixedIborDefinition.from(SETTLEMENT_DATE, CMS_INDEX_1, 1.0, RATE, FIXED_IS_PAYER);
  // Swap 2Y
  private static final Period ANNUITY_TENOR_2 = Period.ofYears(2);
  private static final IndexSwap CMS_INDEX_2 =
      new IndexSwap(FIXED_PAYMENT_PERIOD, FIXED_DAY_COUNT, IBOR_INDEX, ANNUITY_TENOR_2);
  private static final SwapFixedIborDefinition SWAP_DEFINITION_2 =
      SwapFixedIborDefinition.from(SETTLEMENT_DATE, CMS_INDEX_2, 1.0, RATE, FIXED_IS_PAYER);
  // CMS spread coupon
  private static final double NOTIONAL = 10000000;
  private static final ZonedDateTime PAYMENT_DATE = DateUtils.getUTCDate(2011, 4, 6);
  private static final ZonedDateTime FIXING_DATE = DateUtils.getUTCDate(2010, 12, 30);
  private static final ZonedDateTime ACCRUAL_START_DATE = DateUtils.getUTCDate(2011, 1, 5);
  private static final ZonedDateTime ACCRUAL_END_DATE = DateUtils.getUTCDate(2011, 4, 5);
  private static final DayCount PAYMENT_DAY_COUNT =
      DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final double PAYMENT_ACCRUAL_FACTOR =
      PAYMENT_DAY_COUNT.getDayCountFraction(ACCRUAL_START_DATE, ACCRUAL_END_DATE);
  private static final double STRIKE = 0.0050; // 50 bps
  private static final boolean IS_CAP = true;
  // to derivatives
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2010, 8, 18);
  private static final String FUNDING_CURVE_NAME = "Funding";
  private static final String FORWARD_CURVE_1_NAME = "Forward 1";
  //  private static final String FORWARD_CURVE_2_NAME = "Forward 2";
  private static final String[] CURVES_2_NAME = {FUNDING_CURVE_NAME, FORWARD_CURVE_1_NAME};
  //  private static final String[] CURVES_3_NAME = {FUNDING_CURVE_NAME, FORWARD_CURVE_1_NAME,
  // FORWARD_CURVE_2_NAME};
  private static final FixedCouponSwap<? extends Payment> SWAP_1 =
      SWAP_DEFINITION_1.toDerivative(REFERENCE_DATE, CURVES_2_NAME);
  private static final FixedCouponSwap<? extends Payment> SWAP_2 =
      SWAP_DEFINITION_2.toDerivative(REFERENCE_DATE, CURVES_2_NAME);
  private static final DayCount ACT_ACT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
  private static final ZonedDateTime REFERENCE_DATE_ZONED =
      ZonedDateTime.of(LocalDateTime.ofMidnight(REFERENCE_DATE), TimeZone.UTC);
  private static final double PAYMENT_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE_ZONED, PAYMENT_DATE);
  private static final double FIXING_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE_ZONED, FIXING_DATE);
  private static final double SETTLEMENT_TIME =
      ACT_ACT.getDayCountFraction(
          REFERENCE_DATE_ZONED,
          SWAP_DEFINITION_1.getFixedLeg().getNthPayment(0).getAccrualStartDate());

  private static final CapFloorCMSSpread CMS_SPREAD =
      new CapFloorCMSSpread(
          CUR,
          PAYMENT_TIME,
          PAYMENT_ACCRUAL_FACTOR,
          NOTIONAL,
          FIXING_TIME,
          SWAP_1,
          CMS_INDEX_1,
          SWAP_2,
          CMS_INDEX_2,
          SETTLEMENT_TIME,
          STRIKE,
          IS_CAP,
          FUNDING_CURVE_NAME);

  @Test
  public void testGetter() {
    assertEquals(SWAP_1, CMS_SPREAD.getUnderlyingSwap1());
    assertEquals(CMS_INDEX_1, CMS_SPREAD.getCmsIndex1());
    assertEquals(SWAP_2, CMS_SPREAD.getUnderlyingSwap2());
    assertEquals(CMS_INDEX_2, CMS_SPREAD.getCmsIndex2());
    assertEquals(STRIKE, CMS_SPREAD.getStrike(), 1E-10);
    assertEquals(IS_CAP, CMS_SPREAD.isCap());
  }

  @Test
  public void testEqualHash() {
    final CapFloorCMSSpread newCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            SWAP_1,
            CMS_INDEX_1,
            SWAP_2,
            CMS_INDEX_2,
            SETTLEMENT_TIME,
            STRIKE,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(newCMSSpread.equals(CMS_SPREAD), true);
    assertEquals(newCMSSpread.hashCode() == CMS_SPREAD.hashCode(), true);
    final Currency newCur = Currency.EUR;
    CapFloorCMSSpread modifiedCMSSpread;
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            newCur,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            SWAP_1,
            CMS_INDEX_1,
            SWAP_2,
            CMS_INDEX_2,
            SETTLEMENT_TIME,
            STRIKE,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME + 1.0,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            SWAP_1,
            CMS_INDEX_1,
            SWAP_2,
            CMS_INDEX_2,
            SETTLEMENT_TIME,
            STRIKE,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR + 1.0,
            NOTIONAL,
            FIXING_TIME,
            SWAP_1,
            CMS_INDEX_1,
            SWAP_2,
            CMS_INDEX_2,
            SETTLEMENT_TIME,
            STRIKE,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL + 1.0,
            FIXING_TIME,
            SWAP_1,
            CMS_INDEX_1,
            SWAP_2,
            CMS_INDEX_2,
            SETTLEMENT_TIME,
            STRIKE,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME + 1.0,
            SWAP_1,
            CMS_INDEX_1,
            SWAP_2,
            CMS_INDEX_2,
            SETTLEMENT_TIME,
            STRIKE,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            SWAP_1,
            CMS_INDEX_1,
            SWAP_2,
            CMS_INDEX_2,
            SETTLEMENT_TIME + 1.0,
            STRIKE,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            SWAP_1,
            CMS_INDEX_1,
            SWAP_2,
            CMS_INDEX_2,
            SETTLEMENT_TIME,
            STRIKE + 1.0,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            SWAP_1,
            CMS_INDEX_1,
            SWAP_2,
            CMS_INDEX_2,
            SETTLEMENT_TIME,
            STRIKE,
            !IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            SWAP_2,
            CMS_INDEX_1,
            SWAP_2,
            CMS_INDEX_2,
            SETTLEMENT_TIME,
            STRIKE,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            SWAP_1,
            CMS_INDEX_2,
            SWAP_2,
            CMS_INDEX_2,
            SETTLEMENT_TIME,
            STRIKE,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            SWAP_1,
            CMS_INDEX_1,
            SWAP_1,
            CMS_INDEX_2,
            SETTLEMENT_TIME,
            STRIKE,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
    modifiedCMSSpread =
        new CapFloorCMSSpread(
            CUR,
            PAYMENT_TIME,
            PAYMENT_ACCRUAL_FACTOR,
            NOTIONAL,
            FIXING_TIME,
            SWAP_1,
            CMS_INDEX_1,
            SWAP_2,
            CMS_INDEX_1,
            SETTLEMENT_TIME,
            STRIKE,
            IS_CAP,
            FUNDING_CURVE_NAME);
    assertEquals(modifiedCMSSpread.equals(CMS_SPREAD), false);
  }
}
Example #9
0
  public static synchronized void addFixedIncomeInstrumentConventions(
      final ConventionBundleMaster conventionMaster) {
    ArgumentChecker.notNull(conventionMaster, "convention master");
    final BusinessDayConvention following =
        BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Following");
    final DayCount act360 = DayCountFactory.INSTANCE.getDayCount("Actual/360");
    final ExternalId sg = ExternalSchemes.financialRegionId("TR");

    final ConventionBundleMasterUtils utils = new ConventionBundleMasterUtils(conventionMaster);

    // TODO need to check that these are right for deposit rates
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDR1T Curncy"), simpleNameSecurityId("TRY DEPOSIT 1d")),
        "TRY DEPOSIT 1d",
        act360,
        following,
        Period.ofDays(1),
        0,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDR2T Curncy"), simpleNameSecurityId("TRY DEPOSIT 2d")),
        "TRY DEPOSIT 2d",
        act360,
        following,
        Period.ofDays(1),
        0,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDR3T Curncy"), simpleNameSecurityId("TRY DEPOSIT 3d")),
        "TRY DEPOSIT 3d",
        act360,
        following,
        Period.ofDays(1),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDR1Z Curncy"), simpleNameSecurityId("TRY DEPOSIT 1w")),
        "TRY DEPOSIT 1w",
        act360,
        following,
        Period.ofDays(7),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDR2Z Curncy"), simpleNameSecurityId("TRY DEPOSIT 2w")),
        "TRY DEPOSIT 2w",
        act360,
        following,
        Period.ofDays(14),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDR3Z Curncy"), simpleNameSecurityId("TRY DEPOSIT 3w")),
        "TRY DEPOSIT 3w",
        act360,
        following,
        Period.ofDays(21),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDRA Curncy"), simpleNameSecurityId("TRY DEPOSIT 1m")),
        "TRY DEPOSIT 1m",
        act360,
        following,
        Period.ofMonths(1),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDRB Curncy"), simpleNameSecurityId("TRY DEPOSIT 2m")),
        "TRY DEPOSIT 2m",
        act360,
        following,
        Period.ofMonths(2),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDRC Curncy"), simpleNameSecurityId("TRY DEPOSIT 3m")),
        "TRY DEPOSIT 3m",
        act360,
        following,
        Period.ofMonths(3),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDRD Curncy"), simpleNameSecurityId("TRY DEPOSIT 4m")),
        "TRY DEPOSIT 4m",
        act360,
        following,
        Period.ofMonths(4),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDRE Curncy"), simpleNameSecurityId("TRY DEPOSIT 5m")),
        "TRY DEPOSIT 5m",
        act360,
        following,
        Period.ofMonths(5),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDRF Curncy"), simpleNameSecurityId("TRY DEPOSIT 6m")),
        "TRY DEPOSIT 6m",
        act360,
        following,
        Period.ofMonths(6),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDRG Curncy"), simpleNameSecurityId("TRY DEPOSIT 7m")),
        "TRY DEPOSIT 7m",
        act360,
        following,
        Period.ofMonths(7),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDRH Curncy"), simpleNameSecurityId("TRY DEPOSIT 8m")),
        "TRY DEPOSIT 8m",
        act360,
        following,
        Period.ofMonths(8),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDRI Curncy"), simpleNameSecurityId("TRY DEPOSIT 9m")),
        "TRY DEPOSIT 9m",
        act360,
        following,
        Period.ofMonths(9),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDRJ Curncy"), simpleNameSecurityId("TRY DEPOSIT 10m")),
        "TRY DEPOSIT 10m",
        act360,
        following,
        Period.ofMonths(10),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDRK Curncy"), simpleNameSecurityId("TRY DEPOSIT 11m")),
        "TRY DEPOSIT 11m",
        act360,
        following,
        Period.ofMonths(11),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDR1 Curncy"), simpleNameSecurityId("TRY DEPOSIT 1y")),
        "TRY DEPOSIT 1y",
        act360,
        following,
        Period.ofYears(1),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDR2 Curncy"), simpleNameSecurityId("TRY DEPOSIT 2y")),
        "TRY DEPOSIT 2y",
        act360,
        following,
        Period.ofYears(2),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDR3 Curncy"), simpleNameSecurityId("TRY DEPOSIT 3y")),
        "TRY DEPOSIT 3y",
        act360,
        following,
        Period.ofYears(3),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDR4 Curncy"), simpleNameSecurityId("TRY DEPOSIT 4y")),
        "TRY DEPOSIT 4y",
        act360,
        following,
        Period.ofYears(4),
        2,
        false,
        sg);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            bloombergTickerSecurityId("TYDR5 Curncy"), simpleNameSecurityId("TRY DEPOSIT 5y")),
        "TRY DEPOSIT 5y",
        act360,
        following,
        Period.ofYears(5),
        2,
        false,
        sg);
  }
public class AnnuityCouponIborDefinitionTest {
  // Libor3m
  private static final Period INDEX_TENOR = Period.ofMonths(3);
  private static final PeriodFrequency INDEX_FREQUENCY = PeriodFrequency.QUARTERLY;
  private static final int SETTLEMENT_DAYS = 2;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final DayCount DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final Currency CUR = Currency.USD;
  private static final IborIndex INDEX =
      new IborIndex(CUR, INDEX_TENOR, SETTLEMENT_DAYS, CALENDAR, DAY_COUNT, BUSINESS_DAY, IS_EOM);
  // Annuity description
  private static final Period ANNUITY_TENOR = Period.ofYears(2);
  private static final ZonedDateTime SETTLEMENT_DATE = DateUtils.getUTCDate(2011, 3, 17);
  private static final boolean IS_PAYER = true;
  private static final double NOTIONAL = 1000000;

  private static final ZonedDateTime MATURITY_DATE =
      ScheduleCalculator.getAdjustedDate(
          SETTLEMENT_DATE, BUSINESS_DAY, CALENDAR, IS_EOM, ANNUITY_TENOR);
  private static final ZonedDateTime[] PAYMENT_DATES_UNADJUSTED =
      ScheduleCalculator.getUnadjustedDateSchedule(SETTLEMENT_DATE, MATURITY_DATE, INDEX_FREQUENCY);
  private static final ZonedDateTime[] PAYMENT_DATES =
      ScheduleCalculator.getAdjustedDateSchedule(PAYMENT_DATES_UNADJUSTED, BUSINESS_DAY, CALENDAR);

  private static final AnnuityCouponIborDefinition IBOR_ANNUITY =
      AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, INDEX, IS_PAYER);

  private static final ZonedDateTime REFERENCE_DATE =
      DateUtils.getUTCDate(2011, 3, 15); // For conversion to derivative
  private static final double FIXING_RATE = 0.05;
  private static final DoubleTimeSeries<ZonedDateTime> FIXING_TS;

  static {
    FIXING_TS =
        new ArrayZonedDateTimeDoubleTimeSeries(
            new ZonedDateTime[] {REFERENCE_DATE}, new double[] {FIXING_RATE});
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullConversionDate() {
    IBOR_ANNUITY.toDerivative(null, FIXING_TS, new String[] {"L", "K"});
  }

  @Test
  public void test() {
    final CouponIborDefinition[] coupons = new CouponIborDefinition[PAYMENT_DATES.length];
    final double sign = IS_PAYER ? -1.0 : 1.0;
    // First coupon uses settlement date
    CouponFixedDefinition coupon =
        new CouponFixedDefinition(
            CUR,
            PAYMENT_DATES[0],
            SETTLEMENT_DATE,
            PAYMENT_DATES[0],
            DAY_COUNT.getDayCountFraction(SETTLEMENT_DATE, PAYMENT_DATES[0]),
            sign * NOTIONAL,
            0.0);
    ZonedDateTime fixingDate =
        ScheduleCalculator.getAdjustedDate(
            SETTLEMENT_DATE, BUSINESS_DAY, CALENDAR, -SETTLEMENT_DAYS);
    coupons[0] = CouponIborDefinition.from(coupon, fixingDate, INDEX);
    for (int loopcpn = 1; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      coupon =
          new CouponFixedDefinition(
              CUR,
              PAYMENT_DATES[loopcpn],
              PAYMENT_DATES[loopcpn - 1],
              PAYMENT_DATES[loopcpn],
              DAY_COUNT.getDayCountFraction(PAYMENT_DATES[loopcpn - 1], PAYMENT_DATES[loopcpn]),
              sign * NOTIONAL,
              0.0);
      fixingDate =
          ScheduleCalculator.getAdjustedDate(
              PAYMENT_DATES[loopcpn - 1], BUSINESS_DAY, CALENDAR, -SETTLEMENT_DAYS);
      coupons[loopcpn] = CouponIborDefinition.from(coupon, fixingDate, INDEX);
    }
    final AnnuityCouponIborDefinition iborAnnuity = new AnnuityCouponIborDefinition(coupons);
    //    assertEquals(iborAnnuity.getPayments(), coupons);
    assertEquals(iborAnnuity.isPayer(), IS_PAYER);
    for (int loopcpn = 0; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      assertEquals(iborAnnuity.getNthPayment(loopcpn), coupons[loopcpn]);
      assertEquals(iborAnnuity.getPayments()[loopcpn], coupons[loopcpn]);
    }
    final AnnuityCouponIborDefinition iborAnnuity2 =
        AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, INDEX, IS_PAYER);
    assertEquals(iborAnnuity, iborAnnuity2);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullPayments() {
    new AnnuityCouponIborDefinition(null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testOneNullPayment() {
    final CouponIborDefinition[] coupons = new CouponIborDefinition[PAYMENT_DATES.length];
    // First coupon uses settlement date
    CouponFixedDefinition coupon =
        new CouponFixedDefinition(
            CUR,
            PAYMENT_DATES[0],
            SETTLEMENT_DATE,
            PAYMENT_DATES[0],
            DAY_COUNT.getDayCountFraction(SETTLEMENT_DATE, PAYMENT_DATES[0]),
            NOTIONAL,
            0.0);
    ZonedDateTime fixingDate =
        ScheduleCalculator.getAdjustedDate(
            SETTLEMENT_DATE, BUSINESS_DAY, CALENDAR, -SETTLEMENT_DAYS);
    coupons[0] = null;
    for (int loopcpn = 1; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      coupon =
          new CouponFixedDefinition(
              CUR,
              PAYMENT_DATES[loopcpn],
              PAYMENT_DATES[loopcpn - 1],
              PAYMENT_DATES[loopcpn],
              DAY_COUNT.getDayCountFraction(PAYMENT_DATES[loopcpn - 1], PAYMENT_DATES[loopcpn]),
              NOTIONAL,
              0.0);
      fixingDate =
          ScheduleCalculator.getAdjustedDate(
              PAYMENT_DATES[loopcpn - 1], BUSINESS_DAY, CALENDAR, -SETTLEMENT_DAYS);
      coupons[loopcpn] = CouponIborDefinition.from(coupon, fixingDate, INDEX);
    }
    new AnnuityCouponIborDefinition(coupons);
  }

  @Test
  public void testFrom() {
    final ZonedDateTime settleDate = DateUtils.getUTCDate(2014, 3, 20);
    final Period indexTenor = Period.ofMonths(3);
    final DayCount dayCount = DayCountFactory.INSTANCE.getDayCount("Actual/360");
    final IborIndex index =
        new IborIndex(CUR, indexTenor, SETTLEMENT_DAYS, CALENDAR, dayCount, BUSINESS_DAY, IS_EOM);
    final AnnuityCouponIborDefinition iborAnnuity =
        AnnuityCouponIborDefinition.from(settleDate, Period.ofYears(1), NOTIONAL, index, IS_PAYER);
    final ZonedDateTime[] paymentDates =
        new ZonedDateTime[] {
          DateUtils.getUTCDate(2014, 6, 20),
          DateUtils.getUTCDate(2014, 9, 22),
          DateUtils.getUTCDate(2014, 12, 22),
          DateUtils.getUTCDate(2015, 03, 20)
        };
    final ZonedDateTime[] fixingDates =
        new ZonedDateTime[] {
          DateUtils.getUTCDate(2014, 3, 18),
          DateUtils.getUTCDate(2014, 6, 18),
          DateUtils.getUTCDate(2014, 9, 18),
          DateUtils.getUTCDate(2014, 12, 18)
        };
    final ZonedDateTime[] startPeriodDates =
        new ZonedDateTime[] {
          DateUtils.getUTCDate(2014, 3, 20),
          DateUtils.getUTCDate(2014, 6, 20),
          DateUtils.getUTCDate(2014, 9, 22),
          DateUtils.getUTCDate(2014, 12, 22)
        };
    final ZonedDateTime[] endPeriodDates =
        new ZonedDateTime[] {
          DateUtils.getUTCDate(2014, 6, 20),
          DateUtils.getUTCDate(2014, 9, 22),
          DateUtils.getUTCDate(2014, 12, 22),
          DateUtils.getUTCDate(2015, 03, 23)
        };
    for (int loopcpn = 0; loopcpn < iborAnnuity.getPayments().length; loopcpn++) {
      assertEquals(paymentDates[loopcpn], iborAnnuity.getNthPayment(loopcpn).getPaymentDate());
      assertEquals(fixingDates[loopcpn], iborAnnuity.getNthPayment(loopcpn).getFixingDate());
      assertEquals(
          startPeriodDates[loopcpn], iborAnnuity.getNthPayment(loopcpn).getFixingPeriodStartDate());
      assertEquals(
          endPeriodDates[loopcpn], iborAnnuity.getNthPayment(loopcpn).getFixingPeriodEndDate());
    }
  }

  @Test
  public void testEqualHash() {
    final CouponIborDefinition[] coupons = new CouponIborDefinition[PAYMENT_DATES.length];
    // First coupon uses settlement date
    CouponFixedDefinition coupon =
        new CouponFixedDefinition(
            CUR,
            PAYMENT_DATES[0],
            SETTLEMENT_DATE,
            PAYMENT_DATES[0],
            DAY_COUNT.getDayCountFraction(SETTLEMENT_DATE, PAYMENT_DATES[0]),
            NOTIONAL,
            0.0);
    ZonedDateTime fixingDate =
        ScheduleCalculator.getAdjustedDate(
            SETTLEMENT_DATE, BUSINESS_DAY, CALENDAR, -SETTLEMENT_DAYS);
    coupons[0] = CouponIborDefinition.from(coupon, fixingDate, INDEX);
    for (int loopcpn = 1; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      coupon =
          new CouponFixedDefinition(
              CUR,
              PAYMENT_DATES[loopcpn],
              PAYMENT_DATES[loopcpn - 1],
              PAYMENT_DATES[loopcpn],
              DAY_COUNT.getDayCountFraction(PAYMENT_DATES[loopcpn - 1], PAYMENT_DATES[loopcpn]),
              NOTIONAL,
              0.0);
      fixingDate =
          ScheduleCalculator.getAdjustedDate(
              PAYMENT_DATES[loopcpn - 1], BUSINESS_DAY, CALENDAR, -SETTLEMENT_DAYS);
      coupons[loopcpn] = CouponIborDefinition.from(coupon, fixingDate, INDEX);
    }
    final AnnuityCouponIborDefinition iborAnnuity = new AnnuityCouponIborDefinition(coupons);
    final AnnuityCouponIborDefinition iborAnnuity2 = new AnnuityCouponIborDefinition(coupons);
    assertEquals(iborAnnuity, iborAnnuity2);
    assertEquals(iborAnnuity.hashCode(), iborAnnuity2.hashCode());
    AnnuityCouponIborDefinition modifiedIborAnnuity =
        AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, INDEX, IS_PAYER);
    assertFalse(iborAnnuity.equals(modifiedIborAnnuity));
    final CouponIborDefinition[] couponsModified = new CouponIborDefinition[PAYMENT_DATES.length];
    CouponFixedDefinition couponModified =
        new CouponFixedDefinition(
            CUR,
            PAYMENT_DATES[0],
            SETTLEMENT_DATE,
            PAYMENT_DATES[0],
            DAY_COUNT.getDayCountFraction(SETTLEMENT_DATE, PAYMENT_DATES[0]),
            NOTIONAL,
            0.0);
    fixingDate =
        ScheduleCalculator.getAdjustedDate(
            SETTLEMENT_DATE, BUSINESS_DAY, CALENDAR, -SETTLEMENT_DAYS);
    couponsModified[0] = CouponIborDefinition.from(couponModified, fixingDate, INDEX);
    for (int loopcpn = 1; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      couponModified =
          new CouponFixedDefinition(
              CUR,
              PAYMENT_DATES[loopcpn],
              PAYMENT_DATES[loopcpn - 1],
              PAYMENT_DATES[loopcpn],
              DAY_COUNT.getDayCountFraction(PAYMENT_DATES[loopcpn - 1], PAYMENT_DATES[loopcpn]),
              NOTIONAL + 5.0,
              0.0);
      fixingDate =
          ScheduleCalculator.getAdjustedDate(
              PAYMENT_DATES[loopcpn - 1], BUSINESS_DAY, CALENDAR, -SETTLEMENT_DAYS);
      couponsModified[loopcpn] = CouponIborDefinition.from(couponModified, fixingDate, INDEX);
    }
    modifiedIborAnnuity = new AnnuityCouponIborDefinition(couponsModified);
    assertFalse(iborAnnuity.equals(modifiedIborAnnuity));
  }

  @Test
  public void testToDerivativeAfterFixing() {
    final String fundingCurve = "Funding";
    final String forwardCurve = "Forward";
    final String[] curves = {fundingCurve, forwardCurve};
    final Payment[] couponIborConverted = new Payment[PAYMENT_DATES.length];
    ZonedDateTime date = REFERENCE_DATE.plusMonths(1);
    for (int loopcpn = 0; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      couponIborConverted[loopcpn] =
          IBOR_ANNUITY.getNthPayment(loopcpn).toDerivative(date, FIXING_TS, curves);
    }
    GenericAnnuity<Payment> referenceAnnuity = new GenericAnnuity<Payment>(couponIborConverted);
    GenericAnnuity<? extends Payment> convertedDefinition =
        IBOR_ANNUITY.toDerivative(date, FIXING_TS, curves);
    assertEquals(referenceAnnuity, convertedDefinition);
    assertTrue(convertedDefinition.getNthPayment(0) instanceof CouponFixed);
    assertEquals(
        ((CouponFixed) convertedDefinition.getNthPayment(0)).getFixedRate(), FIXING_RATE, 0);
    for (int i = 1; i < PAYMENT_DATES.length; i++) {
      assertTrue(convertedDefinition.getNthPayment(i) instanceof CouponIbor);
    }
    date = REFERENCE_DATE;
    for (int loopcpn = 0; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      couponIborConverted[loopcpn] =
          IBOR_ANNUITY.getNthPayment(loopcpn).toDerivative(date, FIXING_TS, curves);
    }
    referenceAnnuity = new GenericAnnuity<Payment>(couponIborConverted);
    convertedDefinition = IBOR_ANNUITY.toDerivative(date, FIXING_TS, curves);
    assertEquals(referenceAnnuity, convertedDefinition);
    assertTrue(convertedDefinition.getNthPayment(0) instanceof CouponFixed);
    assertEquals(
        ((CouponFixed) convertedDefinition.getNthPayment(0)).getFixedRate(), FIXING_RATE, 0);
    for (int i = 1; i < PAYMENT_DATES.length; i++) {
      assertTrue(convertedDefinition.getNthPayment(i) instanceof CouponIbor);
    }
  }

  @Test
  public void testToDerivativeBeforeFixing() {
    final String fundingCurve = "Funding";
    final String forwardCurve = "Forward";
    final String[] curves = {fundingCurve, forwardCurve};
    final Payment[] couponIborConverted = new Payment[PAYMENT_DATES.length];
    final ZonedDateTime date = REFERENCE_DATE.minusDays(1);
    for (int loopcpn = 0; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      couponIborConverted[loopcpn] =
          IBOR_ANNUITY.getNthPayment(loopcpn).toDerivative(date, FIXING_TS, curves);
    }
    final GenericAnnuity<Payment> referenceAnnuity =
        new GenericAnnuity<Payment>(couponIborConverted);
    final GenericAnnuity<? extends Payment> convertedDefinition =
        IBOR_ANNUITY.toDerivative(date, FIXING_TS, curves);
    assertEquals(referenceAnnuity, convertedDefinition);
    for (int i = 0; i < PAYMENT_DATES.length; i++) {
      assertTrue(convertedDefinition.getNthPayment(i) instanceof CouponIbor);
    }
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullSettlementDate1() {
    AnnuityCouponIborDefinition.from(null, ANNUITY_TENOR, NOTIONAL, INDEX, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullSettlementDate2() {
    AnnuityCouponIborDefinition.from(null, MATURITY_DATE, NOTIONAL, INDEX, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullSettlementDate3() {
    AnnuityCouponIborDefinition.fromAccrualUnadjusted(
        null, MATURITY_DATE, NOTIONAL, INDEX, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullPeriod() {
    AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, (Period) null, NOTIONAL, INDEX, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullMaturityDate1() {
    AnnuityCouponIborDefinition.from(
        SETTLEMENT_DATE, (ZonedDateTime) null, NOTIONAL, INDEX, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullMaturityDate2() {
    AnnuityCouponIborDefinition.fromAccrualUnadjusted(
        SETTLEMENT_DATE, null, NOTIONAL, INDEX, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNegativeNotional1() {
    AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, -NOTIONAL, INDEX, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNegativeNotional2() {
    AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, MATURITY_DATE, -NOTIONAL, INDEX, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNegativeNotional3() {
    AnnuityCouponIborDefinition.fromAccrualUnadjusted(
        SETTLEMENT_DATE, MATURITY_DATE, -NOTIONAL, INDEX, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullIndex1() {
    AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, null, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullIndex2() {
    AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, null, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullIndex3() {
    AnnuityCouponIborDefinition.fromAccrualUnadjusted(
        SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, null, IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullAnnuity() {
    AnnuityCouponIborDefinition.from(null);
  }

  @Test
  public void testStaticConstruction() {
    AnnuityCouponIborDefinition definition1 =
        AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, INDEX, IS_PAYER);
    AnnuityCouponIborDefinition definition2 =
        AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, INDEX, IS_PAYER);
    assertEquals(definition1, definition2);
    assertEquals(IS_PAYER, definition1.isPayer());
    definition2 =
        AnnuityCouponIborDefinition.from(
            SETTLEMENT_DATE, ANNUITY_TENOR, NOTIONAL, INDEX, !IS_PAYER);
    assertFalse(definition1.equals(definition2));
    definition2 =
        AnnuityCouponIborDefinition.from(
            SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, INDEX, !IS_PAYER);
    assertFalse(definition1.equals(definition2));
    definition1 =
        AnnuityCouponIborDefinition.fromAccrualUnadjusted(
            SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, INDEX, IS_PAYER);
    definition2 =
        AnnuityCouponIborDefinition.fromAccrualUnadjusted(
            SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, INDEX, !IS_PAYER);
    assertFalse(definition1.equals(definition2));
  }

  @Test
  public void testNoSpread() {
    final AnnuityCouponIborDefinition definition =
        AnnuityCouponIborDefinition.from(SETTLEMENT_DATE, MATURITY_DATE, NOTIONAL, INDEX, IS_PAYER);
    final CouponIborDefinition[] noSpreadCoupons = definition.getPayments();
    final int n = noSpreadCoupons.length;
    final double spread = 0.01;
    final CouponIborSpreadDefinition[] spreadCoupons = new CouponIborSpreadDefinition[n];
    for (int i = 0; i < n; i++) {
      final CouponIborDefinition coupon = noSpreadCoupons[i];
      spreadCoupons[i] =
          new CouponIborSpreadDefinition(
              coupon.getCurrency(),
              coupon.getPaymentDate(),
              coupon.getAccrualStartDate(),
              coupon.getAccrualEndDate(),
              coupon.getPaymentYearFraction(),
              coupon.getNotional(),
              coupon.getFixingDate(),
              coupon.getIndex(),
              spread);
    }
    assertEquals(
        definition,
        AnnuityCouponIborDefinition.from(new AnnuityCouponIborSpreadDefinition(spreadCoupons)));
  }
}
/**
 * Class to test the present value and present value rate sensitivity of the cash-settled European
 * swaption in the SABR with extrapolation method. The SABR smile is extrapolated above a certain
 * cut-off strike.
 */
public class SwaptionCashFixedIborSABRExtrapolationRightMethodTest {
  // Swaption description
  private static final ZonedDateTime EXPIRY_DATE = DateUtils.getUTCDate(2014, 3, 18);
  private static final boolean IS_LONG = true;
  private static final int SETTLEMENT_DAYS = 2;
  // Swap 5Y description
  private static final Currency CUR = Currency.USD;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final int ANNUITY_TENOR_YEAR = 5;
  private static final Period ANNUITY_TENOR = Period.ofYears(ANNUITY_TENOR_YEAR);
  private static final ZonedDateTime SETTLEMENT_DATE =
      ScheduleCalculator.getAdjustedDate(EXPIRY_DATE, SETTLEMENT_DAYS, CALENDAR);
  private static final double NOTIONAL = 100000000; // 100m
  //  Fixed leg: Semi-annual bond
  private static final Period FIXED_PAYMENT_PERIOD = Period.ofMonths(6);
  private static final DayCount FIXED_DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("30/360");
  private static final double RATE = 0.04;
  private static final boolean FIXED_IS_PAYER = true;
  //  Ibor leg: quarterly money
  private static final Period INDEX_TENOR = Period.ofMonths(3);
  private static final DayCount DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final IborIndex IBOR_INDEX =
      new IborIndex(CUR, INDEX_TENOR, SETTLEMENT_DAYS, CALENDAR, DAY_COUNT, BUSINESS_DAY, IS_EOM);
  // Swaption construction
  private static final IndexSwap CMS_INDEX =
      new IndexSwap(FIXED_PAYMENT_PERIOD, FIXED_DAY_COUNT, IBOR_INDEX, ANNUITY_TENOR);
  private static final SwapFixedIborDefinition SWAP_DEFINITION_PAYER =
      SwapFixedIborDefinition.from(SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, RATE, FIXED_IS_PAYER);
  private static final SwapFixedIborDefinition SWAP_DEFINITION_RECEIVER =
      SwapFixedIborDefinition.from(SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, RATE, !FIXED_IS_PAYER);
  private static final SwaptionCashFixedIborDefinition SWAPTION_DEFINITION_LONG_PAYER =
      SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, SWAP_DEFINITION_PAYER, IS_LONG);
  private static final SwaptionCashFixedIborDefinition SWAPTION_DEFINITION_LONG_RECEIVER =
      SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, SWAP_DEFINITION_RECEIVER, IS_LONG);
  private static final SwaptionCashFixedIborDefinition SWAPTION_DEFINITION_SHORT_PAYER =
      SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, SWAP_DEFINITION_PAYER, !IS_LONG);
  private static final SwaptionCashFixedIborDefinition SWAPTION_DEFINITION_SHORT_RECEIVER =
      SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, SWAP_DEFINITION_RECEIVER, !IS_LONG);
  // to derivatives
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2008, 8, 18);
  private static final String FUNDING_CURVE_NAME = "Funding";
  private static final String FORWARD_CURVE_NAME = "Forward";
  private static final String[] CURVES_NAME = {FUNDING_CURVE_NAME, FORWARD_CURVE_NAME};
  private static final SwaptionCashFixedIbor SWAPTION_LONG_PAYER =
      SWAPTION_DEFINITION_LONG_PAYER.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final SwaptionCashFixedIbor SWAPTION_LONG_RECEIVER =
      SWAPTION_DEFINITION_LONG_RECEIVER.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final SwaptionCashFixedIbor SWAPTION_SHORT_PAYER =
      SWAPTION_DEFINITION_SHORT_PAYER.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final SwaptionCashFixedIbor SWAPTION_SHORT_RECEIVER =
      SWAPTION_DEFINITION_SHORT_RECEIVER.toDerivative(REFERENCE_DATE, CURVES_NAME);
  // Extrapolation
  private static final double CUT_OFF_STRIKE = 0.08;
  private static final double MU = 10.0;
  private static final SwaptionCashFixedIborSABRExtrapolationRightMethod METHOD_EXTRAPOLATION =
      new SwaptionCashFixedIborSABRExtrapolationRightMethod(CUT_OFF_STRIKE, MU);
  // Calculators
  private static final PresentValueSABRExtrapolationCalculator PVC =
      PresentValueSABRExtrapolationCalculator.getInstance();

  /** Tests present value in the region where there is no extrapolation. Tests long/short parity. */
  @Test
  public void testPresentValueNoExtra() {
    final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
    final SABRInterestRateParameters sabrParameter =
        TestsDataSetsSABR.createSABRExtrapolation1(CUT_OFF_STRIKE, MU);
    final SABRInterestRateDataBundle sabrBundle =
        new SABRInterestRateDataBundle(sabrParameter, curves);
    final SwaptionCashFixedIborSABRExtrapolationRightMethod method =
        new SwaptionCashFixedIborSABRExtrapolationRightMethod(CUT_OFF_STRIKE, MU);
    final double priceLongPayer = method.presentValue(SWAPTION_LONG_PAYER, sabrBundle);
    final double priceShortPayer = method.presentValue(SWAPTION_SHORT_PAYER, sabrBundle);
    final double priceLongReceiver = method.presentValue(SWAPTION_LONG_RECEIVER, sabrBundle);
    final double priceShortReceiver = method.presentValue(SWAPTION_SHORT_RECEIVER, sabrBundle);
    final double priceLongPayerNoExtra = PVC.visit(SWAPTION_LONG_PAYER, sabrBundle);
    final double priceShortPayerNoExtra = PVC.visit(SWAPTION_SHORT_PAYER, sabrBundle);
    final double priceLongReceiverNoExtra = PVC.visit(SWAPTION_LONG_RECEIVER, sabrBundle);
    final double priceShortReceiverNoExtra = PVC.visit(SWAPTION_SHORT_RECEIVER, sabrBundle);
    assertEquals(
        "Swaption cash SABR extrapolation: below cut-off strike",
        priceLongPayerNoExtra,
        priceLongPayer,
        1E-2);
    assertEquals(
        "Swaption cash SABR extrapolation: below cut-off strike",
        priceShortPayerNoExtra,
        priceShortPayer,
        1E-2);
    assertEquals(
        "Swaption cash SABR extrapolation: below cut-off strike",
        priceLongReceiverNoExtra,
        priceLongReceiver,
        1E-2);
    assertEquals(
        "Swaption cash SABR extrapolation: below cut-off strike",
        priceShortReceiverNoExtra,
        priceShortReceiver,
        1E-2);
    assertEquals(
        "Swaption cash SABR extrapolation: below cut-off strike long/short parity",
        priceLongPayer,
        -priceShortPayer,
        1E-2);
    assertEquals(
        "Swaption cash SABR extrapolation: below cut-off strike long/short parity",
        priceLongReceiver,
        -priceShortReceiver,
        1E-2);
  }

  /**
   * Tests present value in the region where there is extrapolation. Test a hard-coded value. Tests
   * long/short parity. Test payer/receiver/swap parity.
   */
  @Test
  public void testPresentValueExtra() {
    final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
    final SABRInterestRateParameters sabrParameter = TestsDataSetsSABR.createSABR1();
    final SABRInterestRateDataBundle sabrBundle =
        new SABRInterestRateDataBundle(sabrParameter, curves);
    final double highStrike = 0.10;
    final SwapFixedIborDefinition swapDefinitionPayerHighStrike =
        SwapFixedIborDefinition.from(
            SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, highStrike, FIXED_IS_PAYER);
    final SwapFixedIborDefinition swapDefinitionReceiverHighStrike =
        SwapFixedIborDefinition.from(
            SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, highStrike, !FIXED_IS_PAYER);
    final SwaptionCashFixedIborDefinition swaptionDefinitionLongPayerHighStrike =
        SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, swapDefinitionPayerHighStrike, IS_LONG);
    final SwaptionCashFixedIborDefinition swaptionDefinitionShortPayerHighStrike =
        SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, swapDefinitionPayerHighStrike, !IS_LONG);
    final SwaptionCashFixedIborDefinition swaptionDefinitionLongReceiverHighStrike =
        SwaptionCashFixedIborDefinition.from(
            EXPIRY_DATE, swapDefinitionReceiverHighStrike, IS_LONG);
    final SwaptionCashFixedIbor swaptionLongPayerHighStrike =
        swaptionDefinitionLongPayerHighStrike.toDerivative(REFERENCE_DATE, CURVES_NAME);
    final SwaptionCashFixedIbor swaptionShortPayerHighStrike =
        swaptionDefinitionShortPayerHighStrike.toDerivative(REFERENCE_DATE, CURVES_NAME);
    final SwaptionCashFixedIbor swaptionLongReceiverHighStrike =
        swaptionDefinitionLongReceiverHighStrike.toDerivative(REFERENCE_DATE, CURVES_NAME);
    final SwaptionCashFixedIborSABRExtrapolationRightMethod method =
        new SwaptionCashFixedIborSABRExtrapolationRightMethod(CUT_OFF_STRIKE, MU);
    final double priceLongPayer = method.presentValue(swaptionLongPayerHighStrike, sabrBundle);
    final double priceShortPayer = method.presentValue(swaptionShortPayerHighStrike, sabrBundle);
    final double priceLongReceiver =
        method.presentValue(swaptionLongReceiverHighStrike, sabrBundle);
    final double priceLongPayerExpected = 557829.033; // Value from previous run
    final double priceLongReceiverExpected = 20759354.082; // Value from previous run
    assertEquals(
        "Swaption cash SABR extrapolation: fixed value",
        priceLongPayerExpected,
        priceLongPayer,
        1E-2);
    assertEquals(
        "Swaption cash SABR extrapolation: fixed value",
        priceLongReceiverExpected,
        priceLongReceiver,
        1E-2);
    assertEquals(
        "Swaption cash SABR extrapolation: long/short parity",
        priceLongPayer,
        -priceShortPayer,
        1E-2);
  }

  @Test
  /**
   * Test the present value sensitivity to rate for a swaption with strike above the cut-off strike.
   */
  public void testPresentValueSensitivityExtra() {
    final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
    final SABRInterestRateParameters sabrParameter = TestsDataSetsSABR.createSABR1();
    final SABRInterestRateDataBundle sabrBundle =
        new SABRInterestRateDataBundle(sabrParameter, curves);
    final double highStrike = 0.10;
    final SwapFixedIborDefinition swapDefinitionPayerHighStrike =
        SwapFixedIborDefinition.from(
            SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, highStrike, FIXED_IS_PAYER);
    final SwaptionCashFixedIborDefinition swaptionDefinitionLongPayerHighStrike =
        SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, swapDefinitionPayerHighStrike, IS_LONG);
    final SwaptionCashFixedIborDefinition swaptionDefinitionShortPayerHighStrike =
        SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, swapDefinitionPayerHighStrike, !IS_LONG);
    final SwaptionCashFixedIbor swaptionLongPayerHighStrike =
        swaptionDefinitionLongPayerHighStrike.toDerivative(REFERENCE_DATE, CURVES_NAME);
    final SwaptionCashFixedIbor swaptionShortPayerHighStrike =
        swaptionDefinitionShortPayerHighStrike.toDerivative(REFERENCE_DATE, CURVES_NAME);
    final SwaptionCashFixedIborSABRExtrapolationRightMethod methodExtra =
        new SwaptionCashFixedIborSABRExtrapolationRightMethod(CUT_OFF_STRIKE, MU);
    // Swaption sensitivity
    InterestRateCurveSensitivity pvsLongPayerExtra =
        methodExtra.presentValueSensitivity(swaptionLongPayerHighStrike, sabrBundle);
    final InterestRateCurveSensitivity pvsShortPayerExtra =
        methodExtra.presentValueSensitivity(swaptionShortPayerHighStrike, sabrBundle);
    // Long/short parity
    final InterestRateCurveSensitivity pvsShortPayer_1 = pvsShortPayerExtra.multiply(-1);
    assertEquals(pvsLongPayerExtra.getSensitivities(), pvsShortPayer_1.getSensitivities());
    // Present value sensitivity comparison with finite difference.
    final double deltaTolerance = 5.0E+4;
    // Testing note: Sensitivity is for a movement of 1. 1E+2 = 1 cent for a 1 bp move. Tolerance
    // increased to cope with numerical imprecision of finite difference.
    final double deltaShift = 1.0E-5;
    pvsLongPayerExtra = pvsLongPayerExtra.clean();
    final double pv = methodExtra.presentValue(swaptionLongPayerHighStrike, sabrBundle);
    // 1. Forward curve sensitivity
    final String bumpedCurveName = "Bumped Curve";
    final String[] bumpedCurvesForwardName = {FUNDING_CURVE_NAME, bumpedCurveName};
    final SwaptionCashFixedIbor swaptionBumpedForward =
        swaptionDefinitionLongPayerHighStrike.toDerivative(REFERENCE_DATE, bumpedCurvesForwardName);
    final YieldAndDiscountCurve curveForward = curves.getCurve(FORWARD_CURVE_NAME);
    final Set<Double> timeForwardSet = new TreeSet<Double>();
    for (final Payment pay :
        swaptionLongPayerHighStrike.getUnderlyingSwap().getSecondLeg().getPayments()) {
      final CouponIbor coupon = (CouponIbor) pay;
      timeForwardSet.add(coupon.getFixingPeriodStartTime());
      timeForwardSet.add(coupon.getFixingPeriodEndTime());
    }
    final int nbForwardDate = timeForwardSet.size();
    final List<Double> timeForwardList = new ArrayList<Double>(timeForwardSet);
    Double[] timeForwardArray = new Double[nbForwardDate];
    timeForwardArray = timeForwardList.toArray(timeForwardArray);
    final double[] yieldsForward = new double[nbForwardDate + 1];
    final double[] nodeTimesForward = new double[nbForwardDate + 1];
    yieldsForward[0] = curveForward.getInterestRate(0.0);
    for (int i = 0; i < nbForwardDate; i++) {
      nodeTimesForward[i + 1] = timeForwardArray[i];
      yieldsForward[i + 1] = curveForward.getInterestRate(nodeTimesForward[i + 1]);
    }
    final YieldAndDiscountCurve tempCurveForward =
        new YieldCurve(
            InterpolatedDoublesCurve.fromSorted(
                nodeTimesForward, yieldsForward, new LinearInterpolator1D()));
    final List<DoublesPair> tempForward =
        pvsLongPayerExtra.getSensitivities().get(FORWARD_CURVE_NAME);
    final double[] resFwd = new double[nbForwardDate];
    for (int i = 0; i < nbForwardDate; i++) {
      final YieldAndDiscountCurve bumpedCurveForward =
          tempCurveForward.withSingleShift(nodeTimesForward[i + 1], deltaShift);
      final YieldCurveBundle curvesBumpedForward = new YieldCurveBundle();
      curvesBumpedForward.addAll(curves);
      curvesBumpedForward.setCurve("Bumped Curve", bumpedCurveForward);
      final SABRInterestRateDataBundle sabrBundleBumped =
          new SABRInterestRateDataBundle(sabrParameter, curvesBumpedForward);
      final double bumpedpv = methodExtra.presentValue(swaptionBumpedForward, sabrBundleBumped);
      resFwd[i] = (bumpedpv - pv) / deltaShift;
      final DoublesPair pair = tempForward.get(i);
      assertEquals(
          "Sensitivity to forward curve: Node " + i,
          nodeTimesForward[i + 1],
          pair.getFirst(),
          1E-8);
      assertEquals(
          "Sensitivity to forward curve: Node " + i, resFwd[i], pair.getSecond(), deltaTolerance);
    }
    // 2. Funding curve sensitivity
    final String[] bumpedCurvesFundingName = {bumpedCurveName, FORWARD_CURVE_NAME};
    final SwaptionCashFixedIbor swaptionBumpedFunding =
        swaptionDefinitionLongPayerHighStrike.toDerivative(REFERENCE_DATE, bumpedCurvesFundingName);
    final int nbPayDate =
        swaptionDefinitionLongPayerHighStrike.getUnderlyingSwap().getIborLeg().getPayments().length;
    final YieldAndDiscountCurve curveFunding = curves.getCurve(FUNDING_CURVE_NAME);
    final double[] yieldsFunding = new double[nbPayDate + 2];
    final double[] nodeTimesFunding = new double[nbPayDate + 2];
    yieldsFunding[0] = curveFunding.getInterestRate(0.0);
    nodeTimesFunding[1] = swaptionLongPayerHighStrike.getSettlementTime();
    yieldsFunding[1] = curveFunding.getInterestRate(nodeTimesFunding[1]);
    for (int i = 0; i < nbPayDate; i++) {
      nodeTimesFunding[i + 2] =
          swaptionLongPayerHighStrike
              .getUnderlyingSwap()
              .getSecondLeg()
              .getNthPayment(i)
              .getPaymentTime();
      yieldsFunding[i + 2] = curveFunding.getInterestRate(nodeTimesFunding[i + 2]);
    }
    final YieldAndDiscountCurve tempCurveFunding =
        new YieldCurve(
            InterpolatedDoublesCurve.fromSorted(
                nodeTimesFunding, yieldsFunding, new LinearInterpolator1D()));
    final List<DoublesPair> tempFunding =
        pvsLongPayerExtra.getSensitivities().get(FUNDING_CURVE_NAME);
    final double[] resDsc = new double[nbPayDate];
    for (int i = 0; i < nbPayDate; i++) {
      final YieldAndDiscountCurve bumpedCurve =
          tempCurveFunding.withSingleShift(nodeTimesFunding[i + 1], deltaShift);
      final YieldCurveBundle curvesBumped = new YieldCurveBundle();
      curvesBumped.addAll(curves);
      curvesBumped.setCurve("Bumped Curve", bumpedCurve);
      final SABRInterestRateDataBundle sabrBundleBumped =
          new SABRInterestRateDataBundle(sabrParameter, curvesBumped);
      final double bumpedpv = methodExtra.presentValue(swaptionBumpedFunding, sabrBundleBumped);
      resDsc[i] = (bumpedpv - pv) / deltaShift;
      final DoublesPair pair = tempFunding.get(i);
      assertEquals(
          "Sensitivity to discounting curve: Node " + i,
          nodeTimesFunding[i + 1],
          pair.getFirst(),
          1E-8);
      assertEquals(
          "Sensitivity to discounting curve: Node " + i,
          resDsc[i],
          pair.getSecond(),
          deltaTolerance);
    }
  }

  @Test
  /**
   * Test the present value sensitivity to SABR parameters for a swaption with strike above the
   * cut-off strike.
   */
  public void testPresentValueSABRSensitivity() {
    final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
    final SABRInterestRateParameters sabrParameter = TestsDataSetsSABR.createSABR1();
    final SABRInterestRateDataBundle sabrBundle =
        new SABRInterestRateDataBundle(sabrParameter, curves);
    final double highStrike = 0.10;
    final SwapFixedIborDefinition swapDefinitionPayerHighStrike =
        SwapFixedIborDefinition.from(
            SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, highStrike, FIXED_IS_PAYER);
    final SwaptionCashFixedIborDefinition swaptionDefinitionLongPayerHighStrike =
        SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, swapDefinitionPayerHighStrike, IS_LONG);
    final SwaptionCashFixedIborDefinition swaptionDefinitionShortPayerHighStrike =
        SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, swapDefinitionPayerHighStrike, !IS_LONG);
    final SwaptionCashFixedIbor swaptionLongPayerHighStrike =
        swaptionDefinitionLongPayerHighStrike.toDerivative(REFERENCE_DATE, CURVES_NAME);
    final SwaptionCashFixedIbor swaptionShortPayerHighStrike =
        swaptionDefinitionShortPayerHighStrike.toDerivative(REFERENCE_DATE, CURVES_NAME);
    //    SwaptionCashFixedIborSABRExtrapolationRightMethod methodExtra = new
    // SwaptionCashFixedIborSABRExtrapolationRightMethod(CUT_OFF_STRIKE, MU);
    // Swaption sensitivity
    final PresentValueSABRSensitivityDataBundle pvsLongPayer =
        METHOD_EXTRAPOLATION.presentValueSABRSensitivity(swaptionLongPayerHighStrike, sabrBundle);
    PresentValueSABRSensitivityDataBundle pvsShortPayer =
        METHOD_EXTRAPOLATION.presentValueSABRSensitivity(swaptionShortPayerHighStrike, sabrBundle);
    // Long/short parity
    pvsShortPayer = PresentValueSABRSensitivityDataBundle.multiplyBy(pvsShortPayer, -1.0);
    assertEquals(pvsLongPayer.getAlpha(), pvsShortPayer.getAlpha());
    // SABR sensitivity vs finite difference
    final double pvLongPayer =
        METHOD_EXTRAPOLATION.presentValue(swaptionLongPayerHighStrike, sabrBundle);
    final DoublesPair expectedExpiryTenor =
        new DoublesPair(swaptionLongPayerHighStrike.getTimeToExpiry(), ANNUITY_TENOR_YEAR);
    final double shift = 0.000005;
    // Alpha sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterAlphaBumped =
        TestsDataSetsSABR.createSABR1AlphaBumped(shift);
    final SABRInterestRateDataBundle sabrBundleAlphaBumped =
        new SABRInterestRateDataBundle(sabrParameterAlphaBumped, curves);
    final double pvLongPayerAlphaBumped =
        METHOD_EXTRAPOLATION.presentValue(swaptionLongPayerHighStrike, sabrBundleAlphaBumped);
    final double expectedAlphaSensi = (pvLongPayerAlphaBumped - pvLongPayer) / shift;
    assertEquals(
        "Number of alpha sensitivity", pvsLongPayer.getAlpha().getMap().keySet().size(), 1);
    assertEquals(
        "Alpha sensitivity expiry/tenor",
        pvsLongPayer.getAlpha().getMap().keySet().contains(expectedExpiryTenor),
        true);
    assertEquals(
        "Alpha sensitivity value",
        expectedAlphaSensi,
        pvsLongPayer.getAlpha().getMap().get(expectedExpiryTenor),
        2.0E+3);
    // Rho sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterRhoBumped =
        TestsDataSetsSABR.createSABR1RhoBumped(shift);
    final SABRInterestRateDataBundle sabrBundleRhoBumped =
        new SABRInterestRateDataBundle(sabrParameterRhoBumped, curves);
    final double pvLongPayerRhoBumped =
        METHOD_EXTRAPOLATION.presentValue(swaptionLongPayerHighStrike, sabrBundleRhoBumped);
    final double expectedRhoSensi = (pvLongPayerRhoBumped - pvLongPayer) / shift;
    assertEquals("Number of rho sensitivity", pvsLongPayer.getRho().getMap().keySet().size(), 1);
    assertEquals(
        "Rho sensitivity expiry/tenor",
        pvsLongPayer.getRho().getMap().keySet().contains(expectedExpiryTenor),
        true);
    assertEquals(
        "Rho sensitivity value",
        expectedRhoSensi,
        pvsLongPayer.getRho().getMap().get(expectedExpiryTenor),
        1.0E+0);
    // Alpha sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterNuBumped =
        TestsDataSetsSABR.createSABR1NuBumped(shift);
    final SABRInterestRateDataBundle sabrBundleNuBumped =
        new SABRInterestRateDataBundle(sabrParameterNuBumped, curves);
    final double pvLongPayerNuBumped =
        METHOD_EXTRAPOLATION.presentValue(swaptionLongPayerHighStrike, sabrBundleNuBumped);
    final double expectedNuSensi = (pvLongPayerNuBumped - pvLongPayer) / shift;
    assertEquals("Number of nu sensitivity", pvsLongPayer.getNu().getMap().keySet().size(), 1);
    assertEquals(
        "Nu sensitivity expiry/tenor",
        pvsLongPayer.getNu().getMap().keySet().contains(expectedExpiryTenor),
        true);
    assertEquals(
        "Nu sensitivity value",
        expectedNuSensi,
        pvsLongPayer.getNu().getMap().get(expectedExpiryTenor),
        5.0E+1);
  }
}
/** Tests related to the pricing of physical delivery swaption in G2++ model. */
public class SwaptionPhysicalFixedIborG2ppMethodTest {
  // Swaption 5Yx5Y
  private static final Currency CUR = Currency.USD;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final int SETTLEMENT_DAYS = 2;
  private static final Period IBOR_TENOR = Period.ofMonths(3);
  private static final DayCount IBOR_DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final IborIndex IBOR_INDEX =
      new IborIndex(
          CUR, IBOR_TENOR, SETTLEMENT_DAYS, CALENDAR, IBOR_DAY_COUNT, BUSINESS_DAY, IS_EOM);
  private static final int SWAP_TENOR_YEAR = 5;
  private static final Period SWAP_TENOR = Period.ofYears(SWAP_TENOR_YEAR);
  private static final Period FIXED_PAYMENT_PERIOD = Period.ofMonths(6);
  private static final DayCount FIXED_DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("30/360");
  private static final CMSIndex CMS_INDEX =
      new CMSIndex(FIXED_PAYMENT_PERIOD, FIXED_DAY_COUNT, IBOR_INDEX, SWAP_TENOR);
  private static final ZonedDateTime EXPIRY_DATE = DateUtils.getUTCDate(2016, 7, 7);
  private static final ZonedDateTime SETTLEMENT_DATE =
      ScheduleCalculator.getAdjustedDate(EXPIRY_DATE, CALENDAR, SETTLEMENT_DAYS);
  private static final double NOTIONAL = 100000000; // 100m
  private static final double RATE = 0.0325;
  private static final boolean FIXED_IS_PAYER = true;
  private static final SwapFixedIborDefinition SWAP_PAYER_DEFINITION =
      SwapFixedIborDefinition.from(SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, RATE, FIXED_IS_PAYER);
  private static final SwapFixedIborDefinition SWAP_RECEIVER_DEFINITION =
      SwapFixedIborDefinition.from(SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, RATE, !FIXED_IS_PAYER);
  private static final boolean IS_LONG = true;
  private static final SwaptionPhysicalFixedIborDefinition SWAPTION_PAYER_LONG_DEFINITION =
      SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, SWAP_PAYER_DEFINITION, IS_LONG);
  private static final SwaptionPhysicalFixedIborDefinition SWAPTION_RECEIVER_LONG_DEFINITION =
      SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, SWAP_RECEIVER_DEFINITION, IS_LONG);
  private static final SwaptionPhysicalFixedIborDefinition SWAPTION_PAYER_SHORT_DEFINITION =
      SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, SWAP_PAYER_DEFINITION, !IS_LONG);
  private static final SwaptionPhysicalFixedIborDefinition SWAPTION_RECEIVER_SHORT_DEFINITION =
      SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, SWAP_RECEIVER_DEFINITION, !IS_LONG);
  // to derivatives
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 7, 7);
  private static final String FUNDING_CURVE_NAME = "Funding";
  private static final String FORWARD_CURVE_NAME = "Forward";
  private static final String[] CURVES_NAME = {FUNDING_CURVE_NAME, FORWARD_CURVE_NAME};
  private static final YieldCurveBundle CURVES = TestsDataSets.createCurves1();
  private static final FixedCouponSwap<Coupon> SWAP_RECEIVER =
      SWAP_RECEIVER_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final SwaptionPhysicalFixedIbor SWAPTION_PAYER_LONG =
      SWAPTION_PAYER_LONG_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final SwaptionPhysicalFixedIbor SWAPTION_RECEIVER_LONG =
      SWAPTION_RECEIVER_LONG_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final SwaptionPhysicalFixedIbor SWAPTION_PAYER_SHORT =
      SWAPTION_PAYER_SHORT_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final SwaptionPhysicalFixedIbor SWAPTION_RECEIVER_SHORT =
      SWAPTION_RECEIVER_SHORT_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  // Calculator
  private static final SwaptionPhysicalFixedIborG2ppApproximationMethod METHOD_G2PP_APPROXIMATION =
      new SwaptionPhysicalFixedIborG2ppApproximationMethod();
  private static final SwaptionPhysicalFixedIborG2ppNumericalIntegrationMethod METHOD_G2PP_NI =
      new SwaptionPhysicalFixedIborG2ppNumericalIntegrationMethod();
  private static final G2ppPiecewiseConstantParameters PARAMETERS_G2PP =
      G2ppTestsDataSet.createG2ppParameters();
  private static final G2ppPiecewiseConstantDataBundle BUNDLE_G2PP =
      new G2ppPiecewiseConstantDataBundle(PARAMETERS_G2PP, CURVES);
  private static final PresentValueCalculator PVC = PresentValueCalculator.getInstance();

  @Test(enabled = false)
  /**
   * Test the present value vs a external system. "enabled = false" for the standard testing: the
   * external system is using a TimeCalculator with ACT/365.
   */
  public void presentValueExternal() {
    G2ppPiecewiseConstantParameters parametersCst = G2ppTestsDataSet.createG2ppCstParameters();
    final YieldAndDiscountCurve curve5 = new YieldCurve(ConstantDoublesCurve.from(0.05));
    final YieldCurveBundle curves = new YieldCurveBundle();
    curves.setCurve(FUNDING_CURVE_NAME, curve5);
    curves.setCurve(FORWARD_CURVE_NAME, curve5);
    G2ppPiecewiseConstantDataBundle bundleCst =
        new G2ppPiecewiseConstantDataBundle(parametersCst, curves);
    CurrencyAmount pv = METHOD_G2PP_APPROXIMATION.presentValue(SWAPTION_PAYER_LONG, bundleCst);
    double pvExternal = 6885626.28245924; // ! TimeCalculator with ACT/365
    assertEquals(
        "Swaption physical - G2++ - present value - external system",
        pvExternal,
        pv.getAmount(),
        1E-2);
  }

  @Test(enabled = true)
  /** Test the present value vs a hard-coded value. */
  public void presentValue() {
    CurrencyAmount pv = METHOD_G2PP_APPROXIMATION.presentValue(SWAPTION_PAYER_LONG, BUNDLE_G2PP);
    double pvExpected = 4893110.87;
    assertEquals(
        "Swaption physical - G2++ - present value - hard coded value",
        pvExpected,
        pv.getAmount(),
        1E-2);
  }

  @Test
  /** Tests long/short parity. */
  public void longShortParity() {
    CurrencyAmount pvPayerLong =
        METHOD_G2PP_APPROXIMATION.presentValue(SWAPTION_PAYER_LONG, BUNDLE_G2PP);
    CurrencyAmount pvPayerShort =
        METHOD_G2PP_APPROXIMATION.presentValue(SWAPTION_PAYER_SHORT, BUNDLE_G2PP);
    assertEquals(
        "Swaption physical - G2++ - present value - long/short parity",
        pvPayerLong.getAmount(),
        -pvPayerShort.getAmount(),
        1E-2);
    CurrencyAmount pvReceiverLong =
        METHOD_G2PP_APPROXIMATION.presentValue(SWAPTION_RECEIVER_LONG, BUNDLE_G2PP);
    CurrencyAmount pvReceiverShort =
        METHOD_G2PP_APPROXIMATION.presentValue(SWAPTION_RECEIVER_SHORT, BUNDLE_G2PP);
    assertEquals(
        "Swaption physical - G2++ - present value - long/short parity",
        pvReceiverLong.getAmount(),
        -pvReceiverShort.getAmount(),
        1E-2);
  }

  @Test
  /** Tests payer/receiver/swap parity. */
  public void payerReceiverParity() {
    CurrencyAmount pvReceiverLong =
        METHOD_G2PP_APPROXIMATION.presentValue(SWAPTION_RECEIVER_LONG, BUNDLE_G2PP);
    CurrencyAmount pvPayerShort =
        METHOD_G2PP_APPROXIMATION.presentValue(SWAPTION_PAYER_SHORT, BUNDLE_G2PP);
    double pvSwap = PVC.visit(SWAP_RECEIVER, CURVES);
    assertEquals(
        "Swaption physical - G2++ - present value - payer/receiver/swap parity",
        pvReceiverLong.getAmount() + pvPayerShort.getAmount(),
        pvSwap,
        1E-2);
  }

  @Test
  /** Test the present value by approximation vs by numerical integration. */
  public void approximationNumericalIntegration() {
    CurrencyAmount pvApproximation =
        METHOD_G2PP_APPROXIMATION.presentValue(SWAPTION_PAYER_LONG, BUNDLE_G2PP);
    CurrencyAmount pvNI = METHOD_G2PP_NI.presentValue(SWAPTION_PAYER_LONG, BUNDLE_G2PP);
    assertEquals(
        "Swaption physical - G2++ - present value - approximation vs Numerical integration",
        pvApproximation.getAmount(),
        pvNI.getAmount(),
        2.0E+3);
  }

  @Test(enabled = false)
  /** Tests of performance. "enabled = false" for the standard testing. */
  public void performance() {
    long startTime, endTime;
    final int nbTest = 100;
    CurrencyAmount pvPayerLongApproximation = CurrencyAmount.of(CUR, 0.0);
    CurrencyAmount pvPayerLongNI = CurrencyAmount.of(CUR, 0.0);
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongApproximation =
          METHOD_G2PP_APPROXIMATION.presentValue(SWAPTION_PAYER_LONG, BUNDLE_G2PP);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest + " pv swaption G2++ approximation method: " + (endTime - startTime) + " ms");
    // Performance note: G2++ price: 24-Aug-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 175 ms for
    // 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongNI = METHOD_G2PP_NI.presentValue(SWAPTION_PAYER_LONG, BUNDLE_G2PP);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " pv swaption G2++ numerical integration method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: G2++ price: 24-Aug-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 1075 ms for
    // 100 swaptions.

    System.out.println("G2++ approximation - present value: " + pvPayerLongApproximation);
    System.out.println("G2++ numerical integration - present value: " + pvPayerLongNI);
  }
}
/** Tests related to the construction of interest rate future security. */
public class InterestRateFutureSecurityTest {
  // EURIBOR 3M Index
  private static final Period TENOR = Period.ofMonths(3);
  private static final int SETTLEMENT_DAYS = 2;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final DayCount DAY_COUNT_INDEX =
      DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final Currency CUR = Currency.EUR;
  private static final IborIndex IBOR_INDEX =
      new IborIndex(CUR, TENOR, SETTLEMENT_DAYS, CALENDAR, DAY_COUNT_INDEX, BUSINESS_DAY, IS_EOM);
  // Future
  private static final ZonedDateTime SPOT_LAST_TRADING_DATE = DateUtil.getUTCDate(2012, 9, 19);
  private static final ZonedDateTime LAST_TRADING_DATE =
      ScheduleCalculator.getAdjustedDate(SPOT_LAST_TRADING_DATE, CALENDAR, -SETTLEMENT_DAYS);
  private static final ZonedDateTime FIXING_END_DATE =
      ScheduleCalculator.getAdjustedDate(
          SPOT_LAST_TRADING_DATE, BUSINESS_DAY, CALENDAR, IS_EOM, TENOR);
  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 InterestRateFutureSecurityDefinition ERU2 = new
  // InterestRateFutureSecurityDefinition(LAST_TRADING_DATE, IBOR_INDEX, NOTIONAL, FUTURE_FACTOR,
  // NAME);

  private static final LocalDate REFERENCE_DATE = LocalDate.of(2010, 8, 18);
  private static final DayCount ACT_ACT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
  private static final ZonedDateTime REFERENCE_DATE_ZONED =
      ZonedDateTime.of(LocalDateTime.ofMidnight(REFERENCE_DATE), TimeZone.UTC);
  private static final double LAST_TRADING_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE_ZONED, LAST_TRADING_DATE);
  private static final double FIXING_START_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE_ZONED, SPOT_LAST_TRADING_DATE);
  private static final double FIXING_END_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE_ZONED, FIXING_END_DATE);
  private static final double FIXING_ACCRUAL =
      DAY_COUNT_INDEX.getDayCountFraction(SPOT_LAST_TRADING_DATE, FIXING_END_DATE);
  private static final String DISCOUNTING_CURVE_NAME = "Funding";
  private static final String FORWARD_CURVE_NAME = "Forward";
  private static final InterestRateFutureSecurity ERU2 =
      new InterestRateFutureSecurity(
          LAST_TRADING_TIME,
          IBOR_INDEX,
          FIXING_START_TIME,
          FIXING_END_TIME,
          FIXING_ACCRUAL,
          NOTIONAL,
          FUTURE_FACTOR,
          NAME,
          DISCOUNTING_CURVE_NAME,
          FORWARD_CURVE_NAME);

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullIndex() {
    new InterestRateFutureSecurity(
        LAST_TRADING_TIME,
        null,
        FIXING_START_TIME,
        FIXING_END_TIME,
        FIXING_ACCRUAL,
        NOTIONAL,
        FUTURE_FACTOR,
        NAME,
        DISCOUNTING_CURVE_NAME,
        FORWARD_CURVE_NAME);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullName() {
    new InterestRateFutureSecurity(
        LAST_TRADING_TIME,
        IBOR_INDEX,
        FIXING_START_TIME,
        FIXING_END_TIME,
        FIXING_ACCRUAL,
        NOTIONAL,
        FUTURE_FACTOR,
        null,
        DISCOUNTING_CURVE_NAME,
        FORWARD_CURVE_NAME);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullDscCurve() {
    new InterestRateFutureSecurity(
        LAST_TRADING_TIME,
        IBOR_INDEX,
        FIXING_START_TIME,
        FIXING_END_TIME,
        FIXING_ACCRUAL,
        NOTIONAL,
        FUTURE_FACTOR,
        NAME,
        null,
        FORWARD_CURVE_NAME);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullForwardCurve() {
    new InterestRateFutureSecurity(
        LAST_TRADING_TIME,
        IBOR_INDEX,
        FIXING_START_TIME,
        FIXING_END_TIME,
        FIXING_ACCRUAL,
        NOTIONAL,
        FUTURE_FACTOR,
        NAME,
        DISCOUNTING_CURVE_NAME,
        null);
  }

  @Test
  public void getter() {
    assertEquals(LAST_TRADING_TIME, ERU2.getLastTradingTime());
    assertEquals(IBOR_INDEX, ERU2.getIborIndex());
    assertEquals(NOTIONAL, ERU2.getNotional());
    assertEquals(FUTURE_FACTOR, ERU2.getPaymentAccrualFactor());
    assertEquals(DISCOUNTING_CURVE_NAME, ERU2.getDiscountingCurveName());
    assertEquals(FORWARD_CURVE_NAME, ERU2.getForwardCurveName());
    assertEquals(NAME, ERU2.getName());
    assertEquals(FIXING_START_TIME, ERU2.getFixingPeriodStartTime());
    assertEquals(FIXING_END_TIME, ERU2.getFixingPeriodEndTime());
    assertEquals(FIXING_ACCRUAL, ERU2.getFixingPeriodAccrualFactor());
  }

  @Test
  public void equalHash() {
    assertTrue(ERU2.equals(ERU2));
    InterestRateFutureSecurity other =
        new InterestRateFutureSecurity(
            LAST_TRADING_TIME,
            IBOR_INDEX,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL,
            NOTIONAL,
            FUTURE_FACTOR,
            NAME,
            DISCOUNTING_CURVE_NAME,
            FORWARD_CURVE_NAME);
    assertTrue(ERU2.equals(other));
    assertTrue(ERU2.hashCode() == other.hashCode());
    assertEquals(ERU2.toString(), other.toString());
    InterestRateFutureSecurity modifiedFuture;
    modifiedFuture =
        new InterestRateFutureSecurity(
            LAST_TRADING_TIME - 0.01,
            IBOR_INDEX,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL,
            NOTIONAL,
            FUTURE_FACTOR,
            NAME,
            DISCOUNTING_CURVE_NAME,
            FORWARD_CURVE_NAME);
    assertFalse(ERU2.equals(modifiedFuture));
    modifiedFuture =
        new InterestRateFutureSecurity(
            LAST_TRADING_TIME,
            IBOR_INDEX,
            FIXING_START_TIME + 0.01,
            FIXING_END_TIME,
            FIXING_ACCRUAL,
            NOTIONAL,
            FUTURE_FACTOR,
            NAME,
            DISCOUNTING_CURVE_NAME,
            FORWARD_CURVE_NAME);
    assertFalse(ERU2.equals(modifiedFuture));
    modifiedFuture =
        new InterestRateFutureSecurity(
            LAST_TRADING_TIME,
            IBOR_INDEX,
            FIXING_START_TIME,
            FIXING_END_TIME + 0.01,
            FIXING_ACCRUAL,
            NOTIONAL,
            FUTURE_FACTOR,
            NAME,
            DISCOUNTING_CURVE_NAME,
            FORWARD_CURVE_NAME);
    assertFalse(ERU2.equals(modifiedFuture));
    modifiedFuture =
        new InterestRateFutureSecurity(
            LAST_TRADING_TIME,
            IBOR_INDEX,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL + 0.01,
            NOTIONAL,
            FUTURE_FACTOR,
            NAME,
            DISCOUNTING_CURVE_NAME,
            FORWARD_CURVE_NAME);
    assertFalse(ERU2.equals(modifiedFuture));
    modifiedFuture =
        new InterestRateFutureSecurity(
            LAST_TRADING_TIME,
            IBOR_INDEX,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL,
            NOTIONAL + 1.0,
            FUTURE_FACTOR,
            NAME,
            DISCOUNTING_CURVE_NAME,
            FORWARD_CURVE_NAME);
    assertFalse(ERU2.equals(modifiedFuture));
    modifiedFuture =
        new InterestRateFutureSecurity(
            LAST_TRADING_TIME,
            IBOR_INDEX,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL,
            NOTIONAL,
            FUTURE_FACTOR + 0.25,
            NAME,
            DISCOUNTING_CURVE_NAME,
            FORWARD_CURVE_NAME);
    assertFalse(ERU2.equals(modifiedFuture));
    modifiedFuture =
        new InterestRateFutureSecurity(
            LAST_TRADING_TIME,
            IBOR_INDEX,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL,
            NOTIONAL,
            FUTURE_FACTOR,
            NAME,
            DISCOUNTING_CURVE_NAME + "NO",
            FORWARD_CURVE_NAME);
    assertFalse(ERU2.equals(modifiedFuture));
    modifiedFuture =
        new InterestRateFutureSecurity(
            LAST_TRADING_TIME,
            IBOR_INDEX,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL,
            NOTIONAL,
            FUTURE_FACTOR,
            NAME,
            DISCOUNTING_CURVE_NAME,
            FORWARD_CURVE_NAME + "NO");
    assertFalse(ERU2.equals(modifiedFuture));
    modifiedFuture =
        new InterestRateFutureSecurity(
            LAST_TRADING_TIME,
            IBOR_INDEX,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL,
            NOTIONAL,
            FUTURE_FACTOR,
            NAME + NAME,
            DISCOUNTING_CURVE_NAME,
            FORWARD_CURVE_NAME);
    assertFalse(ERU2.equals(modifiedFuture));
    IborIndex otherIndex =
        new IborIndex(
            CUR, TENOR, SETTLEMENT_DAYS, CALENDAR, DAY_COUNT_INDEX, BUSINESS_DAY, !IS_EOM);
    modifiedFuture =
        new InterestRateFutureSecurity(
            LAST_TRADING_TIME,
            otherIndex,
            FIXING_START_TIME,
            FIXING_END_TIME,
            FIXING_ACCRUAL,
            NOTIONAL,
            FUTURE_FACTOR,
            NAME,
            DISCOUNTING_CURVE_NAME,
            FORWARD_CURVE_NAME);
    assertFalse(ERU2.equals(modifiedFuture));
    assertFalse(ERU2.equals(LAST_TRADING_DATE));
    assertFalse(ERU2.equals(null));
  }
}
/**
 * Test class for the replication method for CMS caplet/floorlet using a SABR smile with
 * extrapolation.
 */
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 Calendar 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 =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("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 = DayCountFactory.INSTANCE.getDayCount("30/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 =
      DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final double ACCRUAL_FACTOR =
      PAYMENT_DAY_COUNT.getDayCountFraction(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
  /**
   * 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);
    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);
    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);
    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);
    assertEquals(
        "Extrapolation: CMS coupon vs Cap 0", priceCouponExtra, priceCap0Extra, TOLERANCE_PV);
  }

  //  @Test
  //  /**
  //   * Tests the method against the present value calculator.
  //   */
  //  public void presentValueCouponMethodSpecificVsGeneric() {
  //    final double pvSpecific = METHOD_EXTRAPOLATION_CPN.presentValue(CMS_COUPON,
  // SABR_MULTICURVES).getAmount(EUR);
  //    final CurrencyAmount pvGeneric = METHOD_GENERIC.presentValue(CMS_COUPON, SABR_MULTICURVES);
  //    assertEquals("Coupon CMS SABR extrapolation: method : Specific vs Generic", pvSpecific,
  // pvGeneric.getAmount(), TOLERANCE_PRICE);
  //  }

  @Test
  /**
   * 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);
    final double pvCalculator = CMS_CAP_LONG.accept(PVSSXC, SABR_MULTICURVES).getAmount(EUR);
    assertEquals(
        "CMS cap/floor SABR: Present value : method vs calculator",
        pvMethod,
        pvCalculator,
        TOLERANCE_PV);
  }

  @Test
  /**
   * 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);
    final double priceCapLongExtra =
        METHOD_EXTRAPOLATION_CAP.presentValue(CMS_CAP_LONG, SABR_MULTICURVES).getAmount(EUR);
    final double priceCapShortExtra =
        METHOD_EXTRAPOLATION_CAP.presentValue(CMS_CAP_SHORT, SABR_MULTICURVES).getAmount(EUR);
    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
  /**
   * 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);
    AssertSensivityObjects.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);
    AssertSensivityObjects.assertEquals(
        "SwaptionPhysicalFixedIborSABRMethod: presentValueCurveSensitivity ",
        pvpsCapShortExact,
        pvpsCapShortFD,
        TOLERANCE_PV_DELTA);
  }

  @Test
  /**
   * 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);
    AssertSensivityObjects.assertEquals(
        "CMS cap/floor SABR: Present value : method vs calculator",
        pvcsMethod,
        pvcsCalculator,
        TOLERANCE_PV_DELTA);
  }

  @Test
  /** 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);
    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 = new DoublesPair(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);
    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);
    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);
    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);
  }

  @Test
  /** 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);
    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 = new DoublesPair(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);
    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);
    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);
    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);
  }

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

  @Test
  /** 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);
      final double pvShiftDo =
          METHOD_EXTRAPOLATION_CAP.presentValue(cmsCapShiftDo, SABR_MULTICURVES).getAmount(EUR);
      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);
    }
  }

  @Test(enabled = true)
  /**
   * 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);
    @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);
      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);
    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);
  }

  @Test(enabled = false)
  /** Tests of performance. "enabled = false" for the standard testing. */
  public void performanceCoupon() {
    long startTime, endTime;
    final int nbTest = 1000;

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      METHOD_STANDARD_CPN.presentValue(CMS_COUPON, SABR_MULTICURVES);
      METHOD_STANDARD_CPN.presentValueCurveSensitivity(CMS_COUPON, SABR_MULTICURVES);
      METHOD_STANDARD_CPN.presentValueSABRSensitivity(CMS_COUPON, SABR_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " CMS coupon by replication SABR standard (price+delta+vega): "
            + (endTime - startTime)
            + " ms");

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      METHOD_EXTRAPOLATION_CPN.presentValue(CMS_COUPON, SABR_MULTICURVES);
      METHOD_EXTRAPOLATION_CPN.presentValueCurveSensitivity(CMS_COUPON, SABR_MULTICURVES);
      METHOD_EXTRAPOLATION_CPN.presentValueSABRSensitivity(CMS_COUPON, SABR_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " CMS coupon by replication SABR with extrapolation (price+delta+vega): "
            + (endTime - startTime)
            + " ms");
    // Performance note: price (standard SABR): 15-Nov-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon:
    // 55 ms for 1000 CMS coupon 5Y.
    // Performance note: price (SABR with extrapolation): 15-Nov-11: On Mac Pro 3.2 GHz Quad-Core
    // Intel Xeon: 80 ms for 1000 CMS coupon 5Y.
    // Performance note: price+delta (standard SABR): 15-Nov-11: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 215 ms for 1000 CMS coupon 5Y.
    // Performance note: price+delta (SABR with extrapolation): 15-Nov-11: On Mac Pro 3.2 GHz
    // Quad-Core Intel Xeon: 455 ms for 1000 CMS coupon 5Y.
    // Performance note: price+delta+vega (standard SABR): 18-Apr-2012: On Mac Pro 3.2 GHz Quad-Core
    // Intel Xeon: 710 ms for 1000 CMS coupon 5Y.
    // Performance note: price+delta+vega (SABR with extrapolation): 18-Apr-2012: On Mac Pro 3.2 GHz
    // Quad-Core Intel Xeon: 690 ms for 1000 CMS coupon 5Y.

  }

  @Test(enabled = false)
  /** Tests of performance. "enabled = false" for the standard testing. */
  public void performanceCap() {
    long startTime, endTime;
    final int nbTest = 1000;

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      METHOD_STANDARD_CAP.presentValue(CMS_CAP_LONG, SABR_MULTICURVES);
      METHOD_STANDARD_CAP.presentValueCurveSensitivity(CMS_CAP_LONG, SABR_MULTICURVES);
      METHOD_STANDARD_CAP.presentValueSABRSensitivity(CMS_CAP_LONG, SABR_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " CMS cap by replication SABR standard (price+delta+vega): "
            + (endTime - startTime)
            + " ms");

    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      METHOD_EXTRAPOLATION_CAP.presentValue(CMS_CAP_LONG, SABR_MULTICURVES);
      METHOD_EXTRAPOLATION_CAP.presentValueCurveSensitivity(CMS_CAP_LONG, SABR_MULTICURVES);
      METHOD_EXTRAPOLATION_CAP.presentValueSABRSensitivity(CMS_CAP_LONG, SABR_MULTICURVES);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " CMS cap by replication SABR with extrapolation (price+delta+vega): "
            + (endTime - startTime)
            + " ms");
    // Performance note: price+delta+vega (standard SABR): 28-Nov-2012: On Mac Pro 3.2 GHz Quad-Core
    // Intel Xeon: 675 ms for 1000 CMS cap 5Y.
    // Performance note: price+delta+vega (SABR with extrapolation): 28-Nov-2012: On Mac Pro 3.2 GHz
    // Quad-Core Intel Xeon: 515 ms for 1000 CMS cap 5Y.

  }
}
/** Tests finite difference computation of curve sensitivity. */
public class SensitivityFiniteDifferenceTest {
  // Index
  private static final Period TENOR = Period.ofMonths(3);
  private static final int SETTLEMENT_DAYS = 2;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final DayCount DAY_COUNT_INDEX =
      DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final Currency CUR = Currency.USD;
  private static final IborIndex INDEX =
      new IborIndex(CUR, TENOR, SETTLEMENT_DAYS, CALENDAR, DAY_COUNT_INDEX, BUSINESS_DAY, IS_EOM);
  // Dates : The above dates are not standard but selected for insure correct testing.
  private static final ZonedDateTime FIXING_DATE = DateUtils.getUTCDate(2011, 1, 3);
  private static final ZonedDateTime ACCRUAL_START_DATE = DateUtils.getUTCDate(2011, 1, 6);
  private static final ZonedDateTime ACCRUAL_END_DATE = DateUtils.getUTCDate(2011, 4, 4);
  private static final ZonedDateTime PAYMENT_DATE = DateUtils.getUTCDate(2011, 1, 7);
  private static final DayCount DAY_COUNT_PAYMENT =
      DayCountFactory.INSTANCE.getDayCount("Actual/365");
  private static final double ACCRUAL_FACTOR_PAYMENT =
      DAY_COUNT_PAYMENT.getDayCountFraction(ACCRUAL_START_DATE, ACCRUAL_END_DATE);
  private static final double FRA_RATE = 0.05;
  private static final double NOTIONAL = 1000000; // 1m
  // Coupon with specific payment and accrual dates.
  private static final ForwardRateAgreementDefinition FRA_DEFINITION =
      new ForwardRateAgreementDefinition(
          CUR,
          PAYMENT_DATE,
          ACCRUAL_START_DATE,
          ACCRUAL_END_DATE,
          ACCRUAL_FACTOR_PAYMENT,
          NOTIONAL,
          FIXING_DATE,
          INDEX,
          FRA_RATE);
  // To derivatives
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2009, 8, 18);
  private static final String FUNDING_CURVE_NAME = "Funding";
  private static final String FORWARD_CURVE_NAME = "Forward";
  private static final String[] CURVES = {FUNDING_CURVE_NAME, FORWARD_CURVE_NAME};
  private static final ForwardRateAgreement FRA =
      (ForwardRateAgreement) FRA_DEFINITION.toDerivative(REFERENCE_DATE, CURVES);
  private static final ForwardRateAgreementDiscountingMethod FRA_METHOD =
      ForwardRateAgreementDiscountingMethod.getInstance();

  @Test
  public void curveSensitivityFRA() {
    final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
    final double deltaShift = 1.0E-8;
    final double pv = FRA_METHOD.presentValue(FRA, curves).getAmount();
    // 1. Forward curve sensitivity
    final String bumpedCurveName = "Bumped Curve";
    final String[] bumpedCurvesForwardName = {FUNDING_CURVE_NAME, bumpedCurveName};
    final ForwardRateAgreement fraBumpedForward =
        (ForwardRateAgreement) FRA_DEFINITION.toDerivative(REFERENCE_DATE, bumpedCurvesForwardName);
    final YieldAndDiscountCurve curveForward = curves.getCurve(FORWARD_CURVE_NAME);
    final double[] timeForward = new double[2];
    timeForward[0] = FRA.getFixingPeriodStartTime();
    timeForward[1] = FRA.getFixingPeriodEndTime();
    final int nbForwardDate = timeForward.length;
    final double[] yieldsForward = new double[nbForwardDate + 1];
    final double[] nodeTimesForward = new double[nbForwardDate + 1];
    yieldsForward[0] = curveForward.getInterestRate(0.0);
    for (int i = 0; i < nbForwardDate; i++) {
      nodeTimesForward[i + 1] = timeForward[i];
      yieldsForward[i + 1] = curveForward.getInterestRate(nodeTimesForward[i + 1]);
    }
    final YieldAndDiscountCurve tempCurveForward =
        YieldCurve.from(
            InterpolatedDoublesCurve.fromSorted(
                nodeTimesForward, yieldsForward, new LinearInterpolator1D()));
    final double[] sensiPvForwardFD = new double[nbForwardDate];
    for (int i = 0; i < nbForwardDate; i++) {
      final YieldAndDiscountCurve bumpedCurveForward =
          tempCurveForward.withSingleShift(nodeTimesForward[i + 1], deltaShift);
      final YieldCurveBundle curvesBumpedForward = new YieldCurveBundle();
      curvesBumpedForward.addAll(curves);
      curvesBumpedForward.setCurve("Bumped Curve", bumpedCurveForward);
      final double bumpedPv =
          FRA_METHOD.presentValue(fraBumpedForward, curvesBumpedForward).getAmount();
      sensiPvForwardFD[i] = (bumpedPv - pv) / deltaShift;
    }

    final double[] nodeTimesForwardMethod =
        new double[] {FRA.getFixingPeriodStartTime(), FRA.getFixingPeriodEndTime()};
    final double[] sensiForwardMethod =
        SensitivityFiniteDifference.curveSensitivity(
            fraBumpedForward,
            curves,
            pv,
            FORWARD_CURVE_NAME,
            bumpedCurveName,
            nodeTimesForwardMethod,
            deltaShift,
            FRA_METHOD);
    assertEquals(
        "Sensitivity finite difference method: number of node", 2, sensiForwardMethod.length);
    for (int loopnode = 0; loopnode < sensiForwardMethod.length; loopnode++) {
      assertEquals(
          "Sensitivity finite difference method: node sensitivity",
          sensiPvForwardFD[loopnode],
          sensiForwardMethod[loopnode]);
    }

    // 2. Funding curve sensitivity
    final String[] bumpedCurvesFundingName = {bumpedCurveName, FORWARD_CURVE_NAME};
    final ForwardRateAgreement fraBumped =
        (ForwardRateAgreement) FRA_DEFINITION.toDerivative(REFERENCE_DATE, bumpedCurvesFundingName);
    final YieldAndDiscountCurve curveFunding = curves.getCurve(FUNDING_CURVE_NAME);
    final double[] yieldsFunding = new double[2];
    final double[] nodeTimesFunding = new double[2];
    yieldsFunding[0] = curveFunding.getInterestRate(0.0);
    nodeTimesFunding[1] = FRA.getPaymentTime();
    yieldsFunding[1] = curveFunding.getInterestRate(nodeTimesFunding[1]);
    final YieldAndDiscountCurve tempCurveFunding =
        YieldCurve.from(
            InterpolatedDoublesCurve.fromSorted(
                nodeTimesFunding, yieldsFunding, new LinearInterpolator1D()));
    final YieldAndDiscountCurve bumpedCurve =
        tempCurveFunding.withSingleShift(nodeTimesFunding[1], deltaShift);
    final YieldCurveBundle curvesBumped = new YieldCurveBundle();
    curvesBumped.addAll(curves);
    curvesBumped.replaceCurve("Bumped Curve", bumpedCurve);
    final double bumpedPvDsc = FRA_METHOD.presentValue(fraBumped, curvesBumped).getAmount();
    final double[] resDsc = new double[1];
    resDsc[0] = (bumpedPvDsc - pv) / deltaShift;

    final double[] nodeTimesFundingMethod = new double[] {FRA.getPaymentTime()};
    final double[] sensiFundingMethod =
        SensitivityFiniteDifference.curveSensitivity(
            fraBumped,
            curves,
            pv,
            FUNDING_CURVE_NAME,
            bumpedCurveName,
            nodeTimesFundingMethod,
            deltaShift,
            FRA_METHOD);
    assertEquals(
        "Sensitivity finite difference method: number of node", 1, sensiFundingMethod.length);
    for (int loopnode = 0; loopnode < sensiFundingMethod.length; loopnode++) {
      assertEquals(
          "Sensitivity finite difference method: node sensitivity",
          resDsc[loopnode],
          sensiFundingMethod[loopnode]);
    }
  }

  @Test
  public void curveSensitivityCentered() {
    final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
    final double deltaShift = 1.0E-8;
    final double pv = FRA_METHOD.presentValue(FRA, curves).getAmount();
    // 1. Forward curve sensitivity
    final String bumpedCurveName = "Bumped Curve";
    final String[] bumpedCurvesForwardName = {FUNDING_CURVE_NAME, bumpedCurveName};
    final ForwardRateAgreement fraBumpedForward =
        (ForwardRateAgreement) FRA_DEFINITION.toDerivative(REFERENCE_DATE, bumpedCurvesForwardName);
    final double[] nodeTimesForwardMethod =
        new double[] {FRA.getFixingPeriodStartTime(), FRA.getFixingPeriodEndTime()};
    final double[] sensiForward =
        SensitivityFiniteDifference.curveSensitivity(
            fraBumpedForward,
            curves,
            pv,
            FORWARD_CURVE_NAME,
            bumpedCurveName,
            nodeTimesForwardMethod,
            deltaShift,
            FRA_METHOD);
    final double[] sensiForwardCentered =
        SensitivityFiniteDifference.curveSensitivity(
            fraBumpedForward,
            curves,
            pv,
            FORWARD_CURVE_NAME,
            bumpedCurveName,
            nodeTimesForwardMethod,
            deltaShift,
            FRA_METHOD,
            FiniteDifferenceType.CENTRAL);
    final double[] sensiForwardCentered2 =
        SensitivityFiniteDifference.curveSensitivity(
            fraBumpedForward,
            curves,
            FORWARD_CURVE_NAME,
            bumpedCurveName,
            nodeTimesForwardMethod,
            deltaShift,
            FRA_METHOD);
    final double[] sensiForwardForward =
        SensitivityFiniteDifference.curveSensitivity(
            fraBumpedForward,
            curves,
            pv,
            FORWARD_CURVE_NAME,
            bumpedCurveName,
            nodeTimesForwardMethod,
            deltaShift,
            FRA_METHOD,
            FiniteDifferenceType.FORWARD);
    final double[] sensiForwardBackward =
        SensitivityFiniteDifference.curveSensitivity(
            fraBumpedForward,
            curves,
            pv,
            FORWARD_CURVE_NAME,
            bumpedCurveName,
            nodeTimesForwardMethod,
            deltaShift,
            FRA_METHOD,
            FiniteDifferenceType.BACKWARD);
    assertEquals("Sensitivity finite difference method: number of node", 2, sensiForward.length);
    assertEquals(
        "Sensitivity finite difference method: number of node", 2, sensiForwardCentered.length);
    assertEquals(
        "Sensitivity finite difference method: number of node", 2, sensiForwardCentered2.length);
    assertEquals(
        "Sensitivity finite difference method: number of node", 2, sensiForwardForward.length);
    assertEquals(
        "Sensitivity finite difference method: number of node", 2, sensiForwardBackward.length);
    for (int loopnode = 0; loopnode < sensiForward.length; loopnode++) {
      assertEquals(
          "Sensitivity finite difference method: centered vs non-centered",
          sensiForward[loopnode],
          sensiForwardForward[loopnode],
          1.0E-10);
      assertEquals(
          "Sensitivity finite difference method: centered vs non-centered",
          sensiForwardForward[loopnode],
          sensiForwardCentered[loopnode],
          1.0E-1);
      assertEquals(
          "Sensitivity finite difference method: centered vs non-centered",
          sensiForwardBackward[loopnode],
          sensiForwardCentered[loopnode],
          1.0E-1);
      assertEquals(
          "Sensitivity finite difference method: centered vs non-centered",
          sensiForwardCentered[loopnode],
          sensiForwardCentered2[loopnode],
          1.0E-10);
    }
  }
}
public class CapFloorInflationYearOnYearMonthlyDefinitionTest {

  private static final String NAME = "Euro HICP x";
  private static final Currency CUR = Currency.EUR;
  private static final IndexPrice PRICE_INDEX = new IndexPrice(NAME, CUR);
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final ZonedDateTime START_DATE = DateUtils.getUTCDate(2008, 8, 18);
  private static final ZonedDateTime LAST_KNOWN_FIXING_DATE = DateUtils.getUTCDate(2008, 6, 1);
  private static final Period COUPON_TENOR = Period.ofYears(10);
  private static final ZonedDateTime PAYMENT_DATE =
      ScheduleCalculator.getAdjustedDate(START_DATE, COUPON_TENOR, BUSINESS_DAY, CALENDAR);
  private static final ZonedDateTime ACCRUAL_END_DATE = PAYMENT_DATE;
  private static final ZonedDateTime ACCRUAL_START_DATE = ACCRUAL_END_DATE.minusMonths(12);
  private static final double NOTIONAL = 98765432;
  private static final int MONTH_LAG = 3;
  private static final double STRIKE = .02;
  private static final boolean IS_CAP = true;
  private static final ZonedDateTime REFERENCE_START_DATE =
      ACCRUAL_START_DATE.minusMonths(MONTH_LAG).withDayOfMonth(1);
  private static final ZonedDateTime REFERENCE_END_DATE =
      PAYMENT_DATE.minusMonths(MONTH_LAG).withDayOfMonth(1);
  private static final double WEIGHT_START = 0.2;
  private static final double WEIGHT_END = 0.8;
  private static final CapFloorInflationYearOnYearMonthlyDefinition YoY_CAP_DEFINITION =
      new CapFloorInflationYearOnYearMonthlyDefinition(
          CUR,
          PAYMENT_DATE,
          ACCRUAL_START_DATE,
          ACCRUAL_END_DATE,
          1.0,
          NOTIONAL,
          PRICE_INDEX,
          LAST_KNOWN_FIXING_DATE,
          MONTH_LAG,
          3,
          REFERENCE_START_DATE,
          REFERENCE_END_DATE,
          STRIKE,
          IS_CAP);
  private static final DayCount ACT_ACT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullCurrency() {
    new CapFloorInflationYearOnYearMonthlyDefinition(
        null,
        PAYMENT_DATE,
        ACCRUAL_START_DATE,
        ACCRUAL_END_DATE,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        LAST_KNOWN_FIXING_DATE,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        REFERENCE_END_DATE,
        STRIKE,
        IS_CAP);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullPay() {
    new CapFloorInflationYearOnYearMonthlyDefinition(
        CUR,
        null,
        ACCRUAL_START_DATE,
        ACCRUAL_END_DATE,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        LAST_KNOWN_FIXING_DATE,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        REFERENCE_END_DATE,
        STRIKE,
        IS_CAP);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullStart() {
    new CapFloorInflationYearOnYearMonthlyDefinition(
        CUR,
        PAYMENT_DATE,
        null,
        ACCRUAL_END_DATE,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        LAST_KNOWN_FIXING_DATE,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        REFERENCE_END_DATE,
        STRIKE,
        IS_CAP);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullEnd() {
    new CapFloorInflationYearOnYearMonthlyDefinition(
        CUR,
        PAYMENT_DATE,
        ACCRUAL_START_DATE,
        null,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        LAST_KNOWN_FIXING_DATE,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        REFERENCE_END_DATE,
        STRIKE,
        IS_CAP);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullIndex() {
    new CapFloorInflationYearOnYearMonthlyDefinition(
        CUR,
        PAYMENT_DATE,
        ACCRUAL_START_DATE,
        ACCRUAL_END_DATE,
        1.0,
        NOTIONAL,
        null,
        LAST_KNOWN_FIXING_DATE,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        REFERENCE_END_DATE,
        STRIKE,
        IS_CAP);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullRefStart() {
    new CapFloorInflationYearOnYearMonthlyDefinition(
        CUR,
        PAYMENT_DATE,
        ACCRUAL_START_DATE,
        ACCRUAL_END_DATE,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        LAST_KNOWN_FIXING_DATE,
        MONTH_LAG,
        3,
        null,
        REFERENCE_END_DATE,
        STRIKE,
        IS_CAP);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullRefEnd() {
    new CapFloorInflationYearOnYearMonthlyDefinition(
        CUR,
        PAYMENT_DATE,
        ACCRUAL_START_DATE,
        ACCRUAL_END_DATE,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        LAST_KNOWN_FIXING_DATE,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        null,
        STRIKE,
        IS_CAP);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullIsCap() {
    new CapFloorInflationYearOnYearMonthlyDefinition(
        CUR,
        PAYMENT_DATE,
        ACCRUAL_START_DATE,
        ACCRUAL_END_DATE,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        null,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        REFERENCE_END_DATE,
        STRIKE,
        IS_CAP);
  }

  @Test
  /** Tests the class getter. */
  public void getter() {
    assertEquals("Inflation Year on Year cap: getter", CUR, YoY_CAP_DEFINITION.getCurrency());
    assertEquals(
        "Inflation Year on Year cap: getter", PAYMENT_DATE, YoY_CAP_DEFINITION.getPaymentDate());
    assertEquals(
        "Inflation Year on Year cap: getter",
        ACCRUAL_START_DATE,
        YoY_CAP_DEFINITION.getAccrualStartDate());
    assertEquals(
        "Inflation Year on Year cap: getter",
        ACCRUAL_END_DATE,
        YoY_CAP_DEFINITION.getAccrualEndDate());
    assertEquals(
        "Inflation Year on Year cap: getter",
        LAST_KNOWN_FIXING_DATE,
        YoY_CAP_DEFINITION.getLastKnownFixingDate());
    assertEquals(
        "Inflation Year on Year cap: getter", 1.0, YoY_CAP_DEFINITION.getPaymentYearFraction());
    assertEquals("Inflation Year on Year cap: getter", NOTIONAL, YoY_CAP_DEFINITION.getNotional());
    assertEquals(
        "Inflation Year on Year cap: getter", PRICE_INDEX, YoY_CAP_DEFINITION.getPriceIndex());
    assertEquals(
        "Inflation Year on Year cap: getter",
        REFERENCE_START_DATE,
        YoY_CAP_DEFINITION.getReferenceStartDate());
    assertEquals(
        "Inflation Year on Year cap: getter",
        REFERENCE_END_DATE,
        YoY_CAP_DEFINITION.getReferenceEndDate());
    assertEquals(
        "Inflation Year on Year cap: getter",
        MONTH_LAG,
        YoY_CAP_DEFINITION.getConventionalMonthLag());
    assertEquals("Inflation Year on Year cap: getter", IS_CAP, YoY_CAP_DEFINITION.isCap());
    assertEquals(
        "Inflation Year on Year cap: getter", 1.0, YoY_CAP_DEFINITION.getPaymentYearFraction());
    assertEquals("Inflation Year on Year cap: getter", STRIKE, YoY_CAP_DEFINITION.getStrike());
  }

  @Test
  /** Tests the equal and hash-code methods. */
  public void equalHash() {
    assertEquals(YoY_CAP_DEFINITION, YoY_CAP_DEFINITION);
    final CapFloorInflationYearOnYearMonthlyDefinition couponDuplicate =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);
    assertEquals(YoY_CAP_DEFINITION, couponDuplicate);
    assertEquals(YoY_CAP_DEFINITION.hashCode(), couponDuplicate.hashCode());
    CapFloorInflationYearOnYearMonthlyDefinition modified;
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE.minusDays(1),
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE.minusDays(1),
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE.minusDays(1),
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    final ZonedDateTime modifiedReferenceStartDate = REFERENCE_START_DATE.minusDays(1);
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            modifiedReferenceStartDate,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    final ZonedDateTime modifiedReferenceEndDate = REFERENCE_END_DATE.minusDays(1);
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            modifiedReferenceEndDate,
            STRIKE,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            2.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL + 10.0,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE + .01,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            false);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE.minusDays(1),
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE.minusDays(1),
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG - 1,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
    final IndexPrice modifiedPriceIndex = new IndexPrice("US CPI x", Currency.USD);
    modified =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            modifiedPriceIndex,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);
    assertFalse(YoY_CAP_DEFINITION.equals(modified));
  }

  @Test
  /** Tests the first based on indexation lag. */
  public void from() {
    final CapFloorInflationYearOnYearMonthlyDefinition constructor =
        new CapFloorInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            LAST_KNOWN_FIXING_DATE,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            STRIKE,
            IS_CAP);

    final CouponInflationYearOnYearMonthlyDefinition yoyCoupon =
        new CouponInflationYearOnYearMonthlyDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            false);
    final CapFloorInflationYearOnYearMonthlyDefinition from =
        CapFloorInflationYearOnYearMonthlyDefinition.from(
            yoyCoupon, LAST_KNOWN_FIXING_DATE, STRIKE, IS_CAP);
    assertEquals("Inflation zero-coupon : from", constructor, from);
  }

  @Test
  public void toDerivativesNoData() {
    final ZonedDateTime pricingDate = DateUtils.getUTCDate(2011, 7, 29);
    final Coupon zeroCouponConverted = YoY_CAP_DEFINITION.toDerivative(pricingDate);
    // lastKnownFixingTime could be negatif so we don't use the dayfraction
    final double lastKnownFixingTime =
        TimeCalculator.getTimeBetween(pricingDate, LAST_KNOWN_FIXING_DATE);
    final double paymentTime = ACT_ACT.getDayCountFraction(pricingDate, PAYMENT_DATE);
    final double referenceStartTime =
        ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_START_DATE);
    final double referenceEndTime = ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_END_DATE);
    final double naturalPaymentStartPaymentTime =
        ACT_ACT.getDayCountFraction(pricingDate, ACCRUAL_START_DATE);
    final double naturalPaymentEndPaymentTime =
        ACT_ACT.getDayCountFraction(pricingDate, ACCRUAL_END_DATE);
    final CapFloorInflationYearOnYearMonthly zeroCoupon =
        new CapFloorInflationYearOnYearMonthly(
            CUR,
            paymentTime,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            lastKnownFixingTime,
            referenceStartTime,
            naturalPaymentStartPaymentTime,
            referenceEndTime,
            naturalPaymentEndPaymentTime,
            STRIKE,
            IS_CAP);
    assertEquals("Inflation zero-coupon: toDerivative", zeroCouponConverted, zeroCoupon);
  }

  @Test
  public void toDerivativesStartMonthNotknown() {
    final ZonedDateTime pricingDate = DateUtils.getUTCDate(2011, 7, 29);
    final DoubleTimeSeries<ZonedDateTime> priceIndexTS =
        ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(
            new ZonedDateTime[] {
              DateUtils.getUTCDate(2017, 5, 1),
              DateUtils.getUTCDate(2017, 6, 1),
              DateUtils.getUTCDate(2018, 5, 1),
              DateUtils.getUTCDate(2018, 6, 1)
            },
            new double[] {127.23, 127.43, 128.23, 128.43});
    final Coupon zeroCouponConverted = YoY_CAP_DEFINITION.toDerivative(pricingDate, priceIndexTS);
    // lastKnownFixingTime could be negatif so we don't use the dayfraction
    final double lastKnownFixingTime =
        TimeCalculator.getTimeBetween(pricingDate, LAST_KNOWN_FIXING_DATE);
    final double paymentTime = ACT_ACT.getDayCountFraction(pricingDate, PAYMENT_DATE);
    final double referenceStartTime =
        ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_START_DATE);
    final double referenceEndTime = ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_END_DATE);
    final double naturalPaymentStartPaymentTime =
        ACT_ACT.getDayCountFraction(pricingDate, ACCRUAL_START_DATE);
    final double naturalPaymentEndPaymentTime =
        ACT_ACT.getDayCountFraction(pricingDate, ACCRUAL_END_DATE);
    final CapFloorInflationYearOnYearMonthly zeroCoupon =
        new CapFloorInflationYearOnYearMonthly(
            CUR,
            paymentTime,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            lastKnownFixingTime,
            referenceStartTime,
            naturalPaymentStartPaymentTime,
            referenceEndTime,
            naturalPaymentEndPaymentTime,
            STRIKE,
            IS_CAP);
    assertEquals("Inflation zero-coupon: toDerivative", zeroCoupon, zeroCouponConverted);
  }

  @Test
  public void toDerivativesStartMonthKnown() {
    final ZonedDateTime pricingDate = DateUtils.getUTCDate(2018, 6, 25);
    final DoubleTimeSeries<ZonedDateTime> priceIndexTS =
        ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(
            new ZonedDateTime[] {
              DateUtils.getUTCDate(2017, 5, 1),
              DateUtils.getUTCDate(2017, 6, 1),
              DateUtils.getUTCDate(2018, 5, 1),
              DateUtils.getUTCDate(2018, 6, 1)
            },
            new double[] {127.23, 127.43, 128.23, 128.43});
    final Coupon zeroCouponConverted = YoY_CAP_DEFINITION.toDerivative(pricingDate, priceIndexTS);
    final double paymentTime = ACT_ACT.getDayCountFraction(pricingDate, PAYMENT_DATE);
    final CouponFixed zeroCoupon =
        new CouponFixed(
            CUR,
            paymentTime,
            1.0,
            NOTIONAL,
            Math.max(
                (WEIGHT_END * 128.23 + (1 - WEIGHT_END) * 128.43)
                        / (WEIGHT_START * 127.23 + (1 - WEIGHT_START) * 127.43)
                    - 1.0
                    - STRIKE,
                0.0));
    assertEquals("Inflation zero-coupon: toDerivative", zeroCoupon, zeroCouponConverted);
  }
}
/**
 * Tests related to the construction of European physical delivery swaptions and its conversion to
 * derivatives.
 */
public class SwaptionBermudaFixedIborDefinitionTest {
  // General
  private static final Currency CUR = Currency.EUR;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 7, 22);
  // Total swap -5Y semi bond vs quarterly money
  private static final Period FORWARD_TENOR = Period.ofYears(1);
  private static final ZonedDateTime SETTLEMENT_DATE =
      ScheduleCalculator.getAdjustedDate(
          REFERENCE_DATE, FORWARD_TENOR, BUSINESS_DAY, CALENDAR, IS_EOM);
  private static final Period SWAP_TENOR = Period.ofYears(5);
  private static final double NOTIONAL = 123000000;
  private static final boolean FIXED_IS_PAYER = true;
  private static final Period FIXED_PAYMENT_PERIOD = Period.ofMonths(6);
  private static final DayCount FIXED_DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("30/360");
  private static final Period IBOR_TENOR = Period.ofMonths(3);
  private static final int IBOR_SETTLEMENT_DAYS = 2;
  private static final DayCount IBOR_DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final IborIndex IBOR_INDEX =
      new IborIndex(
          CUR, IBOR_TENOR, IBOR_SETTLEMENT_DAYS, IBOR_DAY_COUNT, BUSINESS_DAY, IS_EOM, "Ibor");
  private static final IndexSwap CMS_INDEX =
      new IndexSwap(FIXED_PAYMENT_PERIOD, FIXED_DAY_COUNT, IBOR_INDEX, SWAP_TENOR, CALENDAR);
  private static final double RATE = 0.0325;
  private static final SwapFixedIborDefinition TOTAL_SWAP_DEFINITION =
      SwapFixedIborDefinition.from(
          SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, RATE, FIXED_IS_PAYER, CALENDAR);
  // Semi-annual expiry
  private static final boolean IS_LONG = true;
  private static final int NB_EXPIRY = TOTAL_SWAP_DEFINITION.getFixedLeg().getNumberOfPayments();
  private static final ZonedDateTime[] EXPIRY_DATE = new ZonedDateTime[NB_EXPIRY];
  private static final SwapFixedIborDefinition[] EXPIRY_SWAP_DEFINITION =
      new SwapFixedIborDefinition[NB_EXPIRY];

  static {
    for (int loopexp = 0; loopexp < NB_EXPIRY; loopexp++) {
      EXPIRY_DATE[loopexp] =
          ScheduleCalculator.getAdjustedDate(
              TOTAL_SWAP_DEFINITION.getFixedLeg().getNthPayment(loopexp).getAccrualStartDate(),
              -IBOR_SETTLEMENT_DAYS,
              CALENDAR);
      EXPIRY_SWAP_DEFINITION[loopexp] = TOTAL_SWAP_DEFINITION.trimStart(EXPIRY_DATE[loopexp]);
    }
  }

  private static final SwaptionBermudaFixedIborDefinition BERMUDA_SWAPTION_DEFINITION =
      new SwaptionBermudaFixedIborDefinition(EXPIRY_SWAP_DEFINITION, IS_LONG, EXPIRY_DATE);

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullSwap() {
    new SwaptionBermudaFixedIborDefinition(null, IS_LONG, EXPIRY_DATE);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullExpiry() {
    new SwaptionBermudaFixedIborDefinition(EXPIRY_SWAP_DEFINITION, IS_LONG, null);
  }

  @Test
  /** Tests the Bermuda swaption getters. */
  public void getter() {
    assertEquals(
        "Getter: underlying swaps",
        EXPIRY_SWAP_DEFINITION,
        BERMUDA_SWAPTION_DEFINITION.getUnderlyingSwap());
    assertEquals("Getter: long/short", IS_LONG, BERMUDA_SWAPTION_DEFINITION.isLong());
    assertEquals("Getter: expiry dates", EXPIRY_DATE, BERMUDA_SWAPTION_DEFINITION.getExpiryDate());
  }

  @Test
  /** Tests the Bermuda swaption builder from a unique total swap. */
  public void from() {
    final SwaptionBermudaFixedIborDefinition bermuda2 =
        SwaptionBermudaFixedIborDefinition.from(TOTAL_SWAP_DEFINITION, IS_LONG, EXPIRY_DATE);
    assertEquals("Bermuda swaption builder", BERMUDA_SWAPTION_DEFINITION, bermuda2);
  }

  @Test
  /** Tests the equal and hash-code methods. */
  public void hashEqual() {
    final SwaptionBermudaFixedIborDefinition bermuda2 =
        SwaptionBermudaFixedIborDefinition.from(TOTAL_SWAP_DEFINITION, IS_LONG, EXPIRY_DATE);
    assertTrue("Bermuda swaption", BERMUDA_SWAPTION_DEFINITION.equals(bermuda2));
    assertEquals("Bermuda swaption", BERMUDA_SWAPTION_DEFINITION.hashCode(), bermuda2.hashCode());
    SwaptionBermudaFixedIborDefinition modified;
    modified =
        new SwaptionBermudaFixedIborDefinition(EXPIRY_SWAP_DEFINITION, !IS_LONG, EXPIRY_DATE);
    assertFalse("Bermuda swaption", BERMUDA_SWAPTION_DEFINITION.equals(modified));
    final ZonedDateTime[] expiry2 = new ZonedDateTime[NB_EXPIRY];
    System.arraycopy(EXPIRY_DATE, 0, expiry2, 0, NB_EXPIRY);
    expiry2[0] = EXPIRY_DATE[0].minusDays(1);
    modified = new SwaptionBermudaFixedIborDefinition(EXPIRY_SWAP_DEFINITION, IS_LONG, expiry2);
    assertFalse("Bermuda swaption", BERMUDA_SWAPTION_DEFINITION.equals(modified));
  }

  @Test
  /** Tests the toDerivative method. */
  public void toDerivatives() {
    final DayCount actAct = DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
    final double[] expiryTime = new double[NB_EXPIRY];
    final double[] settleTime = new double[NB_EXPIRY];
    @SuppressWarnings("unchecked")
    final SwapFixedCoupon<Coupon>[] underlyingSwap = new SwapFixedCoupon[NB_EXPIRY];
    for (int loopexp = 0; loopexp < NB_EXPIRY; loopexp++) {
      expiryTime[loopexp] = actAct.getDayCountFraction(REFERENCE_DATE, EXPIRY_DATE[loopexp]);
      underlyingSwap[loopexp] = EXPIRY_SWAP_DEFINITION[loopexp].toDerivative(REFERENCE_DATE);
      settleTime[loopexp] =
          actAct.getDayCountFraction(
              REFERENCE_DATE,
              EXPIRY_SWAP_DEFINITION[loopexp].getFixedLeg().getNthPayment(0).getAccrualStartDate());
    }
    final SwaptionBermudaFixedIbor swaptionBermuda =
        new SwaptionBermudaFixedIbor(underlyingSwap, IS_LONG, expiryTime, settleTime);
    assertEquals(
        "Swaption Bermuda: to derivatives",
        swaptionBermuda,
        BERMUDA_SWAPTION_DEFINITION.toDerivative(REFERENCE_DATE));
  }

  @SuppressWarnings("deprecation")
  @Test
  /** Tests the toDerivative method. */
  public void toDerivativesDeprecated() {
    final DayCount actAct = DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
    final String FUNDING_CURVE_NAME = "Funding";
    final String FORWARD_CURVE_NAME = "Forward";
    final String[] CURVES_NAME = {FUNDING_CURVE_NAME, FORWARD_CURVE_NAME};
    final double[] expiryTime = new double[NB_EXPIRY];
    final double[] settleTime = new double[NB_EXPIRY];
    @SuppressWarnings("unchecked")
    final SwapFixedCoupon<Coupon>[] underlyingSwap = new SwapFixedCoupon[NB_EXPIRY];
    for (int loopexp = 0; loopexp < NB_EXPIRY; loopexp++) {
      expiryTime[loopexp] = actAct.getDayCountFraction(REFERENCE_DATE, EXPIRY_DATE[loopexp]);
      underlyingSwap[loopexp] =
          EXPIRY_SWAP_DEFINITION[loopexp].toDerivative(REFERENCE_DATE, CURVES_NAME);
      settleTime[loopexp] =
          actAct.getDayCountFraction(
              REFERENCE_DATE,
              EXPIRY_SWAP_DEFINITION[loopexp].getFixedLeg().getNthPayment(0).getAccrualStartDate());
    }
    final SwaptionBermudaFixedIbor swaptionBermuda =
        new SwaptionBermudaFixedIbor(underlyingSwap, IS_LONG, expiryTime, settleTime);
    assertEquals(
        "Swaption Bermuda: to derivatives",
        swaptionBermuda,
        BERMUDA_SWAPTION_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME));
  }
}
public class AnnuityCouponFixedDefinitionTest {
  // Semi-annual 2Y
  private static final Currency CUR = Currency.USD;
  private static final PeriodFrequency PAYMENT_FREQUENCY = PeriodFrequency.SEMI_ANNUAL;
  private static final Period PAYMENT_TENOR = Period.ofMonths(6);
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final DayCount DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("30/360");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final Period ANNUITY_TENOR = Period.ofYears(2);
  private static final ZonedDateTime SETTLEMENT_DATE = DateUtils.getUTCDate(2011, 3, 17);
  private static final double NOTIONAL = 1000000;
  private static final double RATE = 0.0325;
  private static final boolean IS_PAYER = true;

  private static final ZonedDateTime MATURITY_DATE = SETTLEMENT_DATE.plus(ANNUITY_TENOR);
  private static final ZonedDateTime[] PAYMENT_DATES_UNADJUSTED =
      ScheduleCalculator.getUnadjustedDateSchedule(
          SETTLEMENT_DATE, MATURITY_DATE, PAYMENT_FREQUENCY);
  private static final ZonedDateTime[] PAYMENT_DATES =
      ScheduleCalculator.getAdjustedDateSchedule(PAYMENT_DATES_UNADJUSTED, BUSINESS_DAY, CALENDAR);

  private static final ZonedDateTime REFERENCE_DATE =
      DateUtils.getUTCDate(2011, 3, 15); // For conversion to derivative

  @Test
  public void test() {
    final CouponFixedDefinition[] coupons = new CouponFixedDefinition[PAYMENT_DATES.length];
    // First coupon uses settlement date
    final double sign = IS_PAYER ? -1.0 : 1.0;
    coupons[0] =
        new CouponFixedDefinition(
            CUR,
            PAYMENT_DATES[0],
            SETTLEMENT_DATE,
            PAYMENT_DATES[0],
            DAY_COUNT.getDayCountFraction(SETTLEMENT_DATE, PAYMENT_DATES[0]),
            sign * NOTIONAL,
            RATE);
    for (int loopcpn = 1; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      coupons[loopcpn] =
          new CouponFixedDefinition(
              CUR,
              PAYMENT_DATES[loopcpn],
              PAYMENT_DATES[loopcpn - 1],
              PAYMENT_DATES[loopcpn],
              DAY_COUNT.getDayCountFraction(PAYMENT_DATES[loopcpn - 1], PAYMENT_DATES[loopcpn]),
              sign * NOTIONAL,
              RATE);
    }
    final AnnuityCouponFixedDefinition fixedAnnuity = new AnnuityCouponFixedDefinition(coupons);

    assertEquals(fixedAnnuity.isPayer(), IS_PAYER);
    for (int loopcpn = 0; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      assertEquals(fixedAnnuity.getNthPayment(loopcpn), coupons[loopcpn]);
    }
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullPayments() {
    new AnnuityCouponFixedDefinition(null);
  }

  @Test
  public void testEqualHash() {
    final double sign = IS_PAYER ? -1.0 : 1.0;
    final CouponFixedDefinition[] coupons = new CouponFixedDefinition[PAYMENT_DATES.length];
    coupons[0] =
        new CouponFixedDefinition(
            CUR,
            PAYMENT_DATES[0],
            SETTLEMENT_DATE,
            PAYMENT_DATES[0],
            DAY_COUNT.getDayCountFraction(SETTLEMENT_DATE, PAYMENT_DATES[0]),
            sign * NOTIONAL,
            RATE);
    for (int loopcpn = 1; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      coupons[loopcpn] =
          new CouponFixedDefinition(
              CUR,
              PAYMENT_DATES[loopcpn],
              PAYMENT_DATES[loopcpn - 1],
              PAYMENT_DATES[loopcpn],
              DAY_COUNT.getDayCountFraction(PAYMENT_DATES[loopcpn - 1], PAYMENT_DATES[loopcpn]),
              sign * NOTIONAL,
              RATE);
    }
    final AnnuityCouponFixedDefinition fixedAnnuity = new AnnuityCouponFixedDefinition(coupons);
    final AnnuityCouponFixedDefinition fixedAnnuity2 =
        AnnuityCouponFixedDefinition.from(
            CUR,
            SETTLEMENT_DATE,
            ANNUITY_TENOR,
            PAYMENT_TENOR,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            IS_PAYER);
    assertEquals(fixedAnnuity, fixedAnnuity2);
    assertEquals(fixedAnnuity.hashCode(), fixedAnnuity2.hashCode());
    final AnnuityCouponFixedDefinition modifiedFixedAnnuity1 =
        AnnuityCouponFixedDefinition.from(
            CUR,
            SETTLEMENT_DATE,
            ANNUITY_TENOR,
            PAYMENT_TENOR,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            !IS_PAYER);
    assertFalse(fixedAnnuity.equals(modifiedFixedAnnuity1));
    final AnnuityCouponFixedDefinition modifiedFixedAnnuity2 =
        AnnuityCouponFixedDefinition.from(
            CUR,
            SETTLEMENT_DATE,
            ANNUITY_TENOR,
            PAYMENT_TENOR,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            IS_PAYER);
    assertFalse(modifiedFixedAnnuity2.equals(modifiedFixedAnnuity1));
    final AnnuityCouponFixedDefinition bond1 =
        AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
            CUR,
            SETTLEMENT_DATE,
            MATURITY_DATE,
            PAYMENT_TENOR,
            true,
            true,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            !IS_PAYER);
    AnnuityCouponFixedDefinition bond2 =
        AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
            CUR,
            SETTLEMENT_DATE,
            MATURITY_DATE,
            PAYMENT_TENOR,
            true,
            true,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            IS_PAYER);
    assertFalse(bond1.equals(bond2));
    bond2 =
        AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
            CUR,
            SETTLEMENT_DATE,
            MATURITY_DATE,
            PAYMENT_TENOR,
            2,
            true,
            true,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            IS_PAYER);
    assertFalse(bond1.equals(bond2));
    bond2 =
        AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
            CUR,
            SETTLEMENT_DATE,
            MATURITY_DATE,
            PAYMENT_TENOR,
            2,
            true,
            true,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            !IS_PAYER);
    assertEquals(bond1, bond2);
    final CouponFixedDefinition[] payments = bond2.getPayments();
    bond2 = new AnnuityCouponFixedDefinition(payments);
    assertEquals(bond1, bond2);
  }

  @Test
  public void testPaymentDates() {
    AnnuityCouponFixedDefinition fixedAnnuity;
    ZonedDateTime[] expectedPaymentDate;
    // End date is modified
    fixedAnnuity =
        AnnuityCouponFixedDefinition.from(
            CUR,
            SETTLEMENT_DATE,
            ANNUITY_TENOR,
            PAYMENT_TENOR,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            IS_PAYER);
    expectedPaymentDate =
        new ZonedDateTime[] {
          DateUtils.getUTCDate(2011, 9, 19),
          DateUtils.getUTCDate(2012, 3, 19),
          DateUtils.getUTCDate(2012, 9, 17),
          DateUtils.getUTCDate(2013, 3, 18)
        };
    for (int loopcpn = 0; loopcpn < expectedPaymentDate.length; loopcpn++) {
      assertEquals(
          expectedPaymentDate[loopcpn], fixedAnnuity.getNthPayment(loopcpn).getPaymentDate());
    }
    // Check modified in modified following.
    final ZonedDateTime settlementDateModified = DateUtils.getUTCDate(2011, 3, 31);
    fixedAnnuity =
        AnnuityCouponFixedDefinition.from(
            CUR,
            settlementDateModified,
            ANNUITY_TENOR,
            PAYMENT_TENOR,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            IS_PAYER);
    expectedPaymentDate =
        new ZonedDateTime[] {
          DateUtils.getUTCDate(2011, 9, 30),
          DateUtils.getUTCDate(2012, 3, 30),
          DateUtils.getUTCDate(2012, 9, 28),
          DateUtils.getUTCDate(2013, 3, 29)
        };
    for (int loopcpn = 0; loopcpn < expectedPaymentDate.length; loopcpn++) {
      assertEquals(
          expectedPaymentDate[loopcpn], fixedAnnuity.getNthPayment(loopcpn).getPaymentDate());
    }
    // End-of-month
    final ZonedDateTime settlementDateEOM = DateUtils.getUTCDate(2011, 2, 28);
    fixedAnnuity =
        AnnuityCouponFixedDefinition.from(
            CUR,
            settlementDateEOM,
            ANNUITY_TENOR,
            PAYMENT_TENOR,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            IS_PAYER);
    expectedPaymentDate =
        new ZonedDateTime[] {
          DateUtils.getUTCDate(2011, 8, 31),
          DateUtils.getUTCDate(2012, 2, 29),
          DateUtils.getUTCDate(2012, 8, 31),
          DateUtils.getUTCDate(2013, 2, 28)
        };
    for (int loopcpn = 0; loopcpn < expectedPaymentDate.length; loopcpn++) {
      assertEquals(
          expectedPaymentDate[loopcpn], fixedAnnuity.getNthPayment(loopcpn).getPaymentDate());
    }
  }

  @Test
  public void testToDerivative() {
    final double sign = IS_PAYER ? -1.0 : 1.0;
    final CouponFixedDefinition[] coupons = new CouponFixedDefinition[PAYMENT_DATES.length];
    // First coupon uses settlement date
    coupons[0] =
        new CouponFixedDefinition(
            CUR,
            PAYMENT_DATES[0],
            SETTLEMENT_DATE,
            PAYMENT_DATES[0],
            DAY_COUNT.getDayCountFraction(SETTLEMENT_DATE, PAYMENT_DATES[0]),
            sign * NOTIONAL,
            RATE);
    for (int loopcpn = 1; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      coupons[loopcpn] =
          new CouponFixedDefinition(
              CUR,
              PAYMENT_DATES[loopcpn],
              PAYMENT_DATES[loopcpn - 1],
              PAYMENT_DATES[loopcpn],
              DAY_COUNT.getDayCountFraction(PAYMENT_DATES[loopcpn - 1], PAYMENT_DATES[loopcpn]),
              sign * NOTIONAL,
              RATE);
    }
    final AnnuityCouponFixedDefinition fixedAnnuity = new AnnuityCouponFixedDefinition(coupons);

    //    final DayCount actAct = DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
    //    final ZonedDateTime zonedDate = ZonedDateTime.of(LocalDateTime.ofMidnight(REFERENCE_DATE),
    // TimeZone.UTC);
    final String fundingCurve = "Funding";
    final CouponFixed[] couponFixedConverted = new CouponFixed[PAYMENT_DATES.length];
    for (int loopcpn = 0; loopcpn < PAYMENT_DATES.length; loopcpn++) {
      couponFixedConverted[loopcpn] =
          fixedAnnuity.getNthPayment(loopcpn).toDerivative(REFERENCE_DATE, fundingCurve);
    }
    final AnnuityCouponFixed referenceAnnuity = new AnnuityCouponFixed(couponFixedConverted);
    final AnnuityCouponFixed convertedDefinition =
        fixedAnnuity.toDerivative(REFERENCE_DATE, fundingCurve);
    assertEquals(referenceAnnuity, convertedDefinition);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullCurrency1() {
    AnnuityCouponFixedDefinition.from(
        null,
        SETTLEMENT_DATE,
        PAYMENT_TENOR,
        ANNUITY_TENOR,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullSettlementDate1() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        null,
        PAYMENT_TENOR,
        ANNUITY_TENOR,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullTenorPeriod() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        SETTLEMENT_DATE,
        (Period) null,
        ANNUITY_TENOR,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullPaymentTenor1() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        SETTLEMENT_DATE,
        PAYMENT_TENOR,
        null,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullCalendar1() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        SETTLEMENT_DATE,
        PAYMENT_TENOR,
        ANNUITY_TENOR,
        null,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullDayCount1() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        SETTLEMENT_DATE,
        PAYMENT_TENOR,
        ANNUITY_TENOR,
        CALENDAR,
        null,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullBusinessDay1() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        SETTLEMENT_DATE,
        PAYMENT_TENOR,
        ANNUITY_TENOR,
        CALENDAR,
        DAY_COUNT,
        null,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullCurrency2() {
    AnnuityCouponFixedDefinition.from(
        null,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        PAYMENT_FREQUENCY,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullSettlementDate2() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        null,
        MATURITY_DATE,
        PAYMENT_FREQUENCY,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullMaturityDate() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        SETTLEMENT_DATE,
        (ZonedDateTime) null,
        PAYMENT_FREQUENCY,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullPaymentFrequency() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        (PeriodFrequency) null,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullCalendar2() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        PAYMENT_FREQUENCY,
        null,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullDayCount2() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        PAYMENT_FREQUENCY,
        CALENDAR,
        null,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullBusinessDay2() {
    AnnuityCouponFixedDefinition.from(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        PAYMENT_FREQUENCY,
        CALENDAR,
        DAY_COUNT,
        null,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullCurrency3() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        null,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        ANNUITY_TENOR,
        true,
        true,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullSettlementDate3() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        null,
        MATURITY_DATE,
        ANNUITY_TENOR,
        true,
        true,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullMaturityDate2() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        SETTLEMENT_DATE,
        null,
        ANNUITY_TENOR,
        true,
        true,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullPaymentTenor2() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        null,
        true,
        true,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullCalendar3() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        ANNUITY_TENOR,
        true,
        true,
        null,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullDayCount3() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        ANNUITY_TENOR,
        true,
        true,
        CALENDAR,
        null,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullBusinessDay3() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        ANNUITY_TENOR,
        true,
        true,
        CALENDAR,
        DAY_COUNT,
        null,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullCurrency4() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        null,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        ANNUITY_TENOR,
        2,
        true,
        true,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullSettlementDate4() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        null,
        MATURITY_DATE,
        ANNUITY_TENOR,
        2,
        true,
        true,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullMaturityDate3() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        SETTLEMENT_DATE,
        null,
        ANNUITY_TENOR,
        2,
        true,
        true,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullPaymentTenor3() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        null,
        2,
        true,
        true,
        CALENDAR,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionPaymentsPerYear() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        ANNUITY_TENOR,
        -2,
        true,
        true,
        null,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullCalendar4() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        ANNUITY_TENOR,
        2,
        true,
        true,
        null,
        DAY_COUNT,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullDayCount4() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        ANNUITY_TENOR,
        2,
        true,
        true,
        CALENDAR,
        null,
        BUSINESS_DAY,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testStaticConstructionNullBusinessDay4() {
    AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
        CUR,
        SETTLEMENT_DATE,
        MATURITY_DATE,
        ANNUITY_TENOR,
        2,
        true,
        true,
        CALENDAR,
        DAY_COUNT,
        null,
        IS_EOM,
        NOTIONAL,
        RATE,
        IS_PAYER);
  }

  @Test
  public void testStaticConstruction() {
    AnnuityCouponFixedDefinition definition1 =
        AnnuityCouponFixedDefinition.from(
            CUR,
            SETTLEMENT_DATE,
            ANNUITY_TENOR,
            PAYMENT_TENOR,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            IS_PAYER);
    AnnuityCouponFixedDefinition definition2 =
        AnnuityCouponFixedDefinition.from(
            CUR,
            SETTLEMENT_DATE,
            MATURITY_DATE,
            PAYMENT_FREQUENCY,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            IS_PAYER);
    assertEquals(definition1, definition2);
    assertEquals(IS_PAYER, definition1.isPayer());
    definition2 =
        AnnuityCouponFixedDefinition.from(
            CUR,
            SETTLEMENT_DATE,
            MATURITY_DATE,
            PAYMENT_FREQUENCY,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            !IS_PAYER);
    assertFalse(definition1.equals(definition2));
    assertEquals(!IS_PAYER, definition2.isPayer());
    definition1 =
        AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
            CUR,
            SETTLEMENT_DATE,
            MATURITY_DATE,
            PAYMENT_TENOR,
            true,
            true,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            IS_PAYER);
    definition2 =
        AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
            CUR,
            SETTLEMENT_DATE,
            MATURITY_DATE,
            PAYMENT_TENOR,
            2,
            true,
            true,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            IS_PAYER);
    assertEquals(definition1, definition2);
    definition2 =
        AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
            CUR,
            SETTLEMENT_DATE,
            MATURITY_DATE,
            PAYMENT_TENOR,
            2,
            true,
            true,
            CALENDAR,
            DAY_COUNT,
            BUSINESS_DAY,
            IS_EOM,
            NOTIONAL,
            RATE,
            !IS_PAYER);
    assertFalse(definition1.equals(definition2));
  }
}
Example #19
0
  public static synchronized void addFixedIncomeInstrumentConventions(
      final ConventionBundleMaster conventionMaster) {
    Validate.notNull(conventionMaster, "convention master");
    final BusinessDayConvention modified =
        BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
    final BusinessDayConvention following =
        BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Following");
    final DayCount act360 = DayCountFactory.INSTANCE.getDayCount("Actual/360");
    final DayCount thirty360 = DayCountFactory.INSTANCE.getDayCount("30/360");
    final Frequency quarterly =
        SimpleFrequencyFactory.INSTANCE.getFrequency(Frequency.QUARTERLY_NAME);
    final Frequency semiAnnual =
        SimpleFrequencyFactory.INSTANCE.getFrequency(Frequency.SEMI_ANNUAL_NAME);
    final Frequency annual = SimpleFrequencyFactory.INSTANCE.getFrequency(Frequency.ANNUAL_NAME);
    final ExternalId ch = ExternalSchemes.financialRegionId("CH");

    final ConventionBundleMasterUtils utils = new ConventionBundleMasterUtils(conventionMaster);
    // TODO check that it's actually libor that we need
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF00O/N Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR O/N")),
        "CHF LIBOR O/N",
        act360,
        following,
        Period.ofDays(1),
        0,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF00S/N Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR S/N")),
        "CHF LIBOR S/N",
        act360,
        following,
        Period.ofDays(1),
        0,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF00T/N Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR T/N")),
        "CHF LIBOR T/N",
        act360,
        following,
        Period.ofDays(1),
        0,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0001W Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 1w")),
        "CHF LIBOR 1w",
        act360,
        following,
        Period.ofDays(7),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0002W Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 2w")),
        "CHF LIBOR 2w",
        act360,
        following,
        Period.ofDays(14),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0001M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 1m")),
        "CHF LIBOR 1m",
        act360,
        following,
        Period.ofMonths(1),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0002M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 2m")),
        "CHF LIBOR 2m",
        act360,
        following,
        Period.ofMonths(2),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0003M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 3m")),
        "CHF LIBOR 3m",
        act360,
        following,
        Period.ofMonths(3),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0004M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 4m")),
        "CHF LIBOR 4m",
        act360,
        following,
        Period.ofMonths(4),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0005M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 5m")),
        "CHF LIBOR 5m",
        act360,
        following,
        Period.ofMonths(5),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0006M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 6m"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFLIBORP6M")),
        "CHF LIBOR 6m",
        act360,
        following,
        Period.ofMonths(6),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0007M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 7m")),
        "CHF LIBOR 7m",
        act360,
        following,
        Period.ofMonths(7),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0008M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 8m")),
        "CHF LIBOR 8m",
        act360,
        following,
        Period.ofMonths(8),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0009M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 9m")),
        "CHF LIBOR 9m",
        act360,
        following,
        Period.ofMonths(9),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0010M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 10m")),
        "CHF LIBOR 10m",
        act360,
        following,
        Period.ofMonths(10),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0011M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 11m")),
        "CHF LIBOR 11m",
        act360,
        following,
        Period.ofMonths(11),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SF0012M Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 12m")),
        "CHF LIBOR 12m",
        act360,
        following,
        Period.ofMonths(12),
        2,
        false,
        ch);

    // TODO need to check that these are right for deposit rates
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDR1T Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 1d")),
        "CHF DEPOSIT 1d",
        act360,
        following,
        Period.ofDays(1),
        0,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDR2T Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 2d")),
        "CHF DEPOSIT 2d",
        act360,
        following,
        Period.ofDays(1),
        1,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDR3T Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 3d")),
        "CHF DEPOSIT 3d",
        act360,
        following,
        Period.ofDays(1),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDR1Z Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 1w")),
        "CHF DEPOSIT 1w",
        act360,
        following,
        Period.ofDays(7),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDR2Z Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 2w")),
        "CHF DEPOSIT 2w",
        act360,
        following,
        Period.ofDays(14),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDR3Z Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 3w")),
        "CHF DEPOSIT 3w",
        act360,
        following,
        Period.ofDays(21),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDRA Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 1m")),
        "CHF DEPOSIT 1m",
        act360,
        following,
        Period.ofMonths(1),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDRB Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 2m")),
        "CHF DEPOSIT 2m",
        act360,
        following,
        Period.ofMonths(2),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDRC Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 3m")),
        "CHF DEPOSIT 3m",
        act360,
        following,
        Period.ofMonths(3),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDRD Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 4m")),
        "CHF DEPOSIT 4m",
        act360,
        following,
        Period.ofMonths(4),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDRE Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 5m")),
        "CHF DEPOSIT 5m",
        act360,
        following,
        Period.ofMonths(5),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDRF Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 6m")),
        "CHF DEPOSIT 6m",
        act360,
        following,
        Period.ofMonths(6),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDRG Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 7m")),
        "CHF DEPOSIT 7m",
        act360,
        following,
        Period.ofMonths(7),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDRH Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 8m")),
        "CHF DEPOSIT 8m",
        act360,
        following,
        Period.ofMonths(8),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDRI Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 9m")),
        "CHF DEPOSIT 9m",
        act360,
        following,
        Period.ofMonths(9),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDRJ Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 10m")),
        "CHF DEPOSIT 10m",
        act360,
        following,
        Period.ofMonths(10),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDRK Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 11m")),
        "CHF DEPOSIT 11m",
        act360,
        following,
        Period.ofMonths(11),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDR1 Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 1y")),
        "CHF DEPOSIT 1y",
        act360,
        following,
        Period.ofYears(1),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDR2 Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 2y")),
        "CHF DEPOSIT 2y",
        act360,
        following,
        Period.ofYears(2),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDR3 Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 3y")),
        "CHF DEPOSIT 3y",
        act360,
        following,
        Period.ofYears(3),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDR4 Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 4y")),
        "CHF DEPOSIT 4y",
        act360,
        following,
        Period.ofYears(4),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("SFDR5 Curncy"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF DEPOSIT 5y")),
        "CHF DEPOSIT 5y",
        act360,
        following,
        Period.ofYears(5),
        2,
        false,
        ch);

    // TODO check reference rate
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF_SWAP")),
        "CHF_SWAP",
        thirty360,
        modified,
        annual,
        2,
        ch,
        act360,
        modified,
        semiAnnual,
        2,
        ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 6m"),
        ch,
        true);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF_3M_SWAP")),
        "CHF_3M_SWAP",
        thirty360,
        modified,
        annual,
        2,
        ch,
        act360,
        modified,
        quarterly,
        2,
        ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 3m"),
        ch,
        true);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF_6M_SWAP")),
        "CHF_6M_SWAP",
        thirty360,
        modified,
        annual,
        2,
        ch,
        act360,
        modified,
        semiAnnual,
        2,
        ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 6m"),
        ch,
        true);

    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF_3M_FRA")),
        "CHF_3M_FRA",
        thirty360,
        modified,
        annual,
        2,
        ch,
        act360,
        modified,
        quarterly,
        2,
        ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 3m"),
        ch,
        true);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF_6M_FRA")),
        "CHF_6M_FRA",
        thirty360,
        modified,
        annual,
        2,
        ch,
        act360,
        modified,
        semiAnnual,
        2,
        ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF LIBOR 6m"),
        ch,
        true);

    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(
                InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, IndexType.Libor + "_CHF_P3M")),
        IndexType.Libor + "_CHF_P3M",
        thirty360,
        modified,
        null,
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(
                InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, IndexType.Libor + "_CHF_P6M")),
        IndexType.Libor + "_CHF_P6M",
        thirty360,
        modified,
        null,
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(
                InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, IndexType.Euribor + "_CHF_P3M")),
        IndexType.Euribor + "_CHF_P3M",
        thirty360,
        modified,
        null,
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(
                InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, IndexType.Euribor + "_CHF_P6M")),
        IndexType.Euribor + "_CHF_P6M",
        thirty360,
        modified,
        null,
        2,
        false,
        ch);

    // Overnight Index Swap Convention have additional flag, publicationLag
    final Integer publicationLagON = 0; // TODO CASE PublicationLag CHF - Confirm 0
    // CHF Overnight Index
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalSchemes.bloombergTickerSecurityId("TOISTOIS Index"),
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF TOISTOIS")),
        "CHF TOIS TOIS",
        act360,
        following,
        Period.ofDays(1),
        2,
        false,
        ch,
        publicationLagON);
    // OIS
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF_OIS_SWAP")),
        "CHF_OIS_SWAP",
        act360,
        modified,
        annual,
        2,
        ch,
        act360,
        modified,
        annual,
        2,
        ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF TOISTOIS"),
        ch,
        true,
        publicationLagON);

    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHF_IBOR_INDEX")),
        "CHF_IBOR_INDEX",
        act360,
        following,
        2,
        false);

    // Identifiers for external data
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP1D"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP1D")),
        "CHFCASHP1D",
        act360,
        following,
        Period.ofDays(1),
        0,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP1M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP1M")),
        "CHFCASHP1M",
        act360,
        modified,
        Period.ofMonths(1),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP2M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP2M")),
        "CHFCASHP2M",
        act360,
        modified,
        Period.ofMonths(2),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP3M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP3M")),
        "CHFCASHP3M",
        act360,
        modified,
        Period.ofMonths(3),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP4M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP4M")),
        "CHFCASHP4M",
        act360,
        modified,
        Period.ofMonths(4),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP5M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP5M")),
        "CHFCASHP5M",
        act360,
        modified,
        Period.ofMonths(5),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP6M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP6M")),
        "CHFCASHP6M",
        act360,
        modified,
        Period.ofMonths(6),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP7M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP7M")),
        "CHFCASHP7M",
        act360,
        modified,
        Period.ofMonths(7),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP8M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP8M")),
        "CHFCASHP8M",
        act360,
        modified,
        Period.ofMonths(8),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP9M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP9M")),
        "CHFCASHP9M",
        act360,
        modified,
        Period.ofMonths(9),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP10M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP10M")),
        "CHFCASHP10M",
        act360,
        modified,
        Period.ofMonths(10),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP11M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP11M")),
        "CHFCASHP11M",
        act360,
        modified,
        Period.ofMonths(11),
        2,
        false,
        ch);
    utils.addConventionBundle(
        ExternalIdBundle.of(
            ExternalId.of(InMemoryConventionBundleMaster.SIMPLE_NAME_SCHEME, "CHFCASHP12M"),
            ExternalId.of(InMemoryConventionBundleMaster.OG_SYNTHETIC_TICKER, "CHFCASHP12M")),
        "CHFCASHP12M",
        act360,
        modified,
        Period.ofMonths(12),
        2,
        false,
        ch);
  }
/**
 * Tests the present value and its sensitivities for zero-coupon with reference index interpolated
 * between months.
 */
public class CouponInflationZeroCouponInterpolationDiscountingMethodTest {
  private static final MarketBundle MARKET = MarketDataSets.createMarket1();
  private static final IndexPrice[] PRICE_INDEXES = MarketDataSets.getPriceIndexes();
  private static final IndexPrice PRICE_INDEX_EUR = PRICE_INDEXES[0];
  //  private static final PriceIndex PRICE_INDEX_UK = PRICE_INDEXES[1];
  private static final IndexPrice PRICE_INDEX_US = PRICE_INDEXES[2];
  private static final IborIndex[] IBOR_INDEXES = MarketDataSets.getIborIndexes();
  private static final IborIndex EURIBOR3M = IBOR_INDEXES[0];
  //  private static final IborIndex EURIBOR6M = IBOR_INDEXES[1];
  private static final IborIndex USDLIBOR3M = IBOR_INDEXES[2];
  private static final Calendar CALENDAR_EUR = EURIBOR3M.getCalendar();
  private static final Calendar CALENDAR_USD = USDLIBOR3M.getCalendar();
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final ZonedDateTime START_DATE = DateUtils.getUTCDate(2008, 8, 18);
  private static final Period COUPON_TENOR = Period.ofYears(10);
  private static final ZonedDateTime PAYMENT_DATE =
      ScheduleCalculator.getAdjustedDate(START_DATE, COUPON_TENOR, BUSINESS_DAY, CALENDAR_EUR);
  private static final double NOTIONAL = 98765432;
  private static final int MONTH_LAG = 3;
  private static final double INDEX_MAY_2008_INT =
      108.4548387; // May index: 108.23 - June Index = 108.64
  private static final CouponInflationZeroCouponInterpolationDefinition ZERO_COUPON_1_DEFINITION =
      CouponInflationZeroCouponInterpolationDefinition.from(
          START_DATE,
          PAYMENT_DATE,
          NOTIONAL,
          PRICE_INDEX_EUR,
          INDEX_MAY_2008_INT,
          MONTH_LAG,
          false);
  private static final ZonedDateTime PRICING_DATE = DateUtils.getUTCDate(2011, 8, 3);
  private static final CouponInflationZeroCouponInterpolation ZERO_COUPON_1 =
      ZERO_COUPON_1_DEFINITION.toDerivative(PRICING_DATE, "not used");
  private static final CouponInflationZeroCouponInterpolationDiscountingMethod METHOD =
      new CouponInflationZeroCouponInterpolationDiscountingMethod();
  private static final PresentValueInflationCalculator PVIC =
      PresentValueInflationCalculator.getInstance();

  @Test
  /** Tests the present value. */
  public void presentValue() {
    CurrencyAmount pv = METHOD.presentValue(ZERO_COUPON_1, MARKET);
    double df =
        MARKET
            .getCurve(ZERO_COUPON_1.getCurrency())
            .getDiscountFactor(ZERO_COUPON_1.getPaymentTime());
    double indexMonth0 =
        MARKET.getCurve(PRICE_INDEX_EUR).getPriceIndex(ZERO_COUPON_1.getReferenceEndTime()[0]);
    double indexMonth1 =
        MARKET.getCurve(PRICE_INDEX_EUR).getPriceIndex(ZERO_COUPON_1.getReferenceEndTime()[1]);
    double finalIndex =
        ZERO_COUPON_1_DEFINITION.getWeight() * indexMonth0
            + (1 - ZERO_COUPON_1_DEFINITION.getWeight()) * indexMonth1;
    double pvExpected = (finalIndex / INDEX_MAY_2008_INT - 1) * df * NOTIONAL;
    assertEquals("Zero-coupon inflation: Present value", pvExpected, pv.getAmount(), 1.0E-2);
  }

  @Test
  /** Tests the present value: Method vs Calculator. */
  public void presentValueMethodVsCalculator() {
    CurrencyAmount pvMethod = METHOD.presentValue(ZERO_COUPON_1, MARKET);
    CurrencyAmount pvCalculator = PVIC.visit(ZERO_COUPON_1, MARKET);
    assertEquals("Zero-coupon inflation: Present value", pvMethod, pvCalculator);
  }

  @Test
  /** Test the present value curves sensitivity. */
  public void presentValueCurveSensitivity() {
    final PresentValueCurveSensitivityMarket pvs =
        METHOD.presentValueCurveSensitivity(ZERO_COUPON_1, MARKET);
    pvs.clean();
    final double deltaTolerancePrice = 1.0E+1;
    // Testing note: Sensitivity is for a movement of 1. 1E+2 = 1 cent for a 1 bp move. Tolerance
    // increased to cope with numerical imprecision of finite difference.
    final double deltaShift = 1.0E-6;
    // 2. Discounting curve sensitivity
    final double[] nodeTimesDisc = new double[] {ZERO_COUPON_1.getPaymentTime()};
    final double[] sensiDisc =
        SensitivityFiniteDifferenceMarket.curveSensitivity(
            ZERO_COUPON_1,
            MARKET,
            ZERO_COUPON_1.getCurrency(),
            nodeTimesDisc,
            deltaShift,
            METHOD,
            FiniteDifferenceType.CENTRAL);
    assertEquals("Sensitivity finite difference method: number of node", 1, sensiDisc.length);
    final List<DoublesPair> sensiPvDisc =
        pvs.getYieldCurveSensitivities()
            .get(MARKET.getCurve(ZERO_COUPON_1.getCurrency()).getName());
    for (int loopnode = 0; loopnode < sensiDisc.length; loopnode++) {
      final DoublesPair pairPv = sensiPvDisc.get(loopnode);
      assertEquals(
          "Sensitivity coupon pv to forward curve: Node " + loopnode,
          nodeTimesDisc[loopnode],
          pairPv.getFirst(),
          1E-8);
      assertEquals(
          "Sensitivity finite difference method: node sensitivity",
          pairPv.second,
          sensiDisc[loopnode],
          deltaTolerancePrice);
    }
    // 3. Price index curve sensitivity
    final double[] nodeTimesPrice = ZERO_COUPON_1.getReferenceEndTime();
    final double[] sensiPrice =
        SensitivityFiniteDifferenceMarket.curveSensitivity(
            ZERO_COUPON_1,
            MARKET,
            ZERO_COUPON_1.getPriceIndex(),
            nodeTimesPrice,
            deltaShift,
            METHOD,
            FiniteDifferenceType.CENTRAL);
    assertEquals("Sensitivity finite difference method: number of node", 2, sensiPrice.length);
    final List<DoublesPair> sensiPvPrice =
        pvs.getPriceCurveSensitivities()
            .get(MARKET.getCurve(ZERO_COUPON_1.getPriceIndex()).getCurve().getName());
    for (int loopnode = 0; loopnode < sensiPrice.length; loopnode++) {
      final DoublesPair pairPv = sensiPvPrice.get(loopnode);
      assertEquals(
          "Sensitivity coupon pv to forward curve: Node " + loopnode,
          nodeTimesPrice[loopnode],
          pairPv.getFirst(),
          1E-8);
      assertEquals(
          "Sensitivity finite difference method: node sensitivity",
          pairPv.second,
          sensiPrice[loopnode],
          deltaTolerancePrice);
    }
  }

  @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);
  }
}
/**
 * Tests related to the pricing method for digital Forex option transactions with Black function and
 * a volatility provider.
 */
public class ForexOptionDigitalCallSpreadMethodTest {
  // General
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final int SETTLEMENT_DAYS = 2;
  // Smile data
  private static final Currency EUR = Currency.EUR;
  private static final Currency USD = Currency.USD;
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 6, 13);
  private static final FXMatrix FX_MATRIX = TestsDataSetsForex.fxMatrix();
  private static final double SPOT = FX_MATRIX.getFxRate(EUR, USD);
  private static final SmileDeltaTermStructureParameter SMILE_TERM =
      TestsDataSetsForex.smile(REFERENCE_DATE);
  private static final SmileDeltaTermStructureParameter SMILE_TERM_FLAT =
      TestsDataSetsForex.smileFlat(REFERENCE_DATE);
  // Methods and curves
  private static final YieldCurveBundle CURVES = TestsDataSetsForex.createCurvesForex();
  private static final String[] CURVES_NAME = TestsDataSetsForex.curveNames();
  private static final Map<String, Currency> CURVE_CURRENCY = TestsDataSetsForex.curveCurrency();
  private static final SmileDeltaTermStructureDataBundle SMILE_BUNDLE =
      new SmileDeltaTermStructureDataBundle(
          FX_MATRIX, CURVE_CURRENCY, CURVES, SMILE_TERM, Pair.of(EUR, USD));
  private static final SmileDeltaTermStructureDataBundle SMILE_BUNDLE_FLAT =
      new SmileDeltaTermStructureDataBundle(
          FX_MATRIX, CURVE_CURRENCY, CURVES, SMILE_TERM_FLAT, Pair.of(EUR, USD));
  private static final ForexOptionVanillaBlackMethod METHOD_VANILLA_BLACK =
      ForexOptionVanillaBlackMethod.getInstance();
  private static final ForexOptionDigitalBlackMethod METHOD_DIGITAL_BLACK =
      ForexOptionDigitalBlackMethod.getInstance();
  private static final double STANDARD_SPREAD = 0.0001;
  private static final ForexOptionDigitalCallSpreadBlackMethod METHOD_DIGITAL_SPREAD =
      new ForexOptionDigitalCallSpreadBlackMethod(STANDARD_SPREAD);
  private static final PresentValueCalculator PVC = PresentValueCalculator.getInstance();
  // option
  private static final double STRIKE = 1.45;
  private static final boolean IS_CALL = true;
  private static final boolean IS_LONG = true;
  private static final double NOTIONAL = 100000000;
  private static final ZonedDateTime OPTION_PAY_DATE =
      ScheduleCalculator.getAdjustedDate(
          REFERENCE_DATE, Period.ofMonths(9), BUSINESS_DAY, CALENDAR);
  private static final ZonedDateTime OPTION_EXP_DATE =
      ScheduleCalculator.getAdjustedDate(OPTION_PAY_DATE, -SETTLEMENT_DAYS, CALENDAR);
  private static final ForexDefinition FOREX_DEFINITION =
      new ForexDefinition(EUR, USD, OPTION_PAY_DATE, NOTIONAL, STRIKE);
  private static final Forex FOREX = FOREX_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final ForexOptionDigitalDefinition FOREX_OPTION_CALL_DEFINITION =
      new ForexOptionDigitalDefinition(FOREX_DEFINITION, OPTION_EXP_DATE, IS_CALL, IS_LONG);
  private static final ForexOptionDigital FOREX_CALL_OPTION =
      FOREX_OPTION_CALL_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final double TOLERANCE_PRICE = 1.0E-2;
  private static final double TOLERANCE_PRICE_FLAT =
      1.0E+1; // The spread size will create a discrepancy.
  private static final double TOLERANCE_CE_FLAT =
      1.0E+2; // The spread size will create a discrepancy.
  private static final double TOLERANCE_DELTA = 1.0E+2; // 0.01 currency unit for 1 bp

  @Test
  /** Tests the present value in a flat smile case. */
  public void presentValueFlat() {
    MultipleCurrencyAmount pvSpread =
        METHOD_DIGITAL_SPREAD.presentValue(FOREX_CALL_OPTION, SMILE_BUNDLE_FLAT);
    MultipleCurrencyAmount pvBlack =
        METHOD_DIGITAL_BLACK.presentValue(FOREX_CALL_OPTION, SMILE_BUNDLE_FLAT);
    assertEquals(
        "Forex Digital option: call spread method - present value",
        pvBlack.getAmount(USD),
        pvSpread.getAmount(USD),
        TOLERANCE_PRICE_FLAT);
  }

  @Test
  /** Tests the present value with an explicit computation. */
  public void presentValue() {
    double strikeM = STRIKE * (1 - STANDARD_SPREAD);
    double strikeP = STRIKE * (1 + STANDARD_SPREAD);
    Forex forexM =
        new Forex(
            FOREX.getPaymentCurrency1().withAmount(1.0),
            FOREX.getPaymentCurrency2().withAmount(-strikeM));
    Forex forexP =
        new Forex(
            FOREX.getPaymentCurrency1().withAmount(1.0),
            FOREX.getPaymentCurrency2().withAmount(-strikeP));
    ForexOptionVanilla vanillaM =
        new ForexOptionVanilla(forexM, FOREX_CALL_OPTION.getExpirationTime(), IS_CALL, IS_LONG);
    ForexOptionVanilla vanillaP =
        new ForexOptionVanilla(forexP, FOREX_CALL_OPTION.getExpirationTime(), IS_CALL, IS_LONG);
    MultipleCurrencyAmount pvP = METHOD_VANILLA_BLACK.presentValue(vanillaP, SMILE_BUNDLE);
    MultipleCurrencyAmount pvM = METHOD_VANILLA_BLACK.presentValue(vanillaM, SMILE_BUNDLE);
    MultipleCurrencyAmount pvExpected =
        pvM.plus(pvP.multipliedBy(-1.0))
            .multipliedBy(
                1.0 / (strikeP - strikeM) * Math.abs(FOREX.getPaymentCurrency2().getAmount()));
    MultipleCurrencyAmount pvComputed =
        METHOD_DIGITAL_SPREAD.presentValue(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertEquals(
        "Forex Digital option: call spread method - present value",
        pvExpected.getAmount(USD),
        pvComputed.getAmount(USD),
        TOLERANCE_PRICE);
  }

  @Test
  /** Tests put call parity. */
  public void presentValuePutCallParity() {
    final double strike = 1.45;
    final boolean isCall = true;
    final boolean isLong = true;
    final double notional = 100000000;
    final ZonedDateTime payDate =
        ScheduleCalculator.getAdjustedDate(
            REFERENCE_DATE, Period.ofMonths(9), BUSINESS_DAY, CALENDAR);
    final ZonedDateTime expDate =
        ScheduleCalculator.getAdjustedDate(payDate, -SETTLEMENT_DAYS, CALENDAR);
    final ForexDefinition forexUnderlyingDefinition =
        new ForexDefinition(EUR, USD, payDate, notional, strike);
    final ForexOptionDigitalDefinition callDefinition =
        new ForexOptionDigitalDefinition(forexUnderlyingDefinition, expDate, isCall, isLong);
    final ForexOptionDigitalDefinition putDefinition =
        new ForexOptionDigitalDefinition(forexUnderlyingDefinition, expDate, !isCall, isLong);
    final ForexOptionDigital call = callDefinition.toDerivative(REFERENCE_DATE, CURVES_NAME);
    final ForexOptionDigital put = putDefinition.toDerivative(REFERENCE_DATE, CURVES_NAME);
    final MultipleCurrencyAmount pvCall = METHOD_DIGITAL_SPREAD.presentValue(call, SMILE_BUNDLE);
    final MultipleCurrencyAmount pvPut = METHOD_DIGITAL_SPREAD.presentValue(put, SMILE_BUNDLE);
    final Double pvCash = PVC.visit(put.getUnderlyingForex().getPaymentCurrency2(), CURVES);
    assertEquals(
        "Forex Digital option: call spread method - present value",
        pvCall.getAmount(USD) + pvPut.getAmount(USD),
        Math.abs(pvCash),
        TOLERANCE_PRICE_FLAT);
  }

  @Test
  /** Tests the present value long/short parity. */
  public void presentValueLongShort() {
    final ForexOptionDigitalDefinition forexOptionShortDefinition =
        new ForexOptionDigitalDefinition(FOREX_DEFINITION, OPTION_EXP_DATE, IS_CALL, !IS_LONG);
    final InstrumentDerivative forexOptionShort =
        forexOptionShortDefinition.toDerivative(REFERENCE_DATE, CURVES_NAME);
    final MultipleCurrencyAmount pvShort =
        METHOD_DIGITAL_SPREAD.presentValue(forexOptionShort, SMILE_BUNDLE);
    final MultipleCurrencyAmount pvLong =
        METHOD_DIGITAL_SPREAD.presentValue(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertEquals(
        "Forex Digital option: present value long/short parity",
        pvLong.getAmount(USD),
        -pvShort.getAmount(USD),
        1E-2);
    final MultipleCurrencyAmount ceShort =
        METHOD_DIGITAL_SPREAD.currencyExposure(forexOptionShort, SMILE_BUNDLE);
    final MultipleCurrencyAmount ceLong =
        METHOD_DIGITAL_SPREAD.currencyExposure(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertEquals(
        "Forex Digital option: currency exposure long/short parity",
        ceLong.getAmount(USD),
        -ceShort.getAmount(USD),
        1E-2);
    assertEquals(
        "Forex Digital option: currency exposure long/short parity",
        ceLong.getAmount(EUR),
        -ceShort.getAmount(EUR),
        1E-2);
  }

  @Test
  /** Tests the currency exposure in a flat smile case. */
  public void currencyExposureFlat() {
    MultipleCurrencyAmount ceSpread =
        METHOD_DIGITAL_SPREAD.currencyExposure(FOREX_CALL_OPTION, SMILE_BUNDLE_FLAT);
    MultipleCurrencyAmount ceBlack =
        METHOD_DIGITAL_BLACK.currencyExposure(FOREX_CALL_OPTION, SMILE_BUNDLE_FLAT);
    assertEquals(
        "Forex Digital option: call spread method - currency exposure",
        ceBlack.getAmount(USD),
        ceSpread.getAmount(USD),
        TOLERANCE_CE_FLAT);
    assertEquals(
        "Forex Digital option: call spread method - currency exposure",
        ceBlack.getAmount(EUR),
        ceSpread.getAmount(EUR),
        TOLERANCE_CE_FLAT);
  }

  @Test
  /** Tests the currency exposure with an explicit computation. */
  public void currencyExposure() {
    double spread = 0.0001; // Relative spread.
    double strikeM = STRIKE * (1 - spread);
    double strikeP = STRIKE * (1 + spread);
    Forex forexM =
        new Forex(
            FOREX.getPaymentCurrency1().withAmount(1.0),
            FOREX.getPaymentCurrency2().withAmount(-strikeM));
    Forex forexP =
        new Forex(
            FOREX.getPaymentCurrency1().withAmount(1.0),
            FOREX.getPaymentCurrency2().withAmount(-strikeP));
    ForexOptionVanilla vanillaM =
        new ForexOptionVanilla(forexM, FOREX_CALL_OPTION.getExpirationTime(), IS_CALL, IS_LONG);
    ForexOptionVanilla vanillaP =
        new ForexOptionVanilla(forexP, FOREX_CALL_OPTION.getExpirationTime(), IS_CALL, IS_LONG);
    MultipleCurrencyAmount ceP = METHOD_VANILLA_BLACK.currencyExposure(vanillaP, SMILE_BUNDLE);
    MultipleCurrencyAmount ceM = METHOD_VANILLA_BLACK.currencyExposure(vanillaM, SMILE_BUNDLE);
    MultipleCurrencyAmount ceExpected =
        ceM.plus(ceP.multipliedBy(-1.0))
            .multipliedBy(
                1.0 / (strikeP - strikeM) * Math.abs(FOREX.getPaymentCurrency2().getAmount()));
    MultipleCurrencyAmount ceComputed =
        METHOD_DIGITAL_SPREAD.currencyExposure(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertEquals(
        "Forex Digital option: call spread method - currency exposure",
        ceExpected.getAmount(USD),
        ceComputed.getAmount(USD),
        TOLERANCE_PRICE);
    assertEquals(
        "Forex Digital option: call spread method - currency exposure",
        ceExpected.getAmount(EUR),
        ceComputed.getAmount(EUR),
        TOLERANCE_PRICE);
  }

  @Test
  /** Tests the currency exposure against the present value. */
  public void currencyExposureVsPresentValue() {
    MultipleCurrencyAmount pv = METHOD_DIGITAL_SPREAD.presentValue(FOREX_CALL_OPTION, SMILE_BUNDLE);
    MultipleCurrencyAmount ce =
        METHOD_DIGITAL_SPREAD.currencyExposure(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertEquals(
        "Forex Digital option: call spread method - currency exposure vs present value",
        ce.getAmount(USD) + ce.getAmount(EUR) * SPOT,
        pv.getAmount(USD),
        TOLERANCE_PRICE);
  }

  @Test
  /** Tests the put/call parity currency exposure. */
  public void currencyExposurePutCallParity() {
    final double strike = 1.45;
    final boolean isCall = true;
    final boolean isLong = true;
    final double notional = 100000000;
    final ZonedDateTime payDate =
        ScheduleCalculator.getAdjustedDate(
            REFERENCE_DATE, Period.ofMonths(9), BUSINESS_DAY, CALENDAR);
    final ZonedDateTime expDate =
        ScheduleCalculator.getAdjustedDate(payDate, -SETTLEMENT_DAYS, CALENDAR);
    final ForexDefinition forexUnderlyingDefinition =
        new ForexDefinition(EUR, USD, payDate, notional, strike);
    final ForexOptionDigitalDefinition forexOptionDefinitionCall =
        new ForexOptionDigitalDefinition(forexUnderlyingDefinition, expDate, isCall, isLong);
    final ForexOptionDigitalDefinition forexOptionDefinitionPut =
        new ForexOptionDigitalDefinition(forexUnderlyingDefinition, expDate, !isCall, isLong);
    final ForexOptionDigital forexOptionCall =
        forexOptionDefinitionCall.toDerivative(REFERENCE_DATE, CURVES_NAME);
    final ForexOptionDigital forexOptionPut =
        forexOptionDefinitionPut.toDerivative(REFERENCE_DATE, CURVES_NAME);
    final MultipleCurrencyAmount currencyExposureCall =
        METHOD_DIGITAL_SPREAD.currencyExposure(forexOptionCall, SMILE_BUNDLE);
    final MultipleCurrencyAmount currencyExposurePut =
        METHOD_DIGITAL_SPREAD.currencyExposure(forexOptionPut, SMILE_BUNDLE);
    final Double pvCash =
        PVC.visit(forexOptionPut.getUnderlyingForex().getPaymentCurrency2(), CURVES);
    assertEquals(
        "Forex Digital option: currency exposure put/call parity foreign",
        0,
        currencyExposureCall.getAmount(EUR) + currencyExposurePut.getAmount(EUR),
        TOLERANCE_PRICE);
    assertEquals(
        "Forex Digital option: currency exposure put/call parity domestic",
        Math.abs(pvCash),
        currencyExposureCall.getAmount(USD) + currencyExposurePut.getAmount(USD),
        TOLERANCE_PRICE);
  }

  @Test
  /** Tests the present value curve sensitivity. */
  public void presentValueCurveSensitivity() {
    double spread = 0.0001; // Relative spread.
    double strikeM = STRIKE * (1 - spread);
    double strikeP = STRIKE * (1 + spread);
    Forex forexM =
        new Forex(
            FOREX.getPaymentCurrency1().withAmount(1.0),
            FOREX.getPaymentCurrency2().withAmount(-strikeM));
    Forex forexP =
        new Forex(
            FOREX.getPaymentCurrency1().withAmount(1.0),
            FOREX.getPaymentCurrency2().withAmount(-strikeP));
    ForexOptionVanilla vanillaM =
        new ForexOptionVanilla(forexM, FOREX_CALL_OPTION.getExpirationTime(), IS_CALL, IS_LONG);
    ForexOptionVanilla vanillaP =
        new ForexOptionVanilla(forexP, FOREX_CALL_OPTION.getExpirationTime(), IS_CALL, IS_LONG);
    MultipleCurrencyInterestRateCurveSensitivity pvcsP =
        METHOD_VANILLA_BLACK.presentValueCurveSensitivity(vanillaP, SMILE_BUNDLE);
    MultipleCurrencyInterestRateCurveSensitivity pvcsM =
        METHOD_VANILLA_BLACK.presentValueCurveSensitivity(vanillaM, SMILE_BUNDLE);
    MultipleCurrencyInterestRateCurveSensitivity pvcsExpected =
        pvcsM
            .plus(pvcsP.multipliedBy(-1.0))
            .multipliedBy(
                1.0 / (strikeP - strikeM) * Math.abs(FOREX.getPaymentCurrency2().getAmount()));
    MultipleCurrencyInterestRateCurveSensitivity pvcsComputed =
        METHOD_DIGITAL_SPREAD.presentValueCurveSensitivity(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertTrue(
        "Forex Digital option: call spread method - present value",
        MultipleCurrencyInterestRateCurveSensitivity.compare(
            pvcsExpected, pvcsComputed, TOLERANCE_DELTA));
  }

  @Test
  /** Tests the present value curve sensitivity. */
  public void presentValueVolatilitySensitivity() {
    double strikeM = STRIKE * (1 - STANDARD_SPREAD);
    double strikeP = STRIKE * (1 + STANDARD_SPREAD);
    Forex forexM =
        new Forex(
            FOREX.getPaymentCurrency1().withAmount(1.0),
            FOREX.getPaymentCurrency2().withAmount(-strikeM));
    Forex forexP =
        new Forex(
            FOREX.getPaymentCurrency1().withAmount(1.0),
            FOREX.getPaymentCurrency2().withAmount(-strikeP));
    ForexOptionVanilla vanillaM =
        new ForexOptionVanilla(forexM, FOREX_CALL_OPTION.getExpirationTime(), IS_CALL, IS_LONG);
    ForexOptionVanilla vanillaP =
        new ForexOptionVanilla(forexP, FOREX_CALL_OPTION.getExpirationTime(), IS_CALL, IS_LONG);
    PresentValueForexBlackVolatilitySensitivity pvbvP =
        METHOD_VANILLA_BLACK.presentValueVolatilitySensitivity(vanillaP, SMILE_BUNDLE);
    PresentValueForexBlackVolatilitySensitivity pvbvM =
        METHOD_VANILLA_BLACK.presentValueVolatilitySensitivity(vanillaM, SMILE_BUNDLE);
    PresentValueForexBlackVolatilitySensitivity pvbvExpected =
        pvbvM
            .plus(pvbvP.multipliedBy(-1.0))
            .multipliedBy(
                1.0 / (strikeP - strikeM) * Math.abs(FOREX.getPaymentCurrency2().getAmount()));
    PresentValueForexBlackVolatilitySensitivity pvbvComputed =
        METHOD_DIGITAL_SPREAD.presentValueVolatilitySensitivity(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertEquals(
        "Forex Digital option: call spread method - present value volatility sensitivity",
        pvbvComputed.getVega().getMap().size(),
        2);
    assertTrue(
        "Forex Digital option: call spread method - present value volatility sensitivity",
        PresentValueForexBlackVolatilitySensitivity.compare(
            pvbvExpected, pvbvComputed, TOLERANCE_DELTA));
  }

  @Test
  /** Tests the present value. Spread change. */
  public void presentValueSpreadChange() {
    double spread1 = 0.0001;
    double spread2 = 0.0002;
    ForexOptionDigitalCallSpreadBlackMethod methodCallSpreadBlack1 =
        new ForexOptionDigitalCallSpreadBlackMethod(spread1);
    ForexOptionDigitalCallSpreadBlackMethod methodCallSpreadBlack2 =
        new ForexOptionDigitalCallSpreadBlackMethod(spread2);
    MultipleCurrencyAmount pv1 =
        methodCallSpreadBlack1.presentValue(FOREX_CALL_OPTION, SMILE_BUNDLE);
    MultipleCurrencyAmount pv2 =
        methodCallSpreadBlack2.presentValue(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertEquals(
        "Forex Digital option: call spread method - present value",
        pv1.getAmount(USD),
        pv2.getAmount(USD),
        10.0);
    //    MultipleCurrencyAmount pvBlack = METHOD_DIGITAL_BLACK.presentValue(FOREX_CALL_OPTION,
    // SMILE_BUNDLE);
    //    assertEquals("Forex Digital option: call spread method - present value",
    // pvBlack.getAmount(USD), pv2.getAmount(USD), 10.0); // Should fail
  }

  @Test
  /** Tests the present value. Method vs Calculator. */
  public void presentValueMethodVCalculator() {
    MultipleCurrencyAmount pv1 =
        METHOD_DIGITAL_SPREAD.presentValue(FOREX_CALL_OPTION, SMILE_BUNDLE);
    PresentValueCallSpreadBlackForexCalculator calculator =
        new PresentValueCallSpreadBlackForexCalculator(STANDARD_SPREAD);
    MultipleCurrencyAmount pvCalculator = calculator.visit(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertEquals(
        "Forex Digital option: call spread method - present value",
        pv1.getAmount(USD),
        pvCalculator.getAmount(USD),
        TOLERANCE_PRICE);
  }

  @Test
  /** Tests the currency exposure. Method vs Calculator. */
  public void currencyExposureMethodVCalculator() {
    MultipleCurrencyAmount ceMethod =
        METHOD_DIGITAL_SPREAD.currencyExposure(FOREX_CALL_OPTION, SMILE_BUNDLE);
    CurrencyExposureCallSpreadBlackForexCalculator calculator =
        new CurrencyExposureCallSpreadBlackForexCalculator(STANDARD_SPREAD);
    MultipleCurrencyAmount ceCalculator = calculator.visit(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertEquals(
        "Forex Digital option: call spread method - currency exposure",
        ceMethod.getAmount(USD),
        ceCalculator.getAmount(USD),
        TOLERANCE_PRICE);
    assertEquals(
        "Forex Digital option: call spread method - currency exposure",
        ceMethod.getAmount(EUR),
        ceCalculator.getAmount(EUR),
        TOLERANCE_PRICE);
  }

  @Test
  /** Tests the present value curve sensitivity. Method vs Calculator. */
  public void presentValueCurveSensitivityMethodVCalculator() {
    MultipleCurrencyInterestRateCurveSensitivity pvcsMethod =
        METHOD_DIGITAL_SPREAD.presentValueCurveSensitivity(FOREX_CALL_OPTION, SMILE_BUNDLE);
    PresentValueCurveSensitivityCallSpreadBlackForexCalculator calculator =
        new PresentValueCurveSensitivityCallSpreadBlackForexCalculator(STANDARD_SPREAD);
    MultipleCurrencyInterestRateCurveSensitivity pvcsCalculator =
        calculator.visit(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertTrue(
        "Forex Digital option: call spread method - present value",
        MultipleCurrencyInterestRateCurveSensitivity.compare(
            pvcsMethod, pvcsCalculator, TOLERANCE_DELTA));
  }

  @Test
  /** Tests the present value volatility sensitivity. Method vs Calculator. */
  public void presentValueVolatilitySensitivityMethodVCalculator() {
    PresentValueForexBlackVolatilitySensitivity pvbvMethod =
        METHOD_DIGITAL_SPREAD.presentValueVolatilitySensitivity(FOREX_CALL_OPTION, SMILE_BUNDLE);
    PresentValueVolatilitySensitivityCallSpreadBlackForexCalculator calculator =
        new PresentValueVolatilitySensitivityCallSpreadBlackForexCalculator(STANDARD_SPREAD);
    PresentValueForexBlackVolatilitySensitivity pvbvCalculator =
        calculator.visit(FOREX_CALL_OPTION, SMILE_BUNDLE);
    assertTrue(
        "Forex Digital option: call spread method - present value volatility sensitivity",
        PresentValueForexBlackVolatilitySensitivity.compare(
            pvbvMethod, pvbvCalculator, TOLERANCE_DELTA));
  }
}
public class BondFixedDescriptionTest {

  // Semi-annual 2Y
  private static final Currency CUR = Currency.USD;
  private static final Period PAYMENT_TENOR = Period.ofMonths(6);
  private static final int PAYMENT_PER_YEAR = 2;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final DayCount DAY_COUNT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ICMA");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Following");
  private static final boolean IS_EOM = false;
  private static final Period BOND_TENOR = Period.ofYears(2);
  private static final ZonedDateTime START_ACCRUAL_DATE = DateUtil.getUTCDate(2011, 7, 13);
  private static final ZonedDateTime MATURITY_DATE = START_ACCRUAL_DATE.plus(BOND_TENOR);
  private static final double RATE = 0.0325;
  private static final YieldConvention YIELD_CONVENTION =
      YieldConventionFactory.INSTANCE.getYieldConvention("STREET CONVENTION");
  private static final AnnuityCouponFixedDefinition COUPON_DEFINITION =
      AnnuityCouponFixedDefinition.fromAccrualUnadjusted(
          CUR,
          START_ACCRUAL_DATE,
          MATURITY_DATE,
          PAYMENT_TENOR,
          PAYMENT_PER_YEAR,
          CALENDAR,
          DAY_COUNT,
          BUSINESS_DAY,
          IS_EOM,
          1.0,
          RATE,
          false);
  private static final AnnuityPaymentFixedDefinition NOMINAL_DEFINITION =
      new AnnuityPaymentFixedDefinition(
          new PaymentFixedDefinition[] {new PaymentFixedDefinition(CUR, MATURITY_DATE, 1.0)});
  // to derivatives: common
  private static final String FUNDING_CURVE_NAME = "Funding";
  private static final String FORWARD_CURVE_NAME = "Forward";
  private static final String[] CURVES_NAME = {FUNDING_CURVE_NAME, FORWARD_CURVE_NAME};
  YieldCurveBundle CURVES = TestsDataSets.createCurves1();
  // to derivatives: first coupon
  private static final ZonedDateTime REFERENCE_DATE_1 = DateUtil.getUTCDate(2011, 8, 18);
  private static final AnnuityCouponFixed COUPON_1 =
      COUPON_DEFINITION.toDerivative(REFERENCE_DATE_1, CURVES_NAME);
  private static final AnnuityPaymentFixed NOMINAL_1 =
      NOMINAL_DEFINITION.toDerivative(REFERENCE_DATE_1, CURVES_NAME);
  private static final BondFixedDescription BOND_DESCRIPTION_1 =
      new BondFixedDescription(NOMINAL_1, COUPON_1, YIELD_CONVENTION);
  // to derivatives: second coupon
  private static final ZonedDateTime REFERENCE_DATE_2 = DateUtil.getUTCDate(2012, 2, 16);
  private static final AnnuityCouponFixed COUPON_2 =
      COUPON_DEFINITION.toDerivative(REFERENCE_DATE_2, CURVES_NAME);
  private static final AnnuityPaymentFixed NOMINAL_2 =
      NOMINAL_DEFINITION.toDerivative(REFERENCE_DATE_2, CURVES_NAME);
  private static final BondFixedDescription BOND_DESCRIPTION_2 =
      new BondFixedDescription(NOMINAL_2, COUPON_2, YIELD_CONVENTION);

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullNominal() {
    new BondFixedDescription(null, COUPON_1, YIELD_CONVENTION);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullCoupon() {
    new BondFixedDescription(NOMINAL_1, null, YIELD_CONVENTION);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullYield() {
    new BondFixedDescription(NOMINAL_1, COUPON_1, null);
  }

  @Test
  public void testGetters1() {
    assertEquals(NOMINAL_1, BOND_DESCRIPTION_1.getNominal());
    assertEquals(COUPON_1, BOND_DESCRIPTION_1.getCoupon());
  }

  @Test
  public void testGetters2() {
    assertEquals(NOMINAL_2, BOND_DESCRIPTION_2.getNominal());
    assertEquals(COUPON_2, BOND_DESCRIPTION_2.getCoupon());
  }
}
/** Tests related to bond futures security Derivative construction. */
public class BondFutureTest {
  // 5-Year U.S. Treasury Note Futures: FVU1
  private static final Currency CUR = Currency.EUR;
  private static final Period PAYMENT_TENOR = Period.ofMonths(6);
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final String ISSUER_NAME = "Issuer";
  private static final DayCount DAY_COUNT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Following");
  private static final boolean IS_EOM = false;
  private static final int SETTLEMENT_DAYS = 1;
  private static final YieldConvention YIELD_CONVENTION =
      YieldConventionFactory.INSTANCE.getYieldConvention("STREET CONVENTION");
  private static final int NB_BOND = 7;
  private static final Period[] BOND_TENOR =
      new Period[] {
        Period.ofYears(5),
        Period.ofYears(5),
        Period.ofYears(5),
        Period.ofYears(8),
        Period.ofYears(5),
        Period.ofYears(5),
        Period.ofYears(5)
      };
  private static final ZonedDateTime[] START_ACCRUAL_DATE =
      new ZonedDateTime[] {
        DateUtils.getUTCDate(2010, 11, 30),
        DateUtils.getUTCDate(2010, 12, 31),
        DateUtils.getUTCDate(2011, 1, 31),
        DateUtils.getUTCDate(2008, 2, 29),
        DateUtils.getUTCDate(2011, 3, 31),
        DateUtils.getUTCDate(2011, 4, 30),
        DateUtils.getUTCDate(2011, 5, 31)
      };
  private static final double[] RATE =
      new double[] {0.01375, 0.02125, 0.0200, 0.02125, 0.0225, 0.0200, 0.0175};
  private static final double[] CONVERSION_FACTOR =
      new double[] {.8317, .8565, .8493, .8516, .8540, .8417, .8292};
  private static final ZonedDateTime[] MATURITY_DATE = new ZonedDateTime[NB_BOND];
  private static final BondFixedSecurityDefinition[] BASKET_DEFINITION =
      new BondFixedSecurityDefinition[NB_BOND];

  static {
    for (int loopbasket = 0; loopbasket < NB_BOND; loopbasket++) {
      MATURITY_DATE[loopbasket] = START_ACCRUAL_DATE[loopbasket].plus(BOND_TENOR[loopbasket]);
      BASKET_DEFINITION[loopbasket] =
          BondFixedSecurityDefinition.from(
              CUR,
              MATURITY_DATE[loopbasket],
              START_ACCRUAL_DATE[loopbasket],
              PAYMENT_TENOR,
              RATE[loopbasket],
              SETTLEMENT_DAYS,
              CALENDAR,
              DAY_COUNT,
              BUSINESS_DAY,
              YIELD_CONVENTION,
              IS_EOM,
              ISSUER_NAME);
    }
  }

  private static final ZonedDateTime LAST_TRADING_DATE = DateUtils.getUTCDate(2011, 9, 21);
  private static final ZonedDateTime FIRST_NOTICE_DATE = DateUtils.getUTCDate(2011, 8, 31);
  private static final ZonedDateTime LAST_NOTICE_DATE = DateUtils.getUTCDate(2011, 9, 29);
  private static final ZonedDateTime FIRST_DELIVERY_DATE =
      ScheduleCalculator.getAdjustedDate(FIRST_NOTICE_DATE, SETTLEMENT_DAYS, CALENDAR);
  private static final ZonedDateTime LAST_DELIVERY_DATE =
      ScheduleCalculator.getAdjustedDate(LAST_NOTICE_DATE, SETTLEMENT_DAYS, CALENDAR);
  private static final double NOTIONAL = 100000;
  private static final double REF_PRICE = 0.0;

  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 6, 20);
  private static final DayCount ACT_ACT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
  private static final double LAST_TRADING_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE, LAST_TRADING_DATE);
  private static final double FIRST_NOTICE_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE, FIRST_NOTICE_DATE);
  private static final double LAST_NOTICE_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE, LAST_NOTICE_DATE);
  private static final double FIRST_DELIVERY_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE, FIRST_DELIVERY_DATE);
  private static final double LAST_DELIVERY_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE, LAST_DELIVERY_DATE);
  private static final BondFixedSecurity[] BASKET = new BondFixedSecurity[NB_BOND];

  static {
    for (int loopbasket = 0; loopbasket < NB_BOND; loopbasket++) {
      BASKET[loopbasket] =
          BASKET_DEFINITION[loopbasket].toDerivative(REFERENCE_DATE, LAST_DELIVERY_DATE);
    }
  }

  private static final BondFuture BOND_FUTURE_SECURITY =
      new BondFuture(
          LAST_TRADING_TIME,
          FIRST_NOTICE_TIME,
          LAST_NOTICE_TIME,
          FIRST_DELIVERY_TIME,
          LAST_DELIVERY_TIME,
          NOTIONAL,
          BASKET,
          CONVERSION_FACTOR,
          REF_PRICE);

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullBasket() {
    new BondFuture(
        LAST_TRADING_TIME,
        FIRST_NOTICE_TIME,
        LAST_NOTICE_TIME,
        FIRST_DELIVERY_TIME,
        LAST_DELIVERY_TIME,
        NOTIONAL,
        null,
        CONVERSION_FACTOR,
        REF_PRICE);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullConversion() {
    new BondFuture(
        LAST_TRADING_TIME,
        FIRST_NOTICE_TIME,
        LAST_NOTICE_TIME,
        FIRST_DELIVERY_TIME,
        LAST_DELIVERY_TIME,
        NOTIONAL,
        BASKET,
        null,
        REF_PRICE);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void zeroBasket() {
    new BondFuture(
        LAST_TRADING_TIME,
        FIRST_NOTICE_TIME,
        LAST_NOTICE_TIME,
        FIRST_DELIVERY_TIME,
        LAST_DELIVERY_TIME,
        NOTIONAL,
        new BondFixedSecurity[0],
        CONVERSION_FACTOR,
        REF_PRICE);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void sizeConversionFactor() {
    final double[] incorrectConversionFactor = new double[NB_BOND - 1];
    new BondFuture(
        LAST_TRADING_TIME,
        FIRST_NOTICE_TIME,
        LAST_NOTICE_TIME,
        FIRST_DELIVERY_TIME,
        LAST_DELIVERY_TIME,
        NOTIONAL,
        BASKET,
        incorrectConversionFactor,
        REF_PRICE);
  }

  @Test
  public void getter() {
    assertEquals(
        "Bond future security derivative: last trading date",
        LAST_TRADING_TIME,
        BOND_FUTURE_SECURITY.getTradingLastTime());
    assertEquals(
        "Bond future security derivative: first notice date",
        FIRST_NOTICE_TIME,
        BOND_FUTURE_SECURITY.getNoticeFirstTime());
    assertEquals(
        "Bond future security derivative: last notice date",
        LAST_NOTICE_TIME,
        BOND_FUTURE_SECURITY.getNoticeLastTime());
    assertEquals(
        "Bond future security derivative: first delivery date",
        FIRST_DELIVERY_TIME,
        BOND_FUTURE_SECURITY.getDeliveryFirstTime());
    assertEquals(
        "Bond future security derivative: last delivery date",
        LAST_DELIVERY_TIME,
        BOND_FUTURE_SECURITY.getDeliveryLastTime());
    assertEquals(
        "Bond future security derivative: basket",
        BASKET,
        BOND_FUTURE_SECURITY.getDeliveryBasket());
    assertEquals(
        "Bond future security derivative: conversion factor",
        CONVERSION_FACTOR,
        BOND_FUTURE_SECURITY.getConversionFactor());
    assertEquals(
        "Bond future security derivative: notional", NOTIONAL, BOND_FUTURE_SECURITY.getNotional());
    assertEquals(
        "Bond future security derivative: currency", CUR, BOND_FUTURE_SECURITY.getCurrency());
  }

  @Test
  /** Tests the equal and hashCode methods. */
  public void equalHash() {
    assertTrue(BOND_FUTURE_SECURITY.equals(BOND_FUTURE_SECURITY));
    final BondFuture other =
        new BondFuture(
            LAST_TRADING_TIME,
            FIRST_NOTICE_TIME,
            LAST_NOTICE_TIME,
            FIRST_DELIVERY_TIME,
            LAST_DELIVERY_TIME,
            NOTIONAL,
            BASKET,
            CONVERSION_FACTOR,
            REF_PRICE);
    assertTrue(BOND_FUTURE_SECURITY.equals(other));
    assertTrue(BOND_FUTURE_SECURITY.hashCode() == other.hashCode());
    BondFuture modifiedFuture;
    modifiedFuture =
        new BondFuture(
            LAST_TRADING_TIME + 0.1,
            FIRST_NOTICE_TIME,
            LAST_NOTICE_TIME,
            FIRST_DELIVERY_TIME,
            LAST_DELIVERY_TIME,
            NOTIONAL,
            BASKET,
            CONVERSION_FACTOR,
            REF_PRICE);
    assertFalse(BOND_FUTURE_SECURITY.equals(modifiedFuture));
    modifiedFuture =
        new BondFuture(
            LAST_TRADING_TIME,
            FIRST_NOTICE_TIME + 0.1,
            LAST_NOTICE_TIME,
            FIRST_DELIVERY_TIME,
            LAST_DELIVERY_TIME,
            NOTIONAL,
            BASKET,
            CONVERSION_FACTOR,
            REF_PRICE);
    assertFalse(BOND_FUTURE_SECURITY.equals(modifiedFuture));
    modifiedFuture =
        new BondFuture(
            LAST_TRADING_TIME,
            FIRST_NOTICE_TIME,
            LAST_NOTICE_TIME + 0.1,
            FIRST_DELIVERY_TIME,
            LAST_DELIVERY_TIME,
            NOTIONAL,
            BASKET,
            CONVERSION_FACTOR,
            REF_PRICE);
    assertFalse(BOND_FUTURE_SECURITY.equals(modifiedFuture));
    modifiedFuture =
        new BondFuture(
            LAST_TRADING_TIME,
            FIRST_NOTICE_TIME,
            LAST_NOTICE_TIME,
            FIRST_DELIVERY_TIME + 0.1,
            LAST_DELIVERY_TIME,
            NOTIONAL,
            BASKET,
            CONVERSION_FACTOR,
            REF_PRICE);
    assertFalse(BOND_FUTURE_SECURITY.equals(modifiedFuture));
    modifiedFuture =
        new BondFuture(
            LAST_TRADING_TIME,
            FIRST_NOTICE_TIME,
            LAST_NOTICE_TIME,
            FIRST_DELIVERY_TIME,
            LAST_DELIVERY_TIME + 0.1,
            NOTIONAL,
            BASKET,
            CONVERSION_FACTOR,
            REF_PRICE);
    assertFalse(BOND_FUTURE_SECURITY.equals(modifiedFuture));
    modifiedFuture =
        new BondFuture(
            LAST_TRADING_TIME,
            FIRST_NOTICE_TIME,
            LAST_NOTICE_TIME,
            FIRST_DELIVERY_TIME,
            LAST_DELIVERY_TIME,
            NOTIONAL + 100000,
            BASKET,
            CONVERSION_FACTOR,
            REF_PRICE);
    assertFalse(BOND_FUTURE_SECURITY.equals(modifiedFuture));
    final BondFixedSecurity[] otherBasket = new BondFixedSecurity[NB_BOND];
    for (int loopbasket = 0; loopbasket < NB_BOND; loopbasket++) {
      otherBasket[loopbasket] =
          BASKET_DEFINITION[loopbasket].toDerivative(REFERENCE_DATE, LAST_NOTICE_DATE);
    }
    modifiedFuture =
        new BondFuture(
            LAST_TRADING_TIME,
            FIRST_NOTICE_TIME,
            LAST_NOTICE_TIME,
            FIRST_DELIVERY_TIME,
            LAST_DELIVERY_TIME,
            NOTIONAL,
            otherBasket,
            CONVERSION_FACTOR,
            REF_PRICE);
    assertFalse(BOND_FUTURE_SECURITY.equals(modifiedFuture));
    final double[] otherConversionFactor =
        new double[] {.9000, .8565, .8493, .8516, .8540, .8417, .8292};
    modifiedFuture =
        new BondFuture(
            LAST_TRADING_TIME,
            FIRST_NOTICE_TIME,
            LAST_NOTICE_TIME,
            FIRST_DELIVERY_TIME,
            LAST_DELIVERY_TIME,
            NOTIONAL,
            BASKET,
            otherConversionFactor,
            REF_PRICE);
    assertFalse(BOND_FUTURE_SECURITY.equals(modifiedFuture));
    assertFalse(BOND_FUTURE_SECURITY.equals(LAST_TRADING_DATE));
    assertFalse(BOND_FUTURE_SECURITY.equals(null));
  }
}
/** Tests the method for interest rate future option with SABR volatility parameter surfaces. */
public class InterestRateFutureOptionMarginSecuritySABRMethodTest {
  // EURIBOR 3M Index
  private static final Period TENOR = Period.ofMonths(3);
  private static final int SETTLEMENT_DAYS = 2;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final DayCount DAY_COUNT_INDEX =
      DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final Currency CUR = Currency.USD;
  private static final IborIndex IBOR_INDEX =
      new IborIndex(CUR, TENOR, SETTLEMENT_DAYS, CALENDAR, DAY_COUNT_INDEX, BUSINESS_DAY, IS_EOM);
  // Future
  private static final ZonedDateTime SPOT_LAST_TRADING_DATE = DateUtil.getUTCDate(2012, 9, 19);
  private static final ZonedDateTime LAST_TRADING_DATE =
      ScheduleCalculator.getAdjustedDate(SPOT_LAST_TRADING_DATE, CALENDAR, -SETTLEMENT_DAYS);
  private static final double NOTIONAL = 1000000.0; // 1m
  private static final double FUTURE_FACTOR = 0.25;
  private static final String NAME = "EDU2";
  private static final InterestRateFutureSecurityDefinition EDU2_DEFINITION =
      new InterestRateFutureSecurityDefinition(
          LAST_TRADING_DATE, IBOR_INDEX, NOTIONAL, FUTURE_FACTOR, NAME);
  private static final ZonedDateTime REFERENCE_DATE = DateUtil.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};
  private static final InterestRateFutureSecurity EDU2 =
      EDU2_DEFINITION.toDerivative(REFERENCE_DATE, CURVES);
  // Option
  private static final ZonedDateTime EXPIRATION_DATE = DateUtil.getUTCDate(2011, 9, 16);
  private static final DayCount ACT_ACT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
  private static final double EXPIRATION_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE, EXPIRATION_DATE);
  private static final double STRIKE = 0.9850;
  private static final boolean IS_CALL = true;
  private static final InterestRateFutureOptionMarginSecurity OPTION_EDU2 =
      new InterestRateFutureOptionMarginSecurity(EDU2, EXPIRATION_TIME, STRIKE, IS_CALL);
  private static final InterestRateFutureOptionMarginSecuritySABRMethod METHOD =
      new InterestRateFutureOptionMarginSecuritySABRMethod();

  final YieldCurveBundle CURVES_BUNDLE = TestsDataSets.createCurves1();
  final SABRInterestRateParameters SABR_PARAMETER = TestsDataSets.createSABR1();
  final SABRInterestRateDataBundle SABR_BUNDLE =
      new SABRInterestRateDataBundle(SABR_PARAMETER, CURVES_BUNDLE);

  @Test
  /** Test the option price from the future price. Mid-curve one year option. */
  public void priceFromFuturePriceMidCurve() {
    final double priceFuture = 0.9905;
    final double priceOption =
        METHOD.optionPriceFromFuturePrice(OPTION_EDU2, SABR_BUNDLE, priceFuture);
    final double delay = EDU2.getLastTradingTime() - EXPIRATION_TIME;
    final double volatility =
        SABR_PARAMETER.getVolatility(EXPIRATION_TIME, delay, 1 - STRIKE, 1 - priceFuture);
    final BlackPriceFunction blackFunction = new BlackPriceFunction();
    final BlackFunctionData dataBlack = new BlackFunctionData(1 - priceFuture, 1.0, volatility);
    final EuropeanVanillaOption option =
        new EuropeanVanillaOption(1 - STRIKE, EXPIRATION_TIME, !IS_CALL);
    final double priceOptionExpected = blackFunction.getPriceFunction(option).evaluate(dataBlack);
    assertEquals(
        "Future option with SABR volatilities: option price from future price",
        priceOptionExpected,
        priceOption);
  }

  @Test
  /** Test the option price from the future price. Standard option. */
  public void priceFromFuturePriceStandard() {
    final double expirationTime = ACT_ACT.getDayCountFraction(REFERENCE_DATE, LAST_TRADING_DATE);
    final InterestRateFutureOptionMarginSecurity optionEDU2Standard =
        new InterestRateFutureOptionMarginSecurity(EDU2, expirationTime, STRIKE, IS_CALL);
    final double priceFuture = 0.9905;
    final double priceOption =
        METHOD.optionPriceFromFuturePrice(optionEDU2Standard, SABR_BUNDLE, priceFuture);
    final double delay = 0.0;
    final double volatility =
        SABR_PARAMETER.getVolatility(expirationTime, delay, 1 - STRIKE, 1 - priceFuture);
    final BlackPriceFunction blackFunction = new BlackPriceFunction();
    final BlackFunctionData dataBlack = new BlackFunctionData(1 - priceFuture, 1.0, volatility);
    final EuropeanVanillaOption option =
        new EuropeanVanillaOption(1 - STRIKE, expirationTime, !IS_CALL);
    final double priceOptionExpected = blackFunction.getPriceFunction(option).evaluate(dataBlack);
    assertEquals(
        "Future option with SABR volatilities: option price from future price",
        priceOptionExpected,
        priceOption);
  }

  @Test
  /** Test the option price from the future price. Standard option. */
  public void priceStandard() {
    final double expirationTime = ACT_ACT.getDayCountFraction(REFERENCE_DATE, LAST_TRADING_DATE);
    final InterestRateFutureOptionMarginSecurity optionEDU2Standard =
        new InterestRateFutureOptionMarginSecurity(EDU2, expirationTime, STRIKE, IS_CALL);
    final double priceOption = METHOD.optionPrice(optionEDU2Standard, SABR_BUNDLE);
    final InterestRateFutureSecurityDiscountingMethod methodFuture =
        InterestRateFutureSecurityDiscountingMethod.getInstance();
    final double priceFuture = methodFuture.priceFromCurves(EDU2, CURVES_BUNDLE);
    final double priceOptionExpected =
        METHOD.optionPriceFromFuturePrice(optionEDU2Standard, SABR_BUNDLE, priceFuture);
    assertEquals(
        "Future option with SABR volatilities: option price", priceOptionExpected, priceOption);
  }
}
/** Tests related to the pricing of cash-settled swaption in Hull-White one factor model. */
public class SwaptionCashFixedIborHullWhiteMethodTest {
  private static final Currency CUR = Currency.EUR;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final int SETTLEMENT_DAYS = 2;
  private static final Period IBOR_TENOR = Period.ofMonths(6);
  private static final DayCount IBOR_DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final IborIndex IBOR_INDEX =
      new IborIndex(
          CUR, IBOR_TENOR, SETTLEMENT_DAYS, CALENDAR, IBOR_DAY_COUNT, BUSINESS_DAY, IS_EOM);
  private static final int SWAP_TENOR_YEAR = 5;
  private static final Period SWAP_TENOR = Period.ofYears(SWAP_TENOR_YEAR);
  private static final Period FIXED_PAYMENT_PERIOD = Period.ofMonths(12);
  private static final DayCount FIXED_DAY_COUNT = DayCountFactory.INSTANCE.getDayCount("30/360");
  private static final IndexSwap CMS_INDEX =
      new IndexSwap(FIXED_PAYMENT_PERIOD, FIXED_DAY_COUNT, IBOR_INDEX, SWAP_TENOR);
  private static final ZonedDateTime EXPIRY_DATE = DateUtils.getUTCDate(2016, 7, 7);
  private static final ZonedDateTime SETTLEMENT_DATE =
      ScheduleCalculator.getAdjustedDate(EXPIRY_DATE, SETTLEMENT_DAYS, CALENDAR);
  private static final double NOTIONAL = 100000000; // 100m
  private static final double RATE = 0.0325;
  private static final boolean FIXED_IS_PAYER = true;
  private static final SwapFixedIborDefinition SWAP_PAYER_DEFINITION =
      SwapFixedIborDefinition.from(SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, RATE, FIXED_IS_PAYER);
  private static final SwapFixedIborDefinition SWAP_RECEIVER_DEFINITION =
      SwapFixedIborDefinition.from(SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, RATE, !FIXED_IS_PAYER);
  private static final boolean IS_LONG = true;
  private static final SwaptionCashFixedIborDefinition SWAPTION_PAYER_LONG_DEFINITION =
      SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, SWAP_PAYER_DEFINITION, IS_LONG);
  private static final SwaptionCashFixedIborDefinition SWAPTION_RECEIVER_LONG_DEFINITION =
      SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, SWAP_RECEIVER_DEFINITION, IS_LONG);
  private static final SwaptionCashFixedIborDefinition SWAPTION_PAYER_SHORT_DEFINITION =
      SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, SWAP_PAYER_DEFINITION, !IS_LONG);
  private static final SwaptionCashFixedIborDefinition SWAPTION_RECEIVER_SHORT_DEFINITION =
      SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, SWAP_RECEIVER_DEFINITION, !IS_LONG);
  // to derivatives
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 7, 7);
  private static final String FUNDING_CURVE_NAME = "Funding";
  private static final String FORWARD_CURVE_NAME = "Forward";
  private static final String[] CURVES_NAME = {FUNDING_CURVE_NAME, FORWARD_CURVE_NAME};
  private static final YieldCurveBundle CURVES = TestsDataSetsSABR.createCurves1();
  private static final FixedCouponSwap<Coupon> SWAP_PAYER =
      SWAP_PAYER_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final SwaptionCashFixedIbor SWAPTION_PAYER_LONG =
      SWAPTION_PAYER_LONG_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final SwaptionCashFixedIbor SWAPTION_RECEIVER_LONG =
      SWAPTION_RECEIVER_LONG_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final SwaptionCashFixedIbor SWAPTION_PAYER_SHORT =
      SWAPTION_PAYER_SHORT_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final SwaptionCashFixedIbor SWAPTION_RECEIVER_SHORT =
      SWAPTION_RECEIVER_SHORT_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  // Calculator
  private static final SwaptionCashFixedIborHullWhiteNumericalIntegrationMethod
      METHOD_HW_INTEGRATION = new SwaptionCashFixedIborHullWhiteNumericalIntegrationMethod();
  private static final SwaptionCashFixedIborHullWhiteApproximationMethod METHOD_HW_APPROXIMATION =
      new SwaptionCashFixedIborHullWhiteApproximationMethod();
  private static final HullWhiteOneFactorPiecewiseConstantParameters PARAMETERS_HW =
      TestsDataSetsHullWhite.createHullWhiteParameters();
  private static final HullWhiteOneFactorPiecewiseConstantDataBundle BUNDLE_HW =
      new HullWhiteOneFactorPiecewiseConstantDataBundle(PARAMETERS_HW, CURVES);

  @Test
  /** Tests long/short parity. */
  public void longShortParity() {
    CurrencyAmount pvLong = METHOD_HW_INTEGRATION.presentValue(SWAPTION_PAYER_LONG, BUNDLE_HW);
    CurrencyAmount pvShort = METHOD_HW_INTEGRATION.presentValue(SWAPTION_PAYER_SHORT, BUNDLE_HW);
    assertEquals(
        "Swaption cash - Hull-White - present value - long/short parity",
        pvLong.getAmount(),
        -pvShort.getAmount(),
        1E-2);
  }

  @Test
  /** Tests long/short parity. */
  public void scaling() {
    double scale = 12.3;
    SwapFixedIborDefinition scaledSwapDefinition =
        SwapFixedIborDefinition.from(
            SETTLEMENT_DATE, CMS_INDEX, scale * NOTIONAL, RATE, FIXED_IS_PAYER);
    SwaptionCashFixedIborDefinition scaledSwaptionDefinition =
        SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, scaledSwapDefinition, IS_LONG);
    SwaptionCashFixedIbor scaledSwaption =
        scaledSwaptionDefinition.toDerivative(REFERENCE_DATE, CURVES_NAME);
    CurrencyAmount pvOriginal = METHOD_HW_INTEGRATION.presentValue(SWAPTION_PAYER_LONG, BUNDLE_HW);
    CurrencyAmount pvScaled = METHOD_HW_INTEGRATION.presentValue(scaledSwaption, BUNDLE_HW);
    assertEquals(
        "Swaption cash - Hull-White - present value - scaling",
        scale * pvOriginal.getAmount(),
        pvScaled.getAmount(),
        1E-1);
  }

  @Test
  /** Compare approximate formula with numerical integration. */
  public void comparison() {
    double bp1 = 10000;
    CurrencyAmount pvPayerLongExplicit =
        METHOD_HW_APPROXIMATION.presentValue(SWAPTION_PAYER_LONG, BUNDLE_HW);
    CurrencyAmount pvPayerLongIntegration =
        METHOD_HW_INTEGRATION.presentValue(SWAPTION_PAYER_LONG, BUNDLE_HW);
    assertEquals(
        "Swaption cash - Hull-White - present value - explicit/numerical integration",
        pvPayerLongExplicit.getAmount() / NOTIONAL * bp1,
        pvPayerLongIntegration.getAmount() / NOTIONAL * bp1,
        3.0E-1);
    CurrencyAmount pvPayerShortExplicit =
        METHOD_HW_APPROXIMATION.presentValue(SWAPTION_PAYER_SHORT, BUNDLE_HW);
    CurrencyAmount pvPayerShortIntegration =
        METHOD_HW_INTEGRATION.presentValue(SWAPTION_PAYER_SHORT, BUNDLE_HW);
    assertEquals(
        "Swaption cash - Hull-White - present value - explicit/numerical integration",
        pvPayerShortExplicit.getAmount() / NOTIONAL * bp1,
        pvPayerShortIntegration.getAmount() / NOTIONAL * bp1,
        3.0E-1);
    CurrencyAmount pvReceiverLongExplicit =
        METHOD_HW_APPROXIMATION.presentValue(SWAPTION_RECEIVER_LONG, BUNDLE_HW);
    CurrencyAmount pvReceiverLongIntegration =
        METHOD_HW_INTEGRATION.presentValue(SWAPTION_RECEIVER_LONG, BUNDLE_HW);
    assertEquals(
        "Swaption cash - Hull-White - present value - explicit/numerical integration",
        pvReceiverLongExplicit.getAmount() / NOTIONAL * bp1,
        pvReceiverLongIntegration.getAmount() / NOTIONAL * bp1,
        5.0E-1);
    CurrencyAmount pvReceiverShortExplicit =
        METHOD_HW_APPROXIMATION.presentValue(SWAPTION_RECEIVER_SHORT, BUNDLE_HW);
    CurrencyAmount pvReceiverShortIntegration =
        METHOD_HW_INTEGRATION.presentValue(SWAPTION_RECEIVER_SHORT, BUNDLE_HW);
    assertEquals(
        "Swaption cash - Hull-White - present value - explicit/numerical integration",
        pvReceiverShortExplicit.getAmount() / NOTIONAL * bp1,
        pvReceiverShortIntegration.getAmount() / NOTIONAL * bp1,
        5.0E-1);
  }

  @Test
  /** Tests the Hull-White parameters sensitivity. */
  public void hullWhiteSensitivity() {
    double[] hwSensitivity =
        METHOD_HW_APPROXIMATION.presentValueHullWhiteSensitivity(SWAPTION_PAYER_LONG, BUNDLE_HW);
    int nbVolatility = PARAMETERS_HW.getVolatility().length;
    double shiftVol = 1.0E-6;
    double[] volatilityBumped = new double[nbVolatility];
    System.arraycopy(PARAMETERS_HW.getVolatility(), 0, volatilityBumped, 0, nbVolatility);
    double[] volatilityTime = new double[nbVolatility - 1];
    System.arraycopy(PARAMETERS_HW.getVolatilityTime(), 1, volatilityTime, 0, nbVolatility - 1);
    double[] pvBumpedPlus = new double[nbVolatility];
    double[] pvBumpedMinus = new double[nbVolatility];
    HullWhiteOneFactorPiecewiseConstantParameters parametersBumped =
        new HullWhiteOneFactorPiecewiseConstantParameters(
            PARAMETERS_HW.getMeanReversion(), volatilityBumped, volatilityTime);
    HullWhiteOneFactorPiecewiseConstantDataBundle bundleBumped =
        new HullWhiteOneFactorPiecewiseConstantDataBundle(parametersBumped, CURVES);
    double[] hwSensitivityExpected = new double[nbVolatility];
    for (int loopvol = 0; loopvol < nbVolatility; loopvol++) {
      volatilityBumped[loopvol] += shiftVol;
      parametersBumped.setVolatility(volatilityBumped);
      pvBumpedPlus[loopvol] =
          METHOD_HW_APPROXIMATION.presentValue(SWAPTION_PAYER_LONG, bundleBumped).getAmount();
      volatilityBumped[loopvol] -= 2 * shiftVol;
      parametersBumped.setVolatility(volatilityBumped);
      pvBumpedMinus[loopvol] =
          METHOD_HW_APPROXIMATION.presentValue(SWAPTION_PAYER_LONG, bundleBumped).getAmount();
      hwSensitivityExpected[loopvol] =
          (pvBumpedPlus[loopvol] - pvBumpedMinus[loopvol]) / (2 * shiftVol);
      assertEquals(
          "Swaption - Hull-White sensitivity adjoint: derivative "
              + loopvol
              + " - difference:"
              + (hwSensitivityExpected[loopvol] - hwSensitivity[loopvol]),
          hwSensitivityExpected[loopvol],
          hwSensitivity[loopvol],
          2.0E+5);
      volatilityBumped[loopvol] = PARAMETERS_HW.getVolatility()[loopvol];
    }
  }

  @Test(enabled = true)
  /** Tests approximation error. "enabled = false" for the standard testing. */
  public void errorAnalysis() {
    double bp1 = 10000;
    double errorLimit = 5.0E-1; // 0.5 bp
    ParRateCalculator prc = ParRateCalculator.getInstance();
    double forward = prc.visit(SWAP_PAYER, CURVES);
    double[] strikeRel = new double[] {-0.0250, -0.0150, -0.0050, 0.0, 0.0050, 0.0150, 0.0250};
    double[] pvPayerApproximation = new double[strikeRel.length];
    double[] pvPayerIntegration = new double[strikeRel.length];
    double[] pvReceiverApproximation = new double[strikeRel.length];
    double[] pvReceiverIntegration = new double[strikeRel.length];
    for (int loopstrike = 0; loopstrike < strikeRel.length; loopstrike++) {
      SwapFixedIborDefinition swapStrikePayerDefinition =
          SwapFixedIborDefinition.from(
              SETTLEMENT_DATE, CMS_INDEX, bp1, forward + strikeRel[loopstrike], FIXED_IS_PAYER);
      SwaptionCashFixedIborDefinition swaptionStrikePayerDefinition =
          SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, swapStrikePayerDefinition, IS_LONG);
      SwaptionCashFixedIbor swaptionStrikePayer =
          swaptionStrikePayerDefinition.toDerivative(REFERENCE_DATE, CURVES_NAME);
      pvPayerApproximation[loopstrike] =
          METHOD_HW_APPROXIMATION.presentValue(swaptionStrikePayer, BUNDLE_HW).getAmount();
      pvPayerIntegration[loopstrike] =
          METHOD_HW_INTEGRATION.presentValue(swaptionStrikePayer, BUNDLE_HW).getAmount();
      assertEquals(
          "Swaption cash - Hull-White - present value - explicit/numerical integration",
          pvPayerApproximation[loopstrike],
          pvPayerIntegration[loopstrike],
          errorLimit);
      SwapFixedIborDefinition swapStrikeReceiverDefinition =
          SwapFixedIborDefinition.from(
              SETTLEMENT_DATE, CMS_INDEX, bp1, forward + strikeRel[loopstrike], !FIXED_IS_PAYER);
      SwaptionCashFixedIborDefinition swaptionStrikeReceiverDefinition =
          SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, swapStrikeReceiverDefinition, IS_LONG);
      SwaptionCashFixedIbor swaptionStrikeReceiver =
          swaptionStrikeReceiverDefinition.toDerivative(REFERENCE_DATE, CURVES_NAME);
      pvReceiverApproximation[loopstrike] =
          METHOD_HW_APPROXIMATION.presentValue(swaptionStrikeReceiver, BUNDLE_HW).getAmount();
      pvReceiverIntegration[loopstrike] =
          METHOD_HW_INTEGRATION.presentValue(swaptionStrikeReceiver, BUNDLE_HW).getAmount();
      assertEquals(
          "Swaption cash - Hull-White - present value - explicit/numerical integration",
          pvReceiverApproximation[loopstrike],
          pvReceiverIntegration[loopstrike],
          errorLimit);
    }
  }

  @Test
  /** Tests the curve sensitivity. */
  public void presentValueCurveSensitivity() {
    InterestRateCurveSensitivity pvsSwaption =
        METHOD_HW_APPROXIMATION.presentValueCurveSensitivity(SWAPTION_PAYER_LONG, BUNDLE_HW);
    pvsSwaption = pvsSwaption.cleaned();
    final double deltaTolerancePrice = 1.0E+4;
    // Testing note: Sensitivity is for a movement of 1. 1E+2 = 1 cent for a 1 bp move. Tolerance
    // increased to cope with numerical imprecision of finite difference.
    final double deltaShift = 1.0E-6;
    // 1. Forward curve sensitivity
    final String bumpedCurveName = "Bumped Curve";
    final SwaptionCashFixedIbor swptBumpedForward =
        SWAPTION_PAYER_LONG_DEFINITION.toDerivative(
            REFERENCE_DATE, new String[] {CURVES_NAME[0], bumpedCurveName});
    DoubleAVLTreeSet forwardTime = new DoubleAVLTreeSet();
    for (int loopcpn = 0;
        loopcpn < SWAPTION_PAYER_LONG.getUnderlyingSwap().getSecondLeg().getNumberOfPayments();
        loopcpn++) {
      CouponIbor cpn =
          (CouponIbor)
              SWAPTION_PAYER_LONG.getUnderlyingSwap().getSecondLeg().getNthPayment(loopcpn);
      forwardTime.add(cpn.getFixingPeriodStartTime());
      forwardTime.add(cpn.getFixingPeriodEndTime());
    }
    double[] nodeTimesForward = forwardTime.toDoubleArray();
    final double[] sensiForwardMethod =
        SensitivityFiniteDifference.curveSensitivity(
            swptBumpedForward,
            BUNDLE_HW,
            CURVES_NAME[1],
            bumpedCurveName,
            nodeTimesForward,
            deltaShift,
            METHOD_HW_APPROXIMATION);
    final List<DoublesPair> sensiPvForward = pvsSwaption.getSensitivities().get(CURVES_NAME[1]);
    for (int loopnode = 0; loopnode < sensiForwardMethod.length; loopnode++) {
      final DoublesPair pairPv = sensiPvForward.get(loopnode);
      assertEquals(
          "Sensitivity swaption pv to forward curve: Node " + loopnode,
          nodeTimesForward[loopnode],
          pairPv.getFirst(),
          1E-8);
      assertEquals(
          "Sensitivity finite difference method: node sensitivity " + loopnode,
          sensiForwardMethod[loopnode],
          pairPv.second,
          deltaTolerancePrice);
    }
    // 2. Discounting curve sensitivity
    final SwaptionCashFixedIbor swptBumpedDisc =
        SWAPTION_PAYER_LONG_DEFINITION.toDerivative(
            REFERENCE_DATE, new String[] {bumpedCurveName, CURVES_NAME[1]});
    DoubleAVLTreeSet discTime = new DoubleAVLTreeSet();
    discTime.add(SWAPTION_PAYER_LONG.getSettlementTime());
    for (int loopcpn = 0;
        loopcpn < SWAPTION_PAYER_LONG.getUnderlyingSwap().getSecondLeg().getNumberOfPayments();
        loopcpn++) {
      CouponIbor cpn =
          (CouponIbor)
              SWAPTION_PAYER_LONG.getUnderlyingSwap().getSecondLeg().getNthPayment(loopcpn);
      discTime.add(cpn.getPaymentTime());
    }
    double[] nodeTimesDisc = discTime.toDoubleArray();
    final double[] sensiDiscMethod =
        SensitivityFiniteDifference.curveSensitivity(
            swptBumpedDisc,
            BUNDLE_HW,
            CURVES_NAME[0],
            bumpedCurveName,
            nodeTimesDisc,
            deltaShift,
            METHOD_HW_APPROXIMATION);
    assertEquals(
        "Sensitivity finite difference method: number of node", 11, sensiDiscMethod.length);
    final List<DoublesPair> sensiPvDisc = pvsSwaption.getSensitivities().get(CURVES_NAME[0]);
    for (int loopnode = 0; loopnode < sensiDiscMethod.length; loopnode++) {
      final DoublesPair pairPv = sensiPvDisc.get(loopnode);
      assertEquals(
          "Sensitivity swaption pv to forward curve: Node " + loopnode,
          nodeTimesDisc[loopnode],
          pairPv.getFirst(),
          1E-8);
      assertEquals(
          "Sensitivity finite difference method: node sensitivity",
          sensiDiscMethod[loopnode],
          pairPv.second,
          deltaTolerancePrice);
    }
  }

  @Test(enabled = false)
  /** Tests of performance. "enabled = false" for the standard testing. */
  public void performance() {
    long startTime, endTime;
    final int nbTest = 1000;
    CurrencyAmount pvPayerLongExplicit = CurrencyAmount.of(CUR, 0.0);
    CurrencyAmount pvPayerLongIntegration = CurrencyAmount.of(CUR, 0.0);
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongExplicit = METHOD_HW_APPROXIMATION.presentValue(SWAPTION_PAYER_LONG, BUNDLE_HW);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest + " pv swaption Hull-White approximation method: " + (endTime - startTime) + " ms");
    // Performance note: HW price: 8-Jul-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 330 ms for
    // 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      METHOD_HW_APPROXIMATION.presentValueHullWhiteSensitivity(SWAPTION_PAYER_LONG, BUNDLE_HW);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " HW sensitivity swaption Hull-White approximation method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW parameters sensitivity: 8-Jul-11: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 525 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      METHOD_HW_APPROXIMATION.presentValueCurveSensitivity(SWAPTION_PAYER_LONG, BUNDLE_HW);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " curve sensitivity swaption Hull-White approximation method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW curve sensitivity: 8-Jul-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon:
    // 550 ms for 10000 swaptions.
    startTime = System.currentTimeMillis();
    for (int looptest = 0; looptest < nbTest; looptest++) {
      pvPayerLongIntegration = METHOD_HW_INTEGRATION.presentValue(SWAPTION_PAYER_LONG, BUNDLE_HW);
    }
    endTime = System.currentTimeMillis();
    System.out.println(
        nbTest
            + " cash swaption Hull-White numerical integration method: "
            + (endTime - startTime)
            + " ms");
    // Performance note: HW numerical integration: 8-Jul-11: On Mac Pro 3.2 GHz Quad-Core Intel
    // Xeon: 1300 ms for 10000 swaptions.

    double difference = 0.0;
    difference = pvPayerLongExplicit.getAmount() - pvPayerLongIntegration.getAmount();
    System.out.println("Difference: " + difference);
  }
}
/**
 * Test related to the pricing and sensitivity of the Ibor cap/floor with the SABR model and
 * extrapolation for high strikes.
 *
 * @deprecated This class tests deprecated functionality.
 */
@Deprecated
public class CapFloorIborSABRExtrapolationRightMethodTest {
  // Details
  private static final Period TENOR = Period.ofMonths(3);
  private static final int SETTLEMENT_DAYS = 2;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final DayCount DAY_COUNT_INDEX =
      DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final Currency CUR = Currency.EUR;
  private static final IborIndex INDEX =
      new IborIndex(CUR, TENOR, SETTLEMENT_DAYS, DAY_COUNT_INDEX, BUSINESS_DAY, IS_EOM, "Ibor");
  private static final ZonedDateTime FIXING_DATE = DateUtils.getUTCDate(2011, 1, 3);
  private static final double NOTIONAL = 1000000; // 1m
  private static final double STRIKE = 0.04;
  private static final double STRIKE_HIGH = 0.09;
  private static final boolean IS_CAP = true;
  // Definition description
  private static final CapFloorIborDefinition CAP_LONG_DEFINITION =
      CapFloorIborDefinition.from(NOTIONAL, FIXING_DATE, INDEX, STRIKE, IS_CAP, CALENDAR);
  private static final CapFloorIborDefinition CAP_HIGH_LONG_DEFINITION =
      CapFloorIborDefinition.from(NOTIONAL, FIXING_DATE, INDEX, STRIKE_HIGH, IS_CAP, CALENDAR);
  private static final CouponIborDefinition COUPON_IBOR_DEFINITION =
      CouponIborDefinition.from(NOTIONAL, FIXING_DATE, INDEX, CALENDAR);
  private static final CouponFixedDefinition COUPON_STRIKE_DEFINITION =
      new CouponFixedDefinition(COUPON_IBOR_DEFINITION, STRIKE);
  private static final CouponFixedDefinition COUPON_STRIKE_HIGH_DEFINITION =
      new CouponFixedDefinition(COUPON_IBOR_DEFINITION, STRIKE_HIGH);
  private static final CapFloorIborDefinition CAP_SHORT_DEFINITION =
      CapFloorIborDefinition.from(-NOTIONAL, FIXING_DATE, INDEX, STRIKE, IS_CAP, CALENDAR);
  private static final CapFloorIborDefinition CAP_HIGH_SHORT_DEFINITION =
      CapFloorIborDefinition.from(-NOTIONAL, FIXING_DATE, INDEX, STRIKE_HIGH, IS_CAP, CALENDAR);
  private static final CapFloorIborDefinition FLOOR_SHORT_DEFINITION =
      CapFloorIborDefinition.from(-NOTIONAL, FIXING_DATE, INDEX, STRIKE, !IS_CAP, CALENDAR);
  private static final CapFloorIborDefinition FLOOR_HIGH_SHORT_DEFINITION =
      CapFloorIborDefinition.from(-NOTIONAL, FIXING_DATE, INDEX, STRIKE_HIGH, !IS_CAP, CALENDAR);
  // Methods and calculator
  private static final double CUT_OFF_STRIKE = 0.08;
  private static final double MU = 2.50;
  private static final CapFloorIborSABRExtrapolationRightMethod METHOD =
      new CapFloorIborSABRExtrapolationRightMethod(CUT_OFF_STRIKE, MU);
  private static final ParRateCalculator PRC = ParRateCalculator.getInstance();
  private static final PresentValueCalculator PVC = PresentValueCalculator.getInstance();
  private static final PresentValueCurveSensitivitySABRExtrapolationCalculator PVSC =
      new PresentValueCurveSensitivitySABRExtrapolationCalculator(CUT_OFF_STRIKE, MU);
  // To derivative
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2008, 8, 18);
  private static final String FUNDING_CURVE_NAME = "Funding";
  private static final String FORWARD_CURVE_NAME = "Forward";
  private static final String[] CURVES_NAME = {FUNDING_CURVE_NAME, FORWARD_CURVE_NAME};
  private static final CapFloorIbor CAP_LONG =
      (CapFloorIbor) CAP_LONG_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final CapFloorIbor CAP_HIGH_LONG =
      (CapFloorIbor) CAP_HIGH_LONG_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final CouponIbor COUPON_IBOR =
      (CouponIbor) COUPON_IBOR_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final CouponFixed COUPON_STRIKE =
      COUPON_STRIKE_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final CouponFixed COUPON_STRIKE_HIGH =
      COUPON_STRIKE_HIGH_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final CapFloorIbor CAP_SHORT =
      (CapFloorIbor) CAP_SHORT_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final CapFloorIbor CAP_HIGH_SHORT =
      (CapFloorIbor) CAP_HIGH_SHORT_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final CapFloorIbor FLOOR_SHORT =
      (CapFloorIbor) FLOOR_SHORT_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  private static final CapFloorIbor FLOOR_HIGH_SHORT =
      (CapFloorIbor) FLOOR_HIGH_SHORT_DEFINITION.toDerivative(REFERENCE_DATE, CURVES_NAME);
  // Data
  private static final YieldCurveBundle CURVES = TestsDataSetsSABR.createCurves1();
  private static final SABRInterestRateParameters SABR_PARAMETERS = TestsDataSetsSABR.createSABR1();
  private static final SABRInterestRateDataBundle SABR_BUNDLE =
      new SABRInterestRateDataBundle(SABR_PARAMETERS, CURVES);

  @Test
  /** Test the present value using the method with the direct formula with extrapolation. */
  public void presentValueBelowCutOff() {
    final CurrencyAmount methodPrice = METHOD.presentValue(CAP_LONG, SABR_BUNDLE);
    final double df =
        CURVES.getCurve(FUNDING_CURVE_NAME).getDiscountFactor(CAP_LONG.getPaymentTime());
    final double forward = CAP_LONG.accept(PRC, CURVES);
    final double maturity = CAP_LONG.getFixingPeriodEndTime() - CAP_LONG.getFixingPeriodStartTime();
    final DoublesPair expiryMaturity = new DoublesPair(CAP_LONG.getFixingTime(), maturity);
    final double alpha = SABR_PARAMETERS.getAlpha(expiryMaturity);
    final double beta = SABR_PARAMETERS.getBeta(expiryMaturity);
    final double rho = SABR_PARAMETERS.getRho(expiryMaturity);
    final double nu = SABR_PARAMETERS.getNu(expiryMaturity);
    final SABRFormulaData sabrParam = new SABRFormulaData(alpha, beta, rho, nu);
    final SABRExtrapolationRightFunction sabrExtrapolation =
        new SABRExtrapolationRightFunction(
            forward, sabrParam, CUT_OFF_STRIKE, CAP_LONG.getFixingTime(), MU);
    final EuropeanVanillaOption option =
        new EuropeanVanillaOption(CAP_LONG.getStrike(), CAP_LONG.getFixingTime(), CAP_LONG.isCap());
    final double expectedPrice =
        sabrExtrapolation.price(option)
            * CAP_LONG.getNotional()
            * CAP_LONG.getPaymentYearFraction()
            * df;
    assertEquals(
        "Cap/floor: SABR with extrapolation pricing", expectedPrice, methodPrice.getAmount(), 1E-2);
  }

  @Test
  /** Test the present value using the method with the direct formula with extrapolation. */
  public void presentValueAboveCutOff() {
    CurrencyAmount methodPrice = METHOD.presentValue(CAP_HIGH_LONG, SABR_BUNDLE);
    final double df =
        CURVES.getCurve(FUNDING_CURVE_NAME).getDiscountFactor(CAP_HIGH_LONG.getPaymentTime());
    final double forward = CAP_HIGH_LONG.accept(PRC, CURVES);
    final double maturity =
        CAP_HIGH_LONG.getFixingPeriodEndTime() - CAP_LONG.getFixingPeriodStartTime();
    final DoublesPair expiryMaturity = new DoublesPair(CAP_HIGH_LONG.getFixingTime(), maturity);
    final double alpha = SABR_PARAMETERS.getAlpha(expiryMaturity);
    final double beta = SABR_PARAMETERS.getBeta(expiryMaturity);
    final double rho = SABR_PARAMETERS.getRho(expiryMaturity);
    final double nu = SABR_PARAMETERS.getNu(expiryMaturity);
    final SABRFormulaData sabrParam = new SABRFormulaData(alpha, beta, rho, nu);
    final SABRExtrapolationRightFunction sabrExtrapolation =
        new SABRExtrapolationRightFunction(
            forward, sabrParam, CUT_OFF_STRIKE, CAP_HIGH_LONG.getFixingTime(), MU);
    final EuropeanVanillaOption option =
        new EuropeanVanillaOption(
            CAP_HIGH_LONG.getStrike(), CAP_HIGH_LONG.getFixingTime(), CAP_HIGH_LONG.isCap());
    final double expectedPrice =
        sabrExtrapolation.price(option)
            * CAP_HIGH_LONG.getNotional()
            * CAP_HIGH_LONG.getPaymentYearFraction()
            * df;
    assertEquals(
        "Cap/floor: SABR with extrapolation pricing", expectedPrice, methodPrice.getAmount(), 1E-2);
    methodPrice = METHOD.presentValue(CAP_HIGH_LONG, SABR_BUNDLE);
    assertEquals(
        "Cap/floor: SABR with extrapolation pricing", expectedPrice, methodPrice.getAmount(), 1E-2);
  }

  @Test
  /** Test the present value using the method with the direct formula with extrapolation. */
  public void presentValueLongShortParityBelowCutOff() {
    final CurrencyAmount priceLong = METHOD.presentValue(CAP_LONG, SABR_BUNDLE);
    final CurrencyAmount priceShort = METHOD.presentValue(CAP_SHORT, SABR_BUNDLE);
    assertEquals(
        "Cap/floor: SABR with extrapolation pricing: long/short parity",
        priceLong.getAmount(),
        -priceShort.getAmount(),
        1E-2);
  }

  @Test
  /** Test the present value using the method with the direct formula with extrapolation. */
  public void presentValueLongShortParityAboveCutOff() {
    final CurrencyAmount priceLong = METHOD.presentValue(CAP_HIGH_LONG, SABR_BUNDLE);
    final CurrencyAmount priceShort = METHOD.presentValue(CAP_HIGH_SHORT, SABR_BUNDLE);
    assertEquals(
        "Cap/floor: SABR with extrapolation pricing: long/short parity",
        priceLong.getAmount(),
        -priceShort.getAmount(),
        1E-2);
  }

  @Test
  /** Test the cap/floor/forward parity below the cut-off strike. */
  public void presentValueCapFloorParityBelowCutOff() {
    final CurrencyAmount priceCap = METHOD.presentValue(CAP_LONG, SABR_BUNDLE);
    final CurrencyAmount priceFloor = METHOD.presentValue(FLOOR_SHORT, SABR_BUNDLE);
    final double priceCouponStrike = COUPON_STRIKE.accept(PVC, CURVES);
    final double priceCouponIbor = COUPON_IBOR.accept(PVC, CURVES);
    assertEquals(
        "Cap/floor: SABR with extrapolation pricing: cap/floor parity",
        priceCouponIbor - priceCouponStrike,
        priceCap.getAmount() + priceFloor.getAmount(),
        1E-2);
  }

  @Test
  /** Test the cap/floor/forward parity above the cut-off strike. */
  public void presentValueCapFloorParityAboveCutOff() {
    final CurrencyAmount priceCap = METHOD.presentValue(CAP_HIGH_LONG, SABR_BUNDLE);
    final CurrencyAmount priceFloor = METHOD.presentValue(FLOOR_HIGH_SHORT, SABR_BUNDLE);
    final double priceCouponStrike = COUPON_STRIKE_HIGH.accept(PVC, CURVES);
    final double priceCouponIbor = COUPON_IBOR.accept(PVC, CURVES);
    assertEquals(
        "Cap/floor: SABR with extrapolation pricing: cap/floor parity",
        priceCouponIbor - priceCouponStrike,
        priceCap.getAmount() + priceFloor.getAmount(),
        1E-2);
  }

  @Test
  /** Test the present value using the method with the direct formula with extrapolation. */
  public void presentValueMethodVsCalculator() {
    final SABRInterestRateDataBundle sabrExtraBundle =
        new SABRInterestRateDataBundle(SABR_PARAMETERS, CURVES);
    final CurrencyAmount pvMethod = METHOD.presentValue(CAP_LONG, SABR_BUNDLE);
    final PresentValueSABRExtrapolationCalculator pvc =
        new PresentValueSABRExtrapolationCalculator(CUT_OFF_STRIKE, MU);
    final double pvCalculator = CAP_LONG.accept(pvc, sabrExtraBundle);
    assertEquals(
        "Cap/floor: SABR with extrapolation pricing - Method vs Calculator",
        pvMethod.getAmount(),
        pvCalculator,
        1E-2);
  }

  @Test
  /**
   * Test the present value rate sensitivity against a finite difference computation; strike below
   * the cut-off strike. Test sensitivity long/short parity.
   */
  public void testPresentValueSensitivityBelowCutOff() {
    final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
    final SABRInterestRateParameters sabrParameter = TestsDataSetsSABR.createSABR1();
    final SABRInterestRateDataBundle sabrBundle =
        new SABRInterestRateDataBundle(sabrParameter, curves);
    InterestRateCurveSensitivity pvsCapLong = METHOD.presentValueSensitivity(CAP_LONG, sabrBundle);
    final InterestRateCurveSensitivity pvsCapShort =
        METHOD.presentValueSensitivity(CAP_SHORT, sabrBundle);
    // Long/short parity
    final InterestRateCurveSensitivity pvsCapShort_1 = pvsCapShort.multipliedBy(-1);
    assertEquals(pvsCapLong.getSensitivities(), pvsCapShort_1.getSensitivities());
    // Present value sensitivity comparison with finite difference.
    final double deltaTolerancePrice = 1.0E-1;
    // Testing note: Sensitivity is for a movement of 1. 1E+2 = 1 cent for a 1 bp move.
    final double deltaShift = 1.0E-7;
    pvsCapLong = pvsCapLong.cleaned();
    final String bumpedCurveName = "Bumped Curve";
    // 1. Forward curve sensitivity
    final String[] CurveNameBumpedForward = {FUNDING_CURVE_NAME, bumpedCurveName};
    final CapFloorIbor capBumpedForward =
        (CapFloorIbor) CAP_LONG_DEFINITION.toDerivative(REFERENCE_DATE, CurveNameBumpedForward);
    final double[] nodeTimesForward =
        new double[] {
          capBumpedForward.getFixingPeriodStartTime(), capBumpedForward.getFixingPeriodEndTime()
        };
    final double[] sensiForwardMethod =
        SensitivityFiniteDifference.curveSensitivity(
            capBumpedForward,
            SABR_BUNDLE,
            FORWARD_CURVE_NAME,
            bumpedCurveName,
            nodeTimesForward,
            deltaShift,
            METHOD);
    assertEquals(
        "Sensitivity finite difference method: number of node", 2, sensiForwardMethod.length);
    final List<DoublesPair> sensiPvForward = pvsCapLong.getSensitivities().get(FORWARD_CURVE_NAME);
    for (int loopnode = 0; loopnode < sensiForwardMethod.length; loopnode++) {
      final DoublesPair pairPv = sensiPvForward.get(loopnode);
      assertEquals(
          "Sensitivity cap/floor pv to forward curve: Node " + loopnode,
          nodeTimesForward[loopnode],
          pairPv.getFirst(),
          1E-8);
      assertEquals(
          "Sensitivity finite difference method: node sensitivity",
          pairPv.second,
          sensiForwardMethod[loopnode],
          deltaTolerancePrice);
    }
    // 2. Discounting curve sensitivity
    final String[] CurveNameBumpedDisc = {bumpedCurveName, FORWARD_CURVE_NAME};
    final CapFloorIbor capBumpedDisc =
        (CapFloorIbor) CAP_LONG_DEFINITION.toDerivative(REFERENCE_DATE, CurveNameBumpedDisc);
    final double[] nodeTimesDisc = new double[] {capBumpedDisc.getPaymentTime()};
    final double[] sensiDiscMethod =
        SensitivityFiniteDifference.curveSensitivity(
            capBumpedDisc,
            SABR_BUNDLE,
            FUNDING_CURVE_NAME,
            bumpedCurveName,
            nodeTimesDisc,
            deltaShift,
            METHOD);
    assertEquals("Sensitivity finite difference method: number of node", 1, sensiDiscMethod.length);
    final List<DoublesPair> sensiPvDisc = pvsCapLong.getSensitivities().get(FUNDING_CURVE_NAME);
    for (int loopnode = 0; loopnode < sensiDiscMethod.length; loopnode++) {
      final DoublesPair pairPv = sensiPvDisc.get(loopnode);
      assertEquals(
          "Sensitivity cap/floor pv to forward curve: Node " + loopnode,
          nodeTimesDisc[loopnode],
          pairPv.getFirst(),
          1E-8);
      assertEquals(
          "Sensitivity finite difference method: node sensitivity",
          pairPv.second,
          sensiDiscMethod[loopnode],
          deltaTolerancePrice);
    }
  }

  @Test
  /**
   * Test the present value rate sensitivity against a finite difference computation; strike above
   * the cut-off strike. Test sensitivity long/short parity.
   */
  public void testPresentValueSensitivityAboveCutOff() {
    final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
    final SABRInterestRateParameters sabrParameter = TestsDataSetsSABR.createSABR1();
    final SABRInterestRateDataBundle sabrBundle =
        new SABRInterestRateDataBundle(sabrParameter, curves);
    InterestRateCurveSensitivity pvsCapLong =
        METHOD.presentValueSensitivity(CAP_HIGH_LONG, sabrBundle);
    final InterestRateCurveSensitivity pvsCapShort =
        METHOD.presentValueSensitivity(CAP_HIGH_SHORT, sabrBundle);
    // Long/short parity
    final InterestRateCurveSensitivity pvsCapShort_1 = pvsCapShort.multipliedBy(-1);
    assertEquals(pvsCapLong.getSensitivities(), pvsCapShort_1.getSensitivities());
    // Present value sensitivity comparison with finite difference.
    final double deltaTolerancePrice = 1.0E-1;
    // Testing note: Sensitivity is for a movement of 1. 1E+2 = 1 cent for a 1 bp move.
    final double deltaShift = 1.0E-7;
    pvsCapLong = pvsCapLong.cleaned();
    final String bumpedCurveName = "Bumped Curve";
    // 1. Forward curve sensitivity
    final String[] CurveNameBumpedForward = {FUNDING_CURVE_NAME, bumpedCurveName};
    final CapFloorIbor capBumpedForward =
        (CapFloorIbor)
            CAP_HIGH_LONG_DEFINITION.toDerivative(REFERENCE_DATE, CurveNameBumpedForward);
    final double[] nodeTimesForward =
        new double[] {
          capBumpedForward.getFixingPeriodStartTime(), capBumpedForward.getFixingPeriodEndTime()
        };
    final double[] sensiForwardMethod =
        SensitivityFiniteDifference.curveSensitivity(
            capBumpedForward,
            SABR_BUNDLE,
            FORWARD_CURVE_NAME,
            bumpedCurveName,
            nodeTimesForward,
            deltaShift,
            METHOD);
    assertEquals(
        "Sensitivity finite difference method: number of node", 2, sensiForwardMethod.length);
    final List<DoublesPair> sensiPvForward = pvsCapLong.getSensitivities().get(FORWARD_CURVE_NAME);
    for (int loopnode = 0; loopnode < sensiForwardMethod.length; loopnode++) {
      final DoublesPair pairPv = sensiPvForward.get(loopnode);
      assertEquals(
          "Sensitivity cap/floor pv to forward curve: Node " + loopnode,
          nodeTimesForward[loopnode],
          pairPv.getFirst(),
          1E-8);
      //      assertEquals("Sensitivity finite difference method: node sensitivity: Node " +
      // loopnode, pairPv.second, sensiForwardMethod[loopnode], deltaTolerancePrice);
    }
    // 2. Discounting curve sensitivity
    final String[] CurveNameBumpedDisc = {bumpedCurveName, FORWARD_CURVE_NAME};
    final CapFloorIbor capBumpedDisc =
        (CapFloorIbor) CAP_HIGH_LONG_DEFINITION.toDerivative(REFERENCE_DATE, CurveNameBumpedDisc);
    final double[] nodeTimesDisc = new double[] {capBumpedDisc.getPaymentTime()};
    final double[] sensiDiscMethod =
        SensitivityFiniteDifference.curveSensitivity(
            capBumpedDisc,
            SABR_BUNDLE,
            FUNDING_CURVE_NAME,
            bumpedCurveName,
            nodeTimesDisc,
            deltaShift,
            METHOD);
    assertEquals("Sensitivity finite difference method: number of node", 1, sensiDiscMethod.length);
    final List<DoublesPair> sensiPvDisc = pvsCapLong.getSensitivities().get(FUNDING_CURVE_NAME);
    for (int loopnode = 0; loopnode < sensiDiscMethod.length; loopnode++) {
      final DoublesPair pairPv = sensiPvDisc.get(loopnode);
      assertEquals(
          "Sensitivity cap/floor pv to forward curve: Node " + loopnode,
          nodeTimesDisc[loopnode],
          pairPv.getFirst(),
          1E-8);
      assertEquals(
          "Sensitivity finite difference method: node sensitivity",
          pairPv.second,
          sensiDiscMethod[loopnode],
          deltaTolerancePrice);
    }
  }

  @Test
  /** Test the present value using the method with the direct formula with extrapolation. */
  public void presentValueCurveSensitivityMethodVsCalculator() {
    final SABRInterestRateDataBundle sabrExtraBundle =
        new SABRInterestRateDataBundle(SABR_PARAMETERS, CURVES);
    final InterestRateCurveSensitivity pvsMethod =
        METHOD.presentValueSensitivity(CAP_HIGH_LONG, SABR_BUNDLE);
    final InterestRateCurveSensitivity pvsCalculator =
        new InterestRateCurveSensitivity(CAP_HIGH_LONG.accept(PVSC, sabrExtraBundle));
    assertEquals(
        "Cap/floor: SABR with extrapolation pv curve sensitivity - Method vs Calculator",
        pvsMethod,
        pvsCalculator);
  }

  @Test
  /**
   * Test the present value SABR parameters sensitivity against a finite difference computation;
   * strike below the cut-off strike.
   */
  public void testPresentValueSABRSensitivityBelowCutOff() {
    final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
    final SABRInterestRateParameters sabrParameter = TestsDataSetsSABR.createSABR1();
    final SABRInterestRateDataBundle sabrBundle =
        new SABRInterestRateDataBundle(sabrParameter, curves);
    final CurrencyAmount pv = METHOD.presentValue(CAP_LONG, sabrBundle);
    final PresentValueSABRSensitivityDataBundle pvsCapLong =
        METHOD.presentValueSABRSensitivity(CAP_LONG, sabrBundle);
    PresentValueSABRSensitivityDataBundle pvsCapShort =
        METHOD.presentValueSABRSensitivity(CAP_SHORT, sabrBundle);
    // Long/short parity
    pvsCapShort = pvsCapShort.multiplyBy(-1.0);
    assertEquals(pvsCapShort.getAlpha(), pvsCapLong.getAlpha());
    // SABR sensitivity vs finite difference
    final double shift = 0.0001;
    final double shiftAlpha = 0.00001;
    final DoublesPair expectedExpiryTenor =
        new DoublesPair(
            CAP_LONG.getFixingTime(),
            CAP_LONG.getFixingPeriodEndTime() - CAP_LONG.getFixingPeriodStartTime());
    // Alpha sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterAlphaBumped =
        TestsDataSetsSABR.createSABR1AlphaBumped(shiftAlpha);
    final SABRInterestRateDataBundle sabrBundleAlphaBumped =
        new SABRInterestRateDataBundle(sabrParameterAlphaBumped, curves);
    final CurrencyAmount pvLongPayerAlphaBumped =
        METHOD.presentValue(CAP_LONG, sabrBundleAlphaBumped);
    final double expectedAlphaSensi =
        (pvLongPayerAlphaBumped.getAmount() - pv.getAmount()) / 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),
        2.0E-1);
    // Rho sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterRhoBumped =
        TestsDataSetsSABR.createSABR1RhoBumped();
    final SABRInterestRateDataBundle sabrBundleRhoBumped =
        new SABRInterestRateDataBundle(sabrParameterRhoBumped, curves);
    final CurrencyAmount pvLongPayerRhoBumped = METHOD.presentValue(CAP_LONG, sabrBundleRhoBumped);
    final double expectedRhoSensi = (pvLongPayerRhoBumped.getAmount() - pv.getAmount()) / 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",
        pvsCapLong.getRho().getMap().get(expectedExpiryTenor),
        expectedRhoSensi,
        1.0E-2);
    // Alpha sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterNuBumped =
        TestsDataSetsSABR.createSABR1NuBumped();
    final SABRInterestRateDataBundle sabrBundleNuBumped =
        new SABRInterestRateDataBundle(sabrParameterNuBumped, curves);
    final CurrencyAmount pvLongPayerNuBumped = METHOD.presentValue(CAP_LONG, sabrBundleNuBumped);
    final double expectedNuSensi = (pvLongPayerNuBumped.getAmount() - pv.getAmount()) / shift;
    assertEquals("Number of nu sensitivity", pvsCapLong.getNu().getMap().keySet().size(), 1);
    assertEquals(
        "Nu sensitivity expiry/tenor",
        pvsCapLong.getNu().getMap().keySet().contains(expectedExpiryTenor),
        true);
    assertEquals(
        "Nu sensitivity value",
        pvsCapLong.getNu().getMap().get(expectedExpiryTenor),
        expectedNuSensi,
        3.0E-2);
  }

  @Test
  /**
   * Test the present value SABR parameters sensitivity against a finite difference computation;
   * strike above the cut-off strike.
   */
  public void testPresentValueSABRSensitivityAboveCutOff() {
    final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1();
    final SABRInterestRateParameters sabrParameter = TestsDataSetsSABR.createSABR1();
    final SABRInterestRateDataBundle sabrBundle =
        new SABRInterestRateDataBundle(sabrParameter, curves);
    final CurrencyAmount pv = METHOD.presentValue(CAP_HIGH_LONG, sabrBundle);
    final PresentValueSABRSensitivityDataBundle pvsCapLong =
        METHOD.presentValueSABRSensitivity(CAP_HIGH_LONG, sabrBundle);
    PresentValueSABRSensitivityDataBundle pvsCapShort =
        METHOD.presentValueSABRSensitivity(CAP_HIGH_SHORT, sabrBundle);
    // Long/short parity
    pvsCapShort = pvsCapShort.multiplyBy(-1.0);
    assertEquals(pvsCapShort.getAlpha(), pvsCapLong.getAlpha());
    // SABR sensitivity vs finite difference
    final double shift = 0.0001;
    final double shiftAlpha = 0.00001;
    final DoublesPair expectedExpiryTenor =
        new DoublesPair(
            CAP_HIGH_LONG.getFixingTime(),
            CAP_HIGH_LONG.getFixingPeriodEndTime() - CAP_HIGH_LONG.getFixingPeriodStartTime());
    // Alpha sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterAlphaBumped =
        TestsDataSetsSABR.createSABR1AlphaBumped(shiftAlpha);
    final SABRInterestRateDataBundle sabrBundleAlphaBumped =
        new SABRInterestRateDataBundle(sabrParameterAlphaBumped, curves);
    final CurrencyAmount pvLongPayerAlphaBumped =
        METHOD.presentValue(CAP_HIGH_LONG, sabrBundleAlphaBumped);
    final double expectedAlphaSensi =
        (pvLongPayerAlphaBumped.getAmount() - pv.getAmount()) / 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),
        1.0E-0);
    // Rho sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterRhoBumped =
        TestsDataSetsSABR.createSABR1RhoBumped();
    final SABRInterestRateDataBundle sabrBundleRhoBumped =
        new SABRInterestRateDataBundle(sabrParameterRhoBumped, curves);
    final CurrencyAmount pvLongPayerRhoBumped =
        METHOD.presentValue(CAP_HIGH_LONG, sabrBundleRhoBumped);
    final double expectedRhoSensi = (pvLongPayerRhoBumped.getAmount() - pv.getAmount()) / 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",
        pvsCapLong.getRho().getMap().get(expectedExpiryTenor),
        expectedRhoSensi,
        1.0E-1);
    // Alpha sensitivity vs finite difference computation
    final SABRInterestRateParameters sabrParameterNuBumped =
        TestsDataSetsSABR.createSABR1NuBumped();
    final SABRInterestRateDataBundle sabrBundleNuBumped =
        new SABRInterestRateDataBundle(sabrParameterNuBumped, curves);
    final CurrencyAmount pvLongPayerNuBumped =
        METHOD.presentValue(CAP_HIGH_LONG, sabrBundleNuBumped);
    final double expectedNuSensi = (pvLongPayerNuBumped.getAmount() - pv.getAmount()) / shift;
    assertEquals("Number of nu sensitivity", pvsCapLong.getNu().getMap().keySet().size(), 1);
    assertEquals(
        "Nu sensitivity expiry/tenor",
        pvsCapLong.getNu().getMap().keySet().contains(expectedExpiryTenor),
        true);
    assertEquals(
        "Nu sensitivity value",
        pvsCapLong.getNu().getMap().get(expectedExpiryTenor),
        expectedNuSensi,
        2.0E-1);
  }
}
public class CouponInflationYearOnYearInterpolationDefinitionTest {

  private static final String NAME = "Euro HICP x";
  private static final Currency CUR = Currency.EUR;
  private static final IndexPrice PRICE_INDEX = new IndexPrice(NAME, CUR);
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final ZonedDateTime START_DATE = DateUtils.getUTCDate(2008, 8, 18);
  private static final Period COUPON_TENOR = Period.ofYears(10);
  private static final ZonedDateTime PAYMENT_DATE =
      ScheduleCalculator.getAdjustedDate(START_DATE, COUPON_TENOR, BUSINESS_DAY, CALENDAR);
  private static final ZonedDateTime ACCRUAL_END_DATE = PAYMENT_DATE;
  private static final ZonedDateTime ACCRUAL_START_DATE = ACCRUAL_END_DATE.minusMonths(12);
  private static final double NOTIONAL = 98765432;
  private static final int MONTH_LAG = 3;
  private static final ZonedDateTime[] REFERENCE_START_DATE = new ZonedDateTime[2];

  static {
    REFERENCE_START_DATE[0] = ACCRUAL_START_DATE.minusMonths(MONTH_LAG).withDayOfMonth(1);
    REFERENCE_START_DATE[1] = REFERENCE_START_DATE[0].plusMonths(1);
  }

  private static final ZonedDateTime[] REFERENCE_END_DATE = new ZonedDateTime[2];

  static {
    REFERENCE_END_DATE[0] = PAYMENT_DATE.minusMonths(MONTH_LAG).withDayOfMonth(1);
    REFERENCE_END_DATE[1] = REFERENCE_END_DATE[0].plusMonths(1);
  }

  private static final double WEIGHT_START = 0.2;
  private static final double WEIGHT_END = 0.8;
  private static final CouponInflationYearOnYearInterpolationDefinition YoY_COUPON_DEFINITION =
      new CouponInflationYearOnYearInterpolationDefinition(
          CUR,
          PAYMENT_DATE,
          ACCRUAL_START_DATE,
          ACCRUAL_END_DATE,
          1.0,
          NOTIONAL,
          PRICE_INDEX,
          MONTH_LAG,
          3,
          REFERENCE_START_DATE,
          REFERENCE_END_DATE,
          false,
          WEIGHT_START,
          WEIGHT_END);
  private static final String DISCOUNTING_CURVE_NAME = "Discounting";
  private static final String PRICE_INDEX_CURVE_NAME = "Price index";
  private static final String[] CURVE_NAMES =
      new String[] {DISCOUNTING_CURVE_NAME, PRICE_INDEX_CURVE_NAME};
  private static final DayCount ACT_ACT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullCurrency() {
    new CouponInflationYearOnYearInterpolationDefinition(
        null,
        PAYMENT_DATE,
        ACCRUAL_START_DATE,
        PAYMENT_DATE,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        REFERENCE_END_DATE,
        false,
        WEIGHT_START,
        WEIGHT_END);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullPay() {
    new CouponInflationYearOnYearInterpolationDefinition(
        CUR,
        null,
        ACCRUAL_START_DATE,
        PAYMENT_DATE,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        REFERENCE_END_DATE,
        false,
        WEIGHT_START,
        WEIGHT_END);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullStart() {
    new CouponInflationYearOnYearInterpolationDefinition(
        CUR,
        PAYMENT_DATE,
        null,
        PAYMENT_DATE,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        REFERENCE_END_DATE,
        false,
        WEIGHT_START,
        WEIGHT_END);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullEnd() {
    new CouponInflationYearOnYearInterpolationDefinition(
        CUR,
        PAYMENT_DATE,
        ACCRUAL_START_DATE,
        null,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        REFERENCE_END_DATE,
        false,
        WEIGHT_START,
        WEIGHT_END);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullIndex() {
    new CouponInflationYearOnYearInterpolationDefinition(
        CUR,
        PAYMENT_DATE,
        ACCRUAL_START_DATE,
        PAYMENT_DATE,
        1.0,
        NOTIONAL,
        null,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        REFERENCE_END_DATE,
        false,
        WEIGHT_START,
        WEIGHT_END);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullRefStart() {
    new CouponInflationYearOnYearInterpolationDefinition(
        CUR,
        PAYMENT_DATE,
        ACCRUAL_START_DATE,
        PAYMENT_DATE,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        MONTH_LAG,
        3,
        null,
        REFERENCE_END_DATE,
        false,
        WEIGHT_START,
        WEIGHT_END);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullRefEnd() {
    new CouponInflationYearOnYearInterpolationDefinition(
        CUR,
        PAYMENT_DATE,
        ACCRUAL_START_DATE,
        PAYMENT_DATE,
        1.0,
        NOTIONAL,
        PRICE_INDEX,
        MONTH_LAG,
        3,
        REFERENCE_START_DATE,
        null,
        false,
        WEIGHT_START,
        WEIGHT_END);
  }

  @Test
  /** Tests the class getter. */
  public void getter() {
    assertEquals("Inflation Year on Year coupon: getter", CUR, YoY_COUPON_DEFINITION.getCurrency());
    assertEquals(
        "Inflation Year on Year coupon: getter",
        PAYMENT_DATE,
        YoY_COUPON_DEFINITION.getPaymentDate());
    assertEquals(
        "Inflation Year on Year coupon: getter",
        ACCRUAL_START_DATE,
        YoY_COUPON_DEFINITION.getAccrualStartDate());
    assertEquals(
        "Inflation Year on Year coupon: getter",
        ACCRUAL_END_DATE,
        YoY_COUPON_DEFINITION.getAccrualEndDate());
    assertEquals(
        "Inflation Year on Year coupon: getter",
        1.0,
        YoY_COUPON_DEFINITION.getPaymentYearFraction());
    assertEquals(
        "Inflation Year on Year coupon: getter", NOTIONAL, YoY_COUPON_DEFINITION.getNotional());
    assertEquals(
        "Inflation Year on Year coupon: getter",
        PRICE_INDEX,
        YoY_COUPON_DEFINITION.getPriceIndex());
    assertEquals(
        "Inflation Year on Year coupon: getter",
        REFERENCE_START_DATE,
        YoY_COUPON_DEFINITION.getReferenceStartDate());
    assertEquals(
        "Inflation Year on Year coupon: getter",
        REFERENCE_END_DATE,
        YoY_COUPON_DEFINITION.getReferenceEndDate());
    assertEquals(
        "Inflation Year on Year coupon: getter",
        MONTH_LAG,
        YoY_COUPON_DEFINITION.getConventionalMonthLag());
  }

  @Test
  /** Tests the equal and hash-code methods. */
  public void equalHash() {
    assertEquals(YoY_COUPON_DEFINITION, YoY_COUPON_DEFINITION);
    CouponInflationYearOnYearInterpolationDefinition couponDuplicate =
        new CouponInflationYearOnYearInterpolationDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            false,
            WEIGHT_START,
            WEIGHT_END);
    assertEquals(YoY_COUPON_DEFINITION, couponDuplicate);
    assertEquals(YoY_COUPON_DEFINITION.hashCode(), couponDuplicate.hashCode());
    CouponInflationYearOnYearInterpolationDefinition modified;
    modified =
        new CouponInflationYearOnYearInterpolationDefinition(
            CUR,
            ACCRUAL_END_DATE.minusDays(1),
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            false,
            WEIGHT_START,
            WEIGHT_END);
    assertFalse(YoY_COUPON_DEFINITION.equals(modified));
    modified =
        new CouponInflationYearOnYearInterpolationDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE.minusDays(1),
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            false,
            WEIGHT_START,
            WEIGHT_END);
    assertFalse(YoY_COUPON_DEFINITION.equals(modified));
    modified =
        new CouponInflationYearOnYearInterpolationDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE.minusDays(1),
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            false,
            WEIGHT_START,
            WEIGHT_END);
    assertFalse(YoY_COUPON_DEFINITION.equals(modified));
    final ZonedDateTime[] modifiedReferenceStartTime = new ZonedDateTime[2];
    modifiedReferenceStartTime[0] = REFERENCE_START_DATE[0];
    modifiedReferenceStartTime[1] = REFERENCE_START_DATE[1].minusDays(1);
    modified =
        new CouponInflationYearOnYearInterpolationDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            modifiedReferenceStartTime,
            REFERENCE_END_DATE,
            false,
            WEIGHT_START,
            WEIGHT_END);
    assertFalse(YoY_COUPON_DEFINITION.equals(modified));
    final ZonedDateTime[] modifiedReferenceEndTime = new ZonedDateTime[2];
    modifiedReferenceEndTime[0] = REFERENCE_START_DATE[0];
    modifiedReferenceEndTime[1] = REFERENCE_START_DATE[1].minusDays(1);
    modified =
        new CouponInflationYearOnYearInterpolationDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            modifiedReferenceEndTime,
            false,
            WEIGHT_START,
            WEIGHT_END);
    assertFalse(YoY_COUPON_DEFINITION.equals(modified));
    modified =
        new CouponInflationYearOnYearInterpolationDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            2.0,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            false,
            WEIGHT_START,
            WEIGHT_END);
    assertFalse(YoY_COUPON_DEFINITION.equals(modified));
    modified =
        new CouponInflationYearOnYearInterpolationDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL + 10.0,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            false,
            WEIGHT_START,
            WEIGHT_END);
    assertFalse(YoY_COUPON_DEFINITION.equals(modified));
    modified =
        new CouponInflationYearOnYearInterpolationDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            false,
            WEIGHT_START + .1,
            WEIGHT_END);
    assertFalse(YoY_COUPON_DEFINITION.equals(modified));
    modified =
        new CouponInflationYearOnYearInterpolationDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            ACCRUAL_END_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            false,
            WEIGHT_START,
            WEIGHT_END + .1);
    assertFalse(YoY_COUPON_DEFINITION.equals(modified));
  }

  @Test
  /** Tests the first based on indexation lag. */
  public void from2() {
    CouponInflationYearOnYearInterpolationDefinition constructor =
        new CouponInflationYearOnYearInterpolationDefinition(
            CUR,
            PAYMENT_DATE,
            ACCRUAL_START_DATE,
            PAYMENT_DATE,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            3,
            REFERENCE_START_DATE,
            REFERENCE_END_DATE,
            false,
            WEIGHT_START,
            WEIGHT_END);
    CouponInflationYearOnYearInterpolationDefinition from =
        CouponInflationYearOnYearInterpolationDefinition.from(
            ACCRUAL_START_DATE,
            PAYMENT_DATE,
            NOTIONAL,
            PRICE_INDEX,
            MONTH_LAG,
            false,
            WEIGHT_START,
            WEIGHT_END);
    assertEquals("Inflation zero-coupon : from", constructor, from);
  }

  @Test
  public void toDerivativesNoData() {
    final ZonedDateTime pricingDate = DateUtils.getUTCDate(2011, 7, 29);
    Coupon yearOnYearCouponConverted = YoY_COUPON_DEFINITION.toDerivative(pricingDate, CURVE_NAMES);
    double paymentTime = ACT_ACT.getDayCountFraction(pricingDate, PAYMENT_DATE);
    final double referenceStartTime0 =
        ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_START_DATE[0]);
    final double referenceEndTime0 =
        ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_END_DATE[0]);
    final double referenceStartTime1 =
        ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_START_DATE[1]);
    final double referenceEndTime1 =
        ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_END_DATE[1]);
    final double naturalPaymentStartPaymentTime =
        ACT_ACT.getDayCountFraction(pricingDate, ACCRUAL_START_DATE);
    final double naturalPaymentEndPaymentTime =
        ACT_ACT.getDayCountFraction(pricingDate, ACCRUAL_END_DATE);
    final double[] referenceStartTime = new double[2];
    final double[] referenceEndTime = new double[2];
    referenceStartTime[0] = referenceStartTime0;
    referenceStartTime[1] = referenceStartTime1;
    referenceEndTime[0] = referenceEndTime0;
    referenceEndTime[1] = referenceEndTime1;
    CouponInflationYearOnYearInterpolation yearOnYearCoupon =
        new CouponInflationYearOnYearInterpolation(
            CUR,
            paymentTime,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            referenceStartTime,
            naturalPaymentStartPaymentTime,
            referenceEndTime,
            naturalPaymentEndPaymentTime,
            false,
            WEIGHT_START,
            WEIGHT_END);
    assertEquals(
        "Inflation year on year coupon: toDerivative", yearOnYearCouponConverted, yearOnYearCoupon);
  }

  @Test
  public void toDerivativesStartMonthNotknown() {
    final ZonedDateTime pricingDate = DateUtils.getUTCDate(2011, 7, 29);
    final DoubleTimeSeries<ZonedDateTime> priceIndexTS =
        ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(
            new ZonedDateTime[] {
              DateUtils.getUTCDate(2017, 5, 1),
              DateUtils.getUTCDate(2017, 6, 1),
              DateUtils.getUTCDate(2018, 5, 1),
              DateUtils.getUTCDate(2018, 6, 1)
            },
            new double[] {127.23, 127.43, 128.23, 128.43});
    Coupon yearOnYearCouponConverted =
        YoY_COUPON_DEFINITION.toDerivative(pricingDate, priceIndexTS, CURVE_NAMES);
    double paymentTime = ACT_ACT.getDayCountFraction(pricingDate, PAYMENT_DATE);
    final double referenceStartTime0 =
        ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_START_DATE[0]);
    final double referenceEndTime0 =
        ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_END_DATE[0]);
    final double referenceStartTime1 =
        ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_START_DATE[1]);
    final double referenceEndTime1 =
        ACT_ACT.getDayCountFraction(pricingDate, REFERENCE_END_DATE[1]);
    final double naturalPaymentStartPaymentTime =
        ACT_ACT.getDayCountFraction(pricingDate, ACCRUAL_START_DATE);
    final double naturalPaymentEndPaymentTime =
        ACT_ACT.getDayCountFraction(pricingDate, ACCRUAL_END_DATE);
    final double[] referenceStartTime = new double[2];
    final double[] referenceEndTime = new double[2];
    referenceStartTime[0] = referenceStartTime0;
    referenceStartTime[1] = referenceStartTime1;
    referenceEndTime[0] = referenceEndTime0;
    referenceEndTime[1] = referenceEndTime1;
    CouponInflationYearOnYearInterpolation yearOnYearCoupon =
        new CouponInflationYearOnYearInterpolation(
            CUR,
            paymentTime,
            1.0,
            NOTIONAL,
            PRICE_INDEX,
            referenceStartTime,
            naturalPaymentStartPaymentTime,
            referenceEndTime,
            naturalPaymentEndPaymentTime,
            false,
            WEIGHT_START,
            WEIGHT_END);
    assertEquals(
        "Inflation zero-coupon: toDerivative", yearOnYearCoupon, yearOnYearCouponConverted);
  }

  @Test
  public void toDerivativesStartMonthKnown() {
    final ZonedDateTime pricingDate = DateUtils.getUTCDate(2018, 6, 25);
    final DoubleTimeSeries<ZonedDateTime> priceIndexTS =
        ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(
            new ZonedDateTime[] {
              DateUtils.getUTCDate(2017, 5, 1),
              DateUtils.getUTCDate(2017, 6, 1),
              DateUtils.getUTCDate(2018, 5, 1),
              DateUtils.getUTCDate(2018, 6, 1)
            },
            new double[] {127.23, 127.43, 128.23, 128.43});
    Coupon zeroCouponConverted =
        YoY_COUPON_DEFINITION.toDerivative(pricingDate, priceIndexTS, CURVE_NAMES);
    double paymentTime = ACT_ACT.getDayCountFraction(pricingDate, PAYMENT_DATE);
    CouponFixed zeroCoupon =
        new CouponFixed(
            CUR,
            paymentTime,
            DISCOUNTING_CURVE_NAME,
            1.0,
            NOTIONAL,
            (WEIGHT_END * 128.23 + (1 - WEIGHT_END) * 128.43)
                    / (WEIGHT_START * 127.23 + (1 - WEIGHT_START) * 127.43)
                - 1.0);
    assertEquals("Inflation zero-coupon: toDerivative", zeroCoupon, zeroCouponConverted);
  }
}
/**
 * This prices a CDS using the ISDA methodology. The API of the public functions mimic as far a
 * possible the ISDA high level ISDA c functions. However this is NOT a line-by-line translation of
 * the ISDA code. We find agreement with ISDA to better than 1 part in 10^12 on a test suit of 200
 * example.
 */
public class ISDACompliantPresentValueCreditDefaultSwap {

  @SuppressWarnings("unused")
  private static final int DEFAULT_CASH_SETTLEMENT_DAYS = 3;

  private static final BusinessDayConvention FOLLOWING =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Following");
  private static final Calendar DEFAULT_CALENDAR = new MondayToFridayCalendar("Weekend_Only");

  private static final DayCount ACT_365 = DayCountFactory.INSTANCE.getDayCount("ACT/365");
  private static final DayCount ACT_360 = DayCountFactory.INSTANCE.getDayCount("ACT/360");

  private final BusinessDayConvention _businessdayAdjustmentConvention;
  private final Calendar _calandar;
  private final DayCount _accuralDayCount;
  private final DayCount _curveDayCount;

  public ISDACompliantPresentValueCreditDefaultSwap() {
    _businessdayAdjustmentConvention = FOLLOWING;
    _calandar = DEFAULT_CALENDAR;
    _accuralDayCount = ACT_360;
    _curveDayCount = ACT_365;
  }

  /**
   * This is the present value of the premium leg per unit of fractional spread - hence it is equal
   * to 10,000 times the RPV01 (Risky PV01). The actual PV of the leg is this multiplied by the
   * notional and the fractional spread (i.e. spread in basis points divided by 10,000)
   *
   * <p>This mimics the ISDA c function <b>JpmcdsCdsFeeLegPV</b>
   *
   * @param today The 'current' date
   * @param stepinDate Date when party assumes ownership. This is normally today + 1 (T+1). Aka
   *     assignment date or effective date.
   * @param valueDate The valuation date. The date that values are PVed to. Is is normally today + 3
   *     business days. Aka cash-settle date.
   * @param startDate The protection start date. If protectStart = true, then protections starts at
   *     the beginning of the day, otherwise it is at the end.
   * @param endDate The protection end date (the protection ends at end of day)
   * @param payAccOnDefault Is the accrued premium paid in the event of a default
   * @param tenor The nominal step between premium payments (e.g. 3 months, 6 months).
   * @param stubType stubType Options are FRONTSHORT, FRONTLONG, BACKSHORT, BACKLONG or NONE -
   *     <b>Note</b> in this code NONE is not allowed
   * @param yieldCurve Curve from which payments are discounted
   * @param hazardRateCurve Curve giving survival probability
   * @param protectStart Does protection start at the beginning of the day
   * @param priceType Clean or Dirty price. The clean price removes the accrued premium if the trade
   *     is between payment times.
   * @return 10,000 times the RPV01 (on a notional of 1)
   */
  public double pvPremiumLegPerUnitSpread(
      final LocalDate today,
      final LocalDate stepinDate,
      final LocalDate valueDate,
      final LocalDate startDate,
      final LocalDate endDate,
      final boolean payAccOnDefault,
      final Period tenor,
      final StubType stubType,
      final ISDACompliantDateYieldCurve yieldCurve,
      final ISDACompliantDateCreditCurve hazardRateCurve,
      final boolean protectStart,
      final PriceType priceType) {
    ArgumentChecker.notNull(today, "null today");
    ArgumentChecker.notNull(stepinDate, "null stepinDate");
    ArgumentChecker.notNull(valueDate, "null valueDate");
    ArgumentChecker.notNull(startDate, "null startDate");
    ArgumentChecker.notNull(endDate, "null endDate");
    ArgumentChecker.notNull(tenor, "null tenor");
    ArgumentChecker.notNull(stubType, "null stubType");
    ArgumentChecker.notNull(yieldCurve, "null yieldCurve");
    ArgumentChecker.notNull(hazardRateCurve, "null hazardRateCurve");
    ArgumentChecker.notNull(priceType, "null priceType");
    ArgumentChecker.isFalse(valueDate.isBefore(today), "Require valueDate >= today");
    ArgumentChecker.isFalse(stepinDate.isBefore(today), "Require stepin >= today");

    final ISDAPremiumLegSchedule paymentSchedule =
        new ISDAPremiumLegSchedule(
            startDate,
            endDate,
            tenor,
            stubType,
            _businessdayAdjustmentConvention,
            _calandar,
            protectStart);
    final int nPayments = paymentSchedule.getNumPayments();

    // these are potentially different from startDate and endDate
    final LocalDate globalAccStart = paymentSchedule.getAccStartDate(0);
    final LocalDate golobalAccEnd = paymentSchedule.getAccEndDate(nPayments - 1);

    // TODO this logic could be part of ISDAPremiumLegSchdule
    final LocalDate matDate = protectStart ? golobalAccEnd.minusDays(1) : golobalAccEnd;

    if (today.isAfter(matDate) || stepinDate.isAfter(matDate)) {
      return 0.0; // trade has expired
    }

    final LocalDate[] yieldCurveDates = yieldCurve.getCurveDates();
    final LocalDate[] creditCurveDates = hazardRateCurve.getCurveDates();
    // This is common to the protection leg
    final LocalDate[] integrationSchedule =
        payAccOnDefault
            ? getIntegrationNodesAsDates(
                globalAccStart, golobalAccEnd, yieldCurveDates, creditCurveDates)
            : null;
    final int obsOffset = protectStart ? -1 : 0; // protection start at the beginning or end day

    double rpv01 = 0.0;
    for (int i = 0; i < nPayments; i++) {

      final LocalDate accStart = paymentSchedule.getAccStartDate(i);
      final LocalDate accEnd = paymentSchedule.getAccEndDate(i);
      final LocalDate pay = paymentSchedule.getPaymentDate(i);

      if (!accEnd.isAfter(stepinDate)) {
        continue; // this cashflow has already been realised
      }

      final double[] temp =
          calculateSinglePeriodRPV01(
              today, accStart, accEnd, pay, obsOffset, yieldCurve, hazardRateCurve);
      rpv01 += temp[0];

      if (payAccOnDefault) {
        final LocalDate offsetStepinDate = stepinDate.plusDays(obsOffset);
        final LocalDate offsetAccStartDate = accStart.plusDays(obsOffset);
        final LocalDate offsetAccEndDate = accEnd.plusDays(obsOffset);
        rpv01 +=
            calculateSinglePeriodAccrualOnDefault(
                today,
                offsetStepinDate,
                offsetAccStartDate,
                offsetAccEndDate,
                temp[1],
                yieldCurve,
                hazardRateCurve,
                integrationSchedule);
      }
    }

    // Compute the discount factor discounting the upfront payment made on the cash settlement date
    // back to the valuation date
    final double t = _curveDayCount.getDayCountFraction(today, valueDate);
    final double df = yieldCurve.getDiscountFactor(t);
    rpv01 /= df;

    // Do we want to calculate the clean price (includes the previously accrued portion of the
    // premium)
    if (priceType == PriceType.CLEAN) {
      rpv01 -= calculateAccruedInterest(paymentSchedule, stepinDate);
    }

    return rpv01;
  }

  /**
   * Computes the risky present value of a premium payment
   *
   * <p>This mimics the ISDA c code function <b>FeePaymentPVWithTimeLine<b>
   *
   * @param today
   * @param valueDate
   * @param stepinDate
   * @param accStartDate
   * @param accEndDate
   * @param payAccOnDefault
   * @return PV
   */
  private double[] calculateSinglePeriodRPV01(
      final LocalDate today,
      final LocalDate accStartDate,
      final LocalDate accEndDate,
      final LocalDate paymentDate,
      final int obsOffset,
      final ISDACompliantDateYieldCurve yieldCurve,
      final ISDACompliantDateCreditCurve hazardRateCurve) {

    final double accTime = _accuralDayCount.getDayCountFraction(accStartDate, accEndDate);
    double t = _curveDayCount.getDayCountFraction(today, paymentDate);
    double tObsOffset = _curveDayCount.getDayCountFraction(today, accEndDate.plusDays(obsOffset));

    // TODO Do we need this?
    // Compensate Java shortcoming
    if (Double.compare(t, -0.0) == 0) {
      t = 0;
    }
    if (Double.compare(tObsOffset, -0.0) == 0) {
      tObsOffset = 0;
    }

    final double survival = hazardRateCurve.getSurvivalProbability(tObsOffset);
    final double discount = yieldCurve.getDiscountFactor(t);
    return new double[] {accTime * discount * survival, accTime};
  }

  /**
   * this mimics the ISDA c JpmcdsAccrualOnDefaultPVWithTimeLine
   *
   * @param today
   * @param valueDate
   * @param offsetStepinDate
   * @param offsetAccStartDate
   * @param offsetAccEndDate
   * @param obsOffset
   * @param yieldCurve
   * @param hazardRateCurve
   * @param integrationSchedule
   * @return The single period accrual on default
   */
  private double calculateSinglePeriodAccrualOnDefault(
      final LocalDate today,
      final LocalDate offsetStepinDate,
      final LocalDate offsetAccStartDate,
      final LocalDate offsetAccEndDate,
      final double accTime,
      final ISDACompliantDateYieldCurve yieldCurve,
      final ISDACompliantDateCreditCurve hazardRateCurve,
      final LocalDate[] integrationSchedule) {

    final LocalDate[] truncatedDateList =
        truncateList(offsetAccStartDate, offsetAccEndDate, integrationSchedule);
    final int nItems = truncatedDateList.length;

    // max(offsetStepinDate,offsetAccStartDate)
    LocalDate subStartDate =
        offsetStepinDate.isAfter(offsetAccStartDate) ? offsetStepinDate : offsetAccStartDate;

    final double tAcc =
        ACT_365.getDayCountFraction(
            offsetAccStartDate, offsetAccEndDate); // This is hardcoded to ACT/365 in ISDA code
    final double accRate = accTime / tAcc;
    double t = ACT_365.getDayCountFraction(today, subStartDate);

    // Compensate Java shortcoming
    if (Double.compare(t, -0.0) == 0) {
      t = 0;
    }
    double s0 = hazardRateCurve.getSurvivalProbability(t);
    double df0 = yieldCurve.getDiscountFactor(t);

    double myPV = 0.0;
    for (int j = 1; j < nItems; ++j) {

      if (!truncatedDateList[j].isAfter(offsetStepinDate)) {
        continue;
      }

      double thisAccPV = 0.0;
      t = ACT_365.getDayCountFraction(today, truncatedDateList[j]);
      final double s1 = hazardRateCurve.getSurvivalProbability(t);
      final double df1 = yieldCurve.getDiscountFactor(t);

      final double t0 =
          ACT_365.getDayCountFraction(offsetAccStartDate, subStartDate)
              + 1 / 730.; // add on half a day
      final double t1 =
          ACT_365.getDayCountFraction(offsetAccStartDate, truncatedDateList[j]) + 1 / 730.;
      t = t1 - t0; // t repurposed

      // TODO check for s0 == s1 -> zero prob of default (and thus zero PV contribution) from this
      // section
      // if (s0 == s1) {
      // continue;
      // }

      // TODO this is a know bug that is fixed in ISDA v.1.8.2

      final double lambda = Math.log(s0 / s1) / t;
      final double fwdRate = Math.log(df0 / df1) / t;
      final double lambdafwdRate = lambda + fwdRate + 1.0e-50;

      thisAccPV =
          lambda
              * accRate
              * s0
              * df0
              * ((t0 + 1.0 / (lambdafwdRate)) / (lambdafwdRate)
                  - (t1 + 1.0 / (lambdafwdRate)) / (lambdafwdRate) * s1 / s0 * df1 / df0);
      myPV += thisAccPV;
      s0 = s1;
      df0 = df1;
      subStartDate = truncatedDateList[j];
    }
    return myPV;
  }

  /**
   * Calculate the accrued premium at the start of a trade
   *
   * @param premiumLegSchedule
   * @param stepinDate The trade effective date
   * @return accrued premium
   */
  private double calculateAccruedInterest(
      final ISDAPremiumLegSchedule premiumLegSchedule, final LocalDate stepinDate) {

    final int n = premiumLegSchedule.getNumPayments();

    // stepinDate is before first accStart or after last accEnd
    if (!stepinDate.isAfter(premiumLegSchedule.getAccStartDate(0))
        || !stepinDate.isBefore(premiumLegSchedule.getAccEndDate(n - 1))) {
      return 0.0;
    }

    int index = premiumLegSchedule.getAccStartDateIndex(stepinDate);
    if (index >= 0) {
      return 0.0; // on accrual start date
    }

    index = -(index + 1); // binary search notation
    if (index == 0) {
      throw new MathException(
          "Error in calculateAccruedInterest - check logic"); // this should never be hit
    }

    return _accuralDayCount.getDayCountFraction(
        premiumLegSchedule.getAccStartDate(index - 1), stepinDate);
  }

  /**
   * Get the value of the protection leg for unit notional
   *
   * <p>This mimics the ISDA c function <b>JpmcdsCdsContingentLegPV</b>
   *
   * @param today The 'current' date
   * @param stepinDate Date when party assumes ownership. This is normally today + 1 (T+1). Aka
   *     assignment date or effective date.
   * @param valueDate The valuation date. The date that values are PVed to. Is is normally today + 3
   *     business days. Aka cash-settle date.
   * @param startDate The protection start date. If protectStart = true, then protections starts at
   *     the beginning of the day, otherwise it is at the end.
   * @param endDate The protection end date (the protection ends at end of day)
   * @param yieldCurve Curve from which payments are discounted
   * @param hazardRateCurve Curve giving survival probability
   * @param recoveryRate The recovery rate of the protected debt
   * @param protectStart Does protection start at the beginning of the day
   * @return unit notional PV of protection (or contingent) leg
   */
  public double calculateProtectionLeg(
      final LocalDate today,
      final LocalDate stepinDate,
      final LocalDate valueDate,
      final LocalDate startDate,
      final LocalDate endDate,
      final ISDACompliantDateYieldCurve yieldCurve,
      final ISDACompliantDateCreditCurve hazardRateCurve,
      final double recoveryRate,
      final boolean protectStart) {
    ArgumentChecker.notNull(today, "null today");
    ArgumentChecker.notNull(valueDate, "null valueDate");
    ArgumentChecker.notNull(startDate, "null startDate");
    ArgumentChecker.notNull(endDate, "null endDate");
    ArgumentChecker.notNull(yieldCurve, "null yieldCurve");
    ArgumentChecker.notNull(hazardRateCurve, "null hazardRateCurve");
    ArgumentChecker.isInRangeInclusive(0, 1.0, recoveryRate);
    ArgumentChecker.isFalse(valueDate.isBefore(today), "Require valueDate >= today");
    ArgumentChecker.isFalse(stepinDate.isBefore(today), "Require stepin >= today");

    if (recoveryRate == 1.0) {
      return 0.0;
    }

    final LocalDate temp = stepinDate.isAfter(startDate) ? stepinDate : startDate;
    final LocalDate effectiveStartDate = protectStart ? temp.minusDays(1) : temp;

    if (!endDate.isAfter(effectiveStartDate)) {
      return 0.0; // the protection has expired
    }

    final LocalDate[] yieldCurveDates = yieldCurve.getCurveDates();
    final LocalDate[] creditCurveDates = hazardRateCurve.getCurveDates();
    final double[] integrationSchedule =
        ISDACompliantScheduleGenerator.getIntegrationNodesAsTimes(
            today, effectiveStartDate, endDate, yieldCurveDates, creditCurveDates);

    // double s1 = hazardRateCurve.getSurvivalProbability(integrationSchedule[0]);
    // double df1 = yieldCurve.getDiscountFactor(integrationSchedule[0]);

    double ht1 = hazardRateCurve.getRT(integrationSchedule[0]);
    double rt1 = yieldCurve.getRT(integrationSchedule[0]);
    double s1 = Math.exp(-ht1);
    double p1 = Math.exp(-rt1);
    double pv = 0.0;
    final int n = integrationSchedule.length;
    for (int i = 1; i < n; ++i) {

      final double ht0 = ht1;
      final double rt0 = rt1;
      final double p0 = p1;
      final double s0 = s1;

      ht1 = hazardRateCurve.getRT(integrationSchedule[i]);
      rt1 = yieldCurve.getRT(integrationSchedule[i]);
      s1 = Math.exp(-ht1);
      p1 = Math.exp(-rt1);
      final double dht = ht1 - ht0;
      final double drt = rt1 - rt0;
      final double dhrt = dht + drt;

      // this is equivalent to the ISDA code without explicitly calculating the time step - it also
      // handles the limit
      double dPV;
      if (Math.abs(dhrt) < 1e-5) {
        dPV = dht * (1 - dhrt * (0.5 - dhrt / 6)) * p0 * s0;
      } else {
        dPV = dht / dhrt * (p0 * s0 - p1 * s1);
      }

      // *************
      // ISDA code
      // **************
      // final double dt = integrationSchedule[i] - integrationSchedule[i - 1];
      // final double s0 = s1;
      // final double df0 = df1;
      // s1 = hazardRateCurve.getSurvivalProbability(integrationSchedule[i]);
      // df1 = yieldCurve.getDiscountFactor(integrationSchedule[i]);
      // final double hazardRate = Math.log(s0 / s1) / dt;
      // final double interestRate = Math.log(df0 / df1) / dt;
      // pv += (hazardRate / (hazardRate + interestRate)) * (1.0 - Math.exp(-(hazardRate +
      // interestRate) * dt)) * s0 * df0;

      pv += dPV;
    }
    pv *= 1.0 - recoveryRate;
    // System.out.println(pv);

    // Compute the discount factor discounting the upfront payment made on the cash settlement date
    // back to the valuation date
    final double t = _curveDayCount.getDayCountFraction(today, valueDate);
    final double df = yieldCurve.getDiscountFactor(t);
    pv /= df;

    return pv;
  }

  // *****************************************************************************************************
  // Legacy stuff
  // *****************************************************************************************************

  /**
   * Get the RPV01 of the premium leg - i.e. the value of the leg per point of spread (expressed as
   * a fraction, so 1bs is 0.0001)
   *
   * <p>This exists to duplicate the function of the same name from PresentValueCreditDefaultSwap.
   * <b>Note</b> this version agrees with the ISDA c library.
   *
   * @param valuationDate The valuation date - this is taken to be the same as today
   * @param cds Description of the CDS
   * @param yieldCurve The discount curve
   * @param hazardRateCurve The survival curve
   * @param priceType Clean or dirty
   * @return The RPV01 of the premium leg
   * @deprecated use calculateRPV01
   */
  @Deprecated
  public double calculatePremiumLeg(
      final ZonedDateTime valuationDate,
      final CreditDefaultSwapDefinition cds,
      final ISDADateCurve yieldCurve,
      final HazardRateCurve hazardRateCurve,
      final PriceType priceType) {

    ArgumentChecker.notNull(valuationDate, "null valuationDate");
    ArgumentChecker.notNull(cds, "null cds");
    ArgumentChecker.notNull(yieldCurve, "null yieldCurve");
    ArgumentChecker.notNull(hazardRateCurve, "null hazardRateCurve");
    ArgumentChecker.notNull(priceType, "null priceType");

    final LocalDate valueDate = valuationDate.toLocalDate();
    final LocalDate today = valueDate;
    final LocalDate stepinDate = cds.getEffectiveDate().toLocalDate();
    final LocalDate startDate = cds.getStartDate().toLocalDate();
    final LocalDate endDate = cds.getMaturityDate().toLocalDate();

    return cds.getNotional()
        * pvPremiumLegPerUnitSpread(
            today,
            stepinDate,
            valueDate,
            startDate,
            endDate,
            cds.getIncludeAccruedPremium(),
            cds.getCouponFrequency().getPeriod(),
            cds.getStubType(),
            ISDACompliantDateYieldCurve.fromISDADateCurve(yieldCurve),
            ISDACompliantDateCreditCurve.fromHazardRateCurve(hazardRateCurve),
            cds.getProtectionStart(),
            priceType);
  }

  /**
   * Get the value of the contingent (or protection) leg
   *
   * <p>This exists to duplicate the function of the same name from PresentValueCreditDefaultSwap.
   * <b>Note</b> this version agrees with the ISDA c library.
   *
   * @param valuationDate The valuation date - this is taken to be the same as today
   * @param cds Description of the CDS
   * @param yieldCurve The discount curve
   * @param hazardRateCurve The survival curve
   * @return Present Value of protection (or contingent) leg
   * @deprecated use calculateProtectionLeg
   */
  @Deprecated
  public double calculateContingentLeg(
      final ZonedDateTime valuationDate,
      final CreditDefaultSwapDefinition cds,
      final ISDADateCurve yieldCurve,
      final HazardRateCurve hazardRateCurve) {
    ArgumentChecker.notNull(valuationDate, "null valuationDate");
    ArgumentChecker.notNull(cds, "null cds");
    ArgumentChecker.notNull(yieldCurve, "null yieldCurve");
    ArgumentChecker.notNull(hazardRateCurve, "null hazardRateCurve");

    final LocalDate valueDate = valuationDate.toLocalDate();
    final LocalDate today = valueDate;
    final LocalDate stepinDate = cds.getEffectiveDate().toLocalDate();
    final LocalDate startDate = cds.getStartDate().toLocalDate();
    final LocalDate endDate = cds.getMaturityDate().toLocalDate();
    final double rr = cds.getRecoveryRate();
    final boolean protectionStart = cds.getProtectionStart();

    return cds.getNotional()
        * calculateProtectionLeg(
            today,
            stepinDate,
            valueDate,
            startDate,
            endDate,
            ISDACompliantDateYieldCurve.fromISDADateCurve(yieldCurve),
            ISDACompliantDateCreditCurve.fromHazardRateCurve(hazardRateCurve),
            rr,
            protectionStart);
  }
}
/** Tests on the construction of interest rate future option with up-front payment. */
public class InterestRateFutureOptionMarginSecurityTest {
  // EURIBOR 3M Index
  private static final Period TENOR = Period.ofMonths(3);
  private static final int SETTLEMENT_DAYS = 2;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final DayCount DAY_COUNT_INDEX =
      DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final Currency CUR = Currency.EUR;
  private static final IborIndex IBOR_INDEX =
      new IborIndex(CUR, TENOR, SETTLEMENT_DAYS, DAY_COUNT_INDEX, BUSINESS_DAY, IS_EOM);
  // 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, -SETTLEMENT_DAYS, CALENDAR);
  private static final double NOTIONAL = 1000000.0; // 1m
  private static final double FUTURE_FACTOR = 0.25;
  private static final String NAME = "EDU2";
  private static final double STRIKE = 0.9850;
  private static final InterestRateFutureSecurityDefinition EDU2_DEFINITION =
      new InterestRateFutureSecurityDefinition(
          LAST_TRADING_DATE, IBOR_INDEX, NOTIONAL, FUTURE_FACTOR, NAME, CALENDAR);
  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};
  private static final InterestRateFutureSecurity EDU2 =
      EDU2_DEFINITION.toDerivative(REFERENCE_DATE, CURVES);
  // Option
  private static final ZonedDateTime EXPIRATION_DATE = DateUtils.getUTCDate(2011, 9, 16);
  private static final DayCount ACT_ACT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
  private static final double EXPIRATION_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE, EXPIRATION_DATE);
  private static final boolean IS_CALL = true;
  private static final InterestRateFutureOptionPremiumSecurity OPTION_EDU2 =
      new InterestRateFutureOptionPremiumSecurity(EDU2, EXPIRATION_TIME, STRIKE, IS_CALL);

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullUnderlying() {
    new InterestRateFutureOptionPremiumSecurity(null, EXPIRATION_TIME, STRIKE, IS_CALL);
  }

  @Test
  public void getter() {
    assertEquals(EDU2, OPTION_EDU2.getUnderlyingFuture());
    assertEquals(EXPIRATION_TIME, OPTION_EDU2.getExpirationTime());
    assertEquals(STRIKE, OPTION_EDU2.getStrike());
    assertEquals(IS_CALL, OPTION_EDU2.isCall());
    assertEquals(DISCOUNTING_CURVE_NAME, OPTION_EDU2.getDiscountingCurveName());
    assertEquals(FORWARD_CURVE_NAME, OPTION_EDU2.getForwardCurveName());
  }

  @Test
  /** Tests the equal and hash code methods. */
  public void equalHash() {
    final InterestRateFutureOptionPremiumSecurity newOption =
        new InterestRateFutureOptionPremiumSecurity(EDU2, EXPIRATION_TIME, STRIKE, IS_CALL);
    assertTrue(OPTION_EDU2.equals(newOption));
    assertEquals(OPTION_EDU2.hashCode(), newOption.hashCode());
    InterestRateFutureOptionPremiumSecurity modifiedOption;
    modifiedOption =
        new InterestRateFutureOptionPremiumSecurity(EDU2, EXPIRATION_TIME - 0.01, STRIKE, IS_CALL);
    assertFalse(OPTION_EDU2.equals(modifiedOption));
    modifiedOption =
        new InterestRateFutureOptionPremiumSecurity(EDU2, EXPIRATION_TIME, STRIKE + 0.01, IS_CALL);
    assertFalse(OPTION_EDU2.equals(modifiedOption));
    modifiedOption =
        new InterestRateFutureOptionPremiumSecurity(EDU2, EXPIRATION_TIME, STRIKE, !IS_CALL);
    assertFalse(OPTION_EDU2.equals(modifiedOption));
  }
}
/**
 * Tests for the methods related to interest rate securities pricing with Hull-White model convexity
 * adjustment.
 */
public class InterestRateFutureSecurityHullWhiteMethodTest {
  // EURIBOR 3M Index
  private static final Period TENOR = Period.ofMonths(3);
  private static final int SETTLEMENT_DAYS = 2;
  private static final Calendar CALENDAR = new MondayToFridayCalendar("A");
  private static final DayCount DAY_COUNT_INDEX =
      DayCountFactory.INSTANCE.getDayCount("Actual/360");
  private static final BusinessDayConvention BUSINESS_DAY =
      BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention("Modified Following");
  private static final boolean IS_EOM = true;
  private static final Currency CUR = Currency.EUR;
  private static final IborIndex IBOR_INDEX =
      new IborIndex(CUR, TENOR, SETTLEMENT_DAYS, CALENDAR, DAY_COUNT_INDEX, BUSINESS_DAY, IS_EOM);
  // Future
  private static final ZonedDateTime SPOT_LAST_TRADING_DATE = DateUtil.getUTCDate(2012, 9, 19);
  private static final ZonedDateTime LAST_TRADING_DATE =
      ScheduleCalculator.getAdjustedDate(SPOT_LAST_TRADING_DATE, CALENDAR, -SETTLEMENT_DAYS);
  private static final ZonedDateTime FIXING_END_DATE =
      ScheduleCalculator.getAdjustedDate(
          SPOT_LAST_TRADING_DATE, BUSINESS_DAY, CALENDAR, IS_EOM, TENOR);
  private static final double NOTIONAL = 1000000.0; // 1m
  private static final double FUTURE_FACTOR = 0.25;
  private static final String NAME = "ERU2";
  // Time version
  private static final LocalDate REFERENCE_DATE = LocalDate.of(2011, 5, 12);
  private static final DayCount ACT_ACT =
      DayCountFactory.INSTANCE.getDayCount("Actual/Actual ISDA");
  private static final ZonedDateTime REFERENCE_DATE_ZONED =
      ZonedDateTime.of(LocalDateTime.ofMidnight(REFERENCE_DATE), TimeZone.UTC);
  private static final double LAST_TRADING_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE_ZONED, LAST_TRADING_DATE);
  private static final double FIXING_START_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE_ZONED, SPOT_LAST_TRADING_DATE);
  private static final double FIXING_END_TIME =
      ACT_ACT.getDayCountFraction(REFERENCE_DATE_ZONED, FIXING_END_DATE);
  private static final double FIXING_ACCRUAL =
      DAY_COUNT_INDEX.getDayCountFraction(SPOT_LAST_TRADING_DATE, FIXING_END_DATE);
  private static final String DISCOUNTING_CURVE_NAME = "Funding";
  private static final String FORWARD_CURVE_NAME = "Forward";
  private static final InterestRateFutureSecurity ERU2 =
      new InterestRateFutureSecurity(
          LAST_TRADING_TIME,
          IBOR_INDEX,
          FIXING_START_TIME,
          FIXING_END_TIME,
          FIXING_ACCRUAL,
          NOTIONAL,
          FUTURE_FACTOR,
          NAME,
          DISCOUNTING_CURVE_NAME,
          FORWARD_CURVE_NAME);
  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 InterestRateFutureSecurityHullWhiteMethod METHOD =
      new InterestRateFutureSecurityHullWhiteMethod(MODEL_PARAMETERS);
  private static final HullWhiteOneFactorPiecewiseConstantInterestRateModel MODEL =
      new HullWhiteOneFactorPiecewiseConstantInterestRateModel();

  @Test
  /** Test the constructors. */
  public void constructor() {
    final InterestRateFutureSecurityHullWhiteMethod methodParameters =
        new InterestRateFutureSecurityHullWhiteMethod(MEAN_REVERSION, VOLATILITY, VOLATILITY_TIME);
    assertTrue(METHOD.equals(methodParameters));
  }

  @Test
  /** Test the price computed from the curves */
  public void price() {
    final YieldCurveBundle curves = TestsDataSets.createCurves1();
    final double price = METHOD.price(ERU2, curves);
    final YieldAndDiscountCurve forwardCurve = curves.getCurve(FORWARD_CURVE_NAME);
    final double forward =
        (forwardCurve.getDiscountFactor(FIXING_START_TIME)
                    / forwardCurve.getDiscountFactor(FIXING_END_TIME)
                - 1)
            / FIXING_ACCRUAL;
    final double factor = MODEL.futureConvexityFactor(ERU2, MODEL_PARAMETERS);
    final double expectedPrice = 1.0 - factor * forward + (1 - factor) / FIXING_ACCRUAL;
    assertEquals("Future price from curves in Hull-White one factor model", expectedPrice, price);
  }

  @Test
  /** Compare the price with a price without convexity adjustment. */
  public void comparisonDiscounting() {
    final YieldCurveBundle curves = TestsDataSets.createCurves1();
    final InterestRateFutureSecurityDiscountingMethod methodDiscounting =
        InterestRateFutureSecurityDiscountingMethod.getInstance();
    final double priceDiscounting = methodDiscounting.priceFromCurves(ERU2, curves);
    final double priceHullWhite = METHOD.price(ERU2, curves);
    assertTrue(
        "Future price comparison with no convexity adjustment", priceDiscounting > priceHullWhite);
  }

  @Test
  public void equalHash() {
    assertTrue(METHOD.equals(METHOD));
    InterestRateFutureSecurityHullWhiteMethod other =
        new InterestRateFutureSecurityHullWhiteMethod(MODEL_PARAMETERS);
    assertTrue(METHOD.equals(other));
    assertTrue(METHOD.hashCode() == other.hashCode());
    InterestRateFutureSecurityHullWhiteMethod modifiedMethod;
    HullWhiteOneFactorPiecewiseConstantParameters modifiedParameter =
        new HullWhiteOneFactorPiecewiseConstantParameters(
            MEAN_REVERSION * 2, VOLATILITY, VOLATILITY_TIME);
    modifiedMethod = new InterestRateFutureSecurityHullWhiteMethod(modifiedParameter);
    assertFalse(METHOD.equals(modifiedMethod));
    assertFalse(METHOD.equals(CUR));
    assertFalse(METHOD.equals(null));
  }
}