using System; using System.Threading; using System.Collections; using System.Linq; using System.Collections.Generic; using MarketData.MarketDataModel; using MarketData.Utils; // Filename: Numerics.cs // Author:Sean Kessler / Werner Stanzl // Date:07/2003 namespace MarketData.Numerical { public class Numerics { public enum CorrelationType{PerfectDownhill,StrongDownhill,ModerateDownhill,WeakDownhill,NoLinearRelationship,WeakUphill,ModerateUphill,StrongUphill,PerfectUphill}; // (i.e.) 2.789 will round to 2.79 public static double Round(double x) { return Math.Round(x, 2, MidpointRounding.AwayFromZero); } public static void ZeroForNaNOrInfinity(ref float[] floatArray) { for(int index=0;index-2*stddev select value).ToArray(); double[] newObservations=(from double value in observations where value (deviations*-1)*stddev select value).ToArray(); return newObservations; } public static LeastSquaresResult LeastSquares(double[] observations) { return LeastSquaresHelper.CalculateLeastSquares(observations); } public static LeastSquaresResultWithR2 LeastSquaresWithR2(double[] observations) { return LeastSquaresHelper.CalculateLeastSquaresWithR2(observations); } public static double RSquared(double[] observations) { try { double[] estimated = new double[observations.Length]; double[] estimatedLessMeanSquared = new double[observations.Length]; double sumOfEstimatedLessMeanSquared = 0.00; double rSquared = 0.00; LeastSquaresResult leastSquaresResult = null; double mean = Numerics.Mean(ref observations); double sumofsquares = 0.00; foreach (double observation in observations) sumofsquares += Math.Pow(observation - mean, 2); leastSquaresResult = LeastSquares(observations); double slope = leastSquaresResult.Slope * -1.00; // LeastSquares generator reverses the slope. Because prices fed to it are in reverse order double yIntercept = leastSquaresResult.YIntercept; for (int index = 0; index < observations.Length; index++) estimated[index] = yIntercept + (slope * (index + 1)); for (int index = 0; index < observations.Length; index++) estimatedLessMeanSquared[index] = Math.Pow(estimated[index] - mean, 2); foreach (double value in estimatedLessMeanSquared) sumOfEstimatedLessMeanSquared += value; rSquared = sumOfEstimatedLessMeanSquared / sumofsquares; return rSquared; } catch (Exception) { return double.NaN; } } /// YIntercept - Calculates slope of values. /// YIntercept public static double YIntercept(double xMean,double yMean,double slope) { return yMean-(slope*xMean); } public static double Slope(ref double[] x,ref double[] y) { double sumxy=0.00; double sumx=0.00; double sumy=0.00; double sumx2=0.00; if(x.Length!=y.Length)return double.NaN; for(int index=0;indexSlope - Calculates slope of values. /// y-values x-values are assumed to be sequential /// Slope public static float Slope(float[] y) { float sum1 = 0.00F; float sum2 = 0.00F; float[] x=new float[y.Length]; for (int index = 0; index < y.Length; index++) x[index] = index + 1; float averageY = Mean(ref y); float averageX = Mean(ref x); for (int index = 0; index < y.Length; index++) { float currX = x[index]; sum1+=(currX-averageX)*(y[index]-averageY); sum2 += (float)Math.Pow(currX-averageX,2); } if (0 == sum2) return float.NaN; return sum1 / sum2; } /// Slope - Calculates slope of values. /// y-values x-values are assumed to be sequential /// Slope public static double Slope(ref double[] y) { double sum1 = 0.00F; double sum2 = 0.00F; double[] x=new double[y.Length]; for (int index = 0; index < y.Length; index++) x[index] = index + 1; double averageY = Mean(ref y); double averageX = Mean(ref x); for (int index = 0; index < y.Length; index++) { double currX = x[index]; sum1+=(currX-averageX)*(y[index]-averageY); sum2 += (float)Math.Pow(currX-averageX,2); } if (0 == sum2) return float.NaN; return sum1 / sum2; } /// Slope - Calculates slope of values. /// y-values x-values are assumed to be sequential /// Slope public static double Slope(double[] y) { double sum1 = 0.00F; double sum2 = 0.00F; double[] x = new double[y.Length]; for (int index = 0; index < y.Length; index++) x[index] = index + 1; double averageY = Mean(ref y); double averageX = Mean(ref x); for (int index = 0; index < y.Length; index++) { double currX = x[index]; sum1 += (currX - averageX) * (y[index] - averageY); sum2 += (float)Math.Pow(currX - averageX, 2); } if (0 == sum2) return float.NaN; return sum1 / sum2; } /// Median - Calculates median of values. /// values /// Median public static double Median(ref double[] values) { int length=values.Length; if (length == 0)throw new Exception("Numerics::cannot calculate median of an empty array"); if (length == 1 )return values[0]; double [] sorted = new double[length]; Array.Copy(values, 0, sorted, 0, length); Array.Sort(sorted); if( (length%2) == 0 ) return (sorted[length/2]+sorted[length/2-1])/2; return sorted[(length-1)/2]; } /// Floor - Calculates floor of values. /// values /// floor public static void Floor(ref double[] values) { for (int i=0; i< values.Length; i++) { values[i] = Math.Floor(values[i]); } } /// Percentile - Calculates percentile of values. /// values /// Percentile public static float Percentile(int perc,ref float[] values) { if(values.Length<5)return float.NaN; int index; Array.Sort(values); index=(int)Math.Floor(perc*(values.Length)/100.00F)-1; if(index<0)index=0; else if(index>=values.Length)index=values.Length-1; return values[index]; } /// Min - Calculates minimum of values. /// values /// minimum public static float Min(ref float[] values) { if(0==values.Length)return 0; float min=values[0]; for(int index=1;indexMin - Calculates minimum of values. /// values /// minimum public static double Min(ref double[] values) { if(0==values.Length)return 0; double min=values[0]; for(int index=1;indexMax - Calculates maximum of values. /// values /// maximum public static float Max(ref float[] values) { if(0==values.Length)return 0; float max=values[0]; for(int index=1;indexmax)max=values[index]; } return max; } /// Max - Calculates maximum of values. /// values /// maximum public static double Max(ref double[] values) { double max=values[0]; for(int index=1;indexmax)max=values[index]; } return max; } /// Mean - Calculates mean of values. /// values /// Mean public static float Mean(ref float[] values) { if (null == values) return float.NaN; int length=values.Length; float mean=0; if(0==length)return float.NaN; for(int index=0;indexMean - Calculates mean of values. /// values /// Mean public static double Mean(ref double[] values) { if (null == values) return float.NaN; int length=values.Length; double mean=0; if(0==values.Length)return double.NaN; for(int index=0;indexMeanAbs - Calculates mean of abs(values). /// values /// Mean public static float MeanAbs(ref float[] values) { int length=values.Length; float mean=0; if(0==length)return mean; for(int index=0;indexGeometricMean - Calculates mean of values. /// values /// Mean public static float GeometricMean(ref float[] values) { float geometricMean=1.00F; int length=values.Length; if(0==length)return geometricMean; for(int index=0;indexSum - Calculates Sum. /// float array x. /// float Sum public static float Sum(ref float[] x) { float sum=0; int length=x.Length; if(0==length)return sum; for(int index=0;indexSum - Calculates Sum. /// double array x. /// double Sum public static double Sum(ref double[] x) { double sum=0; int length=x.Length; if(0==length)return sum; for(int index=0;indexAnnualizedVolatility - Calculates annualized volatility of values. can be any number of period /// values /// volatility public static float AnnualizedVolatility(ref float[] values) { return (float)(Math.Sqrt(252.00)*StdDev(ref values)); // 252 is average number of trading days in a year } /// AnnualizedVolatility - Calculates annualized volatility of values. can be any number of periods /// values /// volatility public static double AnnualizedVolatility(ref double[] values) { return Math.Sqrt(252)*StdDev(ref values); // 252 is average number of trading days in a year } /// Volatility - Calculates volatility of values. /// values /// volatility public static float Volatility(ref float[] values) { return StdDev(ref values); } /// Volatility - Calculates volatility of values. /// values /// volatility public static double Volatility(ref double[] values) { return StdDev(ref values); } /// Standardize - Standardizes the input. /// values /// volatility public static float[] Standardize(ref float[] values) { float[] returnData=new float[values.Length]; float valuesMean=Mean(ref values); float valuesStd=Volatility(ref values); if(0==valuesStd)return values; for(int index=0;indexDownStd - Returns downside standard deviation of values. /// values /// downside standard deviation public static float DownStd(ref float[] values) { float average; float downStd=0; if(1>=values.Length)return downStd; average=Mean(ref values); foreach(float value in values) { if(valueBattingAverage - Returns batting average of values. /// values /// batting average public static float BattingAverage(ref float[] values) { float battingAverage=0; if(0==values.Length)return float.NaN; foreach(float value in values) { if(value>0)battingAverage++; } return battingAverage/values.Length; } /// AverageReturnWithSpline -This is a collection of prices ordered highest date first. /// values /// AverageReturnWithSpline public static double AverageReturnWithSpline(TimeSeriesCollection timeSeriesCollection) { List sourceElements = new List(); List destElements = null; List values = new List(); if (null == timeSeriesCollection || 0 == timeSeriesCollection.Count) return double.NaN; for (int index = timeSeriesCollection.Count-1; index >=0; index--) { TimeSeriesElement timeSeriesElement=timeSeriesCollection[index]; sourceElements.Add(new Element(Utility.DateToLong(timeSeriesElement.AsOf), timeSeriesElement.Value)); } DateTime startDate = timeSeriesCollection[timeSeriesCollection.Count - 1].AsOf; DateTime endDate = timeSeriesCollection[0].AsOf; DateTime valueDate = startDate; while (valueDate <= endDate) { destElements = new List(); destElements.Add(new Element(Utility.DateToLong(valueDate), 0)); CatmullRom.PerformSpline((Element[])sourceElements.ToArray(), (Element[])destElements.ToArray()); double value = destElements[0].Row; values.Add((float)value); valueDate = new DateTime(valueDate.Year+1,valueDate.Month,valueDate.Day); } List inverseValues = new List(); for (int index = values.Count - 1; index >= 0; index--) { inverseValues.Add(values[index]); } float[] fvalues = inverseValues.ToArray(); double averageReturn = Numerics.AverageReturn(ref fvalues); return averageReturn; } /// AverageReturnWithSpline -This is a collection of prices ordered highest date first. /// values /// AverageReturnWithSpline public static double AverageReturnWithSpline(TimeSeriesCollection timeSeriesCollection,ReturnItems returnItems) { List sourceElements = new List(); List destElements = null; returnItems.Clear(); if (null == timeSeriesCollection || 0 == timeSeriesCollection.Count) return double.NaN; for (int index = timeSeriesCollection.Count - 1; index >= 0; index--) { TimeSeriesElement timeSeriesElement = timeSeriesCollection[index]; sourceElements.Add(new Element(Utility.DateToLong(timeSeriesElement.AsOf), timeSeriesElement.Value)); } DateTime startDate = timeSeriesCollection[timeSeriesCollection.Count - 1].AsOf; DateTime endDate = timeSeriesCollection[0].AsOf; DateTime valueDate = startDate; while (valueDate <= endDate) { destElements = new List(); destElements.Add(new Element(Utility.DateToLong(valueDate), 0)); CatmullRom.PerformSpline((Element[])sourceElements.ToArray(), (Element[])destElements.ToArray()); double value = destElements[0].Row; returnItems.Add(new ReturnItem(valueDate,value)); valueDate = new DateTime(valueDate.Year + 1, valueDate.Month, valueDate.Day); } returnItems.CalculateReturns(); float[] values = null; values = returnItems.ToFloat(); double averageReturn = Numerics.Mean(ref values); return averageReturn; } /// AverageReturn -Assumes this is a collection of prices ordered highest date first. /// timeSeriesCollection,if exclusionThreshold is provided then return values>than threshold will be thrown away /// AverageReturn public static double AverageReturn(TimeSeriesCollection timeSeriesCollection) { if(null==timeSeriesCollection || 0==timeSeriesCollection.Count)return double.NaN; float[] values = timeSeriesCollection.ToFloat(); return AverageReturn(ref values); } /// AverageReturn -Assumes this is a collection of prices ordered highest date first. /// values,if exclusionThreshold is provided then return values>than threshold will be thrown away /// AverageReturn public static double AverageReturn(ref float[] values) { try { if (0 == values.Length) return double.NaN; List returns = new List(); for (int index = 0; index < values.Length - 1; index++) { float current = values[index]; float prev = values[index + 1]; if (0 == prev) returns.Add(0.00); else { double currentReturn=double.NaN; if (prev == 0.00) currentReturn = 0; else currentReturn = (float)((current - prev) / Math.Abs(prev)); returns.Add(currentReturn); } } double[] returnsArray = returns.ToArray(); return Mean(ref returnsArray); } catch (Exception) { return double.NaN; } } /// AverageReturnTop -Assumes this is a collection of prices ordered highest date first. /// values /// AverageReturnTop - Calculates return of top n elements, count must be greater than 1 public static double AverageReturnTop(ref float[] values,int top) { try { if (0 == values.Length || 1==values.Length || values.LengthPeriodicReturn -Assumes this is a collection of daily prices ordered highest date first. /// values /// PeriodicReturn - Calculates return of elements public static double AnnualReturn(ref float[] values) { double periodicReturn = double.NaN; double p0 = values[values.Length - 1]; double p1 = values[0]; double returnValue=(p1-p0)/Math.Abs(p0); double n = values.Length / 365; periodicReturn = Math.Pow(1 + returnValue, 1 / n) - 1; return periodicReturn; } /// PowerHit - Returns power hitting of vector x. /// values /// power hit public static float PowerHitting(ref float[] values) { float win=0; long winCount=0; float lose=0; long loseCount=0; if(0==values.Length)return float.NaN; foreach(float value in values) { if(value>0) { win+=value; winCount++; } else if(value<0) { lose+=(-value); loseCount++; } } return (loseCount*win/(winCount*lose)); } /// Product - Returns sum of products. /// values /// product public static float Product(ref float[] values) { float product=1; if(0==values.Length)return 0; foreach(float value in values) { product*=value; } return product; } /// CumProduct - Returns cumulative product of values. /// values /// cumulative product public static float[] CumProduct(ref float[] values) { if(0==values.Length)return new float[0]; float[] cumProduct=new float[values.Length]; cumProduct[0]=values[0]; for(int index=1;indexStdDev - Calculates standard deviation of values. /// values /// standard deviation public static float StdDev(ref float[] values) { long length = 0;// values.Length; float value; float sum=0; float sqr=0; if(null==values || 1>=(length=values.Length))return float.NaN; for(int index=0;indexStdDev - Calculates standard deviation of values. /// values /// standard deviation public static double StdDev(ref double[] values) { long length = 0; ; double value; double sum=0; double sqr=0; if(null==values || 1>=(length=values.Length))return float.NaN; for(int index=0;indexStDevWithDecay - Calculates StDev with a Decay. /// float array x. /// float StDev public static float StdDevWithDecay(ref float[] x) { if(1>=x.Length)return 0; return ApplyDecay(ref x); } /// Covariance - Calculates covariance of x and y. /// vector x /// vector y. /// covariance ///In probability theory and statistics, covariance is a measure of the joint variability of two random variables. ///[1] If the greater values of one variable mainly correspond with the greater values of the other variable, ///and the same holds for the lesser values, (i.e., the variables tend to show similar behavior), ///the covariance is positive.[2] In the opposite case, when the greater values of one variable mainly ///correspond to the lesser values of the other, (i.e., the variables tend to show opposite behavior), ///the covariance is negative. The sign of the covariance therefore shows the tendency in the linear ///relationship between the variables. The magnitude of the covariance is not easy to interpret because ///it is not normalized and hence depends on the magnitudes of the variables. The normalized version of the ///covariance, the correlation coefficient, however, shows by its magnitude the strength of the linear relation. public static float Covariance(ref float[] x,ref float[] y) { float meanx; float meany; int length; float product; if(0==x.Length && 0==y.Length)return 0; if((length=x.Length)!=y.Length)return 0; product=0; meanx=Mean(ref x); meany=Mean(ref y); for(int index=0;indexCovariance - Calculates covariance of x and y. /// vector x /// vector y. /// covariance public static double Covariance(ref double[] x,ref double[] y) { double meanx; double meany; int length; double product; if(0==x.Length && 0==y.Length)return 0; if((length=x.Length)!=y.Length)return 0; product=0; meanx=Mean(ref x); meany=Mean(ref y); for(int index=0;indexVariance - Calculates variance of x (population). /// vector x /// variance public static float Variance(ref float[] xarray) { return Covariance(ref xarray, ref xarray); } /// Variance - Calculates variance of x (population). /// vector x /// variance public static double Variance(ref double[] xarray) { return Covariance(ref xarray, ref xarray); } /// Skewness - Calculates skewness of x (population). /// vector x /// skewness public static float Skewness(ref float[] x) { float meanx; float sd_x; int length; float product; if(0==x.Length)return float.NaN; product=0; meanx=Mean(ref x); sd_x=StdDev(ref x); if(float.NaN==sd_x)return float.NaN; length=x.Length; for(int index=0;indexKurtosis - Calculates kurtosis of x. /// vector x /// kurtosis public static float Kurtosis(ref float[] x) { float meanx; float sd_x; int length; float product; if(0==x.Length)return float.NaN; product=0; meanx=Mean(ref x); sd_x=StdDev(ref x); if(float.NaN==sd_x) return float.NaN; length=x.Length; for(int index=0;indexRemoveDuplicates /// Removes duplicates from x and y and stores the rest of the values in result. /// This is a helper function for KStest. /// vector x /// vector y /// ArrayList result /// x without duplicates private static float[] RemoveDuplicates(float[] x,float[] y,ArrayList result) { ArrayList list= new ArrayList(); int newLength=0; for(int i=0; i Do not reject the null hypothesis at 0.05 significance level. H = 1 => Reject the null hypothesis at 0.05 significance level. (2) pValue: the asymptotic P-value P. (3) KSstat: the K-S test statistic, T = max|S(x) - CDF|, where S(x) is the empirical c.d.f. estimated from the sample vector X and CDF is the standard normal. (4) criticalValue: the critical value of the test, on which the decision to reject the null hypothesis is based. NaN's are removed and a blank is returned if the length of the input array is 0. The implementation of this function is based on the Matlab function kstest.m */ public static KSTest KSTest(ref float[]x) { float alpha=0.05f; KSTest blank=new KSTest(0,Double.NaN,Double.NaN,Double.NaN); ArrayList xNoNaNs=new ArrayList(); for(int i=0; icriticalValue?1:0; double lambda=Math.Max((Math.Sqrt(n)+0.12+0.11/Math.Sqrt(n))*KSstatistic,0); int[] j=new int[101]; double sumP=0; for(int i=0; i1)pValue=1; KSTest ret=new KSTest(H,pValue,KSstatistic,criticalValue); return ret; } /* ERFC Complementary error function for each element of x. * The function is defined as: * erfc(x) = 2/sqrt(pi) * integral from x to inf of exp(-t^2) dt. * = 1 - erf(x). * * This is a helper function to KStest and is based on the Matlab function erfc.m * / */ private static double[] ERFCore(double[] x, int jint) { double[] result = new double[x.Length]; for(int i=0; i0) { double[] a=new double[] {3.16112374387056560e00, 1.13864154151050156e02, 3.77485237685302021e02, 3.20937758913846947e03,1.85777706184603153e-1}; double[] b=new double[] {2.36012909523441209e01, 2.44024637934444173e02, 1.28261652607737228e03, 2.84423683343917062e03}; double[] y=new double[k.Length]; double[] z=new double[k.Length]; double[] xnum=new double[k.Length]; double[] xden=new double[k.Length]; for(int i=0; ixbreak && Math.Abs(x[i])<=4.0) { kList1.Add(i); newLength1++; } int[] k1=new int[newLength1]; kList1.CopyTo(k1); if(k1.Length>0) { double[] c=new double[] {5.64188496988670089e-1, 8.88314979438837594e00, 6.61191906371416295e01, 2.98635138197400131e02, 8.81952221241769090e02, 1.71204761263407058e03, 2.05107837782607147e03, 1.23033935479799725e03, 2.15311535474403846e-8}; double[] d=new double[] {1.57449261107098347e01, 1.17693950891312499e02, 5.37181101862009858e02, 1.62138957456669019e03, 3.29079923573345963e03, 4.36261909014324716e03, 3.43936767414372164e03, 1.23033935480374942e03}; double[] y=new double[k1.Length]; double[] z=new double[k1.Length]; double[] xnum=new double[k1.Length]; double[] xden=new double[k1.Length]; double[] del=new double[k1.Length]; for(int i=0; i0?Math.Floor(y[i]*16)/16:Math.Ceiling(y[i]*16)/16; del[i]=(y[i]-z[i])*(y[i]+z[i]); result[k1[i]]=Math.Exp(z[i]*z[i]*-1)*Math.Exp(del[i]*-1)*result[k1[i]]; } } ArrayList kList2 = new ArrayList(); int newLength2=0; for(int i=0; i4.0) { kList2.Add(i); newLength2++; } int[] k2=new int[newLength2]; kList2.CopyTo(k2); if(k2.Length>0) { double[] p=new double[] {3.05326634961232344e-1, 3.60344899949804439e-1, 1.25781726111229246e-1, 1.60837851487422766e-2, 6.58749161529837803e-4, 1.63153871373020978e-2}; double[] q=new double[] {2.56852019228982242e00, 1.87295284992346047e00, 5.27905102951428412e-1, 6.05183413124413191e-2, 2.33520497626869185e-3}; double[] y=new double[k2.Length]; double[] z=new double[k2.Length]; double[] xnum=new double[k2.Length]; double[] xden=new double[k2.Length]; double[] del=new double[k2.Length]; for(int i=0; i0?Math.Floor(y[i]*16)/16:Math.Ceiling(y[i]*16)/16; del[i]=(y[i]-z[i])*(y[i]+z[i]); result[k2[i]]=Math.Exp(z[i]*z[i]*-1)*Math.Exp(del[i]*-1)*result[k2[i]]; } ArrayList kList3 = new ArrayList(); int newLength3=0; for(int i=0; iCorrelation - Calculates correlation coefficient from input vectors. /// vector x /// vector y. /// correlation coefficient /// Interpretation of results: /// -1 : A perfect downhill (negative) linear relationship /// -0.70 : A strong downhill (negative) linear relationship /// –0.50. A moderate downhill (negative) relationship /// –0.30. A weak downhill (negative) linear relationship /// 0. No linear relationship /// +0.30. A weak uphill (positive) linear relationship /// +0.50. A moderate uphill (positive) relationship /// +0.70. A strong uphill (positive) linear relationship /// Exactly +1. A perfect uphill (positive) linear relationship ///In probability theory and statistics, covariance is a measure of the joint variability of two random variables. ///[1] If the greater values of one variable mainly correspond with the greater values of the other variable, ///and the same holds for the lesser values, (i.e., the variables tend to show similar behavior), ///the covariance is positive.[2] In the opposite case, when the greater values of one variable mainly ///correspond to the lesser values of the other, (i.e., the variables tend to show opposite behavior), ///the covariance is negative. The sign of the covariance therefore shows the tendency in the linear ///relationship between the variables. The magnitude of the covariance is not easy to interpret because ///it is not normalized and hence depends on the magnitudes of the variables. The normalized version of the ///covariance, the correlation coefficient, however, shows by its magnitude the strength of the linear relation. public static float Correlation(ref float[] x, ref float[] y) { float sd_x = StdDev(ref x); float sd_y = StdDev(ref y); return Covariance(ref x, ref y)*x.Length/((sd_x * sd_y)*(x.Length-1)); } public static Numerics.CorrelationType GetCorrelationType(float correlationCovarianeResult) { if(correlationCovarianeResult>=1)return CorrelationType.PerfectUphill; if(correlationCovarianeResult>=.70)return CorrelationType.StrongUphill; if(correlationCovarianeResult>=.50)return CorrelationType.ModerateUphill; if(correlationCovarianeResult>=.50)return CorrelationType.ModerateUphill; if(correlationCovarianeResult>=.30)return CorrelationType.WeakUphill; if(correlationCovarianeResult<=-1)return CorrelationType.PerfectDownhill; if(correlationCovarianeResult<=-.70)return CorrelationType.StrongDownhill; if(correlationCovarianeResult<=-.50)return CorrelationType.ModerateDownhill; if(correlationCovarianeResult<=-.30)return CorrelationType.WeakDownhill; return CorrelationType.NoLinearRelationship; } /// Correlation - Calculates correlation matrix from input matrix. /// source matrix /// number of columns in source. /// number of columns in source. /// tranposed array public static float[,] Correlation(ref float[,] matrix,int rows,int cols) { float[,] result=new float[cols,cols]; float[] x=new float[rows]; float[] y=new float[rows]; int col=0; int row; for(int srcIndex=0;srcIndexCreateCorrelationMatrix - Creates correlation matrix from input matrix. /// the input matrix. /// indicates whether to transpose the input matrix. /// float[,] correlation matrix public static float[,] CreateCorrelationMatrix(ref float[,] values,bool transpose) { int columns=values.GetLength(1); int rows=values.GetLength(0); if(!transpose)return Correlation(ref values,rows,columns); float[,] transposeMatrix=Transpose(ref values,ref rows,ref columns); return Correlation(ref transposeMatrix,rows,columns); } /// Transpose - Convert horizontal range of cells to vertical. /// number of rows in source /// number of columns in source. /// the source matrix. /// tranposed array public static float[] Transpose(ref int srcRows,ref int srcCols,ref float[] source) { float[] result=new float[srcRows*srcCols]; long dstRow=0; long dstCol=0; for(int srcRow=0;srcRowTranspose - Convert horizontal range of cells to vertical. /// number of rows in source /// number of columns in source. /// the source matrix. /// tranposed array public static float[,] Transpose(ref float[,] source,ref int srcRows,ref int srcCols) { float[,] result=new float[srcCols,srcRows]; long dstRow=0; long dstCol=0; for(int srcRow=0;srcRowTransposeXAY - Transpose(x)*A*y. /// row vector /// matrix. /// column vector. /// number of elements in each dimension. /// tranposed array public static float TransposeXAY(ref float[] x,ref float[,] a,ref float[] y,int elements) { float[] acol=new float[elements]; float[] intermediate=new float[elements]; for(int col=0;colMMult - Performs matrix multiplication of vectors. /// the row vector /// the column vector /// Product public static float MMult(ref float[] rowVector,ref float[] colVector) { float product=0; int length; if((length=rowVector.Length)!=colVector.Length)return product; for(int index=0;indexGetXY - Get vertical columns from matrix[,] into x and y. /// column from matrix to copy to x array /// column from matrix to copy to y array /// source matrix /// destination array x /// destination array y /// None private static void GetXY(int xColumn,int yColumn,ref float[,] matrix,ref float[] x,ref float[] y,int rows) { for(int row=0;rowGetX - Get vertical column from matrix[,] into x. /// column from matrix to copy /// the source matrix. /// the destination vector. /// number of rows in matrix. /// None private static void GetX(int xColumn,ref float[,] matrix,ref float[] x,int rows) { for(int row=0;rowBeta - Calculates Beta. /// ticker returns. /// sector returns. /// Beta value /// A beta of 1.00 indicates that the security's price will move with the market /// A beta of less than 1.00 indicates that the security will be less volatile than the market /// A beta of more than 1.00 indicates that the security will be more volatile than the market /// The revised code (i.e.) Beta=Covariance(x,y)/Variance(x) was taken from Investopedia public static double Beta(ref double[] assetReturns, ref double[] benchmarkReturns) { return Covariance(ref assetReturns, ref benchmarkReturns) / Variance(ref benchmarkReturns); } /// ApplyDecay - Apply exponential weighting. /// the samples to weight. /// The weighted standard deviation private static float ApplyDecay(ref float[] samples) { int numSamples=samples.Length; Decay decay=new Decay(numSamples); float average=0; float weightedVariance=0; float weightedError=0; float stddev=0; float error=0; for(int item=0;itemTStatistic - Calculate TStatistic. /// The average for the samples. /// Standard deviation of the samples. /// The number of samples. /// TStatistic public static float TStatistic(float average,float stddev,int samples) { if(0==samples||0==stddev)return float.NaN; return (float)((average/stddev)*Math.Sqrt(samples)); } /// TStatistic - Calculate TStatistic. /// Least squares estimates. /// Standard errors. /// TStatistic public static double[] TStatistic(ref double[] leastSquaresEstimates,ref double[] standardErrors) { double[] tStats; int length; if((length=leastSquaresEstimates.Length)!=standardErrors.Length)return new double[0]; tStats=new double[length]; for(int index=0;index maxPrice) maxPrice = prices[i]; else if (prices[i] < maxPrice) maxDd = Math.Min(maxDd, prices[i] / maxPrice - 1); } return maxDd; } // a float version public static float MaxDrawdown(float[] prices) { if (prices.Length <= 1) return 0; float maxPrice = prices[0]; float maxDd = 0; for (int i = 1; i < prices.Length; i++) { if (prices[i] > maxPrice) maxPrice = prices[i]; else if (prices[i] < maxPrice) maxDd = Math.Min(maxDd, prices[i] / maxPrice - 1); } return maxDd; } // float MaxUpside public static float MaxUpside(float[] prices) { if (prices.Length <= 1) return 0; float minPrice = prices[0]; float maxUpside = 0; for (int i = 1; i < prices.Length; i++) { if (prices[i] < minPrice) minPrice = prices[i]; else if (prices[i] > minPrice) maxUpside = Math.Max(maxUpside, prices[i] / minPrice - 1); } return maxUpside; } } }