Пример #1
0
        /// <summary>
        /// Returns the sample variance of an array.
        /// </summary>
        /// <param name="array">Array of data for which we are calculating the variance.  For time series, the last element (index = n-1), is the most recent.</param>
        /// <param name="decayFactor">In most applications, the decay factor is between 0 and 1.  Weigth on the last element in array is 1.0, the 2nd to last element d, 3rd to last d^2, ...</param>
        public static double Variance(double[] array, double decayFactor)
        {
            if (array.Length == 1)
            {
                return(0.0);
            }

            int    n = array.Length;
            double v = 0.0;
            double d = 1.0;

            for (int i = 0; i < n; i++)
            {
                v += d * array[n - 1 - i] * array[n - 1 - i];
                d *= decayFactor;
            }

            double m  = Mean(array, decayFactor);
            double s1 = GeometricSeries.SumOfGeometricSeries(decayFactor, n);
            double s2 = GeometricSeries.SumOfGeometricSeries(decayFactor * decayFactor, n);
            double a  = s1 / (s1 * s1 - s2);
            double b  = s1 * a;

            v = a * v - b * m * m;

            //Occasionally floating-point error will cause v to be less than zero when it should be exactly zero or very close to zero.
            if (v < 0)
            {
                bool allEqual = Tools.ArrayAllEqual(array);
                return(allEqual ? 0 : double.Epsilon);
            }

            return(v);
        }
Пример #2
0
        /// <summary>
        /// Calculates the sample variance of an array using a rolling window.
        /// The first element (index = 0) of the output array is the variance of points [0] to [length - 1] in 'array',
        /// the second element of the output array is the variance of points [1] to [length] in 'array', and so on.
        /// </summary>
        /// <param name="array">Array of data for which we are calculating the variance.  For time series, the last element (index = n-1), is the most recent.</param>
        /// <param name="decayFactor">In most applications, the decay factor is between 0 and 1.  Weigth on the last element in array is 1.0, the 2nd to last element d, 3rd to last d^2, ...</param>
        /// <param name="length">>Length of rolling window length. Must be less than or equal to the lenght of the array of data.</param>
        /// <returns></returns>
        public static double[] RollingVariance(double[] array, double decayFactor, int length)
        {
            if (array.Length < length)
            {
                throw new ArgumentException("Not enought points in array. Number of points in array must be greater than or equal to length.");
            }

            double s1 = GeometricSeries.SumOfGeometricSeries(decayFactor, length);
            double s2 = GeometricSeries.SumOfGeometricSeries(decayFactor * decayFactor, length);
            double c  = 1 / (s1 * s1 - s2);
            double a  = s1 * c;

            double z1 = 0.0, z2 = 0.0;
            double d = 1.0;

            for (int i = 0; i < length; i++)
            {
                z1 += d * array[length - 1 - i] * array[length - 1 - i];
                z2 += d * array[length - 1 - i];
                d  *= decayFactor;
            }

            double dToLength = Math.Pow(decayFactor, length);

            double[] vArray = new double[array.Length - length + 1];
            vArray[0] = a * z1 - c * z2 * z2;
            for (int i = 1; i < vArray.Length; i++)
            {
                z1        = decayFactor * z1 + array[length - 1 + i] * array[length - 1 + i] - dToLength * array[i - 1] * array[i - 1];
                z2        = decayFactor * z2 + array[length - 1 + i] - dToLength * array[i - 1];
                vArray[i] = a * z1 - c * z2 * z2;
            }
            return(vArray);
        }
Пример #3
0
        /// <summary>
        /// Hybrid VaR is based on historical data, but weights more recent data more heavily.
        /// </summary>
        /// <param name="returnArray">Historical returns from which VaR is to be calculated. The last value, with the highest index is assumed to be the most recent data point.</param>
        /// <param name="windowLength">Length of the VaR window. The number of historical returns that will be used to calculate the VaR.</param>
        /// <param name="confidenceLevel">VaR confidence level. 95% and 99% are typical values. If confidenceLevel is 95% then we expect 95% of days to be better (have a more positive return) than the VaR.</param>
        /// <param name="decayFactor">For a decay factor d, the most recent data point has weight 1, the second d, the third d^2, ...</param>
        public static double HybridValueAtRisk(double[] returnArray, int windowLength, double confidenceLevel, double decayFactor)
        {
            if (returnArray.Length < windowLength)
            {
                throw new ArgumentException(string.Format("returnArray does not have enough data points to calcualte VaR for nDay = {0}.", windowLength));
            }

            if (confidenceLevel < 0.50)
            {
                double[] negReturnArray = new double[returnArray.Length];
                for (int j = 0; j < returnArray.Length; j++)
                {
                    negReturnArray[j] = -returnArray[j];
                }
                return(-HybridValueAtRisk(negReturnArray, windowLength, 1.0 - confidenceLevel, decayFactor));
            }

            //initialize VaR to the minimum return
            double var = double.MaxValue;

            for (int j = returnArray.Length - windowLength; j < returnArray.Length; j++)
            {
                if (returnArray[j] < var)
                {
                    var = returnArray[j];
                }
            }

            //Loop through all data to find the minimum return, then the second worst, ...
            //This is generally faster than sorting when confidenceLevel is high, becaus we only need to identify a few minimums.
            double     totalWt    = GeometricSeries.SumOfGeometricSeries(decayFactor, windowLength);
            double     varLimitWt = (1 - confidenceLevel) * totalWt;
            double     cummWt     = 0;
            List <int> alreadyHaveMinIndexList = new List <int>();

            for (int i = 0; i < windowLength; i++)
            {
                double min      = double.MaxValue;
                int    minIndex = -1;
                for (int j = returnArray.Length - windowLength; j < returnArray.Length; j++)
                {
                    if (returnArray[j] >= var && returnArray[j] < min && alreadyHaveMinIndexList.Contains(j) == false)
                    {
                        min      = returnArray[j];
                        minIndex = j;
                    }
                }
                alreadyHaveMinIndexList.Add(minIndex);

                double wt = Math.Pow(decayFactor, returnArray.Length - minIndex - 1);
                cummWt += wt;
                if (cummWt >= varLimitWt)
                {
                    break;
                }
                var = min;
            }
            return(-var);    //By convention VaR is quoted as a positive value, even though it corresponds to a loss.
        }
Пример #4
0
        /// <summary>
        /// Returns the sample covariance between two arrays.
        /// Arrays should be of equal length, and contain more than one element.
        /// </summary>
        /// <param name="array1"></param>
        /// <param name="array2"></param>
        /// <param name="decayFactor">In most applications, the decay factor is between 0 and 1.  Weigth on the last element in arrays is 1.0, the 2nd to last element d, 3rd to last d^2, ...</param>
        public static double Covariance(double[] array1, double[] array2, double decayFactor)
        {
            if (array1.Length != array2.Length)
            {
                throw new ArgumentException("Arrays must be the same length");
            }

            if (Tools.ArrayAllEqual(array1) || Tools.ArrayAllEqual(array2))
            {
                return(0.0);
            }

            int n = array1.Length;

            if (n == 1)
            {
                return(double.NaN);
            }
            double covar = 0.0;
            double d     = 1.0;

            for (int i = 0; i < n; i++)
            {
                covar += d * array1[n - 1 - i] * array2[n - 1 - i];
                d     *= decayFactor;
            }

            double m1 = Mean(array1, decayFactor);
            double m2 = Mean(array2, decayFactor);
            double S1 = GeometricSeries.SumOfGeometricSeries(decayFactor, n);
            double S2 = GeometricSeries.SumOfGeometricSeries(decayFactor * decayFactor, n);
            double A  = S1 / (S1 * S1 - S2);
            double B  = S1 * A;

            covar = A * covar - B * m1 * m2;
            return(covar);
        }