1444 lines
52 KiB
C#
1444 lines
52 KiB
C#
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<floatArray.Length;index++)
|
||
{
|
||
if(float.IsNaN(floatArray[index]))floatArray[index]=0.0f;
|
||
else if(float.IsInfinity(floatArray[index]))floatArray[index]=0.0f;
|
||
}
|
||
}
|
||
public static double[] ToDouble(float[] floatArray)
|
||
{
|
||
double[] doubleArray=new double[floatArray.Length];
|
||
for(int index=0;index<floatArray.Length;index++)doubleArray[index]=floatArray[index];
|
||
return doubleArray;
|
||
}
|
||
public static float[] ToFloat(double[] doubleArray)
|
||
{
|
||
float[] floatArray=new float[doubleArray.Length];
|
||
for(int index=0;index<doubleArray.Length;index++)floatArray[index]=(float)doubleArray[index];
|
||
return floatArray;
|
||
}
|
||
public static float[] Reverse(ref float[] x)
|
||
{
|
||
float[] y=new float[x.Length];
|
||
for(int index=0;index<x.Length;index++)
|
||
{
|
||
y[index]=x[x.Length-index-1];
|
||
}
|
||
return y;
|
||
}
|
||
public static double[] Reverse(ref double[] x)
|
||
{
|
||
double[] y=new double[x.Length];
|
||
for(int index=0;index<x.Length;index++)
|
||
{
|
||
y[index]=x[x.Length-index-1];
|
||
}
|
||
return y;
|
||
}
|
||
// Removes the outliers from the observations
|
||
public static double[] RemoveOutliers(double[] observations,int deviations=2)
|
||
{
|
||
double stddev=StdDev(ref observations);
|
||
deviations=Math.Abs(deviations);
|
||
if(deviations<1)deviations=1;
|
||
// double[] newObservations=(from double value in observations where value<deviations*stddev && value>-2*stddev select value).ToArray<double>();
|
||
double[] newObservations=(from double value in observations where value<deviations*stddev && value > (deviations*-1)*stddev select value).ToArray<double>();
|
||
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;
|
||
}
|
||
}
|
||
/// <summary>YIntercept - Calculates slope of values.</summary>
|
||
/// <returns>YIntercept</returns>
|
||
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;index<x.Length;index++)
|
||
{
|
||
sumxy+=(x[index]*y[index]);
|
||
sumx+=x[index];
|
||
sumy+=y[index];
|
||
sumx2+=(x[index]*x[index]);
|
||
}
|
||
return ((sumxy-sumx*sumy/x.Length)/(sumx2-sumx*sumx/x.Length));
|
||
}
|
||
/// <summary>Slope - Calculates slope of values.</summary>
|
||
/// <param name="y">y-values x-values are assumed to be sequential</param>
|
||
/// <returns>Slope</returns>
|
||
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;
|
||
}
|
||
/// <summary>Slope - Calculates slope of values.</summary>
|
||
/// <param name="y">y-values x-values are assumed to be sequential</param>
|
||
/// <returns>Slope</returns>
|
||
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;
|
||
}
|
||
/// <summary>Slope - Calculates slope of values.</summary>
|
||
/// <param name="y">y-values x-values are assumed to be sequential</param>
|
||
/// <returns>Slope</returns>
|
||
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;
|
||
}
|
||
/// <summary>Median - Calculates median of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>Median</returns>
|
||
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];
|
||
}
|
||
/// <summary>Floor - Calculates floor of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>floor</returns>
|
||
public static void Floor(ref double[] values)
|
||
{
|
||
for (int i=0; i< values.Length; i++)
|
||
{
|
||
values[i] = Math.Floor(values[i]);
|
||
}
|
||
}
|
||
/// <summary>Percentile - Calculates percentile of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>Percentile</returns>
|
||
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];
|
||
}
|
||
/// <summary>Min - Calculates minimum of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>minimum</returns>
|
||
public static float Min(ref float[] values)
|
||
{
|
||
if(0==values.Length)return 0;
|
||
float min=values[0];
|
||
for(int index=1;index<values.Length;index++)
|
||
{
|
||
if(values[index]<min)min=values[index];
|
||
}
|
||
return min;
|
||
}
|
||
/// <summary>Min - Calculates minimum of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>minimum</returns>
|
||
public static double Min(ref double[] values)
|
||
{
|
||
if(0==values.Length)return 0;
|
||
double min=values[0];
|
||
for(int index=1;index<values.Length;index++)
|
||
{
|
||
if(values[index]<min)min=values[index];
|
||
}
|
||
return min;
|
||
}
|
||
/// <summary>Max - Calculates maximum of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>maximum</returns>
|
||
public static float Max(ref float[] values)
|
||
{
|
||
if(0==values.Length)return 0;
|
||
float max=values[0];
|
||
for(int index=1;index<values.Length;index++)
|
||
{
|
||
if(values[index]>max)max=values[index];
|
||
}
|
||
return max;
|
||
}
|
||
/// <summary>Max - Calculates maximum of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>maximum</returns>
|
||
public static double Max(ref double[] values)
|
||
{
|
||
double max=values[0];
|
||
for(int index=1;index<values.Length;index++)
|
||
{
|
||
if(values[index]>max)max=values[index];
|
||
}
|
||
return max;
|
||
}
|
||
/// <summary>Mean - Calculates mean of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>Mean</returns>
|
||
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;index<length;index++)
|
||
{
|
||
mean+=values[index];
|
||
}
|
||
return mean/length;
|
||
}
|
||
/// <summary>Mean - Calculates mean of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>Mean</returns>
|
||
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;index<length;index++)
|
||
{
|
||
mean+=values[index];
|
||
}
|
||
return mean/length;
|
||
}
|
||
/// <summary>MeanAbs - Calculates mean of abs(values).</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>Mean</returns>
|
||
public static float MeanAbs(ref float[] values)
|
||
{
|
||
int length=values.Length;
|
||
float mean=0;
|
||
if(0==length)return mean;
|
||
for(int index=0;index<length;index++)
|
||
{
|
||
mean+=Math.Abs(values[index]);
|
||
}
|
||
return mean/length;
|
||
}
|
||
/// <summary>GeometricMean - Calculates mean of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>Mean</returns>
|
||
public static float GeometricMean(ref float[] values)
|
||
{
|
||
float geometricMean=1.00F;
|
||
int length=values.Length;
|
||
if(0==length)return geometricMean;
|
||
for(int index=0;index<length;index++)
|
||
{
|
||
if(0.00==values[index])geometricMean*=1.00F;
|
||
else geometricMean*=values[index];
|
||
}
|
||
bool isNegative=geometricMean<0.00?true:false;
|
||
double result=Math.Pow(isNegative?geometricMean*-1.00:geometricMean,1.00/(double)length);
|
||
if(isNegative)result*=-1.00;
|
||
return (float)result;
|
||
}
|
||
/// <summary>Sum - Calculates Sum.</summary>
|
||
/// <param name="x">float array x.</param>
|
||
/// <returns>float Sum</returns>
|
||
public static float Sum(ref float[] x)
|
||
{
|
||
float sum=0;
|
||
int length=x.Length;
|
||
if(0==length)return sum;
|
||
for(int index=0;index<length;index++)sum+=x[index];
|
||
return sum;
|
||
}
|
||
/// <summary>Sum - Calculates Sum.</summary>
|
||
/// <param name="x">double array x.</param>
|
||
/// <returns>double Sum</returns>
|
||
public static double Sum(ref double[] x)
|
||
{
|
||
double sum=0;
|
||
int length=x.Length;
|
||
if(0==length)return sum;
|
||
for(int index=0;index<length;index++)sum+=x[index];
|
||
return sum;
|
||
}
|
||
|
||
/// <summary>AnnualizedVolatility - Calculates annualized volatility of values. can be any number of period</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>volatility</returns>
|
||
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
|
||
}
|
||
/// <summary>AnnualizedVolatility - Calculates annualized volatility of values. can be any number of periods</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>volatility</returns>
|
||
public static double AnnualizedVolatility(ref double[] values)
|
||
{
|
||
return Math.Sqrt(252)*StdDev(ref values); // 252 is average number of trading days in a year
|
||
}
|
||
/// <summary>Volatility - Calculates volatility of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>volatility</returns>
|
||
public static float Volatility(ref float[] values)
|
||
{
|
||
return StdDev(ref values);
|
||
}
|
||
/// <summary>Volatility - Calculates volatility of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>volatility</returns>
|
||
public static double Volatility(ref double[] values)
|
||
{
|
||
return StdDev(ref values);
|
||
}
|
||
/// <summary>Standardize - Standardizes the input.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>volatility</returns>
|
||
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;index<values.Length;index++)
|
||
{
|
||
returnData[index]=(values[index]-valuesMean)/valuesStd;
|
||
}
|
||
return returnData;
|
||
}
|
||
/// <summary>DownStd - Returns downside standard deviation of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>downside standard deviation</returns>
|
||
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(value<average)downStd+=(float)Math.Pow(value-average,2);
|
||
}
|
||
return (float)Math.Sqrt(downStd/(values.Length-1));
|
||
}
|
||
/// <summary>BattingAverage - Returns batting average of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>batting average</returns>
|
||
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;
|
||
}
|
||
/// <summary>AverageReturnWithSpline -This is a collection of prices ordered highest date first.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>AverageReturnWithSpline</returns>
|
||
public static double AverageReturnWithSpline(TimeSeriesCollection timeSeriesCollection)
|
||
{
|
||
List<Element> sourceElements = new List<Element>();
|
||
List<Element> destElements = null;
|
||
List<float> values = new List<float>();
|
||
|
||
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<Element>();
|
||
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<float> inverseValues = new List<float>();
|
||
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;
|
||
}
|
||
/// <summary>AverageReturnWithSpline -This is a collection of prices ordered highest date first.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>AverageReturnWithSpline</returns>
|
||
public static double AverageReturnWithSpline(TimeSeriesCollection timeSeriesCollection,ReturnItems returnItems)
|
||
{
|
||
List<Element> sourceElements = new List<Element>();
|
||
List<Element> 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<Element>();
|
||
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;
|
||
}
|
||
/// <summary>AverageReturn -Assumes this is a collection of prices ordered highest date first.</summary>
|
||
/// <param name="timeSeriesColletion">timeSeriesCollection,if exclusionThreshold is provided then return values>than threshold will be thrown away</param>
|
||
/// <returns>AverageReturn</returns>
|
||
public static double AverageReturn(TimeSeriesCollection timeSeriesCollection)
|
||
{
|
||
if(null==timeSeriesCollection || 0==timeSeriesCollection.Count)return double.NaN;
|
||
float[] values = timeSeriesCollection.ToFloat();
|
||
return AverageReturn(ref values);
|
||
}
|
||
/// <summary>AverageReturn -Assumes this is a collection of prices ordered highest date first.</summary>
|
||
/// <param name="values">values,if exclusionThreshold is provided then return values>than threshold will be thrown away</param>
|
||
/// <returns>AverageReturn</returns>
|
||
public static double AverageReturn(ref float[] values)
|
||
{
|
||
try
|
||
{
|
||
if (0 == values.Length) return double.NaN;
|
||
List<double> returns = new List<double>();
|
||
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;
|
||
}
|
||
}
|
||
/// <summary>AverageReturnTop -Assumes this is a collection of prices ordered highest date first.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>AverageReturnTop - Calculates return of top n elements, count must be greater than 1</returns>
|
||
public static double AverageReturnTop(ref float[] values,int top)
|
||
{
|
||
try
|
||
{
|
||
if (0 == values.Length || 1==values.Length || values.Length<top) return double.NaN;
|
||
double[] returns = new double[top-1];
|
||
for (int index = 0; index < top-1; index++)
|
||
{
|
||
float current = values[index];
|
||
float prev = values[index + 1];
|
||
if (0 == prev) returns[index] = 0;
|
||
else returns[index] = (float)((current - prev) / Math.Abs(prev));
|
||
}
|
||
return Mean(ref returns);
|
||
}
|
||
catch (Exception)
|
||
{
|
||
return double.NaN;
|
||
}
|
||
}
|
||
/// <summary>PeriodicReturn -Assumes this is a collection of daily prices ordered highest date first.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>PeriodicReturn - Calculates return of elements</returns>
|
||
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;
|
||
}
|
||
/// <summary>PowerHit - Returns power hitting of vector x.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>power hit</returns>
|
||
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));
|
||
}
|
||
/// <summary>Product - Returns sum of products.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>product</returns>
|
||
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;
|
||
}
|
||
/// <summary>CumProduct - Returns cumulative product of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>cumulative product</returns>
|
||
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;index<values.Length;index++)
|
||
{
|
||
cumProduct[index]=cumProduct[index-1]*values[index];
|
||
}
|
||
return cumProduct;
|
||
}
|
||
/// <summary>StdDev - Calculates standard deviation of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>standard deviation</returns>
|
||
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;index<length;index++)
|
||
{
|
||
value=values[index];
|
||
sum+=value;
|
||
sqr+=(value*value);
|
||
}
|
||
return (float)Math.Sqrt(Math.Abs((length*sqr-(sum*sum))/(length*(length-1))));
|
||
}
|
||
/// <summary>StdDev - Calculates standard deviation of values.</summary>
|
||
/// <param name="values">values</param>
|
||
/// <returns>standard deviation</returns>
|
||
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;index<length;index++)
|
||
{
|
||
value=values[index];
|
||
sum+=value;
|
||
sqr+=(value*value);
|
||
}
|
||
return (double)Math.Sqrt(Math.Abs((length*sqr-(sum*sum))/(length*(length-1))));
|
||
}
|
||
/// <summary>StDevWithDecay - Calculates StDev with a Decay.</summary>
|
||
/// <param name="x">float array x.</param>
|
||
/// <returns>float StDev</returns>
|
||
public static float StdDevWithDecay(ref float[] x)
|
||
{
|
||
if(1>=x.Length)return 0;
|
||
return ApplyDecay(ref x);
|
||
}
|
||
/// <summary>Covariance - Calculates covariance of x and y.</summary>
|
||
/// <param name="x">vector x</param>
|
||
/// <param name="y">vector y.</param>
|
||
/// <returns>covariance</returns>
|
||
///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;index<length;index++)
|
||
{
|
||
product+=(x[index]-meanx)*(y[index]-meany);
|
||
}
|
||
return product/length;
|
||
}
|
||
/// <summary>Covariance - Calculates covariance of x and y.</summary>
|
||
/// <param name="x">vector x</param>
|
||
/// <param name="y">vector y.</param>
|
||
/// <returns>covariance</returns>
|
||
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;index<length;index++)
|
||
{
|
||
product+=(x[index]-meanx)*(y[index]-meany);
|
||
}
|
||
return product/length;
|
||
}
|
||
|
||
/// <summary>Variance - Calculates variance of x (population).</summary>
|
||
/// <param name="x">vector x</param>
|
||
/// <returns>variance</returns>
|
||
public static float Variance(ref float[] xarray)
|
||
{
|
||
return Covariance(ref xarray, ref xarray);
|
||
}
|
||
/// <summary>Variance - Calculates variance of x (population).</summary>
|
||
/// <param name="x">vector x</param>
|
||
/// <returns>variance</returns>
|
||
public static double Variance(ref double[] xarray)
|
||
{
|
||
return Covariance(ref xarray, ref xarray);
|
||
}
|
||
/// <summary>Skewness - Calculates skewness of x (population).</summary>
|
||
/// <param name="x">vector x</param>
|
||
/// <returns>skewness</returns>
|
||
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;index<length;index++)
|
||
{
|
||
product+=(x[index]-meanx)*(x[index]-meanx)*(x[index]-meanx);
|
||
}
|
||
return product/(length*sd_x*sd_x*sd_x);
|
||
}
|
||
/// <summary>Kurtosis - Calculates kurtosis of x.</summary>
|
||
/// <param name="x">vector x</param>
|
||
/// <returns>kurtosis</returns>
|
||
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;index<length;index++)
|
||
{
|
||
product+=(x[index]-meanx)*(x[index]-meanx)*(x[index]-meanx)*(x[index]-meanx);
|
||
}
|
||
return product/(length*sd_x*sd_x*sd_x*sd_x);
|
||
}
|
||
|
||
/// <summary>RemoveDuplicates
|
||
/// Removes duplicates from x and y and stores the rest of the values in result.
|
||
/// This is a helper function for KStest.</summary>
|
||
/// <param name="x">vector x</param>
|
||
/// <param name="x">vector y</param>
|
||
/// <param name="x">ArrayList result</param>
|
||
/// <returns>x without duplicates</returns>
|
||
private static float[] RemoveDuplicates(float[] x,float[] y,ArrayList result)
|
||
{
|
||
ArrayList list= new ArrayList();
|
||
int newLength=0;
|
||
for(int i=0; i<x.Length; i++)
|
||
{
|
||
if(!list.Contains(x[i]))
|
||
{
|
||
list.Add(x[i]);
|
||
result.Add(y[i]);
|
||
newLength++;
|
||
}
|
||
}
|
||
float[] ret = new float[newLength];
|
||
list.CopyTo(ret);
|
||
|
||
return ret;
|
||
}
|
||
|
||
|
||
/* KSTEST Single sample Kolmogorov-Smirnov goodness-of-fit hypothesis test.
|
||
KStest(X) performs a Kolmogorov-Smirnov (K-S) test
|
||
to determine if a random sample X could have the hypothesized, continuous
|
||
cumulative distribution function CDF (standard normal) at the default = 0.05
|
||
significance level; this is a 2-tailed test. The following info is returned
|
||
as part of KSTest:
|
||
(1) H, indicating the result of the hypothesis test:
|
||
H = 0 => 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; i<x.Length; i++)
|
||
if(!Single.IsNaN(x[i]))
|
||
xNoNaNs.Add(x[i]);
|
||
float[] xNoNaNsarr=new float[xNoNaNs.Count];
|
||
xNoNaNs.CopyTo(xNoNaNsarr);
|
||
x=xNoNaNsarr;
|
||
if(0==x.Length)
|
||
{
|
||
return blank;
|
||
}
|
||
|
||
int n=x.Length;
|
||
for(int i=0; i<n; i++)
|
||
if(Single.IsNaN(x[i]))
|
||
return blank;
|
||
|
||
|
||
float [] yCDFcdfcalc=new float[n+1];
|
||
|
||
|
||
Array.Sort(x);
|
||
yCDFcdfcalc[0]=0;
|
||
for(int i=1; i<=n;i++)
|
||
{
|
||
yCDFcdfcalc[i]=(float)i/n;
|
||
}
|
||
ArrayList sampleCDFarr=new ArrayList();
|
||
float[] xCDFcdfcalc=RemoveDuplicates(x,yCDFcdfcalc,sampleCDFarr);
|
||
sampleCDFarr.Add(yCDFcdfcalc[yCDFcdfcalc.Length-1]);
|
||
float [] sampleCDF=new float[sampleCDFarr.Count];
|
||
|
||
sampleCDFarr.CopyTo(sampleCDF);
|
||
|
||
|
||
float[] xCDF=new float[xCDFcdfcalc.Length];
|
||
Array.Copy(xCDFcdfcalc,xCDF,xCDFcdfcalc.Length);
|
||
|
||
double[] minusZsqrt = new double[xCDFcdfcalc.Length];
|
||
for(int i=0; i<xCDFcdfcalc.Length; i++)
|
||
minusZsqrt[i]=(xCDFcdfcalc[i]*-1.0)/Math.Sqrt(2);
|
||
|
||
double[] yCDF=ERFCore(minusZsqrt,1);
|
||
for(int i=0; i<yCDF.Length; i++)
|
||
{
|
||
yCDF[i]=yCDF[i]*.5;
|
||
}
|
||
|
||
double[] nullCDF= new double[yCDF.Length];
|
||
Array.Copy(yCDF,nullCDF,yCDF.Length);
|
||
|
||
double[] delta1= new double[sampleCDF.Length-1];
|
||
double[] delta2= new double[sampleCDF.Length-1];
|
||
for(int i=0; i<delta1.Length; i++)
|
||
{
|
||
delta1[i]=sampleCDF[i]-nullCDF[i];
|
||
delta2[i]=sampleCDF[i+1]-nullCDF[i];
|
||
}
|
||
double[] deltaCDF= new double[delta1.Length+delta2.Length];
|
||
Array.Copy(delta1,0,deltaCDF,0,delta1.Length);
|
||
Array.Copy(delta2,0,deltaCDF,delta1.Length,delta2.Length);
|
||
for(int i=0; i<deltaCDF.Length; i++)
|
||
{
|
||
deltaCDF[i]=Math.Abs(deltaCDF[i]);
|
||
}
|
||
float alpha1=alpha/2;
|
||
|
||
Array.Sort(deltaCDF);
|
||
double KSstatistic=deltaCDF[deltaCDF.Length-1];
|
||
|
||
double criticalValue;
|
||
if(n<=20)
|
||
{
|
||
double[] a1=new double[] {0.00500, 0.01000, 0.02500, 0.05000, 0.10000};
|
||
double[][] exact= new double[][]{new double[]{0.99500, 0.99000, 0.97500, 0.95000, 0.90000},new double[]{0.92929, 0.90000, 0.84189, 0.77639, 0.68377},new double[]{0.82900, 0.78456, 0.70760, 0.63604, 0.56481},new double[]{0.73424, 0.68887, 0.62394, 0.56522, 0.49265},new double[]{0.66853, 0.62718, 0.56328, 0.50945, 0.44698},new double[]{0.61661, 0.57741, 0.51926, 0.46799, 0.41037},new double[]{0.57581, 0.53844, 0.48342, 0.43607, 0.38148},new double[]{0.54179, 0.50654, 0.45427, 0.40962, 0.35831},new double[]{0.51332, 0.47960, 0.43001, 0.38746, 0.33910},new double[]{0.48893, 0.45662, 0.40925, 0.36866, 0.32260},new double[]{0.46770, 0.43670, 0.39122, 0.35242, 0.30829},new double[]{0.44905, 0.41918, 0.37543, 0.33815, 0.29577},new double[]{0.43247, 0.40362, 0.36143, 0.32549, 0.28470},new double[]{0.41762, 0.38970, 0.34890, 0.31417, 0.27481},new double[]{0.40420, 0.37713, 0.33760, 0.30397, 0.26588},new double[]{0.39201, 0.36571, 0.32733, 0.29472, 0.25778},new double[]{0.38086, 0.35528, 0.31796, 0.28627, 0.25039},new double[]{0.37062, 0.34569, 0.30936, 0.27851, 0.24360},new double[]{0.36117, 0.33685, 0.30143, 0.27136, 0.23735},new double[]{0.35241, 0.32866, 0.29408, 0.26473, 0.23156}};
|
||
criticalValue=exact[n-1][2];
|
||
}
|
||
else
|
||
{
|
||
double A=0.09037*Math.Pow((-1*Math.Log10(alpha1)),1.5) + 0.01515*Math.Pow((Math.Log10(alpha1)),2) - 0.08467*alpha1 - 0.11143;
|
||
double asymptoticStat=Math.Sqrt(-0.5*Math.Log(alpha1)/n);
|
||
double criticalValue1=asymptoticStat - 0.16693/n - A/Math.Pow(n,1.5);
|
||
criticalValue=Math.Min(criticalValue1,1-alpha1);
|
||
}
|
||
int H=KSstatistic>criticalValue?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; i<j.Length; i++)
|
||
{
|
||
j[i]=i+1;
|
||
sumP+=(Math.Pow(-1,j[i]-1)*Math.Exp(-2*lambda*lambda*Math.Pow(j[i],2)));
|
||
}
|
||
double pValue=2*sumP;
|
||
if(pValue<0)pValue=0;
|
||
if(pValue>1)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; i<x.Length;i++)
|
||
result[i]=Single.NaN;
|
||
|
||
double xbreak=0.46875;
|
||
|
||
ArrayList kList = new ArrayList();
|
||
int newLength=0;
|
||
for(int i=0; i<x.Length; i++)
|
||
if(Math.Abs(x[i])<=xbreak)
|
||
{
|
||
kList.Add(i);
|
||
newLength++;
|
||
}
|
||
|
||
int[] k=new int[newLength];
|
||
kList.CopyTo(k);
|
||
|
||
if(k.Length>0)
|
||
{
|
||
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; i<y.Length; i++)
|
||
{
|
||
y[i]=Math.Abs(x[k[i]]);
|
||
z[i]=y[i]*y[i];
|
||
xnum[i]=a[4]*z[i];
|
||
xden[i]=z[i];
|
||
}
|
||
for(int i=0; i<3; i++)
|
||
{
|
||
for(int j=0; j<y.Length; j++)
|
||
{
|
||
xnum[j]=(xnum[j]+a[i])*z[j];
|
||
xden[j]=(xden[j]+b[i])*z[j];
|
||
}
|
||
}
|
||
for(int i=0; i<k.Length; i++)
|
||
{
|
||
result[k[i]]=x[k[i]]*(xnum[i]+a[3])/(xden[i]+b[3]);
|
||
result[k[i]]=1-result[k[i]];
|
||
}
|
||
|
||
}
|
||
|
||
|
||
ArrayList kList1 = new ArrayList();
|
||
int newLength1=0;
|
||
for(int i=0; i<x.Length; i++)
|
||
if(Math.Abs(x[i])>xbreak && 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; i<y.Length; i++)
|
||
{
|
||
y[i]=Math.Abs(x[k1[i]]);
|
||
xnum[i]=c[8]*y[i];
|
||
xden[i]=y[i];
|
||
}
|
||
for(int i=0; i<7; i++)
|
||
{
|
||
for(int j=0; j<y.Length; j++)
|
||
{
|
||
xnum[j]=(xnum[j]+c[i])*y[j];
|
||
xden[j]=(xden[j]+d[i])*y[j];
|
||
}
|
||
}
|
||
for(int i=0; i<k1.Length; i++)
|
||
{
|
||
result[k1[i]]=(xnum[i]+c[7])/(xden[i]+d[7]);
|
||
}
|
||
|
||
for(int i=0; i<y.Length; i++)
|
||
{
|
||
z[i]=(y[i]*16)>0?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; i<x.Length; i++)
|
||
if(Math.Abs(x[i])>4.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; i<y.Length; i++)
|
||
{
|
||
y[i]=Math.Abs(x[k2[i]]);
|
||
z[i]=1/(y[i]*y[i]);
|
||
xnum[i]=p[5]*z[i];
|
||
xden[i]=z[i];
|
||
}
|
||
for(int i=0; i<4; i++)
|
||
{
|
||
for(int j=0; j<y.Length; j++)
|
||
{
|
||
xnum[j]=(xnum[j]+p[i])*z[j];
|
||
xden[j]=(xden[j]+q[i])*z[j];
|
||
}
|
||
}
|
||
for(int i=0; i<k2.Length; i++)
|
||
{
|
||
result[k2[i]]=z[i]*(xnum[i]+p[4])/(xden[i]+q[4]);
|
||
result[k2[i]]=(1/Math.Sqrt(Math.PI) - result[k2[i]])/y[i];
|
||
}
|
||
|
||
for(int i=0; i<y.Length; i++)
|
||
{
|
||
z[i]=(y[i]*16)>0?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; i<result.Length; i++)
|
||
if(Double.IsInfinity(result[i]) || Double.IsNaN(result[i]) || Double.IsNegativeInfinity(result[i]) || Double.IsPositiveInfinity(result[i]))
|
||
{
|
||
kList3.Add(i);
|
||
newLength3++;
|
||
}
|
||
|
||
int[] k3=new int[newLength3];
|
||
kList3.CopyTo(k3);
|
||
|
||
for(int i=0; i<k3.Length; i++)
|
||
{
|
||
result[k3[i]]=0*k3[i];
|
||
}
|
||
}
|
||
|
||
ArrayList kList4 = new ArrayList();
|
||
int newLength4=0;
|
||
for(int i=0; i<x.Length; i++)
|
||
if(x[i]<(xbreak*-1))
|
||
{
|
||
kList4.Add(i);
|
||
newLength4++;
|
||
}
|
||
|
||
int[] k4=new int[newLength4];
|
||
kList4.CopyTo(k4);
|
||
|
||
for(int i=0; i<k4.Length; i++)
|
||
{
|
||
result[k4[i]]=2.0-result[k4[i]];
|
||
}
|
||
|
||
double[] resultRet= new double[result.Length];
|
||
Array.Copy(result,resultRet,result.Length);
|
||
return resultRet;
|
||
}
|
||
/// <summary>Correlation - Calculates correlation coefficient from input vectors.</summary>
|
||
/// <param name="x">vector x</param>
|
||
/// <param name="y">vector y.</param>
|
||
/// <returns>correlation coefficient</returns>
|
||
/// Interpretation of results:
|
||
/// -1 : A perfect downhill (negative) linear relationship
|
||
/// -0.70 : A strong downhill (negative) linear relationship
|
||
/// <20>0.50. A moderate downhill (negative) relationship
|
||
/// <20>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;
|
||
}
|
||
|
||
/// <summary>Correlation - Calculates correlation matrix from input matrix.</summary>
|
||
/// <param name="matrix">source matrix</param>
|
||
/// <param name="rows">number of columns in source.</param>
|
||
/// <param name="cols">number of columns in source.</param>
|
||
/// <returns>tranposed array</returns>
|
||
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;srcIndex<cols;srcIndex++)
|
||
{
|
||
row=0;
|
||
for(int dstIndex=0;dstIndex<cols;dstIndex++)
|
||
{
|
||
GetXY(srcIndex,dstIndex,ref matrix,ref x,ref y,rows);
|
||
result[row,col]=Correlation(ref x,ref y);
|
||
row++;
|
||
}
|
||
col++;
|
||
}
|
||
return result;
|
||
}
|
||
/// <summary>CreateCorrelationMatrix - Creates correlation matrix from input matrix.</summary>
|
||
/// <param name="values">the input matrix.</param>
|
||
/// <param name="transpose">indicates whether to transpose the input matrix.</param>
|
||
/// <returns>float[,] correlation matrix</returns>
|
||
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);
|
||
}
|
||
/// <summary>Transpose - Convert horizontal range of cells to vertical.</summary>
|
||
/// <param name="srcRows">number of rows in source</param>
|
||
/// <param name="srcCols">number of columns in source.</param>
|
||
/// <param name="source">the source matrix.</param>
|
||
/// <returns>tranposed array</returns>
|
||
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;srcRow<srcRows;srcRow++)
|
||
{
|
||
dstRow=0;
|
||
for(int srcCol=0;srcCol<srcCols;srcCol++)
|
||
{
|
||
result[(dstRow*srcRows)+dstCol]=source[(srcRow*srcCols)+srcCol];
|
||
dstRow++;
|
||
}
|
||
dstCol++;
|
||
}
|
||
int tmpRows=srcRows;
|
||
srcRows=srcCols;
|
||
srcCols=tmpRows;
|
||
return result;
|
||
}
|
||
|
||
/// <summary>Transpose - Convert horizontal range of cells to vertical.</summary>
|
||
/// <param name="srcRows">number of rows in source</param>
|
||
/// <param name="srcCols">number of columns in source.</param>
|
||
/// <param name="source">the source matrix.</param>
|
||
/// <returns>tranposed array</returns>
|
||
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;srcRow<srcRows;srcRow++)
|
||
{
|
||
dstRow=0;
|
||
for(int srcCol=0;srcCol<srcCols;srcCol++)
|
||
{
|
||
result[dstRow,dstCol]=source[srcRow,srcCol];
|
||
dstRow++;
|
||
}
|
||
dstCol++;
|
||
}
|
||
int tmpRows=srcRows;
|
||
srcRows=srcCols;
|
||
srcCols=tmpRows;
|
||
return result;
|
||
}
|
||
/// <summary>TransposeXAY - Transpose(x)*A*y.</summary>
|
||
/// <param name="x">row vector</param>
|
||
/// <param name="a">matrix.</param>
|
||
/// <param name="y">column vector.</param>
|
||
/// <param name="elements">number of elements in each dimension.</param>
|
||
/// <returns>tranposed array</returns>
|
||
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;col<elements;col++)
|
||
{
|
||
GetX(col,ref a,ref acol,elements);
|
||
intermediate[col]=MMult(ref x,ref acol);
|
||
}
|
||
return MMult(ref intermediate,ref y);
|
||
}
|
||
/// <summary>MMult - Performs matrix multiplication of vectors.</summary>
|
||
/// <param name="rowVector">the row vector</param>
|
||
/// <param name="colVector">the column vector</param>
|
||
/// <returns>Product</returns>
|
||
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;index<length;index++)product+=rowVector[index]*colVector[index];
|
||
return product;
|
||
}
|
||
/// <summary>GetXY - Get vertical columns from matrix[,] into x and y.</summary>
|
||
/// <param name="xColumn">column from matrix to copy to x array</param>
|
||
/// <param name="yColumn">column from matrix to copy to y array</param>
|
||
/// <param name="matrix">source matrix</param>
|
||
/// <param name="x">destination array x</param>
|
||
/// <param name="y">destination array y</param>
|
||
/// <returns>None</returns>
|
||
private static void GetXY(int xColumn,int yColumn,ref float[,] matrix,ref float[] x,ref float[] y,int rows)
|
||
{
|
||
for(int row=0;row<rows;row++)
|
||
{
|
||
x[row]=matrix[row,xColumn];
|
||
y[row]=matrix[row,yColumn];
|
||
}
|
||
}
|
||
/// <summary>GetX - Get vertical column from matrix[,] into x.</summary>
|
||
/// <param name="xColumn">column from matrix to copy</param>
|
||
/// <param name="matrix">the source matrix.</param>
|
||
/// <param name="x">the destination vector.</param>
|
||
/// <param name="rows">number of rows in matrix.</param>
|
||
/// <returns>None</returns>
|
||
private static void GetX(int xColumn,ref float[,] matrix,ref float[] x,int rows)
|
||
{
|
||
for(int row=0;row<rows;row++)
|
||
{
|
||
x[row]=matrix[row,xColumn];
|
||
}
|
||
}
|
||
/// <summary>Beta - Calculates Beta.</summary>
|
||
/// <param name="x">ticker returns.</param>
|
||
/// <param name="y">sector returns.</param>
|
||
/// <returns>Beta value</returns>
|
||
/// 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);
|
||
}
|
||
/// <summary>ApplyDecay - Apply exponential weighting.</summary>
|
||
/// <param name="samples">the samples to weight.</param>
|
||
/// <returns>The weighted standard deviation</returns>
|
||
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;item<numSamples;item++)average+=(float)samples[item];
|
||
average/=numSamples;
|
||
for(int item=0;item<numSamples;item++)
|
||
{
|
||
error=(float)Math.Pow(samples[item]-average,2);
|
||
weightedError=error*decay[item]*(numSamples);
|
||
weightedVariance+=weightedError;
|
||
}
|
||
weightedVariance/=(numSamples-1);
|
||
stddev=(float)Math.Sqrt(Math.Abs(weightedVariance));
|
||
return stddev;
|
||
}
|
||
/// <summary>TStatistic - Calculate TStatistic.</summary>
|
||
/// <param name="average">The average for the samples.</param>
|
||
/// <param name="stddev">Standard deviation of the samples.</param>
|
||
/// <param name="samples">The number of samples.</param>
|
||
/// <returns>TStatistic</returns>
|
||
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));
|
||
}
|
||
/// <summary>TStatistic - Calculate TStatistic.</summary>
|
||
/// <param name="leastSquaresEstimates">Least squares estimates.</param>
|
||
/// <param name="standardErrors">Standard errors.</param>
|
||
/// <returns>TStatistic</returns>
|
||
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<length;index++)
|
||
{
|
||
if(0==standardErrors[index])tStats[index]=0;
|
||
else tStats[index]=leastSquaresEstimates[index]/standardErrors[index];
|
||
}
|
||
return tStats;
|
||
}
|
||
// Calculate max drawdown of series
|
||
public static double MaxDrawdown(double[] prices)
|
||
{
|
||
if (prices.Length <= 1) return 0;
|
||
double maxPrice = prices[0];
|
||
double 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;
|
||
}
|
||
// 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;
|
||
}
|
||
}
|
||
}
|