mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-01 03:07:43 +00:00
LinReg
This commit is contained in:
+1
-3
@@ -20,7 +20,7 @@
|
||||
| BIAS - Bias |✔️|||✔️|
|
||||
| ENTR - Entropy |✔️|||✔️|
|
||||
| KUR - Kurtosis |✔️|||✔️|
|
||||
| LINREG - Linear Regression ||✔️|✔️||
|
||||
| LINREG - Linear Regression |✔️|✔️|✔️||
|
||||
| MAD - Mean Absolute Deviation |✔️||✔️|✔️|
|
||||
| MAPE - Mean Absolute Percent Error |✔️||✔️||
|
||||
| MAX - Max value |✔️|✔️|||
|
||||
@@ -30,9 +30,7 @@
|
||||
| PSDEV - Population Standard Deviation |✔️||||
|
||||
| PVAR - Population Variance |✔️||||
|
||||
| QUANTILE ||||✔️|
|
||||
| RS - R-Squared Coefficient |||✔️||
|
||||
| SKEW - Skewness ||||✔️|
|
||||
| SLOPE - Slope |||✔️||
|
||||
| SMAPE - Symmetric Mean Absolute Percent Error |✔️||||
|
||||
| SDEV - Sample Standard Deviation |✔️|✔️|✔️|✔️|
|
||||
| VAR - Sample Variance |✔️|||✔️|
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
namespace QuanTAlib;
|
||||
using System;
|
||||
|
||||
/* <summary>
|
||||
LINREG: Linear Regression (using Least Square Method)
|
||||
Linear Regression provides a slope of a straight line that is the best approximation of the given set of data.
|
||||
The method of least squares is a standard approach in linear regression analysis to approximate the solution
|
||||
by minimizing the sum of the squares of the residuals made in the results of each individual equation.
|
||||
|
||||
Additional outputs provided by LINREG:
|
||||
.Intercept - y-intercept point of the best fit line
|
||||
.RSquared - R-Squared (R²), Coefficient of Determination
|
||||
.StdDev - Standard Deviation of data over given periods
|
||||
|
||||
y = Slope * x + Intercept
|
||||
|
||||
Sources:
|
||||
https://en.wikipedia.org/wiki/Least_squares
|
||||
|
||||
</summary> */
|
||||
|
||||
public class LINREG_Series : Single_TSeries_Indicator
|
||||
{
|
||||
public readonly TSeries Intercept = new();
|
||||
public readonly TSeries RSquared = new();
|
||||
public readonly TSeries StdDev = new();
|
||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||
|
||||
public LINREG_Series(TSeries source, int period, bool useNaN = false)
|
||||
: base(source, period, useNaN)
|
||||
{
|
||||
if (this._data.Count > 0) { base.Add(this._data); }
|
||||
}
|
||||
|
||||
public override void Add((System.DateTime t, double v) TValue, bool update)
|
||||
{
|
||||
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
|
||||
else { this._buffer.Add(TValue.v); }
|
||||
if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); }
|
||||
|
||||
int _len = this._buffer.Count;
|
||||
|
||||
// get averages for period
|
||||
double sumX = 0;
|
||||
double sumY = 0;
|
||||
|
||||
for (int p = 0; p < _len; p++)
|
||||
{
|
||||
sumX += this.Count - _len + 2 + p;
|
||||
sumY += _buffer[p];
|
||||
}
|
||||
double avgX = sumX / _len;
|
||||
double avgY = sumY / _len;
|
||||
|
||||
// least squares method
|
||||
double sumSqX = 0;
|
||||
double sumSqY = 0;
|
||||
double sumSqXY = 0;
|
||||
|
||||
for (int p = 0; p < _len; p++)
|
||||
{
|
||||
double devX = this.Count - _len + 2 + p - avgX;
|
||||
double devY = _buffer[p] - avgY;
|
||||
|
||||
sumSqX += devX * devX;
|
||||
sumSqY += devY * devY;
|
||||
sumSqXY += devX * devY;
|
||||
}
|
||||
|
||||
double _slope = sumSqXY / sumSqX;
|
||||
double _intercept = avgY - (_slope * avgX);
|
||||
|
||||
// calculate Standard Deviation and R-Squared
|
||||
double stdDevX = Math.Sqrt((double)sumSqX / _len);
|
||||
double stdDevY = Math.Sqrt((double)sumSqY / _len);
|
||||
double _StdDev = stdDevY;
|
||||
|
||||
double arrr = (stdDevX * stdDevY != 0) ? (double)sumSqXY / (stdDevX * stdDevY) / _len : 0;
|
||||
double _RSquared = arrr * arrr;
|
||||
|
||||
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _slope);
|
||||
base.Add(ret, update);
|
||||
|
||||
ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _intercept);
|
||||
Intercept.Add(ret, update);
|
||||
|
||||
ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _StdDev);
|
||||
StdDev.Add(ret, update);
|
||||
|
||||
ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _RSquared);
|
||||
RSquared.Add(ret, update);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Xunit;
|
||||
using System;
|
||||
using QuanTAlib;
|
||||
|
||||
namespace Statistics;
|
||||
public class LINREG_Test
|
||||
{
|
||||
[Fact]
|
||||
public void Add_Test()
|
||||
{
|
||||
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
|
||||
LINREG_Series c = new(a, 3);
|
||||
Assert.Equal(6, c.Count);
|
||||
a.Add(5);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(0, update: true);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Edge_Test()
|
||||
{
|
||||
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
|
||||
LINREG_Series c = new(a, 3);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.NaN);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
a.Add(double.PositiveInfinity);
|
||||
Assert.Equal(a.Count, c.Count);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -161,4 +161,16 @@ public class Skender_Stock
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Alma!, 8), Math.Round(QL.Last().v, 8));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LINREG()
|
||||
{
|
||||
LINREG_Series QL = new(this.bars.Close, this.period, useNaN: false);
|
||||
var SK = this.quotes.GetSlope(this.period);
|
||||
|
||||
Assert.Equal(Math.Round((double)SK.Last().Slope!, 8), Math.Round(QL.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().Intercept!, 8), Math.Round(QL.Intercept.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().RSquared!, 8), Math.Round(QL.RSquared.Last().v, 8));
|
||||
Assert.Equal(Math.Round((double)SK.Last().StdDev!, 8), Math.Round(QL.StdDev.Last().v, 8));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user