Esempio n. 1
0
 // -------------------------------------------------------------------------
 public void test_builder_ensureDefaults() {
   ResetSchedule test =
       ResetSchedule.builder()
           .resetFrequency(P1M)
           .businessDayAdjustment(BusinessDayAdjustment.of(FOLLOWING, GBLO))
           .build();
   assertEquals(test.getResetFrequency(), P1M);
   assertEquals(test.getBusinessDayAdjustment(), BusinessDayAdjustment.of(FOLLOWING, GBLO));
   assertEquals(test.getResetMethod(), UNWEIGHTED);
 }
Esempio n. 2
0
  // -----------------------------------------------------------------------
  // create a vanilla fixed vs libor 3m swap
  private static Trade createVanillaFixedVsLibor3mSwap() {
    NotionalSchedule notional = NotionalSchedule.of(Currency.USD, 100_000_000);

    SwapLeg payLeg =
        RateCalculationSwapLeg.builder()
            .payReceive(PayReceive.PAY)
            .accrualSchedule(
                PeriodicSchedule.builder()
                    .startDate(LocalDate.of(2014, 9, 12))
                    .endDate(LocalDate.of(2021, 9, 12))
                    .frequency(Frequency.P6M)
                    .businessDayAdjustment(
                        BusinessDayAdjustment.of(MODIFIED_FOLLOWING, HolidayCalendarIds.USNY))
                    .build())
            .paymentSchedule(
                PaymentSchedule.builder()
                    .paymentFrequency(Frequency.P6M)
                    .paymentDateOffset(DaysAdjustment.NONE)
                    .build())
            .notionalSchedule(notional)
            .calculation(FixedRateCalculation.of(0.015, DayCounts.THIRTY_U_360))
            .build();

    SwapLeg receiveLeg =
        RateCalculationSwapLeg.builder()
            .payReceive(PayReceive.RECEIVE)
            .accrualSchedule(
                PeriodicSchedule.builder()
                    .startDate(LocalDate.of(2014, 9, 12))
                    .endDate(LocalDate.of(2021, 9, 12))
                    .frequency(Frequency.P3M)
                    .businessDayAdjustment(
                        BusinessDayAdjustment.of(MODIFIED_FOLLOWING, HolidayCalendarIds.USNY))
                    .build())
            .paymentSchedule(
                PaymentSchedule.builder()
                    .paymentFrequency(Frequency.P3M)
                    .paymentDateOffset(DaysAdjustment.NONE)
                    .build())
            .notionalSchedule(notional)
            .calculation(IborRateCalculation.of(IborIndices.USD_LIBOR_3M))
            .build();

    return SwapTrade.builder()
        .product(Swap.of(payLeg, receiveLeg))
        .info(
            TradeInfo.builder()
                .addAttribute(TradeAttributeType.DESCRIPTION, "Fixed vs Libor 3m")
                .counterparty(StandardId.of("example", "A"))
                .settlementDate(LocalDate.of(2014, 9, 12))
                .build())
        .build();
  }
Esempio n. 3
0
 // -------------------------------------------------------------------------
 public void coverage() {
   ResetSchedule test =
       ResetSchedule.builder()
           .resetFrequency(P1M)
           .businessDayAdjustment(BusinessDayAdjustment.of(FOLLOWING, GBLO))
           .build();
   coverImmutableBean(test);
   ResetSchedule test2 =
       ResetSchedule.builder()
           .resetFrequency(P3M)
           .businessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO))
           .resetMethod(WEIGHTED)
           .build();
   coverBeanEquals(test, test2);
 }
Esempio n. 4
0
 public void test_serialization() {
   ResetSchedule test =
       ResetSchedule.builder()
           .resetFrequency(P1M)
           .businessDayAdjustment(BusinessDayAdjustment.of(FOLLOWING, GBLO))
           .build();
   assertSerialization(test);
 }
Esempio n. 5
0
 public void test_usdLibor3m() {
   IborIndex test = IborIndex.of("USD-LIBOR-3M");
   assertEquals(test.getCurrency(), USD);
   assertEquals(test.getName(), "USD-LIBOR-3M");
   assertEquals(test.getTenor(), TENOR_3M);
   assertEquals(test.getFixingCalendar(), GBLO);
   assertEquals(test.getFixingDateOffset(), DaysAdjustment.ofBusinessDays(-2, GBLO));
   assertEquals(
       test.getEffectiveDateOffset(),
       DaysAdjustment.ofBusinessDays(
           2, GBLO, BusinessDayAdjustment.of(FOLLOWING, GBLO.combineWith(USNY))));
   assertEquals(
       test.getMaturityDateOffset(),
       TenorAdjustment.ofLastBusinessDay(
           TENOR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO.combineWith(USNY))));
   assertEquals(test.getDayCount(), ACT_360);
   assertEquals(test.toString(), "USD-LIBOR-3M");
 }
Esempio n. 6
0
 public void test_gbpLibor3m() {
   IborIndex test = IborIndex.of("GBP-LIBOR-3M");
   assertEquals(test.getCurrency(), GBP);
   assertEquals(test.getName(), "GBP-LIBOR-3M");
   assertEquals(test.getTenor(), TENOR_3M);
   assertEquals(test.getFixingCalendar(), GBLO);
   assertEquals(
       test.getFixingDateOffset(),
       DaysAdjustment.ofCalendarDays(0, BusinessDayAdjustment.of(PRECEDING, GBLO)));
   assertEquals(
       test.getEffectiveDateOffset(),
       DaysAdjustment.ofCalendarDays(0, BusinessDayAdjustment.of(FOLLOWING, GBLO)));
   assertEquals(
       test.getMaturityDateOffset(),
       TenorAdjustment.ofLastBusinessDay(
           TENOR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO)));
   assertEquals(test.getDayCount(), ACT_365F);
   assertEquals(test.toString(), "GBP-LIBOR-3M");
 }
 public void test_of_indexOnly() {
   ImmutableIborFixingDepositConvention test =
       ImmutableIborFixingDepositConvention.of(GBP_LIBOR_6M);
   assertEquals(
       test.getBusinessDayAdjustment(),
       BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBP_LIBOR_6M.getFixingCalendar()));
   assertEquals(test.getCurrency(), GBP_LIBOR_6M.getCurrency());
   assertEquals(test.getDayCount(), GBP_LIBOR_6M.getDayCount());
   assertEquals(test.getFixingDateOffset(), GBP_LIBOR_6M.getFixingDateOffset());
   assertEquals(test.getIndex(), GBP_LIBOR_6M);
   assertEquals(test.getSpotDateOffset(), GBP_LIBOR_6M.getEffectiveDateOffset());
 }
Esempio n. 8
0
 public void test_euibor3m() {
   IborIndex test = IborIndex.of("EUR-EURIBOR-3M");
   assertEquals(test.getCurrency(), EUR);
   assertEquals(test.getName(), "EUR-EURIBOR-3M");
   assertEquals(test.getTenor(), TENOR_3M);
   assertEquals(test.getFixingCalendar(), EUTA);
   assertEquals(test.getFixingDateOffset(), DaysAdjustment.ofBusinessDays(-2, EUTA));
   assertEquals(test.getEffectiveDateOffset(), DaysAdjustment.ofBusinessDays(2, EUTA));
   assertEquals(
       test.getMaturityDateOffset(),
       TenorAdjustment.ofLastBusinessDay(
           TENOR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUTA)));
   assertEquals(test.getDayCount(), ACT_360);
   assertEquals(test.toString(), "EUR-EURIBOR-3M");
 }
 public void test_expand() {
   ImmutableIborFixingDepositConvention base =
       ImmutableIborFixingDepositConvention.of(EUR_LIBOR_3M);
   IborFixingDepositConvention test = base.expand();
   IborFixingDepositConvention expected =
       ImmutableIborFixingDepositConvention.builder()
           .businessDayAdjustment(
               BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUR_LIBOR_3M.getFixingCalendar()))
           .currency(EUR_LIBOR_3M.getCurrency())
           .dayCount(EUR_LIBOR_3M.getDayCount())
           .fixingDateOffset(EUR_LIBOR_3M.getFixingDateOffset())
           .index(EUR_LIBOR_3M)
           .name(EUR_LIBOR_3M.getName())
           .spotDateOffset(EUR_LIBOR_3M.getEffectiveDateOffset())
           .build();
   assertEquals(test.getName(), EUR_LIBOR_3M.getName());
   assertEquals(test, expected);
 }
Esempio n. 10
0
 // -------------------------------------------------------------------------
 public void test_resolve() {
   ResetSchedule test =
       ResetSchedule.builder()
           .resetFrequency(P1M)
           .businessDayAdjustment(BusinessDayAdjustment.of(FOLLOWING, GBLO))
           .build();
   SchedulePeriod accrualPeriod =
       SchedulePeriod.of(DATE_01_06, DATE_04_07, DATE_01_05, DATE_04_05);
   Schedule schedule = test.createSchedule(DAY_5, REF_DATA).apply(accrualPeriod);
   Schedule expected =
       Schedule.builder()
           .periods(
               SchedulePeriod.of(DATE_01_06, DATE_02_05, DATE_01_05, DATE_02_05),
               SchedulePeriod.of(DATE_02_05, DATE_03_05, DATE_02_05, DATE_03_05),
               SchedulePeriod.of(DATE_03_05, DATE_04_07, DATE_03_05, DATE_04_05))
           .frequency(P1M)
           .rollConvention(DAY_5)
           .build();
   assertEquals(schedule, expected);
 }
Esempio n. 11
0
/** Test {@link TermDepositTrade}. */
@Test
public class TermDepositTradeTest {

  private static final TermDeposit DEPOSIT =
      TermDeposit.builder()
          .buySell(BuySell.BUY)
          .currency(GBP)
          .notional(100000000d)
          .startDate(LocalDate.of(2015, 1, 19))
          .endDate(LocalDate.of(2015, 7, 19))
          .businessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO))
          .dayCount(ACT_365F)
          .rate(0.0250)
          .build();
  private static final TradeInfo TRADE_INFO =
      TradeInfo.builder().tradeDate(date(2014, 6, 30)).build();

  // -------------------------------------------------------------------------
  public void test_builder() {
    TermDepositTrade test =
        TermDepositTrade.builder().product(DEPOSIT).tradeInfo(TRADE_INFO).build();
    assertEquals(test.getProduct(), DEPOSIT);
    assertEquals(test.getTradeInfo(), TRADE_INFO);
  }

  // -------------------------------------------------------------------------
  public void coverage() {
    TermDepositTrade test1 =
        TermDepositTrade.builder().product(DEPOSIT).tradeInfo(TRADE_INFO).build();
    coverImmutableBean(test1);
    TermDepositTrade test2 = TermDepositTrade.builder().product(DEPOSIT).build();
    coverBeanEquals(test1, test2);
  }

  public void test_serialization() {
    TermDepositTrade test =
        TermDepositTrade.builder().product(DEPOSIT).tradeInfo(TRADE_INFO).build();
    assertSerialization(test);
  }
}
/** Test {@link IborFixingDepositConvention}. */
@Test
public class IborFixingDepositConventionTest {

  private static final BusinessDayAdjustment BDA_MOD_FOLLOW =
      BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUTA);
  private static final DaysAdjustment SPOT_ADJ = DaysAdjustment.ofBusinessDays(2, EUTA);
  private static final DaysAdjustment FIXING_ADJ =
      DaysAdjustment.ofBusinessDays(-2, EUTA, BusinessDayAdjustment.of(PRECEDING, GBLO));

  public void test_builder_full() {
    ImmutableIborFixingDepositConvention test =
        ImmutableIborFixingDepositConvention.builder()
            .businessDayAdjustment(BDA_MOD_FOLLOW)
            .currency(EUR)
            .dayCount(ACT_365F)
            .fixingDateOffset(FIXING_ADJ)
            .index(EUR_LIBOR_3M)
            .spotDateOffset(SPOT_ADJ)
            .build();
    assertEquals(test.getBusinessDayAdjustment(), BDA_MOD_FOLLOW);
    assertEquals(test.getCurrency(), EUR);
    assertEquals(test.getDayCount(), ACT_365F);
    assertEquals(test.getFixingDateOffset(), FIXING_ADJ);
    assertEquals(test.getIndex(), EUR_LIBOR_3M);
    assertEquals(test.getName(), EUR_LIBOR_3M.getName());
    assertEquals(test.getSpotDateOffset(), SPOT_ADJ);
  }

  public void test_builder_indexOnly() {
    ImmutableIborFixingDepositConvention test =
        ImmutableIborFixingDepositConvention.builder().index(GBP_LIBOR_6M).build();
    assertEquals(
        test.getBusinessDayAdjustment(),
        BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBP_LIBOR_6M.getFixingCalendar()));
    assertEquals(test.getCurrency(), GBP_LIBOR_6M.getCurrency());
    assertEquals(test.getDayCount(), GBP_LIBOR_6M.getDayCount());
    assertEquals(test.getFixingDateOffset(), GBP_LIBOR_6M.getFixingDateOffset());
    assertEquals(test.getIndex(), GBP_LIBOR_6M);
    assertEquals(test.getSpotDateOffset(), GBP_LIBOR_6M.getEffectiveDateOffset());
  }

  public void test_of_indexOnly() {
    ImmutableIborFixingDepositConvention test =
        ImmutableIborFixingDepositConvention.of(GBP_LIBOR_6M);
    assertEquals(
        test.getBusinessDayAdjustment(),
        BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBP_LIBOR_6M.getFixingCalendar()));
    assertEquals(test.getCurrency(), GBP_LIBOR_6M.getCurrency());
    assertEquals(test.getDayCount(), GBP_LIBOR_6M.getDayCount());
    assertEquals(test.getFixingDateOffset(), GBP_LIBOR_6M.getFixingDateOffset());
    assertEquals(test.getIndex(), GBP_LIBOR_6M);
    assertEquals(test.getSpotDateOffset(), GBP_LIBOR_6M.getEffectiveDateOffset());
  }

  public void test_expand() {
    ImmutableIborFixingDepositConvention base =
        ImmutableIborFixingDepositConvention.of(EUR_LIBOR_3M);
    IborFixingDepositConvention test = base.expand();
    IborFixingDepositConvention expected =
        ImmutableIborFixingDepositConvention.builder()
            .businessDayAdjustment(
                BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUR_LIBOR_3M.getFixingCalendar()))
            .currency(EUR_LIBOR_3M.getCurrency())
            .dayCount(EUR_LIBOR_3M.getDayCount())
            .fixingDateOffset(EUR_LIBOR_3M.getFixingDateOffset())
            .index(EUR_LIBOR_3M)
            .name(EUR_LIBOR_3M.getName())
            .spotDateOffset(EUR_LIBOR_3M.getEffectiveDateOffset())
            .build();
    assertEquals(test.getName(), EUR_LIBOR_3M.getName());
    assertEquals(test, expected);
  }

  public void test_toTemplate() {
    IborFixingDepositConvention convention = IborFixingDepositConvention.of(GBP_LIBOR_6M);
    IborFixingDepositTemplate template = convention.toTemplate();
    assertEquals(template.getConvention(), convention);
    assertEquals(template.getDepositPeriod(), GBP_LIBOR_6M.getTenor().getPeriod());
  }

  public void test_toTrade() {
    IborFixingDepositConvention convention =
        ImmutableIborFixingDepositConvention.builder()
            .businessDayAdjustment(BDA_MOD_FOLLOW)
            .currency(EUR)
            .dayCount(ACT_365F)
            .fixingDateOffset(FIXING_ADJ)
            .index(EUR_LIBOR_3M)
            .spotDateOffset(SPOT_ADJ)
            .build();
    LocalDate tradeDate = LocalDate.of(2015, 1, 22);
    Period depositPeriod = Period.ofMonths(3);
    double notional = 1d;
    double fixedRate = 0.045;
    IborFixingDepositTrade trade =
        convention.toTrade(tradeDate, depositPeriod, BUY, notional, fixedRate);
    LocalDate startExpected = SPOT_ADJ.adjust(tradeDate);
    LocalDate endExpected = startExpected.plus(depositPeriod);
    IborFixingDeposit productExpected =
        IborFixingDeposit.builder()
            .businessDayAdjustment(BDA_MOD_FOLLOW)
            .buySell(BUY)
            .currency(EUR)
            .dayCount(ACT_365F)
            .startDate(startExpected)
            .endDate(endExpected)
            .fixedRate(fixedRate)
            .fixingDateOffset(FIXING_ADJ)
            .index(EUR_LIBOR_3M)
            .notional(notional)
            .build();
    TradeInfo tradeInfoExpected = TradeInfo.builder().tradeDate(tradeDate).build();
    assertEquals(trade.getProduct(), productExpected);
    assertEquals(trade.getTradeInfo(), tradeInfoExpected);
  }

  // -------------------------------------------------------------------------
  @DataProvider(name = "name")
  static Object[][] data_name() {
    return new Object[][] {
      {ImmutableIborFixingDepositConvention.of(GBP_LIBOR_3M), "GBP-LIBOR-3M"},
      {ImmutableIborFixingDepositConvention.of(USD_LIBOR_3M), "USD-LIBOR-3M"},
    };
  }

  @Test(dataProvider = "name")
  public void test_name(IborFixingDepositConvention convention, String name) {
    assertEquals(convention.getName(), name);
  }

  @Test(dataProvider = "name")
  public void test_toString(IborFixingDepositConvention convention, String name) {
    assertEquals(convention.toString(), name);
  }

  @Test(dataProvider = "name")
  public void test_of_lookup(IborFixingDepositConvention convention, String name) {
    assertEquals(IborFixingDepositConvention.of(name), convention);
  }

  @Test(dataProvider = "name")
  public void test_extendedEnum(IborFixingDepositConvention convention, String name) {
    IborFixingDepositConvention.of(name); // ensures map is populated
    ImmutableMap<String, IborFixingDepositConvention> map =
        IborFixingDepositConvention.extendedEnum().lookupAll();
    assertEquals(map.get(name), convention);
  }

  public void test_of_lookup_notFound() {
    assertThrowsIllegalArg(() -> IborFixingDepositConvention.of("Rubbish"));
  }

  public void test_of_lookup_null() {
    assertThrowsIllegalArg(() -> IborFixingDepositConvention.of((String) null));
  }

  // -------------------------------------------------------------------------
  public void coverage() {
    ImmutableIborFixingDepositConvention test1 =
        ImmutableIborFixingDepositConvention.of(GBP_LIBOR_6M);
    coverImmutableBean(test1);
    ImmutableIborFixingDepositConvention test2 =
        ImmutableIborFixingDepositConvention.of(EUR_LIBOR_3M).toBuilder().name("Foo").build();
    coverBeanEquals(test1, test2);

    coverPrivateConstructor(IborFixingDepositConventions.class);
    coverPrivateConstructor(IborFixingDepositConventionLookup.class);
  }

  public void test_serialization() {
    ImmutableIborFixingDepositConvention test =
        ImmutableIborFixingDepositConvention.of(GBP_LIBOR_6M);
    assertSerialization(test);
  }
}
Esempio n. 13
0
/** Helper methods for testing curves. */
final class CurveTestUtils {

  private static final String TEST_SCHEME = "test";

  private static final BusinessDayAdjustment BDA_FOLLOW =
      BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, HolidayCalendars.GBLO);

  private static final IborRateSwapLegConvention FLOATING_CONVENTION =
      IborRateSwapLegConvention.of(IborIndices.USD_LIBOR_3M);

  private static final FixedRateSwapLegConvention FIXED_CONVENTION =
      FixedRateSwapLegConvention.of(Currency.USD, DayCounts.ACT_360, Frequency.P6M, BDA_FOLLOW);

  private static final FixedIborSwapConvention SWAP_CONVENTION =
      ImmutableFixedIborSwapConvention.of("USD-Swap", FIXED_CONVENTION, FLOATING_CONVENTION);

  private CurveTestUtils() {}

  static InterpolatedNodalCurveDefinition fraCurveDefinition() {
    String fra1x4 = "fra1x4";
    String fra2x5 = "fra2x5";
    String fra3x6 = "fra3x6";
    String fra6x9 = "fra6x9";
    String fra9x12 = "fra9x12";
    String fra12x15 = "fra12x15";
    String fra18x21 = "fra18x21";

    FraCurveNode fra1x4Node = fraNode(1, fra1x4);
    FraCurveNode fra2x5Node = fraNode(2, fra2x5);
    FraCurveNode fra3x6Node = fraNode(3, fra3x6);
    FraCurveNode fra6x9Node = fraNode(6, fra6x9);
    FraCurveNode fra9x12Node = fraNode(9, fra9x12);
    FraCurveNode fra12x15Node = fraNode(12, fra12x15);
    FraCurveNode fra18x21Node = fraNode(18, fra18x21);

    CurveName curveName = CurveName.of("FRA Curve");

    List<CurveNode> nodes =
        ImmutableList.of(
            fra1x4Node,
            fra2x5Node,
            fra3x6Node,
            fra6x9Node,
            fra9x12Node,
            fra12x15Node,
            fra18x21Node);

    return InterpolatedNodalCurveDefinition.builder()
        .name(curveName)
        .xValueType(ValueType.YEAR_FRACTION)
        .yValueType(ValueType.ZERO_RATE)
        .dayCount(DayCounts.ACT_ACT_ISDA)
        .nodes(nodes)
        .interpolator(CurveInterpolators.DOUBLE_QUADRATIC)
        .extrapolatorLeft(CurveExtrapolators.FLAT)
        .extrapolatorRight(CurveExtrapolators.FLAT)
        .build();
  }

  static InterpolatedNodalCurveDefinition fraSwapCurveDefinition() {
    String fra3x6 = "fra3x6";
    String fra6x9 = "fra6x9";
    String swap1y = "swap1y";
    String swap2y = "swap2y";
    String swap3y = "swap3y";

    FraCurveNode fra3x6Node = CurveTestUtils.fraNode(3, fra3x6);
    FraCurveNode fra6x9Node = CurveTestUtils.fraNode(6, fra6x9);
    FixedIborSwapCurveNode swap1yNode = fixedIborSwapNode(Tenor.TENOR_1Y, swap1y);
    FixedIborSwapCurveNode swap2yNode = fixedIborSwapNode(Tenor.TENOR_2Y, swap2y);
    FixedIborSwapCurveNode swap3yNode = fixedIborSwapNode(Tenor.TENOR_3Y, swap3y);

    CurveName curveName = CurveName.of("FRA and Fixed-Float Swap Curve");
    List<CurveNode> nodes =
        ImmutableList.of(fra3x6Node, fra6x9Node, swap1yNode, swap2yNode, swap3yNode);

    return InterpolatedNodalCurveDefinition.builder()
        .name(curveName)
        .xValueType(ValueType.YEAR_FRACTION)
        .yValueType(ValueType.ZERO_RATE)
        .dayCount(DayCounts.ACT_ACT_ISDA)
        .nodes(nodes)
        .interpolator(CurveInterpolators.DOUBLE_QUADRATIC)
        .extrapolatorLeft(CurveExtrapolators.FLAT)
        .extrapolatorRight(CurveExtrapolators.FLAT)
        .build();
  }

  static FraCurveNode fraNode(int startMonths, String id) {
    Period periodToStart = Period.ofMonths(startMonths);
    QuoteKey quoteKey = QuoteKey.of(StandardId.of(TEST_SCHEME, id));
    return FraCurveNode.of(FraTemplate.of(periodToStart, IborIndices.USD_LIBOR_3M), quoteKey);
  }

  static FixedIborSwapCurveNode fixedIborSwapNode(Tenor tenor, String id) {
    QuoteKey quoteKey = QuoteKey.of(StandardId.of(TEST_SCHEME, id));
    FixedIborSwapTemplate template = FixedIborSwapTemplate.of(Period.ZERO, tenor, SWAP_CONVENTION);
    return FixedIborSwapCurveNode.of(template, quoteKey);
  }

  static ObservableId id(String nodeName) {
    return QuoteId.of(StandardId.of(TEST_SCHEME, nodeName));
  }

  static ObservableId id(CurveNode node) {
    if (node instanceof FraCurveNode) {
      return ((FraCurveNode) node).getRateKey().toObservableId(MarketDataFeed.NONE);
    } else if (node instanceof FixedIborSwapCurveNode) {
      return ((FixedIborSwapCurveNode) node).getRateKey().toObservableId(MarketDataFeed.NONE);
    } else {
      throw new IllegalArgumentException("Unsupported node type " + node.getClass().getName());
    }
  }
}
/** Test {@link ThreeLegBasisSwapConvention}. */
@Test
public class ThreeLegBasisSwapConventionTest {

  private static final ReferenceData REF_DATA = ReferenceData.standard();
  private static final double NOTIONAL_2M = 2_000_000d;
  private static final BusinessDayAdjustment BDA_FOLLOW = BusinessDayAdjustment.of(FOLLOWING, EUTA);
  private static final DaysAdjustment PLUS_ONE_DAY = DaysAdjustment.ofBusinessDays(1, EUTA);

  private static final String NAME = "EUR-Swap";
  private static final FixedRateSwapLegConvention FIXED =
      FixedRateSwapLegConvention.of(EUR, THIRTY_U_360, P12M, BDA_FOLLOW);
  private static final IborRateSwapLegConvention IBOR3M =
      IborRateSwapLegConvention.of(EUR_EURIBOR_3M);
  private static final IborRateSwapLegConvention IBOR6M =
      IborRateSwapLegConvention.of(EUR_EURIBOR_6M);
  private static final IborRateSwapLegConvention IBOR12M =
      IborRateSwapLegConvention.of(EUR_EURIBOR_12M);

  // -------------------------------------------------------------------------
  public void test_of() {
    ImmutableThreeLegBasisSwapConvention test =
        ImmutableThreeLegBasisSwapConvention.of(NAME, FIXED, IBOR6M, IBOR12M);
    assertEquals(test.getName(), NAME);
    assertEquals(test.getSpreadLeg(), FIXED);
    assertEquals(test.getSpreadFloatingLeg(), IBOR6M);
    assertEquals(test.getFlatFloatingLeg(), IBOR12M);
    assertEquals(test.getSpotDateOffset(), EUR_EURIBOR_6M.getEffectiveDateOffset());
  }

  public void test_of_spotDateOffset() {
    ImmutableThreeLegBasisSwapConvention test =
        ImmutableThreeLegBasisSwapConvention.of(NAME, FIXED, IBOR6M, IBOR12M, PLUS_ONE_DAY);
    assertEquals(test.getName(), NAME);
    assertEquals(test.getSpreadLeg(), FIXED);
    assertEquals(test.getSpreadFloatingLeg(), IBOR6M);
    assertEquals(test.getFlatFloatingLeg(), IBOR12M);
    assertEquals(test.getSpotDateOffset(), PLUS_ONE_DAY);
  }

  public void test_builder() {
    ImmutableThreeLegBasisSwapConvention test =
        ImmutableThreeLegBasisSwapConvention.builder()
            .name(NAME)
            .spreadLeg(FIXED)
            .spreadFloatingLeg(IBOR6M)
            .flatFloatingLeg(IBOR12M)
            .spotDateOffset(PLUS_ONE_DAY)
            .build();
    assertEquals(test.getName(), NAME);
    assertEquals(test.getSpreadLeg(), FIXED);
    assertEquals(test.getSpreadFloatingLeg(), IBOR6M);
    assertEquals(test.getFlatFloatingLeg(), IBOR12M);
    assertEquals(test.getSpotDateOffset(), PLUS_ONE_DAY);
  }

  // -------------------------------------------------------------------------
  public void test_toTrade_tenor() {
    ThreeLegBasisSwapConvention base =
        ImmutableThreeLegBasisSwapConvention.of(NAME, FIXED, IBOR6M, IBOR12M);
    LocalDate tradeDate = LocalDate.of(2015, 5, 5);
    LocalDate startDate = date(2015, 5, 7);
    LocalDate endDate = date(2025, 5, 7);
    SwapTrade test = base.createTrade(tradeDate, TENOR_10Y, BUY, NOTIONAL_2M, 0.25d, REF_DATA);
    Swap expected =
        Swap.of(
            FIXED.toLeg(startDate, endDate, PAY, NOTIONAL_2M, 0.25d),
            IBOR6M.toLeg(startDate, endDate, PAY, NOTIONAL_2M),
            IBOR12M.toLeg(startDate, endDate, RECEIVE, NOTIONAL_2M));
    assertEquals(test.getInfo().getTradeDate(), Optional.of(tradeDate));
    assertEquals(test.getProduct(), expected);
  }

  public void test_toTrade_periodTenor() {
    ThreeLegBasisSwapConvention base =
        ImmutableThreeLegBasisSwapConvention.of(NAME, FIXED, IBOR6M, IBOR12M);
    LocalDate tradeDate = LocalDate.of(2015, 5, 5);
    LocalDate startDate = date(2015, 8, 7);
    LocalDate endDate = date(2025, 8, 7);
    SwapTrade test =
        base.createTrade(
            tradeDate, Period.ofMonths(3), TENOR_10Y, BUY, NOTIONAL_2M, 0.25d, REF_DATA);
    Swap expected =
        Swap.of(
            FIXED.toLeg(startDate, endDate, PAY, NOTIONAL_2M, 0.25d),
            IBOR6M.toLeg(startDate, endDate, PAY, NOTIONAL_2M),
            IBOR12M.toLeg(startDate, endDate, RECEIVE, NOTIONAL_2M));
    assertEquals(test.getInfo().getTradeDate(), Optional.of(tradeDate));
    assertEquals(test.getProduct(), expected);
  }

  public void test_toTrade_dates() {
    ThreeLegBasisSwapConvention base =
        ImmutableThreeLegBasisSwapConvention.of(NAME, FIXED, IBOR6M, IBOR12M);
    LocalDate tradeDate = LocalDate.of(2015, 5, 5);
    LocalDate startDate = date(2015, 8, 5);
    LocalDate endDate = date(2015, 11, 5);
    SwapTrade test = base.toTrade(tradeDate, startDate, endDate, BUY, NOTIONAL_2M, 0.25d);
    Swap expected =
        Swap.of(
            FIXED.toLeg(startDate, endDate, PAY, NOTIONAL_2M, 0.25d),
            IBOR6M.toLeg(startDate, endDate, PAY, NOTIONAL_2M),
            IBOR12M.toLeg(startDate, endDate, RECEIVE, NOTIONAL_2M));
    assertEquals(test.getInfo().getTradeDate(), Optional.of(tradeDate));
    assertEquals(test.getProduct(), expected);
  }

  // -------------------------------------------------------------------------
  @DataProvider(name = "name")
  static Object[][] data_name() {
    return new Object[][] {
      {
        ThreeLegBasisSwapConventions.EUR_FIXED_1Y_EURIBOR_3M_EURIBOR_6M,
        "EUR-FIXED-1Y-EURIBOR-3M-EURIBOR-6M"
      },
    };
  }

  @Test(dataProvider = "name")
  public void test_name(ThreeLegBasisSwapConvention convention, String name) {
    assertEquals(convention.getName(), name);
  }

  @Test(dataProvider = "name")
  public void test_toString(ThreeLegBasisSwapConvention convention, String name) {
    assertEquals(convention.toString(), name);
  }

  @Test(dataProvider = "name")
  public void test_of_lookup(ThreeLegBasisSwapConvention convention, String name) {
    assertEquals(ThreeLegBasisSwapConvention.of(name), convention);
  }

  @Test(dataProvider = "name")
  public void test_extendedEnum(ThreeLegBasisSwapConvention convention, String name) {
    ThreeLegBasisSwapConvention.of(name); // ensures map is populated
    ImmutableMap<String, ThreeLegBasisSwapConvention> map =
        ThreeLegBasisSwapConvention.extendedEnum().lookupAll();
    assertEquals(map.get(name), convention);
  }

  public void test_of_lookup_notFound() {
    assertThrowsIllegalArg(() -> ThreeLegBasisSwapConvention.of("Rubbish"));
  }

  public void test_of_lookup_null() {
    assertThrowsIllegalArg(() -> ThreeLegBasisSwapConvention.of((String) null));
  }

  // -------------------------------------------------------------------------
  public void coverage() {
    ImmutableThreeLegBasisSwapConvention test =
        ImmutableThreeLegBasisSwapConvention.of(NAME, FIXED, IBOR6M, IBOR12M);
    coverImmutableBean(test);
    ImmutableThreeLegBasisSwapConvention test2 =
        ImmutableThreeLegBasisSwapConvention.of("swap", FIXED, IBOR3M, IBOR6M);
    coverBeanEquals(test, test2);
    ImmutableThreeLegBasisSwapConvention test3 =
        ImmutableThreeLegBasisSwapConvention.of(NAME, FIXED, IBOR3M, IBOR12M);
    coverBeanEquals(test, test3);
  }

  public void test_serialization() {
    ThreeLegBasisSwapConvention test =
        ImmutableThreeLegBasisSwapConvention.of(NAME, FIXED, IBOR6M, IBOR12M);
    assertSerialization(test);
  }
}
/** Test {@link IborIborSwapConvention}. */
@Test
public class IborIborSwapConventionTest {

  private static final double NOTIONAL_2M = 2_000_000d;
  private static final BusinessDayAdjustment BDA_FOLLOW = BusinessDayAdjustment.of(FOLLOWING, GBLO);
  private static final DaysAdjustment NEXT_SAME_BUS_DAY =
      DaysAdjustment.ofCalendarDays(0, BDA_FOLLOW);
  private static final DaysAdjustment PLUS_ONE_DAY = DaysAdjustment.ofBusinessDays(1, GBLO);

  private static final String NAME = "USD-Swap";
  private static final IborRateSwapLegConvention IBOR1M =
      IborRateSwapLegConvention.of(USD_LIBOR_1M);
  private static final IborRateSwapLegConvention IBOR3M =
      IborRateSwapLegConvention.of(USD_LIBOR_3M);
  private static final IborRateSwapLegConvention IBOR6M =
      IborRateSwapLegConvention.of(USD_LIBOR_6M);

  // -------------------------------------------------------------------------
  public void test_of() {
    ImmutableIborIborSwapConvention test = ImmutableIborIborSwapConvention.of(NAME, IBOR3M, IBOR6M);
    assertEquals(test.getName(), NAME);
    assertEquals(test.getSpreadLeg(), IBOR3M);
    assertEquals(test.getFlatLeg(), IBOR6M);
    assertEquals(test.getSpotDateOffset(), USD_LIBOR_3M.getEffectiveDateOffset());
  }

  // -------------------------------------------------------------------------
  public void test_builder_notEnoughData() {
    assertThrowsIllegalArg(
        () -> ImmutableIborIborSwapConvention.builder().spotDateOffset(NEXT_SAME_BUS_DAY).build());
  }

  // -------------------------------------------------------------------------
  public void test_expand() {
    ImmutableIborIborSwapConvention test =
        ImmutableIborIborSwapConvention.of(NAME, IBOR3M, IBOR6M).expand();
    assertEquals(test.getName(), NAME);
    assertEquals(test.getSpreadLeg(), IBOR3M.expand());
    assertEquals(test.getFlatLeg(), IBOR6M.expand());
    assertEquals(test.getSpotDateOffset(), USD_LIBOR_3M.getEffectiveDateOffset());
  }

  public void test_expandAllSpecified() {
    ImmutableIborIborSwapConvention test =
        ImmutableIborIborSwapConvention.builder()
            .name(NAME)
            .spreadLeg(IBOR3M)
            .flatLeg(IBOR6M)
            .spotDateOffset(PLUS_ONE_DAY)
            .build()
            .expand();
    assertEquals(test.getSpreadLeg(), IBOR3M.expand());
    assertEquals(test.getFlatLeg(), IBOR6M.expand());
    assertEquals(test.getSpotDateOffset(), PLUS_ONE_DAY);
  }

  // -------------------------------------------------------------------------
  public void test_toTrade_tenor() {
    IborIborSwapConvention base = ImmutableIborIborSwapConvention.of(NAME, IBOR3M, IBOR6M);
    LocalDate tradeDate = LocalDate.of(2015, 5, 5);
    LocalDate startDate = date(2015, 5, 7);
    LocalDate endDate = date(2025, 5, 7);
    SwapTrade test = base.toTrade(tradeDate, TENOR_10Y, BUY, NOTIONAL_2M, 0.25d);
    Swap expected =
        Swap.of(
            IBOR3M.toLeg(startDate, endDate, PAY, NOTIONAL_2M, 0.25d),
            IBOR6M.toLeg(startDate, endDate, RECEIVE, NOTIONAL_2M));
    assertEquals(test.getTradeInfo().getTradeDate(), Optional.of(tradeDate));
    assertEquals(test.getProduct(), expected);
  }

  public void test_toTrade_periodTenor() {
    IborIborSwapConvention base = ImmutableIborIborSwapConvention.of(NAME, IBOR3M, IBOR6M);
    LocalDate tradeDate = LocalDate.of(2015, 5, 5);
    LocalDate startDate = date(2015, 8, 7);
    LocalDate endDate = date(2025, 8, 7);
    SwapTrade test =
        base.toTrade(tradeDate, Period.ofMonths(3), TENOR_10Y, BUY, NOTIONAL_2M, 0.25d);
    Swap expected =
        Swap.of(
            IBOR3M.toLeg(startDate, endDate, PAY, NOTIONAL_2M, 0.25d),
            IBOR6M.toLeg(startDate, endDate, RECEIVE, NOTIONAL_2M));
    assertEquals(test.getTradeInfo().getTradeDate(), Optional.of(tradeDate));
    assertEquals(test.getProduct(), expected);
  }

  public void test_toTrade_dates() {
    IborIborSwapConvention base = ImmutableIborIborSwapConvention.of(NAME, IBOR3M, IBOR6M);
    LocalDate tradeDate = LocalDate.of(2015, 5, 5);
    LocalDate startDate = date(2015, 8, 5);
    LocalDate endDate = date(2015, 11, 5);
    SwapTrade test = base.toTrade(tradeDate, startDate, endDate, BUY, NOTIONAL_2M, 0.25d);
    Swap expected =
        Swap.of(
            IBOR3M.toLeg(startDate, endDate, PAY, NOTIONAL_2M, 0.25d),
            IBOR6M.toLeg(startDate, endDate, RECEIVE, NOTIONAL_2M));
    assertEquals(test.getTradeInfo().getTradeDate(), Optional.of(tradeDate));
    assertEquals(test.getProduct(), expected);
  }

  // -------------------------------------------------------------------------
  @DataProvider(name = "name")
  static Object[][] data_name() {
    return new Object[][] {
      {IborIborSwapConventions.USD_LIBOR_1M_LIBOR_3M, "USD-LIBOR-1M-LIBOR-3M"},
      {IborIborSwapConventions.USD_LIBOR_3M_LIBOR_6M, "USD-LIBOR-3M-LIBOR-6M"},
    };
  }

  @Test(dataProvider = "name")
  public void test_name(IborIborSwapConvention convention, String name) {
    assertEquals(convention.getName(), name);
  }

  @Test(dataProvider = "name")
  public void test_toString(IborIborSwapConvention convention, String name) {
    assertEquals(convention.toString(), name);
  }

  @Test(dataProvider = "name")
  public void test_of_lookup(IborIborSwapConvention convention, String name) {
    assertEquals(IborIborSwapConvention.of(name), convention);
  }

  @Test(dataProvider = "name")
  public void test_extendedEnum(IborIborSwapConvention convention, String name) {
    IborIborSwapConvention.of(name); // ensures map is populated
    ImmutableMap<String, IborIborSwapConvention> map =
        IborIborSwapConvention.extendedEnum().lookupAll();
    assertEquals(map.get(name), convention);
  }

  public void test_of_lookup_notFound() {
    assertThrowsIllegalArg(() -> IborIborSwapConvention.of("Rubbish"));
  }

  public void test_of_lookup_null() {
    assertThrowsIllegalArg(() -> IborIborSwapConvention.of((String) null));
  }

  // -------------------------------------------------------------------------
  public void coverage() {
    ImmutableIborIborSwapConvention test = ImmutableIborIborSwapConvention.of(NAME, IBOR3M, IBOR6M);
    coverImmutableBean(test);
    ImmutableIborIborSwapConvention test2 =
        ImmutableIborIborSwapConvention.of(NAME, IBOR1M, IBOR6M);
    coverBeanEquals(test, test2);
    ImmutableIborIborSwapConvention test3 =
        ImmutableIborIborSwapConvention.of(NAME, IBOR1M, IBOR3M);
    coverBeanEquals(test, test3);
  }

  public void test_serialization() {
    IborIborSwapConvention test = ImmutableIborIborSwapConvention.of(NAME, IBOR3M, IBOR6M);
    assertSerialization(test);
  }
}
/** Test {@link OvernightRateSwapLegConvention}. */
@Test
public class OvernightRateSwapLegConventionTest {

  private static final double NOTIONAL_2M = 2_000_000d;
  private static final BusinessDayAdjustment BDA_FOLLOW = BusinessDayAdjustment.of(FOLLOWING, GBLO);
  private static final BusinessDayAdjustment BDA_MOD_FOLLOW =
      BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO);
  private static final DaysAdjustment PLUS_TWO_DAYS = DaysAdjustment.ofBusinessDays(2, GBLO);

  // -------------------------------------------------------------------------
  public void test_of() {
    OvernightRateSwapLegConvention test = OvernightRateSwapLegConvention.of(GBP_SONIA, P12M, 2);
    assertEquals(test.getIndex(), GBP_SONIA);
    assertEquals(test.getAccrualMethod(), COMPOUNDED);
    assertEquals(test.getRateCutOffDays(), 0);
    assertEquals(test.getCurrency(), GBP);
    assertEquals(test.getDayCount(), ACT_365F);
    assertEquals(test.getAccrualFrequency(), P12M);
    assertEquals(test.getAccrualBusinessDayAdjustment(), BDA_MOD_FOLLOW);
    assertEquals(test.getStartDateBusinessDayAdjustment(), BDA_MOD_FOLLOW);
    assertEquals(test.getEndDateBusinessDayAdjustment(), BDA_MOD_FOLLOW);
    assertEquals(test.getStubConvention(), StubConvention.SHORT_INITIAL);
    assertEquals(test.getRollConvention(), RollConventions.NONE);
    assertEquals(test.getPaymentFrequency(), P12M);
    assertEquals(
        test.getPaymentDateOffset(),
        DaysAdjustment.ofBusinessDays(2, GBP_SONIA.getFixingCalendar()));
    assertEquals(test.getCompoundingMethod(), CompoundingMethod.NONE);
  }

  public void test_of_method() {
    OvernightRateSwapLegConvention test =
        OvernightRateSwapLegConvention.of(GBP_SONIA, P12M, 2, AVERAGED);
    assertEquals(test.getIndex(), GBP_SONIA);
    assertEquals(test.getAccrualMethod(), AVERAGED);
    assertEquals(test.getRateCutOffDays(), 0);
    assertEquals(test.getCurrency(), GBP);
    assertEquals(test.getDayCount(), ACT_365F);
    assertEquals(test.getAccrualFrequency(), P12M);
    assertEquals(test.getAccrualBusinessDayAdjustment(), BDA_MOD_FOLLOW);
    assertEquals(test.getStartDateBusinessDayAdjustment(), BDA_MOD_FOLLOW);
    assertEquals(test.getEndDateBusinessDayAdjustment(), BDA_MOD_FOLLOW);
    assertEquals(test.getStubConvention(), StubConvention.SHORT_INITIAL);
    assertEquals(test.getRollConvention(), RollConventions.NONE);
    assertEquals(test.getPaymentFrequency(), P12M);
    assertEquals(
        test.getPaymentDateOffset(),
        DaysAdjustment.ofBusinessDays(2, GBP_SONIA.getFixingCalendar()));
    assertEquals(test.getCompoundingMethod(), CompoundingMethod.NONE);
  }

  // -------------------------------------------------------------------------
  public void test_builder_notEnoughData() {
    assertThrowsIllegalArg(() -> OvernightRateSwapLegConvention.builder().build());
  }

  // -------------------------------------------------------------------------
  public void test_expand() {
    OvernightRateSwapLegConvention test =
        OvernightRateSwapLegConvention.of(GBP_SONIA, P12M, 2).expand();
    assertEquals(test.getIndex(), GBP_SONIA);
    assertEquals(test.getAccrualMethod(), COMPOUNDED);
    assertEquals(test.getRateCutOffDays(), 0);
    assertEquals(test.getCurrency(), GBP);
    assertEquals(test.getDayCount(), ACT_365F);
    assertEquals(test.getAccrualFrequency(), P12M);
    assertEquals(test.getAccrualBusinessDayAdjustment(), BDA_MOD_FOLLOW);
    assertEquals(test.getStartDateBusinessDayAdjustment(), BDA_MOD_FOLLOW);
    assertEquals(test.getEndDateBusinessDayAdjustment(), BDA_MOD_FOLLOW);
    assertEquals(test.getStubConvention(), StubConvention.SHORT_INITIAL);
    assertEquals(test.getRollConvention(), RollConventions.NONE);
    assertEquals(test.getPaymentFrequency(), P12M);
    assertEquals(
        test.getPaymentDateOffset(),
        DaysAdjustment.ofBusinessDays(2, GBP_SONIA.getFixingCalendar()));
    assertEquals(test.getCompoundingMethod(), CompoundingMethod.NONE);
  }

  public void test_expandAllSpecified() {
    OvernightRateSwapLegConvention test =
        OvernightRateSwapLegConvention.builder()
            .index(GBP_SONIA)
            .accrualMethod(COMPOUNDED)
            .rateCutOffDays(2)
            .currency(USD)
            .dayCount(ACT_360)
            .accrualFrequency(P6M)
            .accrualBusinessDayAdjustment(BDA_FOLLOW)
            .startDateBusinessDayAdjustment(BDA_FOLLOW)
            .endDateBusinessDayAdjustment(BDA_FOLLOW)
            .stubConvention(LONG_INITIAL)
            .rollConvention(RollConventions.EOM)
            .paymentFrequency(P6M)
            .paymentDateOffset(PLUS_TWO_DAYS)
            .compoundingMethod(CompoundingMethod.FLAT)
            .build();
    assertEquals(test.getIndex(), GBP_SONIA);
    assertEquals(test.getAccrualMethod(), COMPOUNDED);
    assertEquals(test.getRateCutOffDays(), 2);
    assertEquals(test.getCurrency(), USD);
    assertEquals(test.getDayCount(), ACT_360);
    assertEquals(test.getAccrualFrequency(), P6M);
    assertEquals(test.getAccrualBusinessDayAdjustment(), BDA_FOLLOW);
    assertEquals(test.getStartDateBusinessDayAdjustment(), BDA_FOLLOW);
    assertEquals(test.getEndDateBusinessDayAdjustment(), BDA_FOLLOW);
    assertEquals(test.getStubConvention(), StubConvention.LONG_INITIAL);
    assertEquals(test.getRollConvention(), RollConventions.EOM);
    assertEquals(test.getPaymentFrequency(), P6M);
    assertEquals(test.getPaymentDateOffset(), PLUS_TWO_DAYS);
    assertEquals(test.getCompoundingMethod(), CompoundingMethod.FLAT);
  }

  // -------------------------------------------------------------------------
  public void test_toLeg() {
    OvernightRateSwapLegConvention base =
        OvernightRateSwapLegConvention.builder().index(GBP_SONIA).accrualMethod(COMPOUNDED).build();
    LocalDate startDate = LocalDate.of(2015, 5, 5);
    LocalDate endDate = LocalDate.of(2020, 5, 5);
    RateCalculationSwapLeg test = base.toLeg(startDate, endDate, PAY, NOTIONAL_2M);
    RateCalculationSwapLeg expected =
        RateCalculationSwapLeg.builder()
            .payReceive(PAY)
            .accrualSchedule(
                PeriodicSchedule.builder()
                    .frequency(TERM)
                    .startDate(startDate)
                    .endDate(endDate)
                    .businessDayAdjustment(BDA_MOD_FOLLOW)
                    .build())
            .paymentSchedule(
                PaymentSchedule.builder()
                    .paymentFrequency(TERM)
                    .paymentDateOffset(DaysAdjustment.NONE)
                    .build())
            .notionalSchedule(NotionalSchedule.of(GBP, NOTIONAL_2M))
            .calculation(OvernightRateCalculation.of(GBP_SONIA))
            .build();
    assertEquals(test, expected);
  }

  public void test_toLeg_withSpread() {
    OvernightRateSwapLegConvention base =
        OvernightRateSwapLegConvention.builder().index(GBP_SONIA).accrualMethod(AVERAGED).build();
    LocalDate startDate = LocalDate.of(2015, 5, 5);
    LocalDate endDate = LocalDate.of(2020, 5, 5);
    RateCalculationSwapLeg test = base.toLeg(startDate, endDate, PAY, NOTIONAL_2M, 0.25d);
    RateCalculationSwapLeg expected =
        RateCalculationSwapLeg.builder()
            .payReceive(PAY)
            .accrualSchedule(
                PeriodicSchedule.builder()
                    .frequency(TERM)
                    .startDate(startDate)
                    .endDate(endDate)
                    .businessDayAdjustment(BDA_MOD_FOLLOW)
                    .build())
            .paymentSchedule(
                PaymentSchedule.builder()
                    .paymentFrequency(TERM)
                    .paymentDateOffset(DaysAdjustment.NONE)
                    .build())
            .notionalSchedule(NotionalSchedule.of(GBP, NOTIONAL_2M))
            .calculation(
                OvernightRateCalculation.builder()
                    .index(GBP_SONIA)
                    .accrualMethod(AVERAGED)
                    .spread(ValueSchedule.of(0.25d))
                    .build())
            .build();
    assertEquals(test, expected);
  }

  // -------------------------------------------------------------------------
  public void coverage() {
    OvernightRateSwapLegConvention test =
        OvernightRateSwapLegConvention.builder().index(GBP_SONIA).accrualMethod(COMPOUNDED).build();
    coverImmutableBean(test);
    OvernightRateSwapLegConvention test2 =
        OvernightRateSwapLegConvention.builder()
            .index(USD_FED_FUND)
            .accrualMethod(AVERAGED)
            .rateCutOffDays(2)
            .currency(USD)
            .dayCount(ACT_360)
            .accrualFrequency(P6M)
            .accrualBusinessDayAdjustment(BDA_FOLLOW)
            .startDateBusinessDayAdjustment(BDA_FOLLOW)
            .endDateBusinessDayAdjustment(BDA_FOLLOW)
            .stubConvention(LONG_INITIAL)
            .rollConvention(RollConventions.EOM)
            .paymentFrequency(P6M)
            .paymentDateOffset(PLUS_TWO_DAYS)
            .build();
    coverBeanEquals(test, test2);
  }

  public void test_serialization() {
    OvernightRateSwapLegConvention test = OvernightRateSwapLegConvention.of(GBP_SONIA, P12M, 2);
    assertSerialization(test);
  }
}
/** Test {@link TermDepositCurveNode}. */
@Test
public class TermDepositCurveNodeTest {

  private static final ReferenceData REF_DATA = ReferenceData.standard();
  private static final LocalDate VAL_DATE = date(2015, 6, 30);
  private static final BusinessDayAdjustment BDA_MOD_FOLLOW =
      BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUTA);
  private static final DaysAdjustment PLUS_TWO_DAYS = DaysAdjustment.ofBusinessDays(2, EUTA);
  private static final TermDepositConvention CONVENTION = TermDepositConventions.EUR_DEPOSIT_T2;
  private static final Period DEPOSIT_PERIOD = Period.ofMonths(3);
  private static final TermDepositTemplate TEMPLATE =
      TermDepositTemplate.of(DEPOSIT_PERIOD, CONVENTION);
  private static final QuoteId QUOTE_ID = QuoteId.of(StandardId.of("OG-Ticker", "Deposit1"));
  private static final double SPREAD = 0.0015;
  private static final String LABEL = "Label";
  private static final String LABEL_AUTO = "3M";

  public void test_builder() {
    TermDepositCurveNode test =
        TermDepositCurveNode.builder()
            .label(LABEL)
            .template(TEMPLATE)
            .rateId(QUOTE_ID)
            .additionalSpread(SPREAD)
            .date(CurveNodeDate.LAST_FIXING)
            .build();
    assertEquals(test.getLabel(), LABEL);
    assertEquals(test.getRateId(), QUOTE_ID);
    assertEquals(test.getAdditionalSpread(), SPREAD);
    assertEquals(test.getTemplate(), TEMPLATE);
    assertEquals(test.getDate(), CurveNodeDate.LAST_FIXING);
  }

  public void test_builder_defaults() {
    TermDepositCurveNode test =
        TermDepositCurveNode.builder()
            .label(LABEL)
            .template(TEMPLATE)
            .rateId(QUOTE_ID)
            .additionalSpread(SPREAD)
            .build();
    assertEquals(test.getLabel(), LABEL);
    assertEquals(test.getRateId(), QUOTE_ID);
    assertEquals(test.getAdditionalSpread(), SPREAD);
    assertEquals(test.getTemplate(), TEMPLATE);
    assertEquals(test.getDate(), CurveNodeDate.END);
  }

  public void test_of_noSpread() {
    TermDepositCurveNode test = TermDepositCurveNode.of(TEMPLATE, QUOTE_ID);
    assertEquals(test.getLabel(), LABEL_AUTO);
    assertEquals(test.getRateId(), QUOTE_ID);
    assertEquals(test.getAdditionalSpread(), 0.0d);
    assertEquals(test.getTemplate(), TEMPLATE);
  }

  public void test_of_withSpread() {
    TermDepositCurveNode test = TermDepositCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD);
    assertEquals(test.getLabel(), LABEL_AUTO);
    assertEquals(test.getRateId(), QUOTE_ID);
    assertEquals(test.getAdditionalSpread(), SPREAD);
    assertEquals(test.getTemplate(), TEMPLATE);
  }

  public void test_of_withSpreadAndLabel() {
    TermDepositCurveNode test = TermDepositCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD, LABEL);
    assertEquals(test.getLabel(), LABEL);
    assertEquals(test.getRateId(), QUOTE_ID);
    assertEquals(test.getAdditionalSpread(), SPREAD);
    assertEquals(test.getTemplate(), TEMPLATE);
  }

  public void test_requirements() {
    TermDepositCurveNode test = TermDepositCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD);
    Set<ObservableId> set = test.requirements();
    Iterator<ObservableId> itr = set.iterator();
    assertEquals(itr.next(), QUOTE_ID);
    assertFalse(itr.hasNext());
  }

  public void test_trade() {
    TermDepositCurveNode node = TermDepositCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD);
    double rate = 0.035;
    MarketData marketData = ImmutableMarketData.builder(VAL_DATE).addValue(QUOTE_ID, rate).build();
    TermDepositTrade trade = node.trade(1d, marketData, REF_DATA);
    LocalDate startDateExpected = PLUS_TWO_DAYS.adjust(VAL_DATE, REF_DATA);
    LocalDate endDateExpected = startDateExpected.plus(DEPOSIT_PERIOD);
    TermDeposit depositExpected =
        TermDeposit.builder()
            .buySell(BuySell.BUY)
            .currency(EUR)
            .dayCount(ACT_360)
            .startDate(startDateExpected)
            .endDate(endDateExpected)
            .notional(1.0d)
            .businessDayAdjustment(BDA_MOD_FOLLOW)
            .rate(rate + SPREAD)
            .build();
    TradeInfo tradeInfoExpected = TradeInfo.builder().tradeDate(VAL_DATE).build();
    assertEquals(trade.getProduct(), depositExpected);
    assertEquals(trade.getInfo(), tradeInfoExpected);
  }

  public void test_trade_noMarketData() {
    TermDepositCurveNode node = TermDepositCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD);
    LocalDate valuationDate = LocalDate.of(2015, 1, 22);
    MarketData marketData = MarketData.empty(valuationDate);
    assertThrows(() -> node.trade(1d, marketData, REF_DATA), MarketDataNotFoundException.class);
  }

  public void test_initialGuess() {
    TermDepositCurveNode node = TermDepositCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD);
    double rate = 0.035;
    MarketData marketData = ImmutableMarketData.builder(VAL_DATE).addValue(QUOTE_ID, rate).build();
    assertEquals(node.initialGuess(marketData, ValueType.ZERO_RATE), rate);
    assertEquals(node.initialGuess(marketData, ValueType.FORWARD_RATE), rate);
    assertEquals(
        node.initialGuess(marketData, ValueType.DISCOUNT_FACTOR), Math.exp(-rate * 0.25), 1.0e-12);
  }

  public void test_metadata_end() {
    TermDepositCurveNode node = TermDepositCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD);
    LocalDate valuationDate = LocalDate.of(2015, 1, 22);
    ParameterMetadata metadata = node.metadata(valuationDate, REF_DATA);
    assertEquals(((TenorDateParameterMetadata) metadata).getDate(), LocalDate.of(2015, 4, 27));
    assertEquals(((TenorDateParameterMetadata) metadata).getTenor(), Tenor.TENOR_3M);
  }

  public void test_metadata_fixed() {
    LocalDate nodeDate = VAL_DATE.plusMonths(1);
    TermDepositCurveNode node =
        TermDepositCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD).withDate(CurveNodeDate.of(nodeDate));
    LocalDate valuationDate = LocalDate.of(2015, 1, 22);
    DatedParameterMetadata metadata = node.metadata(valuationDate, REF_DATA);
    assertEquals(metadata.getDate(), nodeDate);
    assertEquals(metadata.getLabel(), node.getLabel());
  }

  public void test_metadata_last_fixing() {
    TermDepositCurveNode node =
        TermDepositCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD).withDate(CurveNodeDate.LAST_FIXING);
    assertThrowsWithCause(
        () -> node.metadata(VAL_DATE, REF_DATA), UnsupportedOperationException.class);
  }

  // -------------------------------------------------------------------------
  public void coverage() {
    TermDepositCurveNode test = TermDepositCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD);
    coverImmutableBean(test);
    TermDepositCurveNode test2 =
        TermDepositCurveNode.of(
            TermDepositTemplate.of(Period.ofMonths(1), CONVENTION),
            QuoteId.of(StandardId.of("OG-Ticker", "Deposit2")));
    coverBeanEquals(test, test2);
  }

  public void test_serialization() {
    TermDepositCurveNode test = TermDepositCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD);
    assertSerialization(test);
  }
}
/** Black volatility data sets for testing. */
public class SwaptionNormalVolatilityDataSets {

  private static final double BP1 = 1.0E-4;

  private static final Interpolator1D LINEAR_FLAT =
      CombinedInterpolatorExtrapolator.of(
          CurveInterpolators.LINEAR.getName(),
          CurveExtrapolators.FLAT.getName(),
          CurveExtrapolators.FLAT.getName());
  private static final GridInterpolator2D INTERPOLATOR_2D =
      new GridInterpolator2D(LINEAR_FLAT, LINEAR_FLAT);

  //     =====     Standard figures for testing     =====
  private static final DoubleArray TIMES =
      DoubleArray.of(
          0.50, 1.00, 5.00, 10.0, 0.50, 1.00, 5.00, 10.0, 0.50, 1.00, 5.00, 10.0, 0.50, 1.00, 5.00,
          10.0, 0.50, 1.00, 5.00, 10.0);
  private static final DoubleArray TENOR =
      DoubleArray.of(
          1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 5.0, 5.0, 5.0, 5.0, 10.0, 10.0, 10.0, 10.0, 30.0,
          30.0, 30.0, 30.0);
  private static final DoubleArray NORMAL_VOL =
      DoubleArray.of(
          0.010, 0.011, 0.012, 0.013, 0.011, 0.012, 0.013, 0.014, 0.012, 0.013, 0.014, 0.015, 0.013,
          0.014, 0.015, 0.016, 0.014, 0.015, 0.016, 0.017);
  private static final SurfaceMetadata METADATA =
      DefaultSurfaceMetadata.builder()
          .xValueType(ValueType.YEAR_FRACTION)
          .yValueType(ValueType.YEAR_FRACTION)
          .zValueType(ValueType.VOLATILITY)
          .surfaceName(SurfaceName.of("Normal Vol"))
          .build();
  private static final NodalSurface SURFACE_STD =
      InterpolatedNodalSurface.of(METADATA, TIMES, TENOR, NORMAL_VOL, INTERPOLATOR_2D);

  private static final LocalDate VALUATION_DATE_STD = RatesProviderDataSets.VAL_DATE_2014_01_22;
  private static final LocalTime VALUATION_TIME_STD = LocalTime.of(13, 45);
  private static final ZoneId VALUATION_ZONE_STD = ZoneId.of("Europe/London");
  private static final BusinessDayAdjustment MOD_FOL_US =
      BusinessDayAdjustment.of(MODIFIED_FOLLOWING, USNY);
  private static final FixedRateSwapLegConvention USD_FIXED_1Y_30U360 =
      FixedRateSwapLegConvention.of(USD, THIRTY_U_360, Frequency.P6M, MOD_FOL_US);
  private static final IborRateSwapLegConvention USD_IBOR_LIBOR3M =
      IborRateSwapLegConvention.of(USD_LIBOR_3M);
  public static final FixedIborSwapConvention USD_1Y_LIBOR3M =
      ImmutableFixedIborSwapConvention.of("USD-Swap", USD_FIXED_1Y_30U360, USD_IBOR_LIBOR3M);
  public static final NormalVolatilityExpiryTenorSwaptionProvider
      NORMAL_VOL_SWAPTION_PROVIDER_USD_STD =
          NormalVolatilityExpiryTenorSwaptionProvider.of(
              SURFACE_STD,
              USD_1Y_LIBOR3M,
              DayCounts.ACT_365F,
              VALUATION_DATE_STD,
              VALUATION_TIME_STD,
              VALUATION_ZONE_STD);

  /**
   * Returns the swaption normal volatility surface shifted by a given amount. The shift is
   * parallel.
   *
   * @param shift the shift
   * @return the swaption normal volatility surface
   */
  public static NormalVolatilityExpiryTenorSwaptionProvider normalVolSwaptionProviderUsdStsShifted(
      double shift) {
    DoubleArray volShifted = NORMAL_VOL.map(v -> v + shift);
    return NormalVolatilityExpiryTenorSwaptionProvider.of(
        InterpolatedNodalSurface.of(METADATA, TIMES, TENOR, volShifted, INTERPOLATOR_2D),
        USD_1Y_LIBOR3M,
        DayCounts.ACT_365F,
        VALUATION_DATE_STD,
        VALUATION_TIME_STD,
        VALUATION_ZONE_STD);
  }

  public static NormalVolatilityExpiryTenorSwaptionProvider normalVolSwaptionProviderUsdStd(
      LocalDate valuationDate) {
    return NormalVolatilityExpiryTenorSwaptionProvider.of(
        SURFACE_STD,
        USD_1Y_LIBOR3M,
        DayCounts.ACT_365F,
        valuationDate,
        VALUATION_TIME_STD,
        VALUATION_ZONE_STD);
  }

  //     =====     Flat volatilities for testing     =====

  private static final DoubleArray TIMES_FLAT = DoubleArray.of(0.0, 100.0, 0.0, 100.0);
  private static final DoubleArray TENOR_FLAT = DoubleArray.of(0.0, 0.0, 30.0, 30.0);
  private static final DoubleArray NORMAL_VOL_FLAT = DoubleArray.of(0.01, 0.01, 0.01, 0.01);
  private static final InterpolatedNodalSurface SURFACE_FLAT =
      InterpolatedNodalSurface.of(
          METADATA, TIMES_FLAT, TENOR_FLAT, NORMAL_VOL_FLAT, INTERPOLATOR_2D);

  public static final NormalVolatilityExpiryTenorSwaptionProvider
      NORMAL_VOL_SWAPTION_PROVIDER_USD_FLAT =
          NormalVolatilityExpiryTenorSwaptionProvider.of(
              SURFACE_FLAT,
              USD_1Y_LIBOR3M,
              DayCounts.ACT_365F,
              VALUATION_DATE_STD,
              VALUATION_TIME_STD,
              VALUATION_ZONE_STD);

  //     =====     Market data as of 2014-03-20     =====

  private static final DoubleArray TIMES_20150320 =
      DoubleArray.of(
          0.25, 0.25, 0.25, 0.25, 0.25, 0.50, 0.50, 0.50, 0.50, 0.50, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0,
          2.0, 2.0, 2.0, 2.0, 5.0, 5.0, 5.0, 5.0, 5.0, 10.0, 10.0, 10.0, 10.0, 10.0);
  private static final DoubleArray TENORS_20150320 =
      DoubleArray.of(
          1.0, 2.0, 5.0, 10.0, 30.0, 1.0, 2.0, 5.0, 10.0, 30.0, 1.0, 2.0, 5.0, 10.0, 30.0, 1.0, 2.0,
          5.0, 10.0, 30.0, 1.0, 2.0, 5.0, 10.0, 30.0, 1.0, 2.0, 5.0, 10.0, 30.0);
  private static final DoubleArray NORMAL_VOL_20150320_BP =
      DoubleArray.of(
          43.6, 65.3, 88, 87.5, 88, // 3M
          55.5, 72.2, 90.3, 89.3, 88.6, // 6M
          72.6, 82.7, 91.6, 89.8, 87.3, // 1Y
          90.4, 91.9, 93.4, 84.7, 93.5, // 2Y
          99.3, 96.8, 94.3, 88.6, 77.3, // 5Y
          88.4, 85.9, 82.2, 76.7, 65.1); // 10Y
  private static final DoubleArray NORMAL_VOL_20150320 = NORMAL_VOL_20150320_BP.map(v -> v * BP1);
  private static final NodalSurface SURFACE_20150320 =
      InterpolatedNodalSurface.of(
          METADATA, TIMES_20150320, TENORS_20150320, NORMAL_VOL_20150320, INTERPOLATOR_2D);

  private static final LocalDate VALUATION_DATE_20150320 = LocalDate.of(2015, 3, 20);
  private static final LocalTime VALUATION_TIME_20150320 = LocalTime.of(18, 00);
  private static final ZoneId VALUATION_ZONE_20150320 = ZoneId.of("Europe/London");

  public static final NormalVolatilityExpiryTenorSwaptionProvider
      NORMAL_VOL_SWAPTION_PROVIDER_USD_20150320 =
          NormalVolatilityExpiryTenorSwaptionProvider.of(
              SURFACE_20150320,
              USD_1Y_LIBOR3M,
              DayCounts.ACT_365F,
              VALUATION_DATE_20150320,
              VALUATION_TIME_20150320,
              VALUATION_ZONE_20150320);
}
/** Test {@link SabrExtrapolationReplicationCmsTradePricer}. */
@Test
public class DiscountingCmsTradePricerTest {

  private static final ReferenceData REF_DATA = ReferenceData.standard();

  // trades
  private static final LocalDate VALUATION = LocalDate.of(2015, 8, 18);
  private static final SwapIndex INDEX = SwapIndices.EUR_EURIBOR_1100_5Y;
  private static final LocalDate START = LocalDate.of(2015, 10, 21);
  private static final LocalDate END = LocalDate.of(2020, 10, 21);
  private static final Frequency FREQUENCY = Frequency.P12M;
  private static final BusinessDayAdjustment BUSS_ADJ_EUR =
      BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, EUTA);
  private static final PeriodicSchedule SCHEDULE_EUR =
      PeriodicSchedule.of(
          START, END, FREQUENCY, BUSS_ADJ_EUR, StubConvention.NONE, RollConventions.NONE);
  private static final double NOTIONAL_VALUE = 1.0e6;
  private static final ValueSchedule NOTIONAL = ValueSchedule.of(NOTIONAL_VALUE);
  private static final ResolvedCmsLeg CMS_LEG =
      CmsLeg.builder()
          .index(INDEX)
          .notional(NOTIONAL)
          .payReceive(RECEIVE)
          .paymentSchedule(SCHEDULE_EUR)
          .build()
          .resolve(REF_DATA);
  private static final ResolvedSwapLeg PAY_LEG =
      RateCalculationSwapLeg.builder()
          .payReceive(PAY)
          .accrualSchedule(SCHEDULE_EUR)
          .calculation(FixedRateCalculation.of(0.01, ACT_360))
          .paymentSchedule(
              PaymentSchedule.builder()
                  .paymentFrequency(FREQUENCY)
                  .paymentDateOffset(DaysAdjustment.NONE)
                  .build())
          .notionalSchedule(NotionalSchedule.of(CurrencyAmount.of(EUR, NOTIONAL_VALUE)))
          .build()
          .resolve(REF_DATA);
  private static final ResolvedCms CMS_TWO_LEGS = ResolvedCms.of(CMS_LEG, PAY_LEG);
  private static final ResolvedCms CMS_ONE_LEG = ResolvedCms.of(CMS_LEG);
  private static final Payment PREMIUM =
      Payment.of(CurrencyAmount.of(EUR, -0.03 * NOTIONAL_VALUE), VALUATION);
  private static final TradeInfo TRADE_INFO = TradeInfo.builder().tradeDate(VALUATION).build();
  private static final ResolvedCmsTrade CMS_TRADE =
      ResolvedCmsTrade.builder().product(CMS_TWO_LEGS).info(TRADE_INFO).build();
  private static final ResolvedCmsTrade CMS_TRADE_PREMIUM =
      ResolvedCmsTrade.builder().product(CMS_ONE_LEG).premium(PREMIUM).build();
  // providers
  private static final ImmutableRatesProvider RATES_PROVIDER =
      SwaptionSabrRateVolatilityDataSet.getRatesProviderEur(VALUATION);
  // providers - valuation on payment date
  private static final LocalDate FIXING =
      LocalDate.of(2016, 10, 19); // fixing for the second period.
  private static final double OBS_INDEX = 0.013;
  private static final LocalDateDoubleTimeSeries TIME_SERIES =
      LocalDateDoubleTimeSeries.of(FIXING, OBS_INDEX);
  private static final LocalDate PAYMENT =
      LocalDate.of(2017, 10, 23); // payment date of the second payment
  private static final ImmutableRatesProvider RATES_PROVIDER_ON_PAY =
      SwaptionSabrRateVolatilityDataSet.getRatesProviderEur(PAYMENT, TIME_SERIES);
  // pricers
  private static final DiscountingCmsProductPricer PRODUCT_PRICER =
      DiscountingCmsProductPricer.DEFAULT;
  private static final DiscountingPaymentPricer PREMIUM_PRICER = DiscountingPaymentPricer.DEFAULT;
  private static final DiscountingCmsTradePricer TRADE_PRICER = DiscountingCmsTradePricer.DEFAULT;
  private static final double TOL = 1.0e-13;

  public void test_presentValue() {
    MultiCurrencyAmount pv1 = TRADE_PRICER.presentValue(CMS_TRADE_PREMIUM, RATES_PROVIDER);
    MultiCurrencyAmount pv2 = TRADE_PRICER.presentValue(CMS_TRADE, RATES_PROVIDER);
    MultiCurrencyAmount pvProd1 = PRODUCT_PRICER.presentValue(CMS_ONE_LEG, RATES_PROVIDER);
    MultiCurrencyAmount pvProd2 = PRODUCT_PRICER.presentValue(CMS_TWO_LEGS, RATES_PROVIDER);
    CurrencyAmount pvPrem = PREMIUM_PRICER.presentValue(PREMIUM, RATES_PROVIDER);
    assertEquals(pv1, pvProd1.plus(pvPrem));
    assertEquals(pv2, pvProd2);
  }

  public void test_presentValueSensitivity() {
    PointSensitivities pt1 =
        TRADE_PRICER.presentValueSensitivity(CMS_TRADE_PREMIUM, RATES_PROVIDER);
    PointSensitivities pt2 = TRADE_PRICER.presentValueSensitivity(CMS_TRADE, RATES_PROVIDER);
    PointSensitivityBuilder ptProd1 =
        PRODUCT_PRICER.presentValueSensitivity(CMS_ONE_LEG, RATES_PROVIDER);
    PointSensitivityBuilder ptProd2 =
        PRODUCT_PRICER.presentValueSensitivity(CMS_TWO_LEGS, RATES_PROVIDER);
    PointSensitivityBuilder ptPrem =
        PREMIUM_PRICER.presentValueSensitivity(PREMIUM, RATES_PROVIDER);
    assertEquals(pt1, ptProd1.combinedWith(ptPrem).build());
    assertEquals(pt2, ptProd2.build());
  }

  public void test_currencyExposure() {
    MultiCurrencyAmount computed1 =
        TRADE_PRICER.currencyExposure(CMS_TRADE_PREMIUM, RATES_PROVIDER);
    MultiCurrencyAmount computed2 = TRADE_PRICER.currencyExposure(CMS_TRADE, RATES_PROVIDER);
    MultiCurrencyAmount pv1 = TRADE_PRICER.presentValue(CMS_TRADE_PREMIUM, RATES_PROVIDER);
    PointSensitivities pt1 =
        TRADE_PRICER.presentValueSensitivity(CMS_TRADE_PREMIUM, RATES_PROVIDER);
    MultiCurrencyAmount expected1 = RATES_PROVIDER.currencyExposure(pt1).plus(pv1);
    MultiCurrencyAmount pv2 = TRADE_PRICER.presentValue(CMS_TRADE, RATES_PROVIDER);
    PointSensitivities pt2 = TRADE_PRICER.presentValueSensitivity(CMS_TRADE, RATES_PROVIDER);
    MultiCurrencyAmount expected2 = RATES_PROVIDER.currencyExposure(pt2).plus(pv2);
    assertEquals(
        computed1.getAmount(EUR).getAmount(),
        expected1.getAmount(EUR).getAmount(),
        NOTIONAL_VALUE * TOL);
    assertEquals(
        computed2.getAmount(EUR).getAmount(),
        expected2.getAmount(EUR).getAmount(),
        NOTIONAL_VALUE * TOL);
  }

  public void test_currentCash() {
    MultiCurrencyAmount cc1 = TRADE_PRICER.currentCash(CMS_TRADE_PREMIUM, RATES_PROVIDER);
    MultiCurrencyAmount cc2 = TRADE_PRICER.currentCash(CMS_TRADE, RATES_PROVIDER);
    assertEquals(cc1, MultiCurrencyAmount.of(PREMIUM.getValue()));
    assertEquals(cc2, MultiCurrencyAmount.of(CurrencyAmount.zero(EUR)));
  }

  public void test_currentCash_onPay() {
    MultiCurrencyAmount cc1 = TRADE_PRICER.currentCash(CMS_TRADE_PREMIUM, RATES_PROVIDER_ON_PAY);
    MultiCurrencyAmount cc2 = TRADE_PRICER.currentCash(CMS_TRADE, RATES_PROVIDER_ON_PAY);
    MultiCurrencyAmount ccProd1 = PRODUCT_PRICER.currentCash(CMS_ONE_LEG, RATES_PROVIDER_ON_PAY);
    MultiCurrencyAmount ccProd2 = PRODUCT_PRICER.currentCash(CMS_TWO_LEGS, RATES_PROVIDER_ON_PAY);
    assertEquals(cc1, ccProd1);
    assertEquals(cc2, ccProd2);
  }
}
/** Test */
@Test
public class DiscountingFixedCouponBondProductPricerTest {
  // fixed coupon bond
  private static final StandardId SECURITY_ID = StandardId.of("OG-Ticker", "GOVT1-BOND1");
  private static final StandardId ISSUER_ID = StandardId.of("OG-Ticker", "GOVT1");
  private static final LocalDate VAL_DATE = date(2016, 4, 25);
  private static final YieldConvention YIELD_CONVENTION = YieldConvention.GERMAN_BONDS;
  private static final double NOTIONAL = 1.0e7;
  private static final double FIXED_RATE = 0.015;
  private static final HolidayCalendar EUR_CALENDAR = HolidayCalendars.EUTA;
  private static final DaysAdjustment DATE_OFFSET = DaysAdjustment.ofBusinessDays(3, EUR_CALENDAR);
  private static final DayCount DAY_COUNT = DayCounts.ACT_365F;
  private static final LocalDate START_DATE = LocalDate.of(2015, 4, 12);
  private static final LocalDate END_DATE = LocalDate.of(2025, 4, 12);
  private static final BusinessDayAdjustment BUSINESS_ADJUST =
      BusinessDayAdjustment.of(BusinessDayConventions.MODIFIED_FOLLOWING, EUR_CALENDAR);
  private static final PeriodicSchedule PERIOD_SCHEDULE =
      PeriodicSchedule.of(
          START_DATE,
          END_DATE,
          Frequency.P6M,
          BUSINESS_ADJUST,
          StubConvention.SHORT_INITIAL,
          false);
  private static final DaysAdjustment EX_COUPON =
      DaysAdjustment.ofBusinessDays(-5, EUR_CALENDAR, BUSINESS_ADJUST);
  /** nonzero ex-coupon period */
  private static final FixedCouponBond PRODUCT =
      FixedCouponBond.builder()
          .dayCount(DAY_COUNT)
          .fixedRate(FIXED_RATE)
          .legalEntityId(ISSUER_ID)
          .currency(EUR)
          .notional(NOTIONAL)
          .periodicSchedule(PERIOD_SCHEDULE)
          .settlementDateOffset(DATE_OFFSET)
          .yieldConvention(YIELD_CONVENTION)
          .exCouponPeriod(EX_COUPON)
          .build();

  private static final Security<FixedCouponBond> BOND_SECURITY =
      UnitSecurity.builder(PRODUCT).standardId(SECURITY_ID).build();
  /** no ex-coupon period */
  private static final FixedCouponBond PRODUCT_NO_EXCOUPON =
      FixedCouponBond.builder()
          .dayCount(DAY_COUNT)
          .fixedRate(FIXED_RATE)
          .legalEntityId(ISSUER_ID)
          .currency(EUR)
          .notional(NOTIONAL)
          .periodicSchedule(PERIOD_SCHEDULE)
          .settlementDateOffset(DATE_OFFSET)
          .yieldConvention(YIELD_CONVENTION)
          .build();

  // rates provider
  private static final CurveInterpolator INTERPOLATOR = CurveInterpolators.LINEAR;
  private static final CurveName NAME_REPO = CurveName.of("TestRepoCurve");
  private static final CurveMetadata METADATA_REPO = Curves.zeroRates(NAME_REPO, ACT_365F);
  private static final InterpolatedNodalCurve CURVE_REPO =
      InterpolatedNodalCurve.of(
          METADATA_REPO,
          DoubleArray.of(0.1, 2.0, 10.0),
          DoubleArray.of(0.05, 0.06, 0.09),
          INTERPOLATOR);
  private static final DiscountFactors DSC_FACTORS_REPO =
      ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_REPO);
  private static final BondGroup GROUP_REPO = BondGroup.of("GOVT1 BOND1");
  private static final CurveName NAME_ISSUER = CurveName.of("TestIssuerCurve");
  private static final CurveMetadata METADATA_ISSUER = Curves.zeroRates(NAME_ISSUER, ACT_365F);
  private static final InterpolatedNodalCurve CURVE_ISSUER =
      InterpolatedNodalCurve.of(
          METADATA_ISSUER,
          DoubleArray.of(0.2, 9.0, 15.0),
          DoubleArray.of(0.03, 0.05, 0.13),
          INTERPOLATOR);
  private static final DiscountFactors DSC_FACTORS_ISSUER =
      ZeroRateDiscountFactors.of(EUR, VAL_DATE, CURVE_ISSUER);
  private static final LegalEntityGroup GROUP_ISSUER = LegalEntityGroup.of("GOVT1");
  private static final LegalEntityDiscountingProvider PROVIDER =
      LegalEntityDiscountingProvider.builder()
          .issuerCurves(
              ImmutableMap.<Pair<LegalEntityGroup, Currency>, DiscountFactors>of(
                  Pair.<LegalEntityGroup, Currency>of(GROUP_ISSUER, EUR), DSC_FACTORS_ISSUER))
          .legalEntityMap(ImmutableMap.<StandardId, LegalEntityGroup>of(ISSUER_ID, GROUP_ISSUER))
          .repoCurves(
              ImmutableMap.<Pair<BondGroup, Currency>, DiscountFactors>of(
                  Pair.<BondGroup, Currency>of(GROUP_REPO, EUR), DSC_FACTORS_REPO))
          .bondMap(ImmutableMap.<StandardId, BondGroup>of(SECURITY_ID, GROUP_REPO))
          .valuationDate(VAL_DATE)
          .build();

  private static final double Z_SPREAD = 0.035;
  private static final int PERIOD_PER_YEAR = 4;
  private static final double TOL = 1.0e-12;
  private static final double EPS = 1.0e-6;

  // pricers
  private static final DiscountingFixedCouponBondProductPricer PRICER =
      DiscountingFixedCouponBondProductPricer.DEFAULT;
  private static final DiscountingPaymentPricer PRICER_NOMINAL = DiscountingPaymentPricer.DEFAULT;
  private static final DiscountingFixedCouponBondPaymentPeriodPricer PRICER_COUPON =
      DiscountingFixedCouponBondPaymentPeriodPricer.DEFAULT;
  private static final RatesFiniteDifferenceSensitivityCalculator FD_CAL =
      new RatesFiniteDifferenceSensitivityCalculator(EPS);

  // -------------------------------------------------------------------------
  public void test_presentValue() {
    CurrencyAmount computed = PRICER.presentValue(PRODUCT, PROVIDER);
    ExpandedFixedCouponBond expanded = PRODUCT.expand();
    CurrencyAmount expected =
        PRICER_NOMINAL.presentValue(expanded.getNominalPayment(), DSC_FACTORS_ISSUER);
    int size = expanded.getPeriodicPayments().size();
    double pvCupon = 0d;
    for (int i = 2; i < size; ++i) {
      FixedCouponBondPaymentPeriod payment = expanded.getPeriodicPayments().get(i);
      pvCupon +=
          PRICER_COUPON.presentValue(
              payment, IssuerCurveDiscountFactors.of(DSC_FACTORS_ISSUER, GROUP_ISSUER));
    }
    expected = expected.plus(pvCupon);
    assertEquals(computed.getCurrency(), EUR);
    assertEquals(computed.getAmount(), expected.getAmount(), NOTIONAL * TOL);
  }

  public void test_presentValueWithZSpread_continuous() {
    CurrencyAmount computed =
        PRICER.presentValueWithZSpread(PRODUCT, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
    ExpandedFixedCouponBond expanded = PRODUCT.expand();
    CurrencyAmount expected =
        PRICER_NOMINAL.presentValue(
            expanded.getNominalPayment(), DSC_FACTORS_ISSUER, Z_SPREAD, CONTINUOUS, 0);
    int size = expanded.getPeriodicPayments().size();
    double pvcCupon = 0d;
    for (int i = 2; i < size; ++i) {
      FixedCouponBondPaymentPeriod payment = expanded.getPeriodicPayments().get(i);
      pvcCupon +=
          PRICER_COUPON.presentValueWithSpread(
              payment,
              IssuerCurveDiscountFactors.of(DSC_FACTORS_ISSUER, GROUP_ISSUER),
              Z_SPREAD,
              CONTINUOUS,
              0);
    }
    expected = expected.plus(pvcCupon);
    assertEquals(computed.getCurrency(), EUR);
    assertEquals(computed.getAmount(), expected.getAmount(), NOTIONAL * TOL);
  }

  public void test_presentValueWithZSpread_periodic() {
    CurrencyAmount computed =
        PRICER.presentValueWithZSpread(PRODUCT, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
    ExpandedFixedCouponBond expanded = PRODUCT.expand();
    CurrencyAmount expected =
        PRICER_NOMINAL.presentValue(
            expanded.getNominalPayment(), DSC_FACTORS_ISSUER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
    int size = expanded.getPeriodicPayments().size();
    double pvcCupon = 0d;
    for (int i = 2; i < size; ++i) {
      FixedCouponBondPaymentPeriod payment = expanded.getPeriodicPayments().get(i);
      pvcCupon +=
          PRICER_COUPON.presentValueWithSpread(
              payment,
              IssuerCurveDiscountFactors.of(DSC_FACTORS_ISSUER, GROUP_ISSUER),
              Z_SPREAD,
              PERIODIC,
              PERIOD_PER_YEAR);
    }
    expected = expected.plus(pvcCupon);
    assertEquals(computed.getCurrency(), EUR);
    assertEquals(computed.getAmount(), expected.getAmount(), NOTIONAL * TOL);
  }

  public void test_presentValue_noExcoupon() {
    CurrencyAmount computed = PRICER.presentValue(PRODUCT_NO_EXCOUPON, PROVIDER);
    ExpandedFixedCouponBond expanded = PRODUCT.expand();
    CurrencyAmount expected =
        PRICER_NOMINAL.presentValue(expanded.getNominalPayment(), DSC_FACTORS_ISSUER);
    int size = expanded.getPeriodicPayments().size();
    double pvcCupon = 0d;
    for (int i = 2; i < size; ++i) {
      FixedCouponBondPaymentPeriod payment = expanded.getPeriodicPayments().get(i);
      pvcCupon +=
          PRICER_COUPON.presentValue(
              payment, IssuerCurveDiscountFactors.of(DSC_FACTORS_ISSUER, GROUP_ISSUER));
    }
    expected = expected.plus(pvcCupon);
    assertEquals(computed.getCurrency(), EUR);
    assertEquals(computed.getAmount(), expected.getAmount(), NOTIONAL * TOL);
  }

  public void test_presentValueWithZSpread_continuous_noExcoupon() {
    CurrencyAmount computed =
        PRICER.presentValueWithZSpread(PRODUCT_NO_EXCOUPON, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
    ExpandedFixedCouponBond expanded = PRODUCT.expand();
    CurrencyAmount expected =
        PRICER_NOMINAL.presentValue(
            expanded.getNominalPayment(), DSC_FACTORS_ISSUER, Z_SPREAD, CONTINUOUS, 0);
    int size = expanded.getPeriodicPayments().size();
    double pvcCupon = 0d;
    for (int i = 2; i < size; ++i) {
      FixedCouponBondPaymentPeriod payment = expanded.getPeriodicPayments().get(i);
      pvcCupon +=
          PRICER_COUPON.presentValueWithSpread(
              payment,
              IssuerCurveDiscountFactors.of(DSC_FACTORS_ISSUER, GROUP_ISSUER),
              Z_SPREAD,
              CONTINUOUS,
              0);
    }
    expected = expected.plus(pvcCupon);
    assertEquals(computed.getCurrency(), EUR);
    assertEquals(computed.getAmount(), expected.getAmount(), NOTIONAL * TOL);
  }

  public void test_presentValueWithZSpread_periodic_noExcoupon() {
    CurrencyAmount computed =
        PRICER.presentValueWithZSpread(
            PRODUCT_NO_EXCOUPON, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
    ExpandedFixedCouponBond expanded = PRODUCT.expand();
    CurrencyAmount expected =
        PRICER_NOMINAL.presentValue(
            expanded.getNominalPayment(), DSC_FACTORS_ISSUER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
    int size = expanded.getPeriodicPayments().size();
    double pvcCupon = 0d;
    for (int i = 2; i < size; ++i) {
      FixedCouponBondPaymentPeriod payment = expanded.getPeriodicPayments().get(i);
      pvcCupon +=
          PRICER_COUPON.presentValueWithSpread(
              payment,
              IssuerCurveDiscountFactors.of(DSC_FACTORS_ISSUER, GROUP_ISSUER),
              Z_SPREAD,
              PERIODIC,
              PERIOD_PER_YEAR);
    }
    expected = expected.plus(pvcCupon);
    assertEquals(computed.getCurrency(), EUR);
    assertEquals(computed.getAmount(), expected.getAmount(), NOTIONAL * TOL);
  }

  // -------------------------------------------------------------------------
  public void test_dirtyPriceFromCurves() {
    double computed = PRICER.dirtyPriceFromCurves(BOND_SECURITY, PROVIDER);
    CurrencyAmount pv = PRICER.presentValue(PRODUCT, PROVIDER);
    LocalDate settlement = DATE_OFFSET.adjust(VAL_DATE);
    double df = DSC_FACTORS_REPO.discountFactor(settlement);
    assertEquals(computed, pv.getAmount() / df / NOTIONAL);
  }

  public void test_dirtyPriceFromCurvesWithZSpread_continuous() {
    double computed =
        PRICER.dirtyPriceFromCurvesWithZSpread(BOND_SECURITY, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
    CurrencyAmount pv = PRICER.presentValueWithZSpread(PRODUCT, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
    LocalDate settlement = DATE_OFFSET.adjust(VAL_DATE);
    double df = DSC_FACTORS_REPO.discountFactor(settlement);
    assertEquals(computed, pv.getAmount() / df / NOTIONAL);
  }

  public void test_dirtyPriceFromCurvesWithZSpread_periodic() {
    double computed =
        PRICER.dirtyPriceFromCurvesWithZSpread(
            BOND_SECURITY, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
    CurrencyAmount pv =
        PRICER.presentValueWithZSpread(PRODUCT, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
    LocalDate settlement = DATE_OFFSET.adjust(VAL_DATE);
    double df = DSC_FACTORS_REPO.discountFactor(settlement);
    assertEquals(computed, pv.getAmount() / df / NOTIONAL);
  }

  public void test_dirtyPriceFromCleanPrice_cleanPriceFromDirtyPrice() {
    double dirtyPrice = PRICER.dirtyPriceFromCurves(BOND_SECURITY, PROVIDER);
    LocalDate settlement = DATE_OFFSET.adjust(VAL_DATE);
    double cleanPrice = PRICER.cleanPriceFromDirtyPrice(PRODUCT, settlement, dirtyPrice);
    double accruedInterest = PRICER.accruedInterest(PRODUCT, settlement);
    assertEquals(cleanPrice, dirtyPrice - accruedInterest / NOTIONAL, NOTIONAL * TOL);
    double dirtyPriceRe = PRICER.dirtyPriceFromCleanPrice(PRODUCT, settlement, cleanPrice);
    assertEquals(dirtyPriceRe, dirtyPrice, TOL);
  }

  // -------------------------------------------------------------------------
  public void test_zSpreadFromCurvesAndPV_continuous() {
    double dirtyPrice =
        PRICER.dirtyPriceFromCurvesWithZSpread(BOND_SECURITY, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
    double computed =
        PRICER.zSpreadFromCurvesAndDirtyPrice(BOND_SECURITY, PROVIDER, dirtyPrice, CONTINUOUS, 0);
    assertEquals(computed, Z_SPREAD, TOL);
  }

  public void test_zSpreadFromCurvesAndPV_periodic() {
    double dirtyPrice =
        PRICER.dirtyPriceFromCurvesWithZSpread(
            BOND_SECURITY, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
    double computed =
        PRICER.zSpreadFromCurvesAndDirtyPrice(
            BOND_SECURITY, PROVIDER, dirtyPrice, PERIODIC, PERIOD_PER_YEAR);
    assertEquals(computed, Z_SPREAD, TOL);
  }

  // -------------------------------------------------------------------------
  public void test_presentValueSensitivity() {
    PointSensitivityBuilder point = PRICER.presentValueSensitivity(PRODUCT, PROVIDER);
    CurveCurrencyParameterSensitivities computed =
        PROVIDER.curveParameterSensitivity(point.build());
    CurveCurrencyParameterSensitivities expected =
        FD_CAL.sensitivity(PROVIDER, (p) -> PRICER.presentValue(PRODUCT, (p)));
    assertTrue(computed.equalWithTolerance(expected, 30d * NOTIONAL * EPS));
  }

  public void test_presentValueSensitivityWithZSpread_continuous() {
    PointSensitivityBuilder point =
        PRICER.presentValueSensitivityWithZSpread(PRODUCT, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
    CurveCurrencyParameterSensitivities computed =
        PROVIDER.curveParameterSensitivity(point.build());
    CurveCurrencyParameterSensitivities expected =
        FD_CAL.sensitivity(
            PROVIDER, (p) -> PRICER.presentValueWithZSpread(PRODUCT, (p), Z_SPREAD, CONTINUOUS, 0));
    assertTrue(computed.equalWithTolerance(expected, 20d * NOTIONAL * EPS));
  }

  public void test_presentValueSensitivityWithZSpread_periodic() {
    PointSensitivityBuilder point =
        PRICER.presentValueSensitivityWithZSpread(
            PRODUCT, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
    CurveCurrencyParameterSensitivities computed =
        PROVIDER.curveParameterSensitivity(point.build());
    CurveCurrencyParameterSensitivities expected =
        FD_CAL.sensitivity(
            PROVIDER,
            (p) ->
                PRICER.presentValueWithZSpread(PRODUCT, (p), Z_SPREAD, PERIODIC, PERIOD_PER_YEAR));
    assertTrue(computed.equalWithTolerance(expected, 20d * NOTIONAL * EPS));
  }

  public void test_presentValueProductSensitivity_noExcoupon() {
    PointSensitivityBuilder point = PRICER.presentValueSensitivity(PRODUCT_NO_EXCOUPON, PROVIDER);
    CurveCurrencyParameterSensitivities computed =
        PROVIDER.curveParameterSensitivity(point.build());
    CurveCurrencyParameterSensitivities expected =
        FD_CAL.sensitivity(PROVIDER, (p) -> PRICER.presentValue(PRODUCT_NO_EXCOUPON, (p)));
    assertTrue(computed.equalWithTolerance(expected, 30d * NOTIONAL * EPS));
  }

  public void test_presentValueSensitivityWithZSpread_continuous_noExcoupon() {
    PointSensitivityBuilder point =
        PRICER.presentValueSensitivityWithZSpread(
            PRODUCT_NO_EXCOUPON, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
    CurveCurrencyParameterSensitivities computed =
        PROVIDER.curveParameterSensitivity(point.build());
    CurveCurrencyParameterSensitivities expected =
        FD_CAL.sensitivity(
            PROVIDER,
            (p) ->
                PRICER.presentValueWithZSpread(PRODUCT_NO_EXCOUPON, (p), Z_SPREAD, CONTINUOUS, 0));
    assertTrue(computed.equalWithTolerance(expected, 20d * NOTIONAL * EPS));
  }

  public void test_presentValueSensitivityWithZSpread_periodic_noExcoupon() {
    PointSensitivityBuilder point =
        PRICER.presentValueSensitivityWithZSpread(
            PRODUCT_NO_EXCOUPON, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
    CurveCurrencyParameterSensitivities computed =
        PROVIDER.curveParameterSensitivity(point.build());
    CurveCurrencyParameterSensitivities expected =
        FD_CAL.sensitivity(
            PROVIDER,
            (p) ->
                PRICER.presentValueWithZSpread(
                    PRODUCT_NO_EXCOUPON, (p), Z_SPREAD, PERIODIC, PERIOD_PER_YEAR));
    assertTrue(computed.equalWithTolerance(expected, 20d * NOTIONAL * EPS));
  }

  public void test_dirtyPriceSensitivity() {
    PointSensitivityBuilder point = PRICER.dirtyPriceSensitivity(BOND_SECURITY, PROVIDER);
    CurveCurrencyParameterSensitivities computed =
        PROVIDER.curveParameterSensitivity(point.build());
    CurveCurrencyParameterSensitivities expected =
        FD_CAL.sensitivity(
            PROVIDER,
            (p) -> CurrencyAmount.of(EUR, PRICER.dirtyPriceFromCurves(BOND_SECURITY, (p))));
    assertTrue(computed.equalWithTolerance(expected, NOTIONAL * EPS));
  }

  public void test_dirtyPriceSensitivityWithZspread_continuous() {
    PointSensitivityBuilder point =
        PRICER.dirtyPriceSensitivityWithZspread(BOND_SECURITY, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
    CurveCurrencyParameterSensitivities computed =
        PROVIDER.curveParameterSensitivity(point.build());
    CurveCurrencyParameterSensitivities expected =
        FD_CAL.sensitivity(
            PROVIDER,
            (p) ->
                CurrencyAmount.of(
                    EUR,
                    PRICER.dirtyPriceFromCurvesWithZSpread(
                        BOND_SECURITY, (p), Z_SPREAD, CONTINUOUS, 0)));
    assertTrue(computed.equalWithTolerance(expected, NOTIONAL * EPS));
  }

  public void test_dirtyPriceSensitivityWithZspread_periodic() {
    PointSensitivityBuilder point =
        PRICER.dirtyPriceSensitivityWithZspread(
            BOND_SECURITY, PROVIDER, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR);
    CurveCurrencyParameterSensitivities computed =
        PROVIDER.curveParameterSensitivity(point.build());
    CurveCurrencyParameterSensitivities expected =
        FD_CAL.sensitivity(
            PROVIDER,
            (p) ->
                CurrencyAmount.of(
                    EUR,
                    PRICER.dirtyPriceFromCurvesWithZSpread(
                        BOND_SECURITY, (p), Z_SPREAD, PERIODIC, PERIOD_PER_YEAR)));
    assertTrue(computed.equalWithTolerance(expected, NOTIONAL * EPS));
  }

  // -------------------------------------------------------------------------
  public void test_accruedInterest() {
    // settle before start
    LocalDate settleDate1 = START_DATE.minusDays(5);
    double accruedInterest1 = PRICER.accruedInterest(PRODUCT, settleDate1);
    assertEquals(accruedInterest1, 0d);
    // settle between endDate and endDate -lag
    LocalDate settleDate2 = date(2015, 10, 8);
    double accruedInterest2 = PRICER.accruedInterest(PRODUCT, settleDate2);
    assertEquals(accruedInterest2, -4.0 / 365.0 * FIXED_RATE * NOTIONAL, EPS);
    // normal
    LocalDate settleDate3 = date(2015, 4, 18); // not adjusted
    FixedCouponBond product =
        FixedCouponBond.builder()
            .dayCount(DAY_COUNT)
            .fixedRate(FIXED_RATE)
            .legalEntityId(ISSUER_ID)
            .currency(EUR)
            .notional(NOTIONAL)
            .periodicSchedule(PERIOD_SCHEDULE)
            .settlementDateOffset(DATE_OFFSET)
            .yieldConvention(YIELD_CONVENTION)
            .exCouponPeriod(DaysAdjustment.NONE)
            .build();
    double accruedInterest3 = PRICER.accruedInterest(product, settleDate3);
    assertEquals(accruedInterest3, 6.0 / 365.0 * FIXED_RATE * NOTIONAL, EPS);
  }

  // -------------------------------------------------------------------------
  /* US Street convention */
  private static final LocalDate START_US = date(2006, 11, 15);
  private static final LocalDate END_US = START_US.plusYears(10);
  private static final PeriodicSchedule SCHEDULE_US =
      PeriodicSchedule.of(
          START_US,
          END_US,
          Frequency.P6M,
          BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, HolidayCalendars.SAT_SUN),
          StubConvention.SHORT_INITIAL,
          false);
  private static final FixedCouponBond PRODUCT_US =
      FixedCouponBond.builder()
          .dayCount(DayCounts.ACT_ACT_ICMA)
          .fixedRate(0.04625)
          .legalEntityId(ISSUER_ID)
          .currency(Currency.USD)
          .notional(100)
          .periodicSchedule(SCHEDULE_US)
          .settlementDateOffset(DaysAdjustment.ofBusinessDays(3, HolidayCalendars.SAT_SUN))
          .yieldConvention(YieldConvention.US_STREET)
          .exCouponPeriod(DaysAdjustment.NONE)
          .build();
  private static final LocalDate VALUATION_US = date(2011, 8, 18);
  private static final LocalDate SETTLEMENT_US =
      PRODUCT_US.getSettlementDateOffset().adjust(VALUATION_US);
  private static final LocalDate VALUATION_LAST_US = date(2016, 6, 3);
  private static final LocalDate SETTLEMENT_LAST_US =
      PRODUCT_US.getSettlementDateOffset().adjust(VALUATION_LAST_US);
  private static final double YIELD_US = 0.04;

  public void dirtyPriceFromYieldUS() {
    double dirtyPrice = PRICER.dirtyPriceFromYield(PRODUCT_US, SETTLEMENT_US, YIELD_US);
    assertEquals(dirtyPrice, 1.0417352500524246, TOL); // 2.x.
    double yield = PRICER.yieldFromDirtyPrice(PRODUCT_US, SETTLEMENT_US, dirtyPrice);
    assertEquals(yield, YIELD_US, TOL);
  }

  public void dirtyPriceFromYieldUSLastPeriod() {
    double dirtyPrice = PRICER.dirtyPriceFromYield(PRODUCT_US, SETTLEMENT_LAST_US, YIELD_US);
    assertEquals(dirtyPrice, 1.005635683760684, TOL); // 2.x.
    double yield = PRICER.yieldFromDirtyPrice(PRODUCT_US, SETTLEMENT_LAST_US, dirtyPrice);
    assertEquals(yield, YIELD_US, TOL);
  }

  public void modifiedDurationFromYieldUS() {
    double computed = PRICER.modifiedDurationFromYield(PRODUCT_US, SETTLEMENT_US, YIELD_US);
    double price = PRICER.dirtyPriceFromYield(PRODUCT_US, SETTLEMENT_US, YIELD_US);
    double priceUp = PRICER.dirtyPriceFromYield(PRODUCT_US, SETTLEMENT_US, YIELD_US + EPS);
    double priceDw = PRICER.dirtyPriceFromYield(PRODUCT_US, SETTLEMENT_US, YIELD_US - EPS);
    double expected = 0.5 * (priceDw - priceUp) / price / EPS;
    assertEquals(computed, expected, EPS);
  }

  public void modifiedDurationFromYieldUSLastPeriod() {
    double computed = PRICER.modifiedDurationFromYield(PRODUCT_US, SETTLEMENT_LAST_US, YIELD_US);
    double price = PRICER.dirtyPriceFromYield(PRODUCT_US, SETTLEMENT_LAST_US, YIELD_US);
    double priceUp = PRICER.dirtyPriceFromYield(PRODUCT_US, SETTLEMENT_LAST_US, YIELD_US + EPS);
    double priceDw = PRICER.dirtyPriceFromYield(PRODUCT_US, SETTLEMENT_LAST_US, YIELD_US - EPS);
    double expected = 0.5 * (priceDw - priceUp) / price / EPS;
    assertEquals(computed, expected, EPS);
  }

  public void convexityFromYieldUS() {
    double computed = PRICER.convexityFromYield(PRODUCT_US, SETTLEMENT_US, YIELD_US);
    double duration = PRICER.modifiedDurationFromYield(PRODUCT_US, SETTLEMENT_US, YIELD_US);
    double durationUp = PRICER.modifiedDurationFromYield(PRODUCT_US, SETTLEMENT_US, YIELD_US + EPS);
    double durationDw = PRICER.modifiedDurationFromYield(PRODUCT_US, SETTLEMENT_US, YIELD_US - EPS);
    double expected = 0.5 * (durationDw - durationUp) / EPS + duration * duration;
    assertEquals(computed, expected, EPS);
  }

  public void convexityFromYieldUSLastPeriod() {
    double computed = PRICER.convexityFromYield(PRODUCT_US, SETTLEMENT_LAST_US, YIELD_US);
    double duration = PRICER.modifiedDurationFromYield(PRODUCT_US, SETTLEMENT_LAST_US, YIELD_US);
    double durationUp =
        PRICER.modifiedDurationFromYield(PRODUCT_US, SETTLEMENT_LAST_US, YIELD_US + EPS);
    double durationDw =
        PRICER.modifiedDurationFromYield(PRODUCT_US, SETTLEMENT_LAST_US, YIELD_US - EPS);
    double expected = 0.5 * (durationDw - durationUp) / EPS + duration * duration;
    assertEquals(computed, expected, EPS);
  }

  public void macaulayDurationFromYieldUS() {
    double duration = PRICER.macaulayDurationFromYield(PRODUCT_US, SETTLEMENT_US, YIELD_US);
    assertEquals(duration, 4.6575232098896215, TOL); // 2.x.
  }

  public void macaulayDurationFromYieldUSLastPeriod() {
    double duration = PRICER.macaulayDurationFromYield(PRODUCT_US, SETTLEMENT_LAST_US, YIELD_US);
    assertEquals(duration, 0.43478260869565216, TOL); // 2.x.
  }

  /* UK BUMP/DMO convention */
  private static final LocalDate START_UK = date(2002, 9, 7);
  private static final LocalDate END_UK = START_UK.plusYears(12);
  private static final PeriodicSchedule SCHEDULE_UK =
      PeriodicSchedule.of(
          START_UK,
          END_UK,
          Frequency.P6M,
          BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, HolidayCalendars.SAT_SUN),
          StubConvention.SHORT_INITIAL,
          false);
  private static final FixedCouponBond PRODUCT_UK =
      FixedCouponBond.builder()
          .dayCount(DayCounts.ACT_ACT_ICMA)
          .fixedRate(0.05)
          .legalEntityId(ISSUER_ID)
          .currency(Currency.GBP)
          .notional(100)
          .periodicSchedule(SCHEDULE_UK)
          .settlementDateOffset(DaysAdjustment.ofBusinessDays(1, HolidayCalendars.SAT_SUN))
          .yieldConvention(YieldConvention.UK_BUMP_DMO)
          .exCouponPeriod(
              DaysAdjustment.ofCalendarDays(
                  -7,
                  BusinessDayAdjustment.of(
                      BusinessDayConventions.PRECEDING, HolidayCalendars.SAT_SUN)))
          .build();
  private static final LocalDate VALUATION_UK = date(2011, 9, 2);
  private static final LocalDate SETTLEMENT_UK =
      PRODUCT_UK.getSettlementDateOffset().adjust(VALUATION_UK);
  private static final LocalDate VALUATION_LAST_UK = date(2014, 6, 3);
  private static final LocalDate SETTLEMENT_LAST_UK =
      PRODUCT_UK.getSettlementDateOffset().adjust(VALUATION_LAST_UK);
  private static final double YIELD_UK = 0.04;

  public void dirtyPriceFromYieldUK() {
    double dirtyPrice = PRICER.dirtyPriceFromYield(PRODUCT_UK, SETTLEMENT_UK, YIELD_UK);
    assertEquals(dirtyPrice, 1.0277859038905428, TOL); // 2.x.
    double yield = PRICER.yieldFromDirtyPrice(PRODUCT_UK, SETTLEMENT_UK, dirtyPrice);
    assertEquals(yield, YIELD_UK, TOL);
  }

  public void dirtyPriceFromYieldUKLastPeriod() {
    double dirtyPrice = PRICER.dirtyPriceFromYield(PRODUCT_UK, SETTLEMENT_LAST_UK, YIELD_UK);
    assertEquals(dirtyPrice, 1.0145736043763598, TOL); // 2.x.
    double yield = PRICER.yieldFromDirtyPrice(PRODUCT_UK, SETTLEMENT_LAST_UK, dirtyPrice);
    assertEquals(yield, YIELD_UK, TOL);
  }

  public void modifiedDurationFromYieldUK() {
    double computed = PRICER.modifiedDurationFromYield(PRODUCT_UK, SETTLEMENT_UK, YIELD_UK);
    double price = PRICER.dirtyPriceFromYield(PRODUCT_UK, SETTLEMENT_UK, YIELD_UK);
    double priceUp = PRICER.dirtyPriceFromYield(PRODUCT_UK, SETTLEMENT_UK, YIELD_UK + EPS);
    double priceDw = PRICER.dirtyPriceFromYield(PRODUCT_UK, SETTLEMENT_UK, YIELD_UK - EPS);
    double expected = 0.5 * (priceDw - priceUp) / price / EPS;
    assertEquals(computed, expected, EPS);
  }

  public void modifiedDurationFromYieldUKLastPeriod() {
    double computed = PRICER.modifiedDurationFromYield(PRODUCT_UK, SETTLEMENT_LAST_UK, YIELD_UK);
    double price = PRICER.dirtyPriceFromYield(PRODUCT_UK, SETTLEMENT_LAST_UK, YIELD_UK);
    double priceUp = PRICER.dirtyPriceFromYield(PRODUCT_UK, SETTLEMENT_LAST_UK, YIELD_UK + EPS);
    double priceDw = PRICER.dirtyPriceFromYield(PRODUCT_UK, SETTLEMENT_LAST_UK, YIELD_UK - EPS);
    double expected = 0.5 * (priceDw - priceUp) / price / EPS;
    assertEquals(computed, expected, EPS);
  }

  public void convexityFromYieldUK() {
    double computed = PRICER.convexityFromYield(PRODUCT_UK, SETTLEMENT_UK, YIELD_UK);
    double duration = PRICER.modifiedDurationFromYield(PRODUCT_UK, SETTLEMENT_UK, YIELD_UK);
    double durationUp = PRICER.modifiedDurationFromYield(PRODUCT_UK, SETTLEMENT_UK, YIELD_UK + EPS);
    double durationDw = PRICER.modifiedDurationFromYield(PRODUCT_UK, SETTLEMENT_UK, YIELD_UK - EPS);
    double expected = 0.5 * (durationDw - durationUp) / EPS + duration * duration;
    assertEquals(computed, expected, EPS);
  }

  public void convexityFromYieldUKLastPeriod() {
    double computed = PRICER.convexityFromYield(PRODUCT_UK, SETTLEMENT_LAST_UK, YIELD_UK);
    double duration = PRICER.modifiedDurationFromYield(PRODUCT_UK, SETTLEMENT_LAST_UK, YIELD_UK);
    double durationUp =
        PRICER.modifiedDurationFromYield(PRODUCT_UK, SETTLEMENT_LAST_UK, YIELD_UK + EPS);
    double durationDw =
        PRICER.modifiedDurationFromYield(PRODUCT_UK, SETTLEMENT_LAST_UK, YIELD_UK - EPS);
    double expected = 0.5 * (durationDw - durationUp) / EPS + duration * duration;
    assertEquals(computed, expected, EPS);
  }

  public void macaulayDurationFromYieldUK() {
    double duration = PRICER.macaulayDurationFromYield(PRODUCT_UK, SETTLEMENT_UK, YIELD_UK);
    assertEquals(duration, 2.8312260658609163, TOL); // 2.x.
  }

  public void macaulayDurationFromYieldUKLastPeriod() {
    double duration = PRICER.macaulayDurationFromYield(PRODUCT_UK, SETTLEMENT_LAST_UK, YIELD_UK);
    assertEquals(duration, 0.25815217391304346, TOL); // 2.x.
  }

  /* German bond convention */
  private static final LocalDate START_GER = date(2002, 9, 7);
  private static final LocalDate END_GER = START_GER.plusYears(12);
  private static final PeriodicSchedule SCHEDULE_GER =
      PeriodicSchedule.of(
          START_GER,
          END_GER,
          Frequency.P12M,
          BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, HolidayCalendars.SAT_SUN),
          StubConvention.SHORT_INITIAL,
          false);
  private static final FixedCouponBond PRODUCT_GER =
      FixedCouponBond.builder()
          .dayCount(DayCounts.ACT_ACT_ICMA)
          .fixedRate(0.05)
          .legalEntityId(ISSUER_ID)
          .currency(Currency.EUR)
          .notional(100)
          .periodicSchedule(SCHEDULE_GER)
          .settlementDateOffset(DaysAdjustment.ofBusinessDays(3, HolidayCalendars.SAT_SUN))
          .yieldConvention(YieldConvention.GERMAN_BONDS)
          .exCouponPeriod(DaysAdjustment.NONE)
          .build();
  private static final LocalDate VALUATION_GER = date(2011, 9, 2);
  private static final LocalDate SETTLEMENT_GER =
      PRODUCT_GER.getSettlementDateOffset().adjust(VALUATION_GER);
  private static final LocalDate VALUATION_LAST_GER = date(2014, 6, 3);
  private static final LocalDate SETTLEMENT_LAST_GER =
      PRODUCT_GER.getSettlementDateOffset().adjust(VALUATION_LAST_GER);
  private static final double YIELD_GER = 0.04;

  public void dirtyPriceFromYieldGerman() {
    double dirtyPrice = PRICER.dirtyPriceFromYield(PRODUCT_GER, SETTLEMENT_GER, YIELD_GER);
    assertEquals(dirtyPrice, 1.027750910332271, TOL); // 2.x.
    double yield = PRICER.yieldFromDirtyPrice(PRODUCT_GER, SETTLEMENT_GER, dirtyPrice);
    assertEquals(yield, YIELD_GER, TOL);
  }

  public void dirtyPriceFromYieldGermanLastPeriod() {
    double dirtyPrice = PRICER.dirtyPriceFromYield(PRODUCT_GER, SETTLEMENT_LAST_GER, YIELD_GER);
    assertEquals(dirtyPrice, 1.039406595790844, TOL); // 2.x.
    double yield = PRICER.yieldFromDirtyPrice(PRODUCT_GER, SETTLEMENT_LAST_GER, dirtyPrice);
    assertEquals(yield, YIELD_GER, TOL);
  }

  public void modifiedDurationFromYieldGER() {
    double computed = PRICER.modifiedDurationFromYield(PRODUCT_GER, SETTLEMENT_GER, YIELD_GER);
    double price = PRICER.dirtyPriceFromYield(PRODUCT_GER, SETTLEMENT_GER, YIELD_GER);
    double priceUp = PRICER.dirtyPriceFromYield(PRODUCT_GER, SETTLEMENT_GER, YIELD_GER + EPS);
    double priceDw = PRICER.dirtyPriceFromYield(PRODUCT_GER, SETTLEMENT_GER, YIELD_GER - EPS);
    double expected = 0.5 * (priceDw - priceUp) / price / EPS;
    assertEquals(computed, expected, EPS);
  }

  public void modifiedDurationFromYieldGERLastPeriod() {
    double computed = PRICER.modifiedDurationFromYield(PRODUCT_GER, SETTLEMENT_LAST_GER, YIELD_GER);
    double price = PRICER.dirtyPriceFromYield(PRODUCT_GER, SETTLEMENT_LAST_GER, YIELD_GER);
    double priceUp = PRICER.dirtyPriceFromYield(PRODUCT_GER, SETTLEMENT_LAST_GER, YIELD_GER + EPS);
    double priceDw = PRICER.dirtyPriceFromYield(PRODUCT_GER, SETTLEMENT_LAST_GER, YIELD_GER - EPS);
    double expected = 0.5 * (priceDw - priceUp) / price / EPS;
    assertEquals(computed, expected, EPS);
  }

  public void convexityFromYieldGER() {
    double computed = PRICER.convexityFromYield(PRODUCT_GER, SETTLEMENT_GER, YIELD_GER);
    double duration = PRICER.modifiedDurationFromYield(PRODUCT_GER, SETTLEMENT_GER, YIELD_GER);
    double durationUp =
        PRICER.modifiedDurationFromYield(PRODUCT_GER, SETTLEMENT_GER, YIELD_GER + EPS);
    double durationDw =
        PRICER.modifiedDurationFromYield(PRODUCT_GER, SETTLEMENT_GER, YIELD_GER - EPS);
    double expected = 0.5 * (durationDw - durationUp) / EPS + duration * duration;
    assertEquals(computed, expected, EPS);
  }

  public void convexityFromYieldGERLastPeriod() {
    double computed = PRICER.convexityFromYield(PRODUCT_GER, SETTLEMENT_LAST_GER, YIELD_GER);
    double duration = PRICER.modifiedDurationFromYield(PRODUCT_GER, SETTLEMENT_LAST_GER, YIELD_GER);
    double durationUp =
        PRICER.modifiedDurationFromYield(PRODUCT_GER, SETTLEMENT_LAST_GER, YIELD_GER + EPS);
    double durationDw =
        PRICER.modifiedDurationFromYield(PRODUCT_GER, SETTLEMENT_LAST_GER, YIELD_GER - EPS);
    double expected = 0.5 * (durationDw - durationUp) / EPS + duration * duration;
    assertEquals(computed, expected, EPS);
  }

  public void macaulayDurationFromYieldGER() {
    double duration = PRICER.macaulayDurationFromYield(PRODUCT_GER, SETTLEMENT_GER, YIELD_GER);
    assertEquals(duration, 2.861462874541554, TOL); // 2.x.
  }

  public void macaulayDurationFromYieldGERLastPeriod() {
    double duration = PRICER.macaulayDurationFromYield(PRODUCT_GER, SETTLEMENT_LAST_GER, YIELD_GER);
    assertEquals(duration, 0.26231286613148186, TOL); // 2.x.
  }

  /* Japan simple convention */
  private static final LocalDate START_JP = date(2015, 9, 20);
  private static final LocalDate END_JP = START_JP.plusYears(10);
  private static final PeriodicSchedule SCHEDULE_JP =
      PeriodicSchedule.of(
          START_JP,
          END_JP,
          Frequency.P6M,
          BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, HolidayCalendars.JPTO),
          StubConvention.SHORT_INITIAL,
          false);
  private static final double RATE_JP = 0.004;
  private static final FixedCouponBond PRODUCT_JP =
      FixedCouponBond.builder()
          .dayCount(DayCounts.NL_365)
          .fixedRate(RATE_JP)
          .legalEntityId(ISSUER_ID)
          .currency(Currency.JPY)
          .notional(100)
          .periodicSchedule(SCHEDULE_JP)
          .settlementDateOffset(DaysAdjustment.ofBusinessDays(3, HolidayCalendars.JPTO))
          .yieldConvention(YieldConvention.JAPAN_SIMPLE)
          .exCouponPeriod(DaysAdjustment.NONE)
          .build();
  private static final LocalDate VALUATION_JP = date(2015, 9, 24);
  private static final LocalDate SETTLEMENT_JP =
      PRODUCT_JP.getSettlementDateOffset().adjust(VALUATION_JP);
  private static final LocalDate VALUATION_LAST_JP = date(2025, 6, 3);
  private static final LocalDate SETTLEMENT_LAST_JP =
      PRODUCT_JP.getSettlementDateOffset().adjust(VALUATION_LAST_JP);
  private static final LocalDate VALUATION_ENDED_JP = date(2026, 8, 3);
  private static final LocalDate SETTLEMENT_ENDED_JP =
      PRODUCT_JP.getSettlementDateOffset().adjust(VALUATION_ENDED_JP);
  private static final double YIELD_JP = 0.00321;

  public void dirtyPriceFromYieldJP() {
    double computed = PRICER.dirtyPriceFromYield(PRODUCT_JP, SETTLEMENT_JP, YIELD_JP);
    double maturity = DayCounts.NL_365.relativeYearFraction(SETTLEMENT_JP, END_JP);
    double expected =
        PRICER.dirtyPriceFromCleanPrice(
            PRODUCT_JP, SETTLEMENT_JP, (1d + RATE_JP * maturity) / (1d + YIELD_JP * maturity));
    assertEquals(computed, expected, TOL);
    double yield = PRICER.yieldFromDirtyPrice(PRODUCT_JP, SETTLEMENT_JP, computed);
    assertEquals(yield, YIELD_JP, TOL);
  }

  public void dirtyPriceFromYieldJPLastPeriod() {
    double computed = PRICER.dirtyPriceFromYield(PRODUCT_JP, SETTLEMENT_LAST_JP, YIELD_JP);
    double maturity = DayCounts.NL_365.relativeYearFraction(SETTLEMENT_LAST_JP, END_JP);
    double expected =
        PRICER.dirtyPriceFromCleanPrice(
            PRODUCT_JP, SETTLEMENT_LAST_JP, (1d + RATE_JP * maturity) / (1d + YIELD_JP * maturity));
    assertEquals(computed, expected, TOL);
    double yield = PRICER.yieldFromDirtyPrice(PRODUCT_JP, SETTLEMENT_LAST_JP, computed);
    assertEquals(yield, YIELD_JP, TOL);
  }

  public void dirtyPriceFromYieldJPEnded() {
    double computed = PRICER.dirtyPriceFromYield(PRODUCT_JP, SETTLEMENT_ENDED_JP, YIELD_JP);
    assertEquals(computed, 0d, TOL);
  }

  public void modifiedDurationFromYielddJP() {
    double computed = PRICER.modifiedDurationFromYield(PRODUCT_JP, SETTLEMENT_JP, YIELD_JP);
    double price = PRICER.dirtyPriceFromYield(PRODUCT_JP, SETTLEMENT_JP, YIELD_JP);
    double priceUp = PRICER.dirtyPriceFromYield(PRODUCT_JP, SETTLEMENT_JP, YIELD_JP + EPS);
    double priceDw = PRICER.dirtyPriceFromYield(PRODUCT_JP, SETTLEMENT_JP, YIELD_JP - EPS);
    double expected = 0.5 * (priceDw - priceUp) / price / EPS;
    assertEquals(computed, expected, EPS);
  }

  public void modifiedDurationFromYieldJPLastPeriod() {
    double computed = PRICER.modifiedDurationFromYield(PRODUCT_JP, SETTLEMENT_LAST_JP, YIELD_JP);
    double price = PRICER.dirtyPriceFromYield(PRODUCT_JP, SETTLEMENT_LAST_JP, YIELD_JP);
    double priceUp = PRICER.dirtyPriceFromYield(PRODUCT_JP, SETTLEMENT_LAST_JP, YIELD_JP + EPS);
    double priceDw = PRICER.dirtyPriceFromYield(PRODUCT_JP, SETTLEMENT_LAST_JP, YIELD_JP - EPS);
    double expected = 0.5 * (priceDw - priceUp) / price / EPS;
    assertEquals(computed, expected, EPS);
  }

  public void modifiedDurationFromYielddJPEnded() {
    double computed = PRICER.modifiedDurationFromYield(PRODUCT_JP, SETTLEMENT_ENDED_JP, YIELD_JP);
    assertEquals(computed, 0d, EPS);
  }

  public void convexityFromYieldJP() {
    double computed = PRICER.convexityFromYield(PRODUCT_JP, SETTLEMENT_JP, YIELD_JP);
    double duration = PRICER.modifiedDurationFromYield(PRODUCT_JP, SETTLEMENT_JP, YIELD_JP);
    double durationUp = PRICER.modifiedDurationFromYield(PRODUCT_JP, SETTLEMENT_JP, YIELD_JP + EPS);
    double durationDw = PRICER.modifiedDurationFromYield(PRODUCT_JP, SETTLEMENT_JP, YIELD_JP - EPS);
    double expected = 0.5 * (durationDw - durationUp) / EPS + duration * duration;
    assertEquals(computed, expected, EPS);
  }

  public void convexityFromYieldJPLastPeriod() {
    double computed = PRICER.convexityFromYield(PRODUCT_JP, SETTLEMENT_LAST_JP, YIELD_JP);
    double duration = PRICER.modifiedDurationFromYield(PRODUCT_JP, SETTLEMENT_LAST_JP, YIELD_JP);
    double durationUp =
        PRICER.modifiedDurationFromYield(PRODUCT_JP, SETTLEMENT_LAST_JP, YIELD_JP + EPS);
    double durationDw =
        PRICER.modifiedDurationFromYield(PRODUCT_JP, SETTLEMENT_LAST_JP, YIELD_JP - EPS);
    double expected = 0.5 * (durationDw - durationUp) / EPS + duration * duration;
    assertEquals(computed, expected, EPS);
  }

  public void convexityFromYieldJPEnded() {
    double computed = PRICER.convexityFromYield(PRODUCT_JP, SETTLEMENT_ENDED_JP, YIELD_JP);
    assertEquals(computed, 0d, EPS);
  }

  public void macaulayDurationFromYieldYieldJP() {
    assertThrows(
        () -> PRICER.macaulayDurationFromYield(PRODUCT_JP, SETTLEMENT_JP, YIELD_JP),
        UnsupportedOperationException.class,
        "The convention JAPAN_SIMPLE is not supported.");
  }
}