public virtual void test_createMetadata()
        {
            DirectIborCapletFloorletVolatilityDefinition @base = DirectIborCapletFloorletVolatilityDefinition.of(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, LAMBDA_EXPIRY, LAMBDA_STRIKE, INTERPOLATOR);

            assertEquals(@base.createMetadata(SAMPLE_BLACK), Surfaces.blackVolatilityByExpiryStrike(NAME.Name, ACT_ACT_ISDA));
            assertEquals(@base.createMetadata(SAMPLE_NORMAL), Surfaces.normalVolatilityByExpiryStrike(NAME.Name, ACT_ACT_ISDA));
            assertThrowsIllegalArg(() => @base.createMetadata(RawOptionData.of(EXPIRIES, STRIKES, STRIKE, DATA, ValueType.PRICE)));
        }
        public virtual void test_createMetadata_black()
        {
            SabrIborCapletFloorletVolatilityBootstrapDefinition @base = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan());
            RawOptionData capData = RawOptionData.of(ImmutableList.of(Period.ofYears(1), Period.ofYears(5)), DoubleArray.of(0.005, 0.01, 0.015), ValueType.STRIKE, DoubleMatrix.copyOf(new double[][]
            {
                new double[] { 0.15, 0.12, 0.13 },
                new double[] { 0.1, 0.08, 0.09 }
            }), ValueType.BLACK_VOLATILITY);
            SurfaceMetadata expected = Surfaces.blackVolatilityByExpiryStrike(NAME.Name, ACT_ACT_ISDA);
            SurfaceMetadata computed = @base.createMetadata(capData);

            assertEquals(computed, expected);
        }
        //-------------------------------------------------------------------------
        public virtual void test_parameterSensitivity()
        {
            double    expiry      = ACT_365F.relativeYearFraction(VAL_DATE, LocalDate.of(2015, 8, 14));
            LocalDate fixing      = LocalDate.of(2016, 9, 14);
            double    strikePrice = 1.0025;
            double    futurePrice = 0.9975;
            double    sensitivity = 123456;
            IborFutureOptionSensitivity    point = IborFutureOptionSensitivity.of(VOL_SIMPLE_MONEY_RATE.Name, expiry, fixing, strikePrice, futurePrice, EUR, sensitivity);
            CurrencyParameterSensitivities ps    = VOL_SIMPLE_MONEY_RATE.parameterSensitivity(point);
            double shift = 1.0E-6;
            double v0    = VOL_SIMPLE_MONEY_RATE.volatility(expiry, fixing, strikePrice, futurePrice);

            for (int i = 0; i < NORMAL_VOL_RATES.size(); i++)
            {
                DoubleArray v = NORMAL_VOL_RATES.with(i, NORMAL_VOL_RATES.get(i) + shift);
                InterpolatedNodalSurface param = InterpolatedNodalSurface.of(Surfaces.normalVolatilityByExpirySimpleMoneyness("Rate", ACT_365F, MoneynessType.RATES), TIMES, MONEYNESS_RATES, v, INTERPOLATOR_2D);
                NormalIborFutureOptionExpirySimpleMoneynessVolatilities vol = NormalIborFutureOptionExpirySimpleMoneynessVolatilities.of(EUR_EURIBOR_3M, VAL_DATE_TIME, param);
                double vP = vol.volatility(expiry, fixing, strikePrice, futurePrice);
                double s  = ps.getSensitivity(PARAMETERS_RATE.Name, EUR).Sensitivity.get(i);
                assertEquals(s, (vP - v0) / shift * sensitivity, TOLERANCE_DELTA);
            }
        }
        //-------------------------------------------------------------------------
        public virtual void test_presentValueSensitivity()
        {
            PointSensitivityBuilder        pointCaplet      = PRICER.presentValueSensitivityRatesStickyModel(CAPLET_LONG, RATES, VOLS);
            CurrencyParameterSensitivities computedCaplet   = RATES.parameterSensitivity(pointCaplet.build());
            PointSensitivityBuilder        pointFloorlet    = PRICER.presentValueSensitivityRatesStickyModel(FLOORLET_SHORT, RATES, VOLS);
            CurrencyParameterSensitivities computedFloorlet = RATES.parameterSensitivity(pointFloorlet.build());
            CurrencyParameterSensitivities expectedCaplet   = FD_CAL.sensitivity(RATES, p => PRICER_BASE.presentValue(CAPLET_LONG, p, VOLS));
            CurrencyParameterSensitivities expectedFloorlet = FD_CAL.sensitivity(RATES, p => PRICER_BASE.presentValue(FLOORLET_SHORT, p, VOLS));

            assertTrue(computedCaplet.equalWithTolerance(expectedCaplet, EPS_FD * NOTIONAL * 50d));
            assertTrue(computedFloorlet.equalWithTolerance(expectedFloorlet, EPS_FD * NOTIONAL * 50d));
            // consistency with shifted Black
            PointSensitivityBuilder pointCapletBase   = PRICER.presentValueSensitivityRates(CAPLET_LONG, RATES, VOLS);
            PointSensitivityBuilder pointFloorletBase = PRICER.presentValueSensitivityRates(FLOORLET_SHORT, RATES, VOLS);
            double forward    = RATES.iborIndexRates(EUR_EURIBOR_3M).rate(RATE_COMP.Observation);
            double expiry     = VOLS.relativeTime(CAPLET_LONG.FixingDateTime);
            double volatility = VOLS.volatility(expiry, STRIKE, forward);
            ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities vols = ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities.of(EUR_EURIBOR_3M, VALUATION, ConstantSurface.of("constVol", volatility).withMetadata(Surfaces.blackVolatilityByExpiryStrike("costVol", DayCounts.ACT_ACT_ISDA)), IborCapletFloorletSabrRateVolatilityDataSet.CURVE_CONST_SHIFT);
            PointSensitivityBuilder pointCapletExp   = PRICER_BASE.presentValueSensitivityRates(CAPLET_LONG, RATES, vols);
            PointSensitivityBuilder pointFloorletExp = PRICER_BASE.presentValueSensitivityRates(FLOORLET_SHORT, RATES, vols);

            assertEquals(pointCapletBase, pointCapletExp);
            assertEquals(pointFloorletBase, pointFloorletExp);
        }
        //-------------------------------------------------------------------------
        public virtual void test_presentValue_formula()
        {
            CurrencyAmount computedCaplet   = PRICER.presentValue(CAPLET_LONG, RATES, VOLS);
            CurrencyAmount computedFloorlet = PRICER.presentValue(FLOORLET_SHORT, RATES, VOLS);
            double         forward          = RATES.iborIndexRates(EUR_EURIBOR_3M).rate(RATE_COMP.Observation);
            double         expiry           = VOLS.relativeTime(CAPLET_LONG.FixingDateTime);
            double         volatility       = VOLS.volatility(expiry, STRIKE, forward);
            double         df               = RATES.discountFactor(EUR, CAPLET_LONG.PaymentDate);
            double         expectedCaplet   = NOTIONAL * df * CAPLET_LONG.YearFraction * BlackFormulaRepository.price(forward + SHIFT, STRIKE + SHIFT, expiry, volatility, CALL.Call);
            double         expectedFloorlet = -NOTIONAL *df *FLOORLET_SHORT.YearFraction *BlackFormulaRepository.price(forward + SHIFT, STRIKE + SHIFT, expiry, volatility, PUT.Call);

            assertEquals(computedCaplet.Currency, EUR);
            assertEquals(computedCaplet.Amount, expectedCaplet, NOTIONAL * TOL);
            assertEquals(computedFloorlet.Currency, EUR);
            assertEquals(computedFloorlet.Amount, expectedFloorlet, NOTIONAL * TOL);
            // consistency with shifted Black
            ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities vols = ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities.of(EUR_EURIBOR_3M, VALUATION, ConstantSurface.of("constVol", volatility).withMetadata(Surfaces.blackVolatilityByExpiryStrike("costVol", DayCounts.ACT_ACT_ISDA)), IborCapletFloorletSabrRateVolatilityDataSet.CURVE_CONST_SHIFT);
            CurrencyAmount computedCapletBlack   = PRICER_BASE.presentValue(CAPLET_LONG, RATES, vols);
            CurrencyAmount computedFloorletBlack = PRICER_BASE.presentValue(FLOORLET_SHORT, RATES, vols);

            assertEquals(computedCaplet.Amount, computedCapletBlack.Amount, NOTIONAL * TOL);
            assertEquals(computedFloorlet.Amount, computedFloorletBlack.Amount, NOTIONAL * TOL);
        }