public virtual void test_expired_calibration()
 {
     assertThrowsIllegalArg(() => PRICER_39.Calibrator.calibrateTrinomialTree(CALL_DKO.UnderlyingOption, RATE_PROVIDER_AFTER, VOLS_AFTER));
     // pricing also fails because trinomial data can not be obtained
     assertThrowsIllegalArg(() => PRICER_39.price(CALL_DKO, RATE_PROVIDER_AFTER, VOLS_AFTER));
     assertThrowsIllegalArg(() => PRICER_39.presentValue(CALL_DKO, RATE_PROVIDER_AFTER, VOLS_AFTER));
     assertThrowsIllegalArg(() => PRICER_39.currencyExposure(CALL_DKO, RATE_PROVIDER_AFTER, VOLS_AFTER));
 }
        //-------------------------------------------------------------------------
        public virtual void test_withData()
        {
            ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer pricer = new ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer(5);
            RecombiningTrinomialTreeData data = pricer.Calibrator.calibrateTrinomialTree(CALL_DKO.UnderlyingOption, RATE_PROVIDER, VOLS);
            double price         = pricer.price(CALL_UKI_C, RATE_PROVIDER, VOLS);
            double priceWithData = pricer.price(CALL_UKI_C, RATE_PROVIDER, VOLS, data);

            assertEquals(price, priceWithData);
            CurrencyAmount pv         = pricer.presentValue(CALL_DKO, RATE_PROVIDER, VOLS);
            CurrencyAmount pvWithData = pricer.presentValue(CALL_DKO, RATE_PROVIDER, VOLS, data);

            assertEquals(pv, pvWithData);
            MultiCurrencyAmount ce         = pricer.currencyExposure(CALL_UKI_C, RATE_PROVIDER, VOLS);
            MultiCurrencyAmount ceWithData = pricer.currencyExposure(CALL_UKI_C, RATE_PROVIDER, VOLS, data);

            assertEquals(ce, ceWithData);
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value of the FX barrier option trade.
        /// <para>
        /// The present value of the trade is the value on the valuation date.
        /// </para>
        /// <para>
        /// The trinomial tree is first calibrated to Black volatilities,
        /// then the price is computed based on the calibrated tree.
        ///
        /// </para>
        /// </summary>
        /// <param name="trade">  the option trade </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the present value of the trade </returns>
        public virtual MultiCurrencyAmount presentValue(ResolvedFxSingleBarrierOptionTrade trade, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            ResolvedFxSingleBarrierOption product = trade.Product;
            CurrencyAmount pvProduct = productPricer.presentValue(product, ratesProvider, volatilities);
            Payment        premium   = trade.Premium;
            CurrencyAmount pvPremium = paymentPricer.presentValue(premium, ratesProvider);

            return(MultiCurrencyAmount.of(pvProduct, pvPremium));
        }
        //-------------------------------------------------------------------------
        public virtual void test_presentValueSensitivityRates()
        {
            ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer pricer = new ImpliedTrinomialTreeFxSingleBarrierOptionProductPricer(21);
            CurrencyParameterSensitivities             computed           = pricer.presentValueSensitivityRates(CALL_UKI_C, RATE_PROVIDER, VOLS);
            RatesFiniteDifferenceSensitivityCalculator calc     = new RatesFiniteDifferenceSensitivityCalculator(1.0e-5);
            CurrencyParameterSensitivities             expected = calc.sensitivity(RATE_PROVIDER, p => pricer.presentValue(CALL_UKI_C, p, VOLS));

            assertTrue(computed.equalWithTolerance(expected, 1.0e-13));
        }