@Override
 public SwapTrade trade(LocalDate valuationDate, MarketData marketData) {
   double marketQuote = marketData.getValue(spreadKey) + additionalSpread;
   FxRate fxRate = marketData.getValue(fxKey());
   double rate = fxRate.fxRate(template.getCurrencyPair());
   return template.toTrade(valuationDate, BuySell.BUY, 1, rate, marketQuote);
 }
  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);
  }
 // -------------------------------------------------------------------------
 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_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);
 }
Exemplo n.º 5
0
  /** Test a failure is returned for a convertible value if there is no reporting currency. */
  public void convertResultCurrencyNoReportingCurrency() {
    DoubleArray values = DoubleArray.of(1, 2, 3);
    List<FxRate> rates =
        ImmutableList.of(1.61, 1.62, 1.63)
            .stream()
            .map(rate -> FxRate.of(Currency.GBP, Currency.USD, rate))
            .collect(toImmutableList());
    CurrencyValuesArray list = CurrencyValuesArray.of(Currency.GBP, values);
    CalculationEnvironment marketData =
        CalculationEnvironment.builder()
            .valuationDate(date(2011, 3, 8))
            .addValue(FxRateId.of(Currency.GBP, Currency.USD), rates)
            .build();
    ConvertibleFunction fn = ConvertibleFunction.of(() -> list);
    ReportingRules reportingRules = ReportingRules.empty();
    CalculationTask task = new CalculationTask(TARGET, 0, 0, fn, MAPPINGS, reportingRules);

    CalculationResult calculationResult = task.execute(marketData);
    Result<?> result = calculationResult.getResult();
    assertThat(result).hasFailureMessageMatching("No reporting currency available.*");
  }
  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));
  }
Exemplo n.º 7
0
  /**
   * Test that the result is converted to the reporting currency if it implements
   * CurrencyConvertible and the FX rates are available in the market data. The reporting currency
   * is taken from the reporting rules.
   */
  public void convertResultCurrencyUsingReportingRules() {
    DoubleArray values = DoubleArray.of(1, 2, 3);
    List<FxRate> rates =
        ImmutableList.of(1.61, 1.62, 1.63)
            .stream()
            .map(rate -> FxRate.of(Currency.GBP, Currency.USD, rate))
            .collect(toImmutableList());
    CurrencyValuesArray list = CurrencyValuesArray.of(Currency.GBP, values);
    CalculationEnvironment marketData =
        CalculationEnvironment.builder()
            .valuationDate(date(2011, 3, 8))
            .addValue(FxRateId.of(Currency.GBP, Currency.USD), rates)
            .build();
    ConvertibleFunction fn = ConvertibleFunction.of(() -> list);
    CalculationTask task = new CalculationTask(TARGET, 0, 0, fn, MAPPINGS, REPORTING_RULES);

    DoubleArray expectedValues = DoubleArray.of(1 * 1.61, 2 * 1.62, 3 * 1.63);
    CurrencyValuesArray expectedArray = CurrencyValuesArray.of(Currency.USD, expectedValues);

    CalculationResult calculationResult = task.execute(marketData);
    Result<?> result = calculationResult.getResult();
    assertThat(result).hasValue(expectedArray);
  }
/** 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));
  }
}
/** 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);
  }
}
/**
 * Test for curve calibration in USD and EUR. The USD curve is obtained by OIS and the EUR one by FX
 * Swaps from USD.
 */
@Test
public class CalibrationZeroRateUsdEur2OisFxTest {

  private static final LocalDate VAL_DATE = LocalDate.of(2015, 11, 2);

  private static final CurveInterpolator INTERPOLATOR_LINEAR = CurveInterpolators.LINEAR;
  private static final CurveExtrapolator EXTRAPOLATOR_FLAT = CurveExtrapolators.FLAT;
  private static final DayCount CURVE_DC = ACT_365F;

  private static final String SCHEME = "CALIBRATION";

  /** Curve names */
  private static final String USD_DSCON_STR = "USD-DSCON-OIS";

  private static final CurveName USD_DSCON_CURVE_NAME = CurveName.of(USD_DSCON_STR);
  private static final String EUR_DSC_STR = "EUR-DSC-FX";
  private static final CurveName EUR_DSC_CURVE_NAME = CurveName.of(EUR_DSC_STR);
  /** Curves associations to currencies and indices. */
  private static final Map<CurveName, Currency> DSC_NAMES = new HashMap<>();

  private static final Map<CurveName, Set<Index>> IDX_NAMES = new HashMap<>();
  private static final Map<Index, LocalDateDoubleTimeSeries> TS = new HashMap<>();

  static {
    DSC_NAMES.put(USD_DSCON_CURVE_NAME, USD);
    Set<Index> usdFedFundSet = new HashSet<>();
    usdFedFundSet.add(USD_FED_FUND);
    IDX_NAMES.put(USD_DSCON_CURVE_NAME, usdFedFundSet);
  }

  /** Data FX * */
  private static final FxRate FX_RATE_EUR_USD = FxRate.of(EUR, USD, 1.10);
  /** Data for USD-DSCON curve */
  /* Market values */
  private static final double[] USD_DSC_MARKET_QUOTES =
      new double[] {
        0.0016, 0.0022, 0.0013, 0.0016, 0.0020, 0.0026, 0.0033, 0.0039, 0.0053, 0.0066, 0.0090,
        0.0111
      };

  private static final int USD_DSC_NB_NODES = USD_DSC_MARKET_QUOTES.length;
  private static final String[] USD_DSC_ID_VALUE =
      new String[] {
        "USD-ON",
        "USD-TN",
        "USD-OIS-1M",
        "USD-OIS-2M",
        "USD-OIS-3M",
        "USD-OIS-6M",
        "USD-OIS-9M",
        "USD-OIS-1Y",
        "USD-OIS-18M",
        "USD-OIS-2Y",
        "USD-OIS-3Y",
        "USD-OIS-4Y"
      };
  /* Nodes */
  private static final CurveNode[] USD_DSC_NODES = new CurveNode[USD_DSC_NB_NODES];
  /* Tenors */
  private static final int[] USD_DSC_DEPO_OFFSET = new int[] {0, 1};
  private static final int USD_DSC_NB_DEPO_NODES = USD_DSC_DEPO_OFFSET.length;
  private static final Period[] USD_DSC_OIS_TENORS =
      new Period[] {
        Period.ofMonths(1), Period.ofMonths(2), Period.ofMonths(3), Period.ofMonths(6),
            Period.ofMonths(9),
        Period.ofYears(1), Period.ofMonths(18), Period.ofYears(2), Period.ofYears(3),
            Period.ofYears(4)
      };
  private static final int USD_DSC_NB_OIS_NODES = USD_DSC_OIS_TENORS.length;

  static {
    USD_DSC_NODES[0] =
        TermDepositCurveNode.of(
            TermDepositTemplate.of(Period.ofDays(1), USD_DEPOSIT_T0),
            QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[0])));
    USD_DSC_NODES[1] =
        TermDepositCurveNode.of(
            TermDepositTemplate.of(Period.ofDays(1), USD_DEPOSIT_T1),
            QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[1])));
    for (int i = 0; i < USD_DSC_NB_OIS_NODES; i++) {
      USD_DSC_NODES[USD_DSC_NB_DEPO_NODES + i] =
          FixedOvernightSwapCurveNode.of(
              FixedOvernightSwapTemplate.of(
                  Period.ZERO, Tenor.of(USD_DSC_OIS_TENORS[i]), USD_FIXED_1Y_FED_FUND_OIS),
              QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[USD_DSC_NB_DEPO_NODES + i])));
    }
  }
  /** Data for EUR-DSC curve */
  /* Market values */
  private static final double[] EUR_DSC_MARKET_QUOTES =
      new double[] {
        0.0004, 0.0012, 0.0019, 0.0043, 0.0074,
        0.0109, 0.0193, 0.0294, 0.0519, 0.0757
      };

  private static final int EUR_DSC_NB_NODES = EUR_DSC_MARKET_QUOTES.length;
  private static final String[] EUR_DSC_ID_VALUE =
      new String[] {
        "EUR-USD-FX-1M", "EUR-USD-FX-2M", "EUR-USD-FX-3M", "EUR-USD-FX-6M", "EUR-USD-FX-9M",
        "EUR-USD-FX-1Y", "EUR-USD-FX-18M", "EUR-USD-FX-2Y", "EUR-USD-FX-3Y", "EUR-USD-FX-4Y"
      };
  /* Nodes */
  private static final CurveNode[] EUR_DSC_NODES = new CurveNode[EUR_DSC_NB_NODES];
  /* Tenors */
  private static final Period[] EUR_DSC_FX_TENORS =
      new Period[] {
        Period.ofMonths(1), Period.ofMonths(2), Period.ofMonths(3), Period.ofMonths(6),
            Period.ofMonths(9),
        Period.ofYears(1), Period.ofMonths(18), Period.ofYears(2), Period.ofYears(3),
            Period.ofYears(4)
      };
  private static final int EUR_DSC_NB_FX_NODES = EUR_DSC_FX_TENORS.length;

  static {
    for (int i = 0; i < EUR_DSC_NB_FX_NODES; i++) {
      EUR_DSC_NODES[i] =
          FxSwapCurveNode.of(
              FxSwapTemplate.of(EUR_DSC_FX_TENORS[i], EUR_USD),
              QuoteKey.of(StandardId.of(SCHEME, EUR_DSC_ID_VALUE[i])));
    }
  }

  /** All quotes for the curve calibration */
  private static final ImmutableMarketData ALL_QUOTES;

  static {
    Map<MarketDataKey<?>, Object> map = new HashMap<>();
    for (int i = 0; i < USD_DSC_NB_NODES; i++) {
      map.put(QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[i])), USD_DSC_MARKET_QUOTES[i]);
    }
    for (int i = 0; i < EUR_DSC_NB_NODES; i++) {
      map.put(QuoteKey.of(StandardId.of(SCHEME, EUR_DSC_ID_VALUE[i])), EUR_DSC_MARKET_QUOTES[i]);
    }
    map.put(FxRateKey.of(EUR, USD), FX_RATE_EUR_USD);
    ALL_QUOTES = ImmutableMarketData.of(map);
  }

  private static final DiscountingSwapProductPricer SWAP_PRICER =
      DiscountingSwapProductPricer.DEFAULT;
  private static final DiscountingTermDepositProductPricer DEPO_PRICER =
      DiscountingTermDepositProductPricer.DEFAULT;
  private static final DiscountingFxSwapProductPricer FX_PRICER =
      DiscountingFxSwapProductPricer.DEFAULT;
  private static final MarketQuoteSensitivityCalculator MQC =
      MarketQuoteSensitivityCalculator.DEFAULT;

  private static final CalibrationMeasures CALIBRATION_MEASURES = CalibrationMeasures.DEFAULT;
  private static final CurveCalibrator CALIBRATOR =
      CurveCalibrator.of(1e-9, 1e-9, 100, CALIBRATION_MEASURES);

  // Constants
  private static final double TOLERANCE_PV = 1.0E-6;
  private static final double TOLERANCE_PV_DELTA = 1.0E+3;

  private static final CurveGroupName CURVE_GROUP_NAME = CurveGroupName.of("USD-DSCON-EUR-DSC");
  private static final InterpolatedNodalCurveDefinition USD_DSC_CURVE_DEFN =
      InterpolatedNodalCurveDefinition.builder()
          .name(USD_DSCON_CURVE_NAME)
          .xValueType(ValueType.YEAR_FRACTION)
          .yValueType(ValueType.ZERO_RATE)
          .dayCount(CURVE_DC)
          .interpolator(INTERPOLATOR_LINEAR)
          .extrapolatorLeft(EXTRAPOLATOR_FLAT)
          .extrapolatorRight(EXTRAPOLATOR_FLAT)
          .nodes(USD_DSC_NODES)
          .build();
  private static final InterpolatedNodalCurveDefinition EUR_DSC_CURVE_DEFN =
      InterpolatedNodalCurveDefinition.builder()
          .name(EUR_DSC_CURVE_NAME)
          .xValueType(ValueType.YEAR_FRACTION)
          .yValueType(ValueType.ZERO_RATE)
          .dayCount(CURVE_DC)
          .interpolator(INTERPOLATOR_LINEAR)
          .extrapolatorLeft(EXTRAPOLATOR_FLAT)
          .extrapolatorRight(EXTRAPOLATOR_FLAT)
          .nodes(EUR_DSC_NODES)
          .build();
  private static final CurveGroupDefinition CURVE_GROUP_CONFIG =
      CurveGroupDefinition.builder()
          .name(CURVE_GROUP_NAME)
          .addCurve(USD_DSC_CURVE_DEFN, USD, USD_FED_FUND)
          .addDiscountCurve(EUR_DSC_CURVE_DEFN, EUR)
          .build();

  // -------------------------------------------------------------------------
  public void calibration_present_value_oneGroup() {
    ImmutableRatesProvider result =
        CALIBRATOR.calibrate(CURVE_GROUP_CONFIG, VAL_DATE, ALL_QUOTES, TS);
    assertPresentValue(result);
  }

  private void assertPresentValue(ImmutableRatesProvider result) {
    // Test PV USD;
    List<Trade> usdTrades = new ArrayList<>();
    for (int i = 0; i < USD_DSC_NODES.length; i++) {
      usdTrades.add(USD_DSC_NODES[i].trade(VAL_DATE, ALL_QUOTES));
    }
    // Depo
    for (int i = 0; i < USD_DSC_NB_DEPO_NODES; i++) {
      CurrencyAmount pvDep =
          DEPO_PRICER.presentValue(((TermDepositTrade) usdTrades.get(i)).getProduct(), result);
      assertEquals(pvDep.getAmount(), 0.0, TOLERANCE_PV);
    }
    // OIS
    for (int i = 0; i < USD_DSC_NB_OIS_NODES; i++) {
      MultiCurrencyAmount pvOis =
          SWAP_PRICER.presentValue(
              ((SwapTrade) usdTrades.get(USD_DSC_NB_DEPO_NODES + i)).getProduct(), result);
      assertEquals(pvOis.getAmount(USD).getAmount(), 0.0, TOLERANCE_PV);
    }
    // Test PV EUR;
    List<Trade> eurTrades = new ArrayList<>();
    for (int i = 0; i < EUR_DSC_NODES.length; i++) {
      eurTrades.add(EUR_DSC_NODES[i].trade(VAL_DATE, ALL_QUOTES));
    }
    // Depo
    for (int i = 0; i < EUR_DSC_NB_FX_NODES; i++) {
      MultiCurrencyAmount pvFx =
          FX_PRICER.presentValue(((FxSwapTrade) eurTrades.get(i)).getProduct(), result);
      assertEquals(pvFx.convertedTo(USD, result).getAmount(), 0.0, TOLERANCE_PV);
    }
  }

  public void calibration_market_quote_sensitivity_one_group() {
    double shift = 1.0E-6;
    Function<MarketData, ImmutableRatesProvider> f =
        ov -> CALIBRATOR.calibrate(CURVE_GROUP_CONFIG, VAL_DATE, ov, TS);
    calibration_market_quote_sensitivity_check(f, shift);
  }

  private void calibration_market_quote_sensitivity_check(
      Function<MarketData, ImmutableRatesProvider> calibrator, double shift) {

    double notional = 100_000_000.0;
    double fx = 1.1111;
    double fxPts = 0.0012;
    FxSwapTrade trade =
        EUR_USD.toTrade(
            VAL_DATE, Period.ofWeeks(6), Period.ofMonths(5), BuySell.BUY, notional, fx, fxPts);
    ImmutableRatesProvider result =
        CALIBRATOR.calibrate(CURVE_GROUP_CONFIG, VAL_DATE, ALL_QUOTES, TS);
    PointSensitivities pts = FX_PRICER.presentValueSensitivity(trade.getProduct(), result);
    CurveCurrencyParameterSensitivities ps = result.curveParameterSensitivity(pts);
    CurveCurrencyParameterSensitivities mqs = MQC.sensitivity(ps, result);
    double pvUsd = FX_PRICER.presentValue(trade.getProduct(), result).getAmount(USD).getAmount();
    double pvEur = FX_PRICER.presentValue(trade.getProduct(), result).getAmount(EUR).getAmount();
    double[] mqsUsd1Computed =
        mqs.getSensitivity(USD_DSCON_CURVE_NAME, USD).getSensitivity().toArray();
    for (int i = 0; i < USD_DSC_NB_NODES; i++) {
      Map<MarketDataKey<?>, Object> map = new HashMap<>(ALL_QUOTES.getValues());
      map.put(
          QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[i])),
          USD_DSC_MARKET_QUOTES[i] + shift);
      ImmutableMarketData marketData = ImmutableMarketData.of(map);
      ImmutableRatesProvider rpShifted = calibrator.apply(marketData);
      double pvS = FX_PRICER.presentValue(trade.getProduct(), rpShifted).getAmount(USD).getAmount();
      assertEquals(mqsUsd1Computed[i], (pvS - pvUsd) / shift, TOLERANCE_PV_DELTA);
    }
    double[] mqsUsd2Computed =
        mqs.getSensitivity(USD_DSCON_CURVE_NAME, EUR).getSensitivity().toArray();
    for (int i = 0; i < USD_DSC_NB_NODES; i++) {
      Map<MarketDataKey<?>, Object> map = new HashMap<>(ALL_QUOTES.getValues());
      map.put(
          QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[i])),
          USD_DSC_MARKET_QUOTES[i] + shift);
      ImmutableMarketData ov = ImmutableMarketData.of(map);
      ImmutableRatesProvider rpShifted = calibrator.apply(ov);
      double pvS = FX_PRICER.presentValue(trade.getProduct(), rpShifted).getAmount(EUR).getAmount();
      assertEquals(mqsUsd2Computed[i], (pvS - pvEur) / shift, TOLERANCE_PV_DELTA);
    }
    double[] mqsEur1Computed =
        mqs.getSensitivity(EUR_DSC_CURVE_NAME, USD).getSensitivity().toArray();
    for (int i = 0; i < EUR_DSC_NB_NODES; i++) {
      assertEquals(mqsEur1Computed[i], 0.0, TOLERANCE_PV_DELTA);
    }
    double[] mqsEur2Computed =
        mqs.getSensitivity(EUR_DSC_CURVE_NAME, EUR).getSensitivity().toArray();
    for (int i = 0; i < EUR_DSC_NB_NODES; i++) {
      Map<MarketDataKey<?>, Object> map = new HashMap<>(ALL_QUOTES.getValues());
      map.put(
          QuoteKey.of(StandardId.of(SCHEME, EUR_DSC_ID_VALUE[i])),
          EUR_DSC_MARKET_QUOTES[i] + shift);
      ImmutableMarketData marketData = ImmutableMarketData.of(map);
      ImmutableRatesProvider rpShifted = calibrator.apply(marketData);
      double pvS = FX_PRICER.presentValue(trade.getProduct(), rpShifted).getAmount(EUR).getAmount();
      assertEquals(mqsEur2Computed[i], (pvS - pvEur) / shift, TOLERANCE_PV_DELTA, "Node " + i);
    }
  }
}