@Override
 public Optional<Currency> defaultReportingCurrency(FxSwapTrade target) {
   Currency base = target.getProduct().getNearLeg().getBaseCurrencyAmount().getCurrency();
   Currency counter = target.getProduct().getNearLeg().getCounterCurrencyAmount().getCurrency();
   CurrencyPair marketConventionPair = CurrencyPair.of(base, counter).toConventional();
   return Optional.of(marketConventionPair.getBase());
 }
 /**
  * Obtains an instance from currency pair, reference currency, reference date and sensitivity
  * value.
  *
  * <p>The sensitivity currency is defaulted to be a currency of the currency pair that is not the
  * reference currency.
  *
  * @param currencyPair the currency pair
  * @param referenceCurrency the reference currency
  * @param referenceDate the reference date
  * @param sensitivity the value of the sensitivity
  * @return the point sensitivity object
  */
 public static FxForwardSensitivity of(
     CurrencyPair currencyPair,
     Currency referenceCurrency,
     LocalDate referenceDate,
     double sensitivity) {
   boolean inverse = referenceCurrency.equals(currencyPair.getCounter());
   CurrencyPair pair = inverse ? currencyPair.inverse() : currencyPair;
   Currency sensitivityCurrency = pair.getCounter();
   return new FxForwardSensitivity(
       currencyPair, referenceCurrency, referenceDate, sensitivityCurrency, sensitivity);
 }
 // -------------------------------------------------------------------------
 @ImmutableValidator
 private void validate() {
   if (!currencyPair.contains(referenceCurrency)) {
     throw new IllegalArgumentException(
         Messages.format(
             "Reference currency {} must be one of those in the currency pair {}",
             referenceCurrency,
             currencyPair));
   }
 }
 @Override
 public int compareKey(PointSensitivity other) {
   if (other instanceof FxForwardSensitivity) {
     FxForwardSensitivity otherFx = (FxForwardSensitivity) other;
     return ComparisonChain.start()
         .compare(currencyPair.toString(), otherFx.currencyPair.toString())
         .compare(currency, otherFx.currency)
         .compare(referenceCurrency, otherFx.referenceCurrency)
         .compare(referenceDate, otherFx.referenceDate)
         .result();
   }
   return getClass().getSimpleName().compareTo(other.getClass().getSimpleName());
 }
 // -------------------------------------------------------------------------
 public void coverage() {
   DiscountFxForwardRates test1 =
       DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_USD);
   coverImmutableBean(test1);
   DiscountFxForwardRates test2 =
       DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE.inverse(), DFCURVE_GBP2, DFCURVE_USD2);
   coverBeanEquals(test1, test2);
   DiscountFxForwardRates test3 =
       DiscountFxForwardRates.of(
           CurrencyPair.of(USD, EUR),
           FxRate.of(EUR, USD, 1.2d),
           DFCURVE_USD,
           ZeroRateDiscountFactors.of(EUR, DATE_VAL, CURVE2));
   coverBeanEquals(test1, test3);
 }
 // -------------------------------------------------------------------------
 public void test_convertedTo() {
   BondFutureOptionSensitivity base =
       BondFutureOptionSensitivity.of(
           NAME, OPTION_EXPIRY, FUTURE_EXPIRY, STRIKE_PRICE, FUTURE_PRICE, GBP, SENSITIVITY);
   double rate = 1.5d;
   FxMatrix matrix = FxMatrix.of(CurrencyPair.of(GBP, USD), rate);
   BondFutureOptionSensitivity test1 = (BondFutureOptionSensitivity) base.convertedTo(USD, matrix);
   BondFutureOptionSensitivity expected =
       BondFutureOptionSensitivity.of(
           NAME,
           OPTION_EXPIRY,
           FUTURE_EXPIRY,
           STRIKE_PRICE,
           FUTURE_PRICE,
           USD,
           SENSITIVITY * rate);
   assertEquals(test1, expected);
   BondFutureOptionSensitivity test2 = (BondFutureOptionSensitivity) base.convertedTo(GBP, matrix);
   assertEquals(test2, base);
 }
 /**
  * Gets the currency counter to the reference currency.
  *
  * <p>The currency pair contains two currencies. One is the reference currency. This method
  * returns the other.
  *
  * @return the counter currency
  */
 public Currency getReferenceCounterCurrency() {
   boolean inverse = referenceCurrency.equals(currencyPair.getBase());
   return inverse ? currencyPair.getCounter() : currencyPair.getBase();
 }
Example #8
0
 /**
  * Gets the FX rate for the specified currency pair on the valuation date.
  *
  * <p>The rate returned is the rate from the base currency to the counter currency as defined by
  * this formula: {@code (1 * baseCurrency = fxRate * counterCurrency)}.
  *
  * @param currencyPair the ordered currency pair defining the rate required
  * @return the current FX rate for the currency pair
  * @throws IllegalArgumentException if the rate is not available
  */
 @Override
 public default double fxRate(CurrencyPair currencyPair) {
   return fxRate(currencyPair.getBase(), currencyPair.getCounter());
 }
/** 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());
  }
}
/** Test {@link DiscountFxForwardRates}. */
@Test
public class DiscountFxForwardRatesTest {

  private static final LocalDate DATE_VAL = date(2015, 6, 4);
  private static final LocalDate DATE_REF = date(2015, 7, 30);
  private static final FxRate FX_RATE = FxRate.of(GBP, USD, 1.5d);
  private static final CurrencyPair CURRENCY_PAIR = CurrencyPair.of(GBP, USD);

  private static final CurveInterpolator INTERPOLATOR = CurveInterpolators.LINEAR;
  private static final CurveMetadata METADATA1 = Curves.zeroRates("TestCurve", ACT_365F);
  private static final CurveMetadata METADATA2 = Curves.zeroRates("TestCurveUSD", ACT_365F);
  private static final InterpolatedNodalCurve CURVE1 =
      InterpolatedNodalCurve.of(
          METADATA1, DoubleArray.of(0, 10), DoubleArray.of(0.01, 0.02), INTERPOLATOR);
  private static final InterpolatedNodalCurve CURVE2 =
      InterpolatedNodalCurve.of(
          METADATA2, DoubleArray.of(0, 10), DoubleArray.of(0.015, 0.025), INTERPOLATOR);
  private static final ZeroRateDiscountFactors DFCURVE_GBP =
      ZeroRateDiscountFactors.of(GBP, DATE_VAL, CURVE1);
  private static final ZeroRateDiscountFactors DFCURVE_GBP2 =
      ZeroRateDiscountFactors.of(GBP, DATE_VAL, CURVE2);
  private static final ZeroRateDiscountFactors DFCURVE_USD =
      ZeroRateDiscountFactors.of(USD, DATE_VAL, CURVE2);
  private static final ZeroRateDiscountFactors DFCURVE_USD2 =
      ZeroRateDiscountFactors.of(USD, DATE_VAL, CURVE1);

  // -------------------------------------------------------------------------
  public void test_of() {
    DiscountFxForwardRates test =
        DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_USD);
    assertEquals(test.getCurrencyPair(), CURRENCY_PAIR);
    assertEquals(test.getValuationDate(), DATE_VAL);
    assertEquals(test.getBaseCurrencyDiscountFactors(), DFCURVE_GBP);
    assertEquals(test.getCounterCurrencyDiscountFactors(), DFCURVE_USD);
    assertEquals(test.getFxRateProvider(), FX_RATE);
    assertEquals(test.findData(CURVE1.getName()), Optional.of(CURVE1));
    assertEquals(test.findData(CURVE2.getName()), Optional.of(CURVE2));
    assertEquals(test.findData(CurveName.of("Rubbish")), Optional.empty());

    int baseSize = DFCURVE_USD.getParameterCount();
    assertEquals(test.getParameterCount(), DFCURVE_GBP.getParameterCount() + baseSize);
    assertEquals(test.getParameter(0), DFCURVE_GBP.getParameter(0));
    assertEquals(test.getParameter(baseSize), DFCURVE_USD.getParameter(0));
    assertEquals(test.getParameterMetadata(0), DFCURVE_GBP.getParameterMetadata(0));
    assertEquals(test.getParameterMetadata(baseSize), DFCURVE_USD.getParameterMetadata(0));
    assertEquals(
        test.withParameter(0, 1d).getBaseCurrencyDiscountFactors(),
        DFCURVE_GBP.withParameter(0, 1d));
    assertEquals(test.withParameter(0, 1d).getCounterCurrencyDiscountFactors(), DFCURVE_USD);
    assertEquals(test.withParameter(baseSize, 1d).getBaseCurrencyDiscountFactors(), DFCURVE_GBP);
    assertEquals(
        test.withParameter(baseSize, 1d).getCounterCurrencyDiscountFactors(),
        DFCURVE_USD.withParameter(0, 1d));
    assertEquals(
        test.withPerturbation((i, v, m) -> v + 1d).getBaseCurrencyDiscountFactors(),
        DFCURVE_GBP.withPerturbation((i, v, m) -> v + 1d));
    assertEquals(
        test.withPerturbation((i, v, m) -> v + 1d).getCounterCurrencyDiscountFactors(),
        DFCURVE_USD.withPerturbation((i, v, m) -> v + 1d));
  }

  public void test_of_nonMatchingCurrency() {
    assertThrowsIllegalArg(
        () -> DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_GBP));
    assertThrowsIllegalArg(
        () -> DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_USD, DFCURVE_USD));
  }

  public void test_of_nonMatchingValuationDates() {
    DiscountFactors curve2 = ZeroRateDiscountFactors.of(USD, DATE_REF, CURVE2);
    assertThrowsIllegalArg(
        () -> DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, curve2));
  }

  public void test_builder() {
    assertThrowsIllegalArg(
        () ->
            DiscountFxForwardRates.meta()
                .builder()
                .setString(DiscountFxForwardRates.meta().currencyPair(), "GBP/USD")
                .build());
    assertThrowsIllegalArg(
        () ->
            DiscountFxForwardRates.meta()
                .builder()
                .setString(DiscountFxForwardRates.meta().currencyPair().name(), "GBP/USD")
                .build());
  }

  // -------------------------------------------------------------------------
  public void test_withDiscountFactors() {
    DiscountFxForwardRates test =
        DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_USD);
    test = test.withDiscountFactors(DFCURVE_GBP2, DFCURVE_USD2);
    assertEquals(test.getCurrencyPair(), CURRENCY_PAIR);
    assertEquals(test.getValuationDate(), DATE_VAL);
    assertEquals(test.getBaseCurrencyDiscountFactors(), DFCURVE_GBP2);
    assertEquals(test.getCounterCurrencyDiscountFactors(), DFCURVE_USD2);
    assertEquals(test.getFxRateProvider(), FX_RATE);
  }

  // -------------------------------------------------------------------------
  public void test_rate() {
    DiscountFxForwardRates test =
        DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_USD);
    double dfCcyBaseAtMaturity = DFCURVE_GBP.discountFactor(DATE_REF);
    double dfCcyCounterAtMaturity = DFCURVE_USD.discountFactor(DATE_REF);
    double expected = FX_RATE.fxRate(GBP, USD) * (dfCcyBaseAtMaturity / dfCcyCounterAtMaturity);
    assertEquals(test.rate(GBP, DATE_REF), expected, 1e-12);
    assertEquals(test.rate(USD, DATE_REF), 1d / expected, 1e-12);
  }

  public void test_rate_nonMatchingCurrency() {
    DiscountFxForwardRates test =
        DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_USD);
    assertThrowsIllegalArg(() -> test.rate(EUR, DATE_VAL));
  }

  // -------------------------------------------------------------------------
  public void test_ratePointSensitivity() {
    DiscountFxForwardRates test =
        DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_USD);
    assertEquals(
        test.ratePointSensitivity(GBP, DATE_REF),
        FxForwardSensitivity.of(CURRENCY_PAIR, GBP, DATE_REF, 1d));
    assertEquals(
        test.ratePointSensitivity(USD, DATE_REF),
        FxForwardSensitivity.of(CURRENCY_PAIR, USD, DATE_REF, 1d));
  }

  public void test_ratePointSensitivity_nonMatchingCurrency() {
    DiscountFxForwardRates test =
        DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_USD);
    assertThrowsIllegalArg(() -> test.ratePointSensitivity(EUR, DATE_VAL));
  }

  // -------------------------------------------------------------------------
  public void test_rateFxSpotSensitivity() {
    DiscountFxForwardRates test =
        DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_USD);
    double dfCcyBaseAtMaturity = DFCURVE_GBP.discountFactor(DATE_REF);
    double dfCcyCounterAtMaturity = DFCURVE_USD.discountFactor(DATE_REF);
    double expected = dfCcyBaseAtMaturity / dfCcyCounterAtMaturity;
    assertEquals(test.rateFxSpotSensitivity(GBP, DATE_REF), expected, 1e-12);
    assertEquals(test.rateFxSpotSensitivity(USD, DATE_REF), 1d / expected, 1e-12);
  }

  public void test_rateFxSpotSensitivity_nonMatchingCurrency() {
    DiscountFxForwardRates test =
        DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_USD);
    assertThrowsIllegalArg(() -> test.rateFxSpotSensitivity(EUR, DATE_VAL));
  }

  // -------------------------------------------------------------------------
  // proper end-to-end tests are elsewhere
  public void test_parameterSensitivity() {
    DiscountFxForwardRates test =
        DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_USD);
    FxForwardSensitivity point = FxForwardSensitivity.of(CURRENCY_PAIR, GBP, DATE_VAL, 1d);
    assertEquals(test.parameterSensitivity(point).size(), 2);
    FxForwardSensitivity point2 = FxForwardSensitivity.of(CURRENCY_PAIR, USD, DATE_VAL, 1d);
    assertEquals(test.parameterSensitivity(point2).size(), 2);
  }

  // -------------------------------------------------------------------------
  public void coverage() {
    DiscountFxForwardRates test1 =
        DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE, DFCURVE_GBP, DFCURVE_USD);
    coverImmutableBean(test1);
    DiscountFxForwardRates test2 =
        DiscountFxForwardRates.of(CURRENCY_PAIR, FX_RATE.inverse(), DFCURVE_GBP2, DFCURVE_USD2);
    coverBeanEquals(test1, test2);
    DiscountFxForwardRates test3 =
        DiscountFxForwardRates.of(
            CurrencyPair.of(USD, EUR),
            FxRate.of(EUR, USD, 1.2d),
            DFCURVE_USD,
            ZeroRateDiscountFactors.of(EUR, DATE_VAL, CURVE2));
    coverBeanEquals(test1, test3);
  }
}