134 lines
6.3 KiB
C#
134 lines
6.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace MarketData.Numerical
|
|
{
|
|
public class LeastSquaresResult
|
|
{
|
|
public double[] LeastSquares { get; set; }
|
|
public double YIntercept { get; set; }
|
|
public double XIntercept { get; set; }
|
|
public double Slope { get; set; }
|
|
public void Extend(int itemCount, double slope) // extend the result set by itemCount by applying the slope to subsequent values
|
|
{
|
|
if (null == LeastSquares || 0 == LeastSquares.Length) return;
|
|
double[] extendedItems = new double[itemCount + LeastSquares.Length];
|
|
Array.Copy(LeastSquares, 0, extendedItems, itemCount, LeastSquares.Length);
|
|
for (int index = itemCount - 1; index >= 0; index--)
|
|
{
|
|
extendedItems[index] = extendedItems[index + 1] + slope;
|
|
}
|
|
LeastSquares = extendedItems;
|
|
}
|
|
}
|
|
public class LeastSquaresResultWithR2 : LeastSquaresResult
|
|
{
|
|
public double RSquared { get; set; }
|
|
}
|
|
// **********************************************************************************************************************************************
|
|
public class LeastSquaresHelper
|
|
{
|
|
private LeastSquaresHelper()
|
|
{
|
|
}
|
|
// This version reverses the slope because the input data is in reverse order
|
|
// The input data should be in the following manner observations[count-1]=earliest data point, observations[0]=most recent data point
|
|
// This version should be retained as-is because it is being referenced in models etc.,
|
|
public static LeastSquaresResult CalculateLeastSquares(double[] observations)
|
|
{
|
|
try
|
|
{
|
|
LeastSquaresResult leastSquaresResult = new LeastSquaresResult();
|
|
double[] xSeries = new double[observations.Length];
|
|
double[] xMinusXMean = new double[observations.Length];
|
|
double[] yMinusYMean = new double[observations.Length];
|
|
double[] meanProduct = new double[observations.Length];
|
|
double[] xMinusXMeanSquared = new double[observations.Length];
|
|
double[] leastSquares = new double[observations.Length];
|
|
double xMean = double.NaN;
|
|
double yMean = double.NaN;
|
|
double slope = double.NaN;
|
|
double yIntercept = double.NaN;
|
|
for (int index = 0; index < xSeries.Length; index++) xSeries[index] = index + 1;
|
|
xMean = Numerics.Mean(ref xSeries);
|
|
yMean = Numerics.Mean(ref observations);
|
|
for (int index = 0; index < observations.Length; index++)
|
|
{
|
|
xMinusXMean[index] = xSeries[index] - xMean;
|
|
yMinusYMean[index] = observations[index] - yMean;
|
|
meanProduct[index] = xMinusXMean[index] * yMinusYMean[index];
|
|
xMinusXMeanSquared[index] = xMinusXMean[index] * xMinusXMean[index];
|
|
}
|
|
slope = Numerics.Sum(ref meanProduct) / Numerics.Sum(ref xMinusXMeanSquared);
|
|
yIntercept = Numerics.YIntercept(xMean, yMean, slope);
|
|
for (int index = 0; index < leastSquares.Length; index++) leastSquares[index] = slope * xSeries[index] + yIntercept;
|
|
leastSquaresResult.LeastSquares = leastSquares;
|
|
leastSquaresResult.YIntercept = yIntercept;
|
|
leastSquaresResult.XIntercept = xMean;
|
|
leastSquaresResult.Slope = slope * -1.00;
|
|
return leastSquaresResult;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG, exception.ToString());
|
|
return null;
|
|
}
|
|
}
|
|
// This version uses the true slope whereas the version above reverses the slope due to the arrangement of the input data
|
|
// The input data should be in the following manner observations[0]=earliest data point, observations[count-1]=most recent data point
|
|
public static LeastSquaresResultWithR2 CalculateLeastSquaresWithR2(double[] observations)
|
|
{
|
|
try
|
|
{
|
|
LeastSquaresResultWithR2 leastSquaresResultWithR2 = new LeastSquaresResultWithR2();
|
|
double[] xSeries = new double[observations.Length];
|
|
double[] xMinusXMean = new double[observations.Length];
|
|
double[] yMinusYMean = new double[observations.Length];
|
|
double[] meanProduct = new double[observations.Length];
|
|
double[] xMinusXMeanSquared = new double[observations.Length];
|
|
double[] leastSquares = new double[observations.Length];
|
|
double xMean = double.NaN;
|
|
double yMean = double.NaN;
|
|
double slope = double.NaN;
|
|
double yIntercept = double.NaN;
|
|
for (int index = 0; index < xSeries.Length; index++) xSeries[index] = index + 1;
|
|
xMean = Numerics.Mean(ref xSeries);
|
|
yMean = Numerics.Mean(ref observations);
|
|
for (int index = 0; index < observations.Length; index++)
|
|
{
|
|
xMinusXMean[index] = xSeries[index] - xMean;
|
|
yMinusYMean[index] = observations[index] - yMean;
|
|
meanProduct[index] = xMinusXMean[index] * yMinusYMean[index];
|
|
xMinusXMeanSquared[index] = xMinusXMean[index] * xMinusXMean[index];
|
|
}
|
|
slope = Numerics.Sum(ref meanProduct) / Numerics.Sum(ref xMinusXMeanSquared);
|
|
yIntercept = Numerics.YIntercept(xMean, yMean, slope);
|
|
for (int index = 0; index < leastSquares.Length; index++) leastSquares[index] = slope * xSeries[index] + yIntercept;
|
|
leastSquaresResultWithR2.LeastSquares = leastSquares;
|
|
leastSquaresResultWithR2.YIntercept = yIntercept;
|
|
leastSquaresResultWithR2.XIntercept = xMean;
|
|
leastSquaresResultWithR2.Slope = slope;
|
|
// calculate the R2
|
|
double[] estimated = new double[observations.Length];
|
|
double[] estimatedLessMeanSquared = new double[observations.Length];
|
|
double sumOfEstimatedLessMeanSquared = 0.00;
|
|
double sumofsquares = 0.00;
|
|
foreach (double observation in observations) sumofsquares += Math.Pow(observation - yMean, 2);
|
|
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] - yMean, 2);
|
|
foreach (double value in estimatedLessMeanSquared) sumOfEstimatedLessMeanSquared += value;
|
|
leastSquaresResultWithR2.RSquared = sumOfEstimatedLessMeanSquared / sumofsquares;
|
|
return leastSquaresResultWithR2;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG, exception.ToString());
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|