public virtual void test_parameterSensitivity_withSpread_full()
        {
            int    periodPerYear = 2;
            double spread        = 0.0011; // 11 bp
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);
            double sensiValue         = 25d;
            ZeroRateSensitivity point = test.zeroRatePointSensitivityWithSpread(DATE_AFTER, spread, PERIODIC, periodPerYear);

            point = point.multipliedBy(sensiValue);
            CurrencyParameterSensitivities sensiObject = test.parameterSensitivity(point);

            assertEquals(sensiObject.Sensitivities.size(), 1);
            DoubleArray sensi0 = sensiObject.Sensitivities.get(0).Sensitivity;
            double      shift  = 1.0E-6;

            for (int i = 0; i < X.size(); i++)
            {
                DoubleArray            yP     = Y.with(i, Y.get(i) + shift);
                InterpolatedNodalCurve curveP = InterpolatedNodalCurve.of(META_ZERO_PERIODIC, X, yP, INTERPOLATOR);
                double                 dfP    = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, curveP).discountFactorWithSpread(DATE_AFTER, spread, PERIODIC, periodPerYear);
                DoubleArray            yM     = Y.with(i, Y.get(i) - shift);
                InterpolatedNodalCurve curveM = InterpolatedNodalCurve.of(META_ZERO_PERIODIC, X, yM, INTERPOLATOR);
                double                 dfM    = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, curveM).discountFactorWithSpread(DATE_AFTER, spread, PERIODIC, periodPerYear);
                assertEquals(sensi0.get(i), sensiValue * (dfP - dfM) / (2 * shift), TOLERANCE_DELTA_FD, "With spread - " + i);
            }
        }
        //-------------------------------------------------------------------------
        public virtual void test_createParameterSensitivity()
        {
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);
            DoubleArray sensitivities            = DoubleArray.of(0.12, 0.15, 0.16);
            CurrencyParameterSensitivities sens  = test.createParameterSensitivity(USD, sensitivities);

            assertEquals(sens.Sensitivities.get(0), CURVE.createParameterSensitivity(USD, sensitivities));
        }
        //-------------------------------------------------------------------------
        public virtual void test_discountFactor()
        {
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);
            double relativeYearFraction          = ACT_365F.relativeYearFraction(DATE_VAL, DATE_AFTER);
            double expected = Math.Pow(1.0d + CURVE.yValue(relativeYearFraction) / CMP_PERIOD, -CMP_PERIOD * relativeYearFraction);

            assertEquals(test.discountFactor(DATE_AFTER), expected);
        }
        //-------------------------------------------------------------------------
        public virtual void coverage()
        {
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);

            coverImmutableBean(test);
            ZeroRatePeriodicDiscountFactors test2 = ZeroRatePeriodicDiscountFactors.of(USD, DATE_VAL.plusDays(1), CURVE2);

            coverBeanEquals(test, test2);
        }
        public virtual void test_zeroRatePointSensitivityWithSpread_sensitivityCurrency_smallYearFraction()
        {
            ZeroRatePeriodicDiscountFactors test     = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);
            ZeroRateSensitivity             expected = ZeroRateSensitivity.of(GBP, 0d, USD, 0.0d);
            ZeroRateSensitivity             computed = test.zeroRatePointSensitivityWithSpread(DATE_VAL, USD, SPREAD, CONTINUOUS, 0);

            assertTrue(computed.compareKey(expected) == 0);
            assertEquals(computed.Sensitivity, expected.Sensitivity, TOLERANCE_DELTA_FD);
        }
        public virtual void test_zeroRatePointSensitivity_sensitivityCurrency()
        {
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);
            double relativeYearFraction          = ACT_365F.relativeYearFraction(DATE_VAL, DATE_AFTER);
            double df = test.discountFactor(DATE_AFTER);
            ZeroRateSensitivity expected = ZeroRateSensitivity.of(GBP, relativeYearFraction, USD, -df * relativeYearFraction);

            assertEquals(test.zeroRatePointSensitivity(DATE_AFTER, USD), expected);
        }
        //-------------------------------------------------------------------------
        public virtual void test_discountFactorWithSpread_continuous()
        {
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);
            double relativeYearFraction          = ACT_365F.relativeYearFraction(DATE_VAL, DATE_AFTER);
            double df       = test.discountFactor(DATE_AFTER);
            double expected = df * Math.Exp(-SPREAD * relativeYearFraction);

            assertEquals(test.discountFactorWithSpread(DATE_AFTER, SPREAD, CONTINUOUS, 0), expected, TOLERANCE_DF);
        }
        //-------------------------------------------------------------------------
        public virtual void test_zeroRate()
        {
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);
            double relativeYearFraction          = ACT_365F.relativeYearFraction(DATE_VAL, DATE_AFTER);
            double discountFactor = test.discountFactor(DATE_AFTER);
            double zeroRate       = test.zeroRate(DATE_AFTER);

            assertEquals(Math.Exp(-zeroRate * relativeYearFraction), discountFactor);
        }
        public virtual void test_zeroRatePointSensitivityWithSpread_sensitivityCurrency_continous()
        {
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);
            double relativeYearFraction          = ACT_365F.relativeYearFraction(DATE_VAL, DATE_AFTER);
            double df = test.discountFactorWithSpread(DATE_AFTER, SPREAD, CONTINUOUS, 0);
            ZeroRateSensitivity expected = ZeroRateSensitivity.of(GBP, relativeYearFraction, USD, -df * relativeYearFraction);
            ZeroRateSensitivity computed = test.zeroRatePointSensitivityWithSpread(DATE_AFTER, USD, SPREAD, CONTINUOUS, 0);

            assertTrue(computed.compareKey(expected) == 0);
            assertEquals(computed.Sensitivity, expected.Sensitivity, TOLERANCE_DELTA);
        }
        public virtual void test_discountFactorWithSpread_periodic()
        {
            int periodPerYear = 4;
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);
            double relativeYearFraction          = ACT_365F.relativeYearFraction(DATE_VAL, DATE_AFTER);
            double discountFactorBase            = test.discountFactor(DATE_AFTER);
            double onePlus  = Math.Pow(discountFactorBase, -1.0d / (periodPerYear * relativeYearFraction));
            double expected = Math.Pow(onePlus + SPREAD / periodPerYear, -periodPerYear * relativeYearFraction);

            assertEquals(test.discountFactorWithSpread(DATE_AFTER, SPREAD, PERIODIC, periodPerYear), expected, TOLERANCE_DF);
        }
        //-------------------------------------------------------------------------
        //-------------------------------------------------------------------------
        public virtual void test_parameterSensitivity()
        {
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);
            double sensiValue         = 25d;
            ZeroRateSensitivity point = test.zeroRatePointSensitivity(DATE_AFTER);

            point = point.multipliedBy(sensiValue);
            CurrencyParameterSensitivities sensiObject = test.parameterSensitivity(point);

            assertEquals(sensiObject.size(), 1);
            CurrencyParameterSensitivity sensi1 = sensiObject.Sensitivities.get(0);

            assertEquals(sensi1.Currency, GBP);
        }
        //-------------------------------------------------------------------------
        public virtual void test_of()
        {
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);

            assertEquals(test.Currency, GBP);
            assertEquals(test.ValuationDate, DATE_VAL);
            assertEquals(test.Curve, CURVE);
            assertEquals(test.ParameterCount, CURVE.ParameterCount);
            assertEquals(test.getParameter(0), CURVE.getParameter(0));
            assertEquals(test.getParameterMetadata(0), CURVE.getParameterMetadata(0));
            assertEquals(test.withParameter(0, 1d).Curve, CURVE.withParameter(0, 1d));
            assertEquals(test.withPerturbation((i, v, m) => v + 1d).Curve, CURVE.withPerturbation((i, v, m) => v + 1d));
            assertEquals(test.findData(CURVE.Name), CURVE);
            assertEquals(test.findData(CurveName.of("Rubbish")), null);
        }
        public virtual void test_of_badCurve()
        {
            InterpolatedNodalCurve notYearFraction       = InterpolatedNodalCurve.of(Curves.prices(NAME), DoubleArray.of(0, 10), DoubleArray.of(1, 2), INTERPOLATOR);
            InterpolatedNodalCurve notZeroRate           = InterpolatedNodalCurve.of(Curves.discountFactors(NAME, ACT_365F), DoubleArray.of(0, 10), DoubleArray.of(1, 2), INTERPOLATOR);
            CurveMetadata          noDayCountMetadata    = DefaultCurveMetadata.builder().curveName(NAME).xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.ZERO_RATE).addInfo(CurveInfoType.COMPOUNDING_PER_YEAR, 4).build();
            InterpolatedNodalCurve notDayCount           = InterpolatedNodalCurve.of(noDayCountMetadata, DoubleArray.of(0, 10), DoubleArray.of(1, 2), INTERPOLATOR);
            CurveMetadata          metaNoCompoundPerYear = DefaultCurveMetadata.builder().curveName(NAME).xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.ZERO_RATE).dayCount(ACT_365F).build();
            InterpolatedNodalCurve notCompoundPerYear    = InterpolatedNodalCurve.of(metaNoCompoundPerYear, DoubleArray.of(0, 10), DoubleArray.of(1, 2), INTERPOLATOR);
            CurveMetadata          metaNegativeNb        = DefaultCurveMetadata.builder().curveName(NAME).xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.ZERO_RATE).dayCount(ACT_365F).addInfo(CurveInfoType.COMPOUNDING_PER_YEAR, -1).build();
            InterpolatedNodalCurve curveNegativeNb       = InterpolatedNodalCurve.of(metaNegativeNb, DoubleArray.of(0, 10), DoubleArray.of(1, 2), INTERPOLATOR);

            assertThrowsIllegalArg(() => ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, notYearFraction));
            assertThrowsIllegalArg(() => ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, notZeroRate));
            assertThrowsIllegalArg(() => ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, notDayCount));
            assertThrowsIllegalArg(() => ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, notCompoundPerYear));
            assertThrowsIllegalArg(() => ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, curveNegativeNb));
        }
        public virtual void test_zeroRatePointSensitivityWithSpread_sensitivityCurrency_periodic()
        {
            int periodPerYear = 4;
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);
            double relativeYearFraction          = ACT_365F.relativeYearFraction(DATE_VAL, DATE_AFTER);
            double df     = test.discountFactor(DATE_AFTER);
            double z      = -1.0 / relativeYearFraction * Math.Log(df);
            double shift  = 1.0E-6;
            double zP     = z + shift;
            double zM     = z - shift;
            double dfSP   = Math.Pow(Math.Pow(Math.Exp(-zP * relativeYearFraction), -1.0 / (relativeYearFraction * periodPerYear)) + SPREAD / periodPerYear, -relativeYearFraction * periodPerYear);
            double dfSM   = Math.Pow(Math.Pow(Math.Exp(-zM * relativeYearFraction), -1.0 / (relativeYearFraction * periodPerYear)) + SPREAD / periodPerYear, -relativeYearFraction * periodPerYear);
            double ddfSdz = (dfSP - dfSM) / (2 * shift);
            ZeroRateSensitivity expected = ZeroRateSensitivity.of(GBP, relativeYearFraction, USD, ddfSdz);
            ZeroRateSensitivity computed = test.zeroRatePointSensitivityWithSpread(DATE_AFTER, USD, SPREAD, PERIODIC, periodPerYear);

            assertTrue(computed.compareKey(expected) == 0);
            assertEquals(computed.Sensitivity, expected.Sensitivity, TOLERANCE_DELTA_FD);
        }
        //-------------------------------------------------------------------------
        public virtual void test_withCurve()
        {
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE).withCurve(CURVE2);

            assertEquals(test.Curve, CURVE2);
        }
        public virtual void test_discountFactorWithSpread_smallYearFraction()
        {
            ZeroRatePeriodicDiscountFactors test = ZeroRatePeriodicDiscountFactors.of(GBP, DATE_VAL, CURVE);

            assertEquals(test.discountFactorWithSpread(DATE_VAL, SPREAD, PERIODIC, 1), 1d, TOLERANCE_DF);
        }