/// <summary>Find a solution of the equation f(x)=0.</summary>
        /// <param name="f">The function to find roots from.</param>
        /// <param name="lowerBound">The low value of the range where the root is supposed to be.</param>
        /// <param name="upperBound">The high value of the range where the root is supposed to be.</param>
        /// <param name="accuracy">Desired accuracy. The root will be refined until the accuracy or the maximum number of iterations is reached.</param>
        /// <param name="maxIterations">Maximum number of iterations. Usually 100.</param>
        /// <param name="root">The root that was found, if any. Undefined if the function returns false.</param>
        /// <returns>True if a root with the specified accuracy was found, else false.</returns>
        public static bool TryFindRoot(Func <double, double> f, double lowerBound, double upperBound, double accuracy, int maxIterations, out double root)
        {
            double fmin = f(lowerBound);
            double fmax = f(upperBound);

            // already there?
            if (Math.Abs(fmin) < accuracy)
            {
                root = lowerBound;
                return(true);
            }
            if (Math.Abs(fmax) < accuracy)
            {
                root = upperBound;
                return(true);
            }

            root = 0.5 * (lowerBound + upperBound);

            // bad bracketing?
            if (Math.Sign(fmin) == Math.Sign(fmax))
            {
                return(false);
            }

            for (int i = 0; i <= maxIterations; i++)
            {
                if (Math.Abs(fmax - fmin) < 0.5 * accuracy && upperBound.AlmostEqualRelative(lowerBound))
                {
                    return(true);
                }

                if ((lowerBound == root) || (upperBound == root))
                {
                    // accuracy not sufficient, but cannot be improved further
                    return(false);
                }

                double midval = f(root);

                if (Math.Sign(midval) == Math.Sign(fmin))
                {
                    lowerBound = root;
                    fmin       = midval;
                }
                else if (Math.Sign(midval) == Math.Sign(fmax))
                {
                    upperBound = root;
                    fmax       = midval;
                }
                else
                {
                    return(true);
                }

                root = 0.5 * (lowerBound + upperBound);
            }

            return(false);
        }
        /// <summary>
        /// Adaptive approximation of the definite integral in the provided interval by the trapezium rule.
        /// </summary>
        /// <param name="f">The analytic smooth function to integrate.</param>
        /// <param name="intervalBegin">Where the interval starts, inclusive and finite.</param>
        /// <param name="intervalEnd">Where the interval stops, inclusive and finite.</param>
        /// <param name="targetError">The expected accuracy of the approximation.</param>
        /// <returns>Approximation of the finite integral in the given interval.</returns>
        public static double IntegrateAdaptive(Func <double, double> f, double intervalBegin, double intervalEnd, double targetError)
        {
            if (f == null)
            {
                throw new ArgumentNullException(nameof(f));
            }

            int    numberOfPartitions = 1;
            double step = intervalEnd - intervalBegin;
            double sum  = 0.5 * step * (f(intervalBegin) + f(intervalEnd));

            for (int k = 0; k < 20; k++)
            {
                double midpointsum = 0;
                for (int i = 0; i < numberOfPartitions; i++)
                {
                    midpointsum += f(intervalBegin + ((i + 0.5) * step));
                }

                midpointsum        *= step;
                sum                 = 0.5 * (sum + midpointsum);
                step               *= 0.5;
                numberOfPartitions *= 2;

                if (sum.AlmostEqualRelative(midpointsum, targetError))
                {
                    break;
                }
            }

            return(sum);
        }
        public static void AlmostEqualRelative(double expected, double actual, int decimalPlaces)
        {
            if (double.IsNaN(expected) && double.IsNaN(actual))
            {
                return;
            }

            if (!expected.AlmostEqualRelative(actual, decimalPlaces))
            {
                Assert.Fail("Not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected, actual);
            }
        }
        /// <summary>
        /// Tries to find what value of volatility x fulfill the following condition: GetEuroPrice(x) == (ask + bid) / 2
        /// </summary>
        private double SigmaImp()
        {
            // double ave = (_ask + _bid) / 2;
            double ave = _lastPrice;

            double sigma1 = SigmaLow;
            double sigma2 = SigmaHigh;

            if (ave.AlmostEqual(0))
            {
                return((sigma1 + sigma2) / 2);
            }

            int i = 0;

            if (GetEuroPrice(0) > ave)
            {
                return(0.0001);
            }

            while (!sigma1.AlmostEqualRelative(sigma2, 1e-6))
            {
                double sigma3 = (sigma1 + sigma2) / 2;
                double x1     = GetEuroPrice(sigma1);
                double x3     = GetEuroPrice(sigma3);

                double decisionVar = (x1 - ave) * (x3 - ave);
                if (decisionVar > 0)
                {
                    sigma1 = sigma3;
                }
                else if (decisionVar < 0)
                {
                    sigma2 = sigma3;
                }

                if (i++ > MaxLoopsNumber)
                {
                    break;
                }
            }

            double impliedVolatility = (sigma1 + sigma2) / 2;

            if (impliedVolatility < 0)
            {
                impliedVolatility = 0;
            }

            return(impliedVolatility.CoerceZero(SignificantDoubleValue));
        }
        /// <summary>
        /// Asserts that the expected value and the actual value are equal up to a certain number of decimal places. If both
        /// <paramref name="expected"/> and <paramref name="actual"/> are NaN then no assert is thrown.
        /// </summary>
        /// <param name="expected">The expected value.</param>
        /// <param name="actual">The actual value.</param>
        /// <param name="decimalPlaces">The number of decimal places to agree on.</param>
        public static void AlmostEqual(double expected, double actual, int decimalPlaces)
        {
            if (double.IsNaN(expected) && double.IsNaN(actual))
            {
                return;
            }

            var pass = expected.AlmostEqualRelative(actual, decimalPlaces);

            if (!pass)
            {
                // signals Gallio that the test failed.
                Assert.Fail("Not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected, actual);
            }
        }
        private static List <double> IdenticalVolumeFilter(ref List <double> price, ref List <double> volume)
        {
            List <double> idenSR = new List <double>();

            bool haveIncidentIdentical = true;

            while (haveIncidentIdentical)
            {
                haveIncidentIdentical = false;

                int lowIndicator = 0;
                for (; lowIndicator < volume.Count - 1; lowIndicator++)
                {
                    double currentVolume = volume[lowIndicator];
                    double nextVolume    = volume[lowIndicator + 1];
                    if (currentVolume.AlmostEqualRelative(nextVolume, AbsoluteError))
                    {
                        haveIncidentIdentical = true;
                        break;
                    }
                }

                if (haveIncidentIdentical)
                {
                    int highIndicator = lowIndicator + 1;
                    for (; highIndicator < volume.Count; highIndicator++)
                    {
                        double currentVolume = volume[highIndicator];
                        double prevVolume    = volume[highIndicator - 1];
                        if (!currentVolume.AlmostEqualRelative(prevVolume, AbsoluteError))
                        {
                            break;
                        }
                    }

                    idenSR.Add(price[lowIndicator]);
                    idenSR.Add(price[highIndicator - 1]);

                    price.RemoveRange(lowIndicator, highIndicator - lowIndicator);
                    volume.RemoveRange(lowIndicator, highIndicator - lowIndicator);
                }
            }

            return(idenSR);
        }
 public static bool GreaterOrEqual(this double var1, double var2, double error = 1e-5)
 {
     return(var1 >= var2 || var1.AlmostEqualRelative(var2, error));
 }