/**
   * Calculates the present value of the swaption product.
   *
   * <p>The result is expressed using the currency of the swapion.
   *
   * @param swaption the product to price
   * @param ratesProvider the rates provider
   * @param volatilityProvider the normal volatility provider
   * @return the present value of the swaption product
   */
  public CurrencyAmount presentValue(
      SwaptionProduct swaption,
      RatesProvider ratesProvider,
      NormalVolatilitySwaptionProvider volatilityProvider) {

    ExpandedSwaption expanded = swaption.expand();
    validate(ratesProvider, expanded, volatilityProvider);
    ZonedDateTime expiryDateTime = expanded.getExpiryDateTime();
    double expiry = volatilityProvider.relativeTime(expiryDateTime);
    ExpandedSwap underlying = expanded.getUnderlying();
    ExpandedSwapLeg fixedLeg = fixedLeg(underlying);
    if (expiry < 0.0d) { // Option has expired already
      return CurrencyAmount.of(fixedLeg.getCurrency(), 0.0d);
    }
    double forward = swapPricer.parRate(underlying, ratesProvider);
    double pvbp = swapPricer.getLegPricer().pvbp(fixedLeg, ratesProvider);
    double strike = swapPricer.getLegPricer().couponEquivalent(fixedLeg, ratesProvider, pvbp);
    double tenor = volatilityProvider.tenor(fixedLeg.getStartDate(), fixedLeg.getEndDate());
    double volatility = volatilityProvider.getVolatility(expiryDateTime, tenor, strike, forward);
    NormalFunctionData normalData = NormalFunctionData.of(forward, Math.abs(pvbp), volatility);
    boolean isCall = (fixedLeg.getPayReceive() == PayReceive.PAY);
    // Payer at strike is exercise when rate > strike, i.e. call on rate
    EuropeanVanillaOption option =
        EuropeanVanillaOption.of(strike, expiry, isCall ? PutCall.CALL : PutCall.PUT);
    // option required to pass the strike (in case the swap has non-constant coupon).
    Function1D<NormalFunctionData, Double> func = NORMAL.getPriceFunction(option);
    double pv =
        func.evaluate(normalData) * ((expanded.getLongShort() == LongShort.LONG) ? 1.0 : -1.0);
    return CurrencyAmount.of(fixedLeg.getCurrency(), pv);
  }
  public void convertCurrencyAmount() {
    List<FxRate> rates =
        ImmutableList.of(
            FxRate.of(Currency.GBP, Currency.USD, 1.61),
            FxRate.of(Currency.GBP, Currency.USD, 1.62),
            FxRate.of(Currency.GBP, Currency.USD, 1.63));
    CalculationEnvironment marketData =
        MarketEnvironment.builder()
            .valuationDate(date(2011, 3, 8))
            .addValue(FxRateId.of(Currency.GBP, Currency.USD), rates)
            .build();
    MarketDataMappings mappings = MarketDataMappings.of(MarketDataFeed.NONE);
    DefaultCalculationMarketData calculationMarketData =
        DefaultCalculationMarketData.of(marketData, mappings);

    SingleScenarioResult<CurrencyAmount> test =
        SingleScenarioResult.of(3, CurrencyAmount.of(Currency.GBP, 2));

    ScenarioResult<?> convertedList = test.convertedTo(Currency.USD, calculationMarketData);
    List<CurrencyAmount> expectedValues =
        ImmutableList.of(
            CurrencyAmount.of(Currency.USD, 2 * 1.61),
            CurrencyAmount.of(Currency.USD, 2 * 1.62),
            CurrencyAmount.of(Currency.USD, 2 * 1.63));
    DefaultScenarioResult<CurrencyAmount> expectedList = DefaultScenarioResult.of(expectedValues);
    assertThat(convertedList).isEqualTo(expectedList);
  }
Пример #3
0
 /**
  * Gets the notional amount, positive if receiving, negative if paying.
  *
  * <p>This is the notional amount applicable during the period. The currency of the notional is
  * specified by {@code currency} unless there is the {@code fxReset} property is present.
  *
  * @return the notional as a {@code CurrencyAmount}
  */
 @Override
 public CurrencyAmount getNotionalAmount() {
   if (fxReset != null) {
     return CurrencyAmount.of(fxReset.getReferenceCurrency(), notional);
   }
   return CurrencyAmount.of(currency, notional);
 }
 // -------------------------------------------------------------------------
 public void test_priceSensitivity() {
   PointSensitivities point =
       OPTION_PRICER.priceSensitivityStickyStrike(
           FUTURE_OPTION_PRODUCT, RATE_PROVIDER, VOL_PROVIDER);
   CurveCurrencyParameterSensitivities computed = RATE_PROVIDER.curveParameterSensitivity(point);
   CurveCurrencyParameterSensitivities expected =
       FD_CAL.sensitivity(
           RATE_PROVIDER,
           (p) ->
               CurrencyAmount.of(
                   EUR, OPTION_PRICER.price(FUTURE_OPTION_PRODUCT, (p), VOL_PROVIDER)));
   double futurePrice = FUTURE_PRICER.price(FUTURE_OPTION_PRODUCT.getUnderlying(), RATE_PROVIDER);
   double strike = FUTURE_OPTION_PRODUCT.getStrikePrice();
   double expiryTime =
       ACT_365F.relativeYearFraction(VALUATION_DATE, FUTURE_OPTION_PRODUCT.getExpiryDate());
   double logMoneyness = Math.log(strike / futurePrice);
   double logMoneynessUp = Math.log(strike / (futurePrice + EPS));
   double logMoneynessDw = Math.log(strike / (futurePrice - EPS));
   double vol = SURFACE.zValue(expiryTime, logMoneyness);
   double volUp = SURFACE.zValue(expiryTime, logMoneynessUp);
   double volDw = SURFACE.zValue(expiryTime, logMoneynessDw);
   double volSensi = 0.5 * (volUp - volDw) / EPS;
   double vega = BlackFormulaRepository.vega(futurePrice, strike, expiryTime, vol);
   CurveCurrencyParameterSensitivities sensiVol =
       RATE_PROVIDER
           .curveParameterSensitivity(
               FUTURE_PRICER.priceSensitivity(
                   FUTURE_OPTION_PRODUCT.getUnderlying(), RATE_PROVIDER))
           .multipliedBy(-vega * volSensi);
   expected = expected.combinedWith(sensiVol);
   assertTrue(computed.equalWithTolerance(expected, 30d * EPS));
 }
 // -------------------------------------------------------------------------
 public void test_priceSensitivity() {
   PointSensitivities point = FUTURE_PRICER.priceSensitivity(FUTURE_PRODUCT, PROVIDER);
   CurrencyParameterSensitivities computed = PROVIDER.parameterSensitivity(point);
   CurrencyParameterSensitivities expected =
       FD_CAL.sensitivity(
           PROVIDER, (p) -> CurrencyAmount.of(USD, FUTURE_PRICER.price(FUTURE_PRODUCT, (p))));
   assertTrue(computed.equalWithTolerance(expected, EPS * 10.0));
 }
 /** Test par spread sensitivity for ISDA FRA Discounting method. */
 public void test_parSpreadSensitivity_ISDA() {
   PointSensitivities sensi = DEFAULT_PRICER.parSpreadSensitivity(FRA, IMM_PROV);
   CurveCurrencyParameterSensitivities sensiComputed = IMM_PROV.curveParameterSensitivity(sensi);
   CurveCurrencyParameterSensitivities sensiExpected =
       CAL_FD.sensitivity(
           IMM_PROV,
           (p) -> CurrencyAmount.of(FRA.getCurrency(), DEFAULT_PRICER.parSpread(FRA, (p))));
   assertTrue(sensiComputed.equalWithTolerance(sensiExpected, EPS_FD));
 }
 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));
 }
 /**
  * Totals all the sensitivity values.
  *
  * <p>The result is the total of all values, as converted to the specified currency. Any FX
  * conversion that is required will use rates from the provider.
  *
  * @param resultCurrency the currency of the result
  * @param rateProvider the provider of FX rates
  * @return the total sensitivity
  * @throws RuntimeException if no FX rate could be found
  */
 public CurrencyAmount total(Currency resultCurrency, FxRateProvider rateProvider) {
   CurveCurrencyParameterSensitivities converted = convertedTo(resultCurrency, rateProvider);
   double total =
       converted
           .sensitivities
           .stream()
           .map(CurveCurrencyParameterSensitivity::getSensitivity)
           .flatMapToDouble(DoubleStream::of)
           .sum();
   return CurrencyAmount.of(resultCurrency, total);
 }
Пример #9
0
/** Test {@link FxSingleTrade}. */
@Test
public class FxSingleTradeTest {

  private static final CurrencyAmount GBP_P1000 = CurrencyAmount.of(GBP, 1_000);
  private static final CurrencyAmount GBP_M1000 = CurrencyAmount.of(GBP, -1_000);
  private static final CurrencyAmount USD_P1600 = CurrencyAmount.of(USD, 1_600);
  private static final CurrencyAmount USD_M1600 = CurrencyAmount.of(USD, -1_600);
  private static final LocalDate DATE_2015_06_30 = date(2015, 6, 30);
  private static final FxSingle FWD1 = FxSingle.of(GBP_P1000, USD_M1600, DATE_2015_06_30);
  private static final FxSingle FWD2 = FxSingle.of(GBP_M1000, USD_P1600, DATE_2015_06_30);

  // -------------------------------------------------------------------------
  public void test_builder() {
    FxSingleTrade test = FxSingleTrade.builder().product(FWD1).build();
    assertEquals(test.getTradeInfo(), TradeInfo.EMPTY);
    assertEquals(test.getProduct(), FWD1);
  }

  // -------------------------------------------------------------------------
  public void coverage() {
    FxSingleTrade test =
        FxSingleTrade.builder()
            .tradeInfo(TradeInfo.builder().tradeDate(date(2014, 6, 30)).build())
            .product(FWD1)
            .build();
    coverImmutableBean(test);
    FxSingleTrade test2 = FxSingleTrade.builder().product(FWD2).build();
    coverBeanEquals(test, test2);
  }

  public void test_serialization() {
    FxSingleTrade test =
        FxSingleTrade.builder()
            .tradeInfo(TradeInfo.builder().tradeDate(date(2014, 6, 30)).build())
            .product(FWD1)
            .build();
    assertSerialization(test);
  }
}
 public void test_priceSensitivityWithZSpread_continuous() {
   PointSensitivities point =
       FUTURE_PRICER.priceSensitivityWithZSpread(
           FUTURE_PRODUCT, PROVIDER, Z_SPREAD, CONTINUOUS, 0);
   CurrencyParameterSensitivities computed = PROVIDER.parameterSensitivity(point);
   CurrencyParameterSensitivities expected =
       FD_CAL.sensitivity(
           PROVIDER,
           (p) ->
               CurrencyAmount.of(
                   USD,
                   FUTURE_PRICER.priceWithZSpread(FUTURE_PRODUCT, (p), Z_SPREAD, CONTINUOUS, 0)));
   assertTrue(computed.equalWithTolerance(expected, EPS * 10.0));
 }
 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));
 }
  /** Test parameter sensitivity with finite difference sensitivity calculator. No cutoff period. */
  public void rateChfNoCutOffParameterSensitivity() {
    LocalDate[] valuationDate = {date(2015, 1, 1), date(2015, 1, 8)};
    double[] time = new double[] {0.0, 0.5, 1.0, 2.0, 5.0, 10.0};
    double[] rate = new double[] {0.0100, 0.0110, 0.0115, 0.0130, 0.0135, 0.0135};

    for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) {
      Curve onCurve =
          InterpolatedNodalCurve.of(Curves.zeroRates("ON", ACT_ACT_ISDA), time, rate, INTERPOLATOR);
      ImmutableRatesProvider prov =
          ImmutableRatesProvider.builder()
              .valuationDate(valuationDate[loopvaldate])
              .indexCurves(ImmutableMap.of(CHF_TOIS, onCurve))
              .timeSeries(ImmutableMap.of(CHF_TOIS, TIME_SERIES_BUILDER.build()))
              .build();
      OvernightAveragedRateObservation ro =
          OvernightAveragedRateObservation.of(CHF_TOIS, FIXING_START_DATE, FIXING_END_DATE, 0);
      ForwardOvernightAveragedRateObservationFn obsFn =
          ForwardOvernightAveragedRateObservationFn.DEFAULT;

      PointSensitivityBuilder sensitivityBuilderComputed =
          obsFn.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, prov);
      CurveCurrencyParameterSensitivities parameterSensitivityComputed =
          prov.curveParameterSensitivity(sensitivityBuilderComputed.build());

      CurveCurrencyParameterSensitivities parameterSensitivityExpected =
          CAL_FD.sensitivity(
              prov,
              (p) ->
                  CurrencyAmount.of(
                      CHF_TOIS.getCurrency(),
                      obsFn.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, (p))));
      assertTrue(
          parameterSensitivityComputed.equalWithTolerance(
              parameterSensitivityExpected, EPS_FD * 10.0));
    }
  }
/** Test {@link FxNdfFunctionGroups}. */
@Test
public class FxNdfFunctionGroupsTest {

  private static final FxRate FX_RATE = FxRate.of(GBP, USD, 1.5d);
  private static final CurrencyAmount NOTIONAL = CurrencyAmount.of(GBP, (double) 100_000_000);
  private static final FxNdf PRODUCT =
      FxNdf.builder()
          .agreedFxRate(FX_RATE)
          .settlementCurrencyNotional(NOTIONAL)
          .index(GBP_USD_WM)
          .paymentDate(date(2015, 3, 19))
          .build();
  public static final FxNdfTrade TRADE =
      FxNdfTrade.builder()
          .tradeInfo(TradeInfo.builder().tradeDate(date(2015, 6, 1)).build())
          .product(PRODUCT)
          .build();

  public void test_discounting() {
    FunctionGroup<FxNdfTrade> test = FxNdfFunctionGroups.discounting();
    assertThat(test.configuredMeasures(TRADE))
        .contains(
            Measure.PRESENT_VALUE,
            Measure.PV01,
            Measure.BUCKETED_PV01,
            Measure.CURRENCY_EXPOSURE,
            Measure.FORWARD_FX_RATE);
  }

  public void test_presentValue() {
    Currency ccy1 = TRADE.getProduct().getNonDeliverableCurrency();
    Currency ccy2 = TRADE.getProduct().getSettlementCurrency();
    LocalDate valDate = TRADE.getProduct().getPaymentDate().plusDays(7);

    FunctionConfig<FxNdfTrade> config =
        FxNdfFunctionGroups.discounting().functionConfig(TRADE, Measure.PRESENT_VALUE).get();
    CalculationSingleFunction<FxNdfTrade, ?> function = config.createFunction();
    FunctionRequirements reqs = function.requirements(TRADE);
    assertThat(reqs.getOutputCurrencies()).containsOnly(ccy1, ccy2);
    assertThat(reqs.getSingleValueRequirements())
        .isEqualTo(ImmutableSet.of(DiscountCurveKey.of(ccy1), DiscountCurveKey.of(ccy2)));
    assertThat(reqs.getTimeSeriesRequirements()).isEqualTo(ImmutableSet.of());
    assertThat(function.defaultReportingCurrency(TRADE)).hasValue(GBP);
    DiscountFactors df1 =
        SimpleDiscountFactors.of(
            ccy1, valDate, ConstantNodalCurve.of(Curves.discountFactors("Test", ACT_360), 0.99));
    DiscountFactors df2 =
        SimpleDiscountFactors.of(
            ccy2, valDate, ConstantNodalCurve.of(Curves.discountFactors("Test", ACT_360), 0.99));
    TestMarketDataMap md =
        new TestMarketDataMap(
            valDate,
            ImmutableMap.of(DiscountCurveKey.of(ccy1), df1, DiscountCurveKey.of(ccy2), df2),
            ImmutableMap.of());
    assertThat(function.execute(TRADE, md))
        .isEqualTo(FxConvertibleList.of(ImmutableList.of(CurrencyAmount.zero(GBP))));
  }

  // -------------------------------------------------------------------------
  public void coverage() {
    coverPrivateConstructor(FxNdfFunctionGroups.class);
  }

  public void coverage_functions() {
    Currency ccy1 = TRADE.getProduct().getNonDeliverableCurrency();
    Currency ccy2 = TRADE.getProduct().getSettlementCurrency();
    LocalDate valDate = TRADE.getProduct().getPaymentDate().plusDays(7);
    Curve df = ConstantNodalCurve.of(Curves.discountFactors("Test", ACT_360), 0.99);
    FxRate fxRate = FxRate.of(ccy1, ccy2, 1.6d);
    TestMarketDataMap md =
        new TestMarketDataMap(
            valDate,
            ImmutableMap.of(
                DiscountCurveKey.of(ccy1), df,
                DiscountCurveKey.of(ccy2), df,
                FxRateKey.of(ccy1, ccy2), fxRate),
            ImmutableMap.of(
                IndexRateKey.of(GBP_USD_WM),
                LocalDateDoubleTimeSeries.of(date(2015, 3, 17), 1.45d)));

    assertNotNull(new FxNdfBucketedPv01Function().execute(TRADE, md));
    assertNotNull(new FxNdfCurrencyExposureFunction().execute(TRADE, md));
    assertNotNull(new FxNdfForwardFxRateFunction().execute(TRADE, md));
    assertNotNull(new FxNdfPv01Function().execute(TRADE, md));
    assertNotNull(new FxNdfPvFunction().execute(TRADE, md));
  }
}
  public void test_cashFlowEquivalent() {
    Swap swap = Swap.builder().legs(IBOR_LEG, FIXED_LEG).build();
    ExpandedSwapLeg computed =
        CashFlowEquivalentCalculator.cashFlowEquivalentSwap(swap.expand(), PROVIDER);
    ExpandedSwapLeg computedIborLeg =
        CashFlowEquivalentCalculator.cashFlowEquivalentIborLeg(IBOR_LEG.expand(), PROVIDER);
    ExpandedSwapLeg computedFixedLeg =
        CashFlowEquivalentCalculator.cashFlowEquivalentFixedLeg(FIXED_LEG.expand(), PROVIDER);
    assertEquals(computedFixedLeg.getPaymentEvents(), computed.getPaymentEvents().subList(0, 2));
    assertEquals(computedIborLeg.getPaymentEvents(), computed.getPaymentEvents().subList(2, 6));

    // expected payments from fixed leg
    NotionalExchange fixedPayment1 =
        NotionalExchange.of(PAYMENT1, CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC1));
    NotionalExchange fixedPayment2 =
        NotionalExchange.of(PAYMENT2, CurrencyAmount.of(GBP, NOTIONAL * RATE * PAY_YC2));
    // expected payments from ibor leg
    LocalDate fixingSTART1 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING1);
    double fixedYearFraction1 =
        GBP_LIBOR_3M
            .getDayCount()
            .relativeYearFraction(
                fixingSTART1, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART1));
    double beta1 =
        (1d + fixedYearFraction1 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(FIXING1))
            * PROVIDER.discountFactor(GBP, PAYMENT1)
            / PROVIDER.discountFactor(GBP, fixingSTART1);
    NotionalExchange iborPayment11 =
        NotionalExchange.of(
            fixingSTART1, CurrencyAmount.of(GBP, -NOTIONAL * beta1 * PAY_YC1 / fixedYearFraction1));
    NotionalExchange iborPayment12 =
        NotionalExchange.of(
            PAYMENT1, CurrencyAmount.of(GBP, NOTIONAL * PAY_YC1 / fixedYearFraction1));
    LocalDate fixingSTART2 = GBP_LIBOR_3M.calculateEffectiveFromFixing(FIXING2);
    double fixedYearFraction2 =
        GBP_LIBOR_3M
            .getDayCount()
            .relativeYearFraction(
                fixingSTART2, GBP_LIBOR_3M.calculateMaturityFromEffective(fixingSTART2));
    double beta2 =
        (1d + fixedYearFraction2 * PROVIDER.iborIndexRates(GBP_LIBOR_3M).rate(FIXING2))
            * PROVIDER.discountFactor(GBP, PAYMENT2)
            / PROVIDER.discountFactor(GBP, fixingSTART2);
    NotionalExchange iborPayment21 =
        NotionalExchange.of(
            fixingSTART2, CurrencyAmount.of(GBP, -NOTIONAL * beta2 * PAY_YC2 / fixedYearFraction2));
    NotionalExchange iborPayment22 =
        NotionalExchange.of(
            PAYMENT2, CurrencyAmount.of(GBP, NOTIONAL * PAY_YC2 / fixedYearFraction2));

    ExpandedSwapLeg expected =
        ExpandedSwapLeg.builder()
            .type(OTHER)
            .payReceive(RECEIVE)
            .paymentEvents(
                fixedPayment1,
                fixedPayment2,
                iborPayment11,
                iborPayment12,
                iborPayment21,
                iborPayment22)
            .build();

    double eps = 1.0e-12;
    assertEquals(computed.getPaymentEvents().size(), expected.getPaymentEvents().size());
    for (int i = 0; i < 6; ++i) {
      NotionalExchange payCmp = (NotionalExchange) computed.getPaymentEvents().get(i);
      NotionalExchange payExp = (NotionalExchange) expected.getPaymentEvents().get(i);
      assertEquals(payCmp.getCurrency(), payExp.getCurrency());
      assertEquals(payCmp.getPaymentDate(), payExp.getPaymentDate());
      assertTrue(
          DoubleMath.fuzzyEquals(
              payCmp.getPaymentAmount().getAmount(),
              payExp.getPaymentAmount().getAmount(),
              NOTIONAL * eps));
    }
  }
/** 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 {@link BlackFxVanillaOptionTradePricer}. */
@Test
public class BlackFxVanillaOptionTradePricerTest {

  private static final LocalDate VAL_DATE = RatesProviderDataSets.VAL_DATE_2014_01_22;
  private static final LocalTime VAL_TIME = LocalTime.of(13, 45);
  private static final ZoneId ZONE = ZoneId.of("Z");
  private static final ZonedDateTime VAL_DATE_TIME = VAL_DATE.atTime(VAL_TIME).atZone(ZONE);
  private static final ZonedDateTime EXPIRY = ZonedDateTime.of(2014, 5, 9, 13, 10, 0, 0, ZONE);

  private static final FxMatrix FX_MATRIX = RatesProviderFxDataSets.fxMatrix();
  private static final RatesProvider RATES_PROVIDER =
      RatesProviderFxDataSets.createProviderEURUSD(VAL_DATE);

  private static final DoubleArray TIME_TO_EXPIRY =
      DoubleArray.of(0.01, 0.252, 0.501, 1.0, 2.0, 5.0);
  private static final DoubleArray ATM = DoubleArray.of(0.175, 0.185, 0.18, 0.17, 0.16, 0.16);
  private static final DoubleArray DELTA = DoubleArray.of(0.10, 0.25);
  private static final DoubleMatrix RISK_REVERSAL =
      DoubleMatrix.ofUnsafe(
          new double[][] {
            {-0.010, -0.0050}, {-0.011, -0.0060}, {-0.012, -0.0070},
            {-0.013, -0.0080}, {-0.014, -0.0090}, {-0.014, -0.0090}
          });
  private static final DoubleMatrix STRANGLE =
      DoubleMatrix.ofUnsafe(
          new double[][] {
            {0.0300, 0.0100},
            {0.0310, 0.0110},
            {0.0320, 0.0120},
            {0.0330, 0.0130},
            {0.0340, 0.0140},
            {0.0340, 0.0140}
          });
  private static final InterpolatedStrikeSmileDeltaTermStructure SMILE_TERM =
      InterpolatedStrikeSmileDeltaTermStructure.of(
          TIME_TO_EXPIRY, DELTA, ATM, RISK_REVERSAL, STRANGLE, ACT_365F);
  private static final CurrencyPair CURRENCY_PAIR = CurrencyPair.of(EUR, USD);
  private static final BlackFxOptionSmileVolatilities VOLS =
      BlackFxOptionSmileVolatilities.of(
          FxOptionVolatilitiesName.of("Test"), CURRENCY_PAIR, VAL_DATE_TIME, SMILE_TERM);

  private static final LocalDate PAYMENT_DATE = LocalDate.of(2014, 5, 13);
  private static final double NOTIONAL = 1.0e6;
  private static final CurrencyAmount EUR_AMOUNT = CurrencyAmount.of(EUR, NOTIONAL);
  private static final CurrencyAmount USD_AMOUNT =
      CurrencyAmount.of(USD, -NOTIONAL * FX_MATRIX.fxRate(EUR, USD));
  private static final ResolvedFxSingle FX_PRODUCT =
      ResolvedFxSingle.of(EUR_AMOUNT, USD_AMOUNT, PAYMENT_DATE);
  private static final ResolvedFxVanillaOption OPTION_PRODUCT =
      ResolvedFxVanillaOption.builder()
          .longShort(SHORT)
          .expiry(EXPIRY)
          .underlying(FX_PRODUCT)
          .build();
  private static final TradeInfo TRADE_INFO = TradeInfo.builder().tradeDate(VAL_DATE).build();
  private static final LocalDate CASH_SETTLE_DATE = LocalDate.of(2014, 1, 25);
  private static final Payment PREMIUM = Payment.of(EUR, NOTIONAL * 0.027, CASH_SETTLE_DATE);
  private static final ResolvedFxVanillaOptionTrade OPTION_TRADE =
      ResolvedFxVanillaOptionTrade.builder()
          .premium(PREMIUM)
          .product(OPTION_PRODUCT)
          .info(TRADE_INFO)
          .build();

  private static final BlackFxVanillaOptionProductPricer PRICER_PRODUCT =
      BlackFxVanillaOptionProductPricer.DEFAULT;
  private static final BlackFxVanillaOptionTradePricer PRICER_TRADE =
      BlackFxVanillaOptionTradePricer.DEFAULT;
  private static final DiscountingPaymentPricer PRICER_PAYMENT = DiscountingPaymentPricer.DEFAULT;
  private static final double TOL = 1.0e-13;

  public void test_presentValue() {
    MultiCurrencyAmount pvSensiTrade =
        PRICER_TRADE.presentValue(OPTION_TRADE, RATES_PROVIDER, VOLS);
    CurrencyAmount pvSensiProduct =
        PRICER_PRODUCT.presentValue(OPTION_PRODUCT, RATES_PROVIDER, VOLS);
    CurrencyAmount pvSensiPremium = PRICER_PAYMENT.presentValue(PREMIUM, RATES_PROVIDER);
    assertEquals(pvSensiTrade, MultiCurrencyAmount.of(pvSensiProduct, pvSensiPremium));
  }

  public void test_presentValueSensitivity() {
    PointSensitivities pvSensiTrade =
        PRICER_TRADE.presentValueSensitivityRates(OPTION_TRADE, RATES_PROVIDER, VOLS);
    PointSensitivities pvSensiProduct =
        PRICER_PRODUCT.presentValueSensitivityRates(OPTION_PRODUCT, RATES_PROVIDER, VOLS);
    PointSensitivities pvSensiPremium =
        PRICER_PAYMENT.presentValueSensitivity(PREMIUM, RATES_PROVIDER).build();
    assertEquals(pvSensiTrade, pvSensiProduct.combinedWith(pvSensiPremium));
  }

  public void test_presentValueSensitivityBlackVolatility() {
    PointSensitivities pvSensiTrade =
        PRICER_TRADE.presentValueSensitivityModelParamsVolatility(
            OPTION_TRADE, RATES_PROVIDER, VOLS);
    PointSensitivities pvSensiProduct =
        PRICER_PRODUCT
            .presentValueSensitivityModelParamsVolatility(OPTION_PRODUCT, RATES_PROVIDER, VOLS)
            .build();
    assertEquals(pvSensiTrade, pvSensiProduct);
  }

  public void test_currencyExposure() {
    MultiCurrencyAmount ceComputed =
        PRICER_TRADE.currencyExposure(OPTION_TRADE, RATES_PROVIDER, VOLS);
    PointSensitivities point =
        PRICER_TRADE.presentValueSensitivityRates(OPTION_TRADE, RATES_PROVIDER, VOLS);
    MultiCurrencyAmount pv = PRICER_TRADE.presentValue(OPTION_TRADE, RATES_PROVIDER, VOLS);
    MultiCurrencyAmount ceExpected = RATES_PROVIDER.currencyExposure(point).plus(pv);
    assertEquals(ceComputed.size(), 2);
    assertEquals(
        ceComputed.getAmount(EUR).getAmount(),
        ceExpected.getAmount(EUR).getAmount(),
        TOL * NOTIONAL);
    assertEquals(
        ceComputed.getAmount(USD).getAmount(),
        ceExpected.getAmount(USD).getAmount(),
        TOL * NOTIONAL);
  }

  public void test_currentCash_zero() {
    assertEquals(
        PRICER_TRADE.currentCash(OPTION_TRADE, VAL_DATE),
        CurrencyAmount.zero(PREMIUM.getCurrency()));
  }

  public void test_currentCash_onSettle() {
    assertEquals(PRICER_TRADE.currentCash(OPTION_TRADE, CASH_SETTLE_DATE), PREMIUM.getValue());
  }
}