public void GetForwardVolga_TestCase_ViaDifferentialQuotientApproximation(ConstantVolatilityStandardEuropeanOptionConfiguration optionConfiguration)
        {
            var optionUnderTest = CreateOption(optionConfiguration.Strike, optionConfiguration.Forward, optionConfiguration.TimeToExpiry, optionConfiguration.DiscountFactor);

            double actualVolga   = optionUnderTest.GetVolga(optionConfiguration.Volatility);
            double expectedVolga = DifferentialQuotientGreekApproximation.GetOptionVolga(optionConfiguration, (K, F, t, df, sigma) => CreateOption(K, F, t, df).GetValue(sigma));

            Assert.That(actualVolga, Is.EqualTo(expectedVolga).Within(1E-4), optionUnderTest.ToString());
        }
        /// <summary>Gets the option kappa, i.e. strike-delta.
        /// </summary>
        /// <param name="optionParameters">The parameters of the option.</param>
        /// <param name="getOptionValue">A delegate that calculates the value of the option for specified parameters.</param>
        /// <returns>A approximation of the kappa.</returns>
        public static double GetOptionKappa(ConstantVolatilityStandardEuropeanOptionConfiguration optionParameters, GetOptionValue getOptionValue)
        {
            double h = 0.0000001;

            double value1 = getOptionValue(optionParameters.Strike + h, optionParameters.Forward, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility);
            double value2 = getOptionValue(optionParameters.Strike, optionParameters.Forward, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility);

            return((value1 - value2) / h);
        }
        /// <summary>Gets the Forward-Vanna of the option, i.e. the derivative \partial^2/ {\partial \sigma \partial F} of the option value.
        /// </summary>
        /// <param name="optionParameters">The parameters of the option.</param>
        /// <param name="getOptionValue">A delegate that calculates the value of the option for specified parameters.</param>
        /// <returns>A approximation of the gamma.</returns>
        public static double GetOptionForwardVanna(ConstantVolatilityStandardEuropeanOptionConfiguration optionParameters, GetOptionValue getOptionValue)
        {
            double h = 0.00005;  // should be not too small, otherwise one get numerical problems
            double k = 0.00005;

            double value             = getOptionValue(optionParameters.Strike, optionParameters.Forward, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility);
            double valuePlusHPlusK   = getOptionValue(optionParameters.Strike, optionParameters.Forward + k, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility + h);
            double valuePlusHMinusK  = getOptionValue(optionParameters.Strike, optionParameters.Forward - k, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility + h);
            double valueMinusHPlusK  = getOptionValue(optionParameters.Strike, optionParameters.Forward + k, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility - h);
            double valueMinusHMinusK = getOptionValue(optionParameters.Strike, optionParameters.Forward - k, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility - h);

            return((valuePlusHPlusK - valuePlusHMinusK - valueMinusHPlusK + valueMinusHMinusK) / (4.0 * h * k));
        }
        public void TryGetImpliedVolatility_ComputedOptionValue_Volatility(ConstantVolatilityStandardEuropeanOptionConfiguration optionConfiguration)
        {
            var optionUnderTest = CreateOption(optionConfiguration.Strike, optionConfiguration.Forward, optionConfiguration.TimeToExpiry, optionConfiguration.DiscountFactor);

            double optionValue = optionUnderTest.GetValue(optionConfiguration.Volatility);

            Assume.That(IsVolatilityInvertibleOptionValue(optionValue, optionUnderTest) == true, String.Format("Option value {0} can not be inverted; intrinsic value {1}", optionValue, optionUnderTest.GetIntrinsicValue()));


            double actualImpliedVolatility;

            Assert.That(optionUnderTest.TryGetImpliedVolatility(optionValue, out actualImpliedVolatility), Is.EqualTo(ImpliedCalculationResultState.ProperResult), String.Format("Option value was: {0}, Intrinsic value: {1}.", optionValue, optionUnderTest.GetIntrinsicValue()));

            Assert.That(actualImpliedVolatility, Is.EqualTo(optionConfiguration.Volatility).Within(1E-8), String.Format("Option value was: {0}, Intrinsic value: {1}", optionValue, optionUnderTest.GetIntrinsicValue()));
        }
        /// <summary>Gets the Volga of the option, i.e. the second derivative with respect to the volatilty.
        /// </summary>
        /// <param name="optionParameters">The parameters of the option.</param>
        /// <param name="getOptionValue">A delegate that calculates the value of the option for specified parameters.</param>
        /// <returns>A approximation of the volga.</returns>
        public static double GetOptionVolga(ConstantVolatilityStandardEuropeanOptionConfiguration optionParameters, GetOptionValue getOptionValue)
        {
            double h = 0.00005;  // should be not too small, otherwise one get numerical problems

            double value        = getOptionValue(optionParameters.Strike, optionParameters.Forward, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility);
            double valueMinusH  = getOptionValue(optionParameters.Strike, optionParameters.Forward, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility - h);
            double valueMinus2H = getOptionValue(optionParameters.Strike, optionParameters.Forward, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility - 2.0 * h);
            double valuePlusH   = getOptionValue(optionParameters.Strike, optionParameters.Forward, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility + h);
            double valuePlus2H  = getOptionValue(optionParameters.Strike, optionParameters.Forward, optionParameters.TimeToExpiry, optionParameters.DiscountFactor, optionParameters.Volatility + 2.0 * h);

            /* approximation of the second derivative: (Richardson's extrapolation)
             *   f''(x) \approx  [-f(x-2h) + 16 * f(x-h) - 30 * f(x) + 16 * f(x+h) - f(x+2h)] / (12 * h^2)
             */
            return((-valueMinus2H + 16.0 * valueMinusH - 30.0 * value + 16.0 * valuePlusH - valuePlus2H) / (12 * h * h));
        }