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);
    }
  }
 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);
   }
 }