diff --git a/QuanTAlib.sln b/QuanTAlib.sln
index e169574a..3242afe2 100644
--- a/QuanTAlib.sln
+++ b/QuanTAlib.sln
@@ -3,10 +3,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32210.308
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuanTAlib", "Source\QuanTAlib.csproj", "{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuanTAlib", "Source\QuanTAlib.csproj", "{AAE21F8A-9BC2-4647-A9EB-4DC86C569080}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Quantower", "Quantower\Quantower.csproj", "{693713F9-F33A-4B33-8F98-63794CA9734C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +23,10 @@ Global
{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{283EACC9-3AF6-4DAE-9C1C-0F7F8C8CD70D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {693713F9-F33A-4B33-8F98-63794CA9734C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {693713F9-F33A-4B33-8F98-63794CA9734C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {693713F9-F33A-4B33-8F98-63794CA9734C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {693713F9-F33A-4B33-8F98-63794CA9734C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Quantower/Indicators/ENTP_chart.cs b/Quantower/Indicators/ENTP_chart.cs
index b5a66f7d..4267974e 100644
--- a/Quantower/Indicators/ENTP_chart.cs
+++ b/Quantower/Indicators/ENTP_chart.cs
@@ -19,13 +19,13 @@ public class ENTP_chart : Indicator
private TBars bars;
///////
- private ENTP_Series indicator;
+ private ENTROPY_Series indicator;
///////
public ENTP_chart()
{
this.SeparateWindow = true;
- this.Name = "ENTP - Entropy (Unpredictability)";
+ this.Name = "ENTROPY - Entropy (Unpredictability)";
this.Description = "Entropy description";
this.AddLineSeries("ENTROPY", Color.RoyalBlue, 3, LineStyle.Solid);
}
diff --git a/Quantower/Indicators/KURT_chart.cs b/Quantower/Indicators/KURT_chart.cs
index 09cdc5e3..e2e74631 100644
--- a/Quantower/Indicators/KURT_chart.cs
+++ b/Quantower/Indicators/KURT_chart.cs
@@ -19,13 +19,13 @@ public class KURT_chart : Indicator
private TBars bars;
///////
- private KURT_Series indicator;
+ private KURTOSIS_Series indicator;
///////
public KURT_chart()
{
this.SeparateWindow = true;
- this.Name = "KURT - Kurtosis (Flatness)";
+ this.Name = "KURTOSIS - Kurtosis (Flatness)";
this.Description = "Kurtosis description";
this.AddLineSeries("KURTOSIS", Color.RoyalBlue, 3, LineStyle.Solid);
}
diff --git a/Quantower/Indicators/MED_chart.cs b/Quantower/Indicators/MED_chart.cs
index e8952bbb..d56fc9e0 100644
--- a/Quantower/Indicators/MED_chart.cs
+++ b/Quantower/Indicators/MED_chart.cs
@@ -19,7 +19,7 @@ public class MED_chart : Indicator
private TBars bars;
///////
- private MED_Series indicator;
+ private MEDIAN_Series indicator;
///////
public MED_chart()
diff --git a/Quantower/Quantower.csproj b/Quantower/Quantower.csproj
index 79e26eb8..9cc46c29 100644
--- a/Quantower/Quantower.csproj
+++ b/Quantower/Quantower.csproj
@@ -13,6 +13,7 @@
AnyCPU
disable
False
+ ..\.sonarlint\mihakralj_quantalibcsharp.ruleset
True
@@ -36,6 +37,9 @@
+
+
+
C:\Quantower\TradingPlatform\v1.124.6\bin\TradingPlatform.BusinessLayer.dll
diff --git a/Source/Basics/ADD_Series.cs b/Source/Basics/ADD_Series.cs
index 13cc8bb5..0588d216 100644
--- a/Source/Basics/ADD_Series.cs
+++ b/Source/Basics/ADD_Series.cs
@@ -23,8 +23,7 @@ public class ADD_Series : Pair_TSeries_Indicator
public override void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update)
{
- (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t,
- TValue1.v+TValue2.v);
+ (System.DateTime t, double v) result = ((TValue1.t > TValue2.t) ? TValue1.t : TValue2.t, TValue1.v+TValue2.v);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
diff --git a/Source/Basics/MAX_Series.cs b/Source/Basics/MAX_Series.cs
index 826aeb10..b8b197c3 100644
--- a/Source/Basics/MAX_Series.cs
+++ b/Source/Basics/MAX_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
MAX - Maximum value in the given period in the series.
@@ -16,18 +17,9 @@ public class MAX_Series : Single_TSeries_Indicator
public override void Add((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._p != 0) { this._buffer.RemoveAt(0); }
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _max = _buffer.Max();
- double _max = TValue.v;
- for (int i = 0; i < this._buffer.Count; i++)
- {
- _max = Math.Max(this._buffer[i], _max);
- }
-
- var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _max);
-
- base.Add(result, update);
+ base.Add((TValue.t, _max), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Basics/MIDPOINT_Series.cs b/Source/Basics/MIDPOINT_Series.cs
index 91ddac5c..9bccdebf 100644
--- a/Source/Basics/MIDPOINT_Series.cs
+++ b/Source/Basics/MIDPOINT_Series.cs
@@ -21,12 +21,7 @@ public class MIDPOINT_Series : Single_TSeries_Indicator
public override void Add((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._p != 0)
- { this._buffer.RemoveAt(0); }
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
double _max = TValue.v;
double _min = TValue.v;
@@ -37,8 +32,6 @@ public class MIDPOINT_Series : Single_TSeries_Indicator
}
double _mid = (_max + _min) * 0.5;
- var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _mid);
-
- base.Add(result, update);
+ base.Add((TValue.t, _mid), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Basics/MIDPRICE_Series.cs b/Source/Basics/MIDPRICE_Series.cs
index f49e1f1c..f7602c3a 100644
--- a/Source/Basics/MIDPRICE_Series.cs
+++ b/Source/Basics/MIDPRICE_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
MIDPRICE: Midpoint price (highhest high + lowest low)/2 in the given period in the series.
@@ -19,32 +20,13 @@ public class MIDPRICE_Series : Single_TBars_Indicator
public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
{
- if (update)
- {
- this._bufferhi[this._bufferhi.Count - 1] = TBar.h;
- this._bufferlo[this._bufferlo.Count - 1] = TBar.l;
- }
- else
- {
- this._bufferhi.Add(TBar.h);
- this._bufferlo.Add(TBar.l);
- }
- if (this._bufferhi.Count > this._p && this._p != 0)
- { this._bufferhi.RemoveAt(0); }
- if (this._bufferlo.Count > this._p && this._p != 0)
- { this._bufferlo.RemoveAt(0); }
+ Add_Replace_Trim(_bufferhi, TBar.h, _p, update);
+ Add_Replace_Trim(_bufferlo, TBar.l, _p, update);
- double _max = TBar.h;
- double _min = TBar.l;
- for (int i = 0; i < this._bufferhi.Count; i++)
- {
- _max = Math.Max(this._bufferhi[i], _max);
- _min = Math.Min(this._bufferlo[i], _min);
- }
+ double _max = _bufferhi.Max();
+ double _min = _bufferlo.Min();
double _mid = (_max + _min) * 0.5;
- var result = (TBar.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _mid);
-
- base.Add(result, update);
+ base.Add((TBar.t, _mid), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Basics/MIN_Series.cs b/Source/Basics/MIN_Series.cs
index ceea135d..2621ec75 100644
--- a/Source/Basics/MIN_Series.cs
+++ b/Source/Basics/MIN_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
MIN - Minimum value in the given period in the series.
@@ -16,18 +17,9 @@ public class MIN_Series : Single_TSeries_Indicator
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._p != 0) { this._buffer.RemoveAt(0); }
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
- double _min = TValue.v;
- for (int i = 0; i < this._buffer.Count; i++)
- {
- _min = Math.Min(this._buffer[i], _min);
- }
-
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _min);
-
- base.Add(result, update);
+ double _min = _buffer.Min();
+ base.Add((TValue.t, _min), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Basics/Abstracts.cs b/Source/Basics/Pair_TSeries_Abstract.cs
similarity index 55%
rename from Source/Basics/Abstracts.cs
rename to Source/Basics/Pair_TSeries_Abstract.cs
index ee3c91df..564a9e39 100644
--- a/Source/Basics/Abstracts.cs
+++ b/Source/Basics/Pair_TSeries_Abstract.cs
@@ -1,148 +1,112 @@
-namespace QuanTAlib;
-using System;
-/*
-Abstract classes with all scaffolding required to build indicators.
- All abstracts support period, NaN, and all permutations of Add() methods.
- Indicator classess need to implement:
- - Chaining constructor (Abstract's constructor executes first)
- - Default Add(value) class
- - optional Add(series) bulk insert class (for optimization of historical analysis)
-
- Single_TSeries_Indicator - one single-value TSeries in, one TSeries out.
- Pair_TSeries_Indicator - Two TSeries in, one TSeries out. (includes simple semaphoring)
- Single_TBars_Indicator - One OHLCV TBars in, one TSeries out.
-
- */
-public abstract class Single_TSeries_Indicator : TSeries
-{
- protected readonly int _p;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
-
- // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN)
- protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN)
- {
- this._data = source;
- this._p = period;
- this._NaN = useNaN;
- this._data.Pub += this.Sub;
- }
-
- // overridable Add() method to add/update a single item at the end of the list
- public new virtual void Add((System.DateTime t, double v) TValue, bool update) => base.Add(TValue, update);
-
- // potentially overridable Add() method for the whole series (could be replaced with faster bulk algo)
- public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { this.Add(TValue: data[i], update: false); }}
-
- public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false);
- public void Add(bool update) => this.Add(TValue: this._data[this._data.Count - 1], update: update);
- public void Add() => this.Add(TValue: this._data[this._data.Count - 1], update: false);
- public new void Sub(object source, TSeriesEventArgs e) => this.Add(TValue: this._data[this._data.Count - 1], update: e.update);
-}
-
-public abstract class Pair_TSeries_Indicator : TSeries
-{
- protected readonly int _p;
- protected readonly bool _NaN;
- protected readonly TSeries _d1;
- protected readonly TSeries _d2;
- protected readonly double _dd1, _dd2;
-
- // Chainable Constructors - add them at the end of primary constructors if needed
- protected Pair_TSeries_Indicator(TSeries source1, TSeries source2, int period, bool useNaN)
- {
- this._p = period;
- this._NaN = useNaN;
- this._d1 = source1;
- this._d2 = source2;
- this._dd1 = double.NaN;
- this._dd2 = double.NaN;
- this._d1.Pub += this.Sub;
- this._d2.Pub += this.Sub;
- }
- protected Pair_TSeries_Indicator(TSeries source1, TSeries source2)
- {
- this._d1 = source1;
- this._d2 = source2;
- this._dd1 = double.NaN;
- this._dd2 = double.NaN;
- this._d1.Pub += this.Sub;
- this._d2.Pub += this.Sub;
- }
- protected Pair_TSeries_Indicator(TSeries source1, double dd2)
- {
- this._d1 = source1;
- this._d2 = new();
- this._dd1 = double.NaN;
- this._dd2 = dd2;
- this._d1.Pub += this.Sub;
- }
- protected Pair_TSeries_Indicator(double dd1, TSeries source2)
- {
- this._d1 = new();
- this._d2 = source2;
- this._dd1 = dd1;
- this._dd2 = double.NaN;
- this._d2.Pub += this.Sub;
- }
-
- // overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list
- public virtual void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update) => base.Add(TValue: (TValue1.t, 0), update: update); // default inserts zeros
-
- // potentially overridable Add() bulk variations (could be replaced with faster bulk algos)
- public virtual void Add(TSeries d1, TSeries d2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], d2[i], update: false); }}
- public virtual void Add(TSeries d1, double dd2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], (d1[i].t, dd2), update: false); }}
- public virtual void Add(double dd1, TSeries d2) { for (int i = 0; i < d2.Count; i++) { this.Add((d2[i].t, dd1), d2[i], update: false); }}
-
- public void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2) => this.Add(TValue1, TValue2, update: false);
-
- public void Add(bool update)
- {
- if ((this._dd1 is double.NaN) && (this._dd2 is double.NaN))
- {
- // (Series, Series)
- if (update || (this._d1.Count > this.Count && this._d2.Count > this.Count))
- { this.Add(this._d1[this._d1.Count - 1], this._d2[this._d2.Count - 1], update); }
- }
- else if ((this._dd2 is not double.NaN) && (this._dd1 is double.NaN))
- {
- // (Series, Double)
- this.Add(TValue1: this._d1[this._d1.Count - 1], TValue2: (this._d1[this._d1.Count - 1].t, this._dd2), update: update);
- }
- else
- {
- // (Double, Series)
- this.Add(TValue1: (this._d2[this._d2.Count - 1].t, this._dd1), TValue2: this._d2[this._d2.Count - 1], update: update);
- }
- }
-
- public void Add() => this.Add(update: false);
- public new void Sub(object source, TSeriesEventArgs e) => this.Add(e.update);
-}
-
-public abstract class Single_TBars_Indicator : TSeries
-{
- protected readonly int _p;
- protected readonly bool _NaN;
- protected readonly TBars _bars;
-
- // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN)
- protected Single_TBars_Indicator(TBars source, int period, bool useNaN)
- {
- this._p = period;
- this._bars = source;
- this._NaN = useNaN;
- this._bars.Pub += this.Sub;
- }
-
- // overridable Add() method to add/update a single item at the end of the list
- public virtual void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar, bool update) => base.Add((TBar.t, 0.0), update);
-
- // potentially overridable Add() method for the whole bars or series (could be replaced with faster bulk algo)
- public virtual void Add(TBars bars) { for (int i = 0; i < bars.Count; i++) { this.Add(TBar: bars[i], update: false); }}
- public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { base.Add(TValue: data[i], update: false); }}
- public void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar) => this.Add(TBar: TBar, update: false);
- public void Add(bool update) => this.Add(TBar: this._bars[this._bars.Count - 1], update: update);
- public void Add() => this.Add(TBar: this._bars[this._bars.Count - 1], update: false);
- public new void Sub(object source, TSeriesEventArgs e) => this.Add(TBar: this._bars[this._bars.Count - 1], update: e.update);
-}
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+Abstract classes with all scaffolding required to build indicators.
+ All abstracts support period, NaN, and all permutations of Add() methods.
+ Indicator classess need to implement:
+ - Chaining constructor (Abstract's constructor executes first)
+ - Default Add(value) class
+ - optional Add(series) bulk insert class (for optimization of historical analysis)
+
+ Single_TSeries_Indicator - one single-value TSeries in, one TSeries out.
+ Pair_TSeries_Indicator - Two TSeries in, one TSeries out. (includes simple semaphoring)
+ Single_TBars_Indicator - One OHLCV TBars in, one TSeries out.
+
+ */
+
+
+public abstract class Pair_TSeries_Indicator : TSeries
+{
+ protected readonly int _p;
+ protected readonly bool _NaN;
+ protected readonly TSeries _d1;
+ protected readonly TSeries _d2;
+ protected readonly double _dd1, _dd2;
+
+ // Chainable Constructors - add them at the end of primary constructors if needed
+ protected Pair_TSeries_Indicator(TSeries source1, TSeries source2, int period, bool useNaN)
+ {
+ this._p = period;
+ this._NaN = useNaN;
+ this._d1 = source1;
+ this._d2 = source2;
+ this._dd1 = double.NaN;
+ this._dd2 = double.NaN;
+ this._d1.Pub += this.Sub;
+ this._d2.Pub += this.Sub;
+ }
+ protected Pair_TSeries_Indicator(TSeries source1, TSeries source2)
+ {
+ this._d1 = source1;
+ this._d2 = source2;
+ this._dd1 = double.NaN;
+ this._dd2 = double.NaN;
+ this._d1.Pub += this.Sub;
+ this._d2.Pub += this.Sub;
+ }
+ protected Pair_TSeries_Indicator(TSeries source1, double dd2)
+ {
+ this._d1 = source1;
+ this._d2 = new();
+ this._dd1 = double.NaN;
+ this._dd2 = dd2;
+ this._d1.Pub += this.Sub;
+ }
+ protected Pair_TSeries_Indicator(double dd1, TSeries source2)
+ {
+ this._d1 = new();
+ this._d2 = source2;
+ this._dd1 = dd1;
+ this._dd2 = double.NaN;
+ this._d2.Pub += this.Sub;
+ }
+
+ // overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list
+ public virtual void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update) => base.Add(TValue: (TValue1.t, 0), update: update); // default inserts zeros
+
+ // potentially overridable Add() bulk variations (could be replaced with faster bulk algos)
+ public virtual void Add(TSeries d1, TSeries d2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], d2[i], update: false); }}
+ public virtual void Add(TSeries d1, double dd2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], (d1[i].t, dd2), update: false); }}
+ public virtual void Add(double dd1, TSeries d2) { for (int i = 0; i < d2.Count; i++) { this.Add((d2[i].t, dd1), d2[i], update: false); }}
+
+ public void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2) => this.Add(TValue1, TValue2, update: false);
+
+ public void Add(bool update)
+ {
+ if ((this._dd1 is double.NaN) && (this._dd2 is double.NaN))
+ {
+ // (Series, Series)
+ if (update || (this._d1.Count > this.Count && this._d2.Count > this.Count))
+ { this.Add(this._d1[this._d1.Count - 1], this._d2[this._d2.Count - 1], update); }
+ }
+ else if ((this._dd2 is not double.NaN) && (this._dd1 is double.NaN))
+ {
+ // (Series, Double)
+ this.Add(TValue1: this._d1[this._d1.Count - 1], TValue2: (this._d1[this._d1.Count - 1].t, this._dd2), update: update);
+ }
+ else
+ {
+ // (Double, Series)
+ this.Add(TValue1: (this._d2[this._d2.Count - 1].t, this._dd1), TValue2: this._d2[this._d2.Count - 1], update: update);
+ }
+ }
+
+ public void Add() => this.Add(update: false);
+ public new void Sub(object source, TSeriesEventArgs e) => this.Add(e.update);
+
+ protected static void Add_Replace(List l, double v, bool update)
+ {
+ if (update)
+ { l[l.Count - 1] = v; }
+ else
+ { l.Add(v); }
+ }
+ protected static void Add_Replace_Trim(List l, double v, int p, bool update)
+ {
+ Add_Replace(l, v, update);
+ if (l.Count > p && p != 0)
+ { l.RemoveAt(0); }
+ }
+}
diff --git a/Source/Basics/Single_TBars_Abstract.cs b/Source/Basics/Single_TBars_Abstract.cs
new file mode 100644
index 00000000..9d24a889
--- /dev/null
+++ b/Source/Basics/Single_TBars_Abstract.cs
@@ -0,0 +1,66 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+Abstract classes with all scaffolding required to build indicators.
+ All abstracts support period, NaN, and all permutations of Add() methods.
+ Indicator classess need to implement:
+ - Chaining constructor (Abstract's constructor executes first)
+ - Default Add(value) class
+ - optional Add(series) bulk insert class (for optimization of historical analysis)
+
+ Single_TSeries_Indicator - one single-value TSeries in, one TSeries out.
+ Pair_TSeries_Indicator - Two TSeries in, one TSeries out. (includes simple semaphoring)
+ Single_TBars_Indicator - One OHLCV TBars in, one TSeries out.
+
+ */
+
+public abstract class Single_TBars_Indicator : TSeries
+{
+ protected readonly int _p;
+ protected readonly bool _NaN;
+ protected readonly TBars _bars;
+
+ // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN)
+ protected Single_TBars_Indicator(TBars source, int period, bool useNaN)
+ {
+ this._p = period;
+ this._bars = source;
+ this._NaN = useNaN;
+ this._bars.Pub += this.Sub;
+ }
+
+ // overridable Add() method to add/update a single item at the end of the list
+
+
+ public virtual void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar, bool update) => base.Add((TBar.t, 0.0), update);
+ public virtual void Add((System.DateTime t, double v) TValue, bool update, bool useNaN)
+ {
+ var res = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : TValue.v);
+ base.Add(res, update);
+ }
+
+ // potentially overridable Add() method for the whole bars or series (could be replaced with faster bulk algo)
+ public virtual void Add(TBars bars) { for (int i = 0; i < bars.Count; i++) { this.Add(TBar: bars[i], update: false); }}
+ public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { base.Add(TValue: data[i], update: false); }}
+ public void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar) => this.Add(TBar: TBar, update: false);
+ public void Add(bool update) => this.Add(TBar: this._bars[this._bars.Count - 1], update: update);
+ public void Add() => this.Add(TBar: this._bars[this._bars.Count - 1], update: false);
+ public new void Sub(object source, TSeriesEventArgs e) => this.Add(TBar: this._bars[this._bars.Count - 1], update: e.update);
+
+ protected static void Add_Replace(List l, double v, bool update)
+ {
+ if (update)
+ { l[l.Count - 1] = v; }
+ else
+ { l.Add(v); }
+ }
+ protected static void Add_Replace_Trim(List l, double v, int p, bool update)
+ {
+ Add_Replace(l, v, update);
+ if (l.Count > p && p != 0)
+ { l.RemoveAt(0); }
+ }
+
+}
diff --git a/Source/Basics/Single_TSeries_Abstract.cs b/Source/Basics/Single_TSeries_Abstract.cs
new file mode 100644
index 00000000..289cc5b9
--- /dev/null
+++ b/Source/Basics/Single_TSeries_Abstract.cs
@@ -0,0 +1,63 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+Abstract classes with all scaffolding required to build indicators.
+ All abstracts support period, NaN, and all permutations of Add() methods.
+ Indicator classess need to implement:
+ - Chaining constructor (Abstract's constructor executes first)
+ - Default Add(value) class
+ - optional Add(series) bulk insert class (for optimization of historical analysis)
+
+ Single_TSeries_Indicator - one single-value TSeries in, one TSeries out.
+ Pair_TSeries_Indicator - Two TSeries in, one TSeries out. (includes simple semaphoring)
+ Single_TBars_Indicator - One OHLCV TBars in, one TSeries out.
+
+ */
+public abstract class Single_TSeries_Indicator : TSeries
+{
+ protected readonly int _p;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN)
+ protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN)
+ {
+ this._data = source;
+ this._p = period;
+ this._NaN = useNaN;
+ this._data.Pub += this.Sub;
+ }
+
+ // overridable Add() method to add/update a single item at the end of the list
+
+ public virtual void Add((System.DateTime t, double v) TValue, bool update, bool useNaN)
+ {
+ var res = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : TValue.v);
+ base.Add(res, update);
+ }
+ public new virtual void Add((System.DateTime t, double v) TValue, bool update) => base.Add(TValue, update);
+
+ // potentially overridable Add() method for the whole series (could be replaced with faster bulk algo)
+ public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { this.Add(TValue: data[i], update: false); }}
+
+ public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false);
+ public void Add(bool update) => this.Add(TValue: this._data[this._data.Count - 1], update: update);
+ public void Add() => this.Add(TValue: this._data[this._data.Count - 1], update: false);
+ public new void Sub(object source, TSeriesEventArgs e) => this.Add(TValue: this._data[this._data.Count - 1], update: e.update);
+
+ protected static void Add_Replace(List l, double v, bool update)
+ {
+ if (update)
+ { l[l.Count - 1] = v; }
+ else
+ { l.Add(v); }
+ }
+ protected static void Add_Replace_Trim(List l, double v, int p, bool update)
+ {
+ Add_Replace(l, v, update);
+ if (l.Count > p && p!=0)
+ { l.RemoveAt(0); }
+ }
+}
diff --git a/Source/Feeds/Alphavantage_Feed.cs b/Source/Feeds/Alphavantage_Feed.cs
index 96cdafdc..d4f76fc7 100644
--- a/Source/Feeds/Alphavantage_Feed.cs
+++ b/Source/Feeds/Alphavantage_Feed.cs
@@ -17,12 +17,11 @@ public class Alphavantage_Feed : TBars
public Alphavantage_Feed(string Symbol = "IBM", string APIkey = "demo")
{
System.Net.Http.HttpClient client = new();
- JsonElement json = new();
string req = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED" + "&symbol=" + Symbol + "&apikey=" + APIkey;
var msg = client.GetStringAsync(req).Result;
var jres = JsonSerializer.Deserialize(msg).RootElement;
- jres.TryGetProperty("Time Series (Daily)", out json);
+ jres.TryGetProperty("Time Series (Daily)", out JsonElement json);
if (json.ValueKind == JsonValueKind.Undefined) {throw new InvalidOperationException("Stock symbol "+Symbol+" not found"); }
foreach (var val in json.EnumerateObject()) { base.Add(GetOHLC(val)); }
diff --git a/Source/Feeds/Yahoo_Feed.cs b/Source/Feeds/Yahoo_Feed.cs
index 5e3f7e2c..4808d888 100644
--- a/Source/Feeds/Yahoo_Feed.cs
+++ b/Source/Feeds/Yahoo_Feed.cs
@@ -9,12 +9,13 @@ Yahoo Finance - Free API feed to collect daily market quotes
Period: number of days of collected history (default: 252)
Usage:
Yahoo_Feed ticker = new("MSFT", 20)
-
+
*/
public class Yahoo_Feed : TBars
{
public Yahoo_Feed(string Symbol = "IBM", int Period = 252) {
+ Period = (int)(Period*1.45);
string requestUrl = "https://query1.finance.yahoo.com/v8/finance/chart/"+
Symbol+"?interval=1d&period1="+
(int)new DateTimeOffset(DateTime.UtcNow.AddDays(-Period+1)).ToUnixTimeSeconds()+"&period2="+
@@ -22,7 +23,7 @@ public class Yahoo_Feed : TBars
System.Net.Http.HttpClient client = new();
var msg = client.GetStringAsync(requestUrl).Result;
var jresult = JsonSerializer.Deserialize(msg).RootElement;
-
+
jresult.TryGetProperty("chart",out JsonElement json);
json.TryGetProperty("result",out json);
json[0].TryGetProperty("timestamp",out JsonElement datetime);
@@ -33,7 +34,7 @@ public class Yahoo_Feed : TBars
json[0].TryGetProperty("low",out JsonElement low);
json[0].TryGetProperty("close",out JsonElement close);
json[0].TryGetProperty("volume",out JsonElement volume);
-
+
for (int i=0; i
CCI: Commodity Channel Index
@@ -32,18 +34,16 @@ public class CCI_Series : Single_TBars_Indicator
if (this._tp.Count > this._p) { this._tp.RemoveAt(0); }
// average TP over _tp buffer
- double _avgTp = 0;
- for (int i = 0; i < this._tp.Count; i++) { _avgTp+=this._tp[i]; }
- _avgTp /= this._tp.Count;
+ double _avgTp = _tp.Average();
// average Deviation over _tp buffer
double _avgDv = 0;
for (int i = 0; i < this._tp.Count; i++) { _avgDv += Math.Abs(_avgTp - this._tp[i]); }
_avgDv /= this._tp.Count;
+
double _cci = (_avgDv == 0) ? double.NaN : (this._tp[this._tp.Count-1] - _avgTp) / (0.015 * _avgDv);
- var result = (TBar.t, (this.Count < this._p && this._NaN) ? double.NaN : _cci);
- base.Add(result, update);
- }
+ base.Add((TBar.t, _cci), update, _NaN);
+ }
}
\ No newline at end of file
diff --git a/Source/QuanTAlib.csproj b/Source/QuanTAlib.csproj
index 10887e79..3a18b409 100644
--- a/Source/QuanTAlib.csproj
+++ b/Source/QuanTAlib.csproj
@@ -2,7 +2,7 @@
QuanTAlib
- 0.1.20
+ 0.1.21
Library of Technical Indicators for .NET
Quantitative Technical Analysis library for both real-time (streaming) and historical data analysis
git
diff --git a/Source/Statistics/BIAS_Series.cs b/Source/Statistics/BIAS_Series.cs
index 3fb543b7..7440a5f3 100644
--- a/Source/Statistics/BIAS_Series.cs
+++ b/Source/Statistics/BIAS_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
BIAS: Rate of change between the source and a moving average.
@@ -23,17 +24,11 @@ public class BIAS_Series : Single_TSeries_Indicator
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._p != 0) { this._buffer.RemoveAt(0); }
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
- double _sma = 0;
- for (int i = 0; i < this._buffer.Count; i++) { _sma += this._buffer[i]; }
- _sma /= this._buffer.Count;
- double _bias = (this._buffer[this._buffer.Count - 1] / ((_sma != 0) ? _sma : 1)) - 1;
+ double _sma = _buffer.Average();
+ double _bias = (_buffer[_buffer.Count - 1] / ((_sma != 0) ? _sma : 1)) - 1;
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _bias);
-
- base.Add(result, update);
+ base.Add((TValue.t, _bias), update, _NaN);
}
}
diff --git a/Source/Statistics/CORR_Series.cs b/Source/Statistics/CORR_Series.cs
index 8d13ab73..f82d82de 100644
--- a/Source/Statistics/CORR_Series.cs
+++ b/Source/Statistics/CORR_Series.cs
@@ -1,5 +1,7 @@
namespace QuanTAlib;
using System;
+using System.Collections.Generic;
+using System.Linq;
/*
CORR: Pearson's Correlation Coefficient
@@ -14,57 +16,37 @@ Sources:
*/
public class CORR_Series : Pair_TSeries_Indicator
-{
- public CORR_Series(TSeries d1, TSeries d2, int period, bool useNaN = false) : base(d1, d2, period, useNaN)
- {
- if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
- }
-
- private readonly System.Collections.Generic.List _x = new();
- private readonly System.Collections.Generic.List _xx = new();
- private readonly System.Collections.Generic.List _y = new();
- private readonly System.Collections.Generic.List _yy = new();
- private readonly System.Collections.Generic.List _xy = new();
-
- public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
- {
- if (update)
- {
- _x[_x.Count - 1] = TValue1.v;
- _xx[_xx.Count - 1] = TValue1.v * TValue1.v;
- _y[_y.Count - 1] = TValue2.v;
- _y[_yy.Count - 1] = TValue2.v * TValue2.v;
- _xy[_xy.Count - 1] = TValue1.v * TValue2.v;
- }
- else
- {
- _x.Add(TValue1.v);
- _xx.Add(TValue1.v * TValue1.v);
- _y.Add(TValue2.v);
- _yy.Add(TValue2.v * TValue2.v);
- _xy.Add(TValue1.v * TValue2.v);
- }
- if (_x.Count > this._p) { _x.RemoveAt(0); }
- if (_xx.Count > this._p) { _xx.RemoveAt(0); }
- if (_y.Count > this._p) { _y.RemoveAt(0); }
- if (_yy.Count > this._p) { _yy.RemoveAt(0); }
- if (_xy.Count > this._p) { _xy.RemoveAt(0); }
-
- double _sumx = 0;
- for (int i = 0; i < _x.Count; i++) { _sumx += _x[i]; }
- double _sumxx = 0;
- for (int i = 0; i < _xx.Count; i++) { _sumxx += _xx[i]; }
- double _sumy = 0;
- for (int i = 0; i < _y.Count; i++) { _sumy += _y[i]; }
- double _sumyy = 0;
- for (int i = 0; i < _yy.Count; i++) { _sumyy += _yy[i]; }
- double _sumxy = 0;
- for (int i = 0; i < _xy.Count; i++) { _sumxy += _xy[i]; }
-
- double _div = (_sumxx - _sumx * _sumx / _p) * (_sumyy - _sumy * _sumy / _p);
- double _cor = (_div != 0) ? (_sumxy - _sumx * _sumy / _p) / Math.Sqrt(_div) : 0.0;
-
- var result = (TValue1.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _cor);
- if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
+{
+ public CORR_Series(TSeries d1, TSeries d2, int period, bool useNaN = false) : base(d1, d2, period, useNaN)
+ {
+ if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
}
-}
\ No newline at end of file
+
+ private readonly System.Collections.Generic.List _x = new();
+ private readonly System.Collections.Generic.List _xx = new();
+ private readonly System.Collections.Generic.List _y = new();
+ private readonly System.Collections.Generic.List _yy = new();
+ private readonly System.Collections.Generic.List _xy = new();
+
+ public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
+ {
+ Add_Replace_Trim(_x, TValue1.v, _p, update);
+ Add_Replace_Trim(_xx, TValue1.v * TValue1.v, _p, update);
+ Add_Replace_Trim(_y, TValue2.v, _p, update);
+ Add_Replace_Trim(_yy, TValue2.v * TValue2.v, _p, update);
+ Add_Replace_Trim(_xy, TValue1.v * TValue2.v, _p, update);
+
+ double _sumx = _x.Sum();
+ double _sumxx = _xx.Sum();
+ double _sumy = _y.Sum();
+ double _sumyy = _yy.Sum();
+ double _sumxy = _xy.Sum();
+
+ double _covar = (_sumxx - _sumx * _sumx / _p) * (_sumyy - _sumy * _sumy / _p);
+ double _cor = (_covar != 0) ? (_sumxy - _sumx * _sumy / _p) / Math.Sqrt(_covar) : 0.0;
+
+ var result = (TValue1.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _cor);
+ if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
+
+ }
+}
diff --git a/Source/Statistics/COVAR_Series.cs b/Source/Statistics/COVAR_Series.cs
index 06c3463d..8fd20b47 100644
--- a/Source/Statistics/COVAR_Series.cs
+++ b/Source/Statistics/COVAR_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
COVAR: Covariance
@@ -19,49 +20,21 @@ public class COVAR_Series : Pair_TSeries_Indicator
}
private readonly System.Collections.Generic.List _x = new();
- private readonly System.Collections.Generic.List _xx = new();
private readonly System.Collections.Generic.List _y = new();
- private readonly System.Collections.Generic.List _yy = new();
private readonly System.Collections.Generic.List _xy = new();
public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
{
- if (update)
- {
- _x[_x.Count - 1] = TValue1.v;
- _xx[_xx.Count - 1] = TValue1.v * TValue1.v;
- _y[_y.Count - 1] = TValue2.v;
- _y[_yy.Count - 1] = TValue2.v * TValue2.v;
- _xy[_xy.Count - 1] = TValue1.v * TValue2.v;
- }
- else
- {
- _x.Add(TValue1.v);
- _xx.Add(TValue1.v * TValue1.v);
- _y.Add(TValue2.v);
- _yy.Add(TValue2.v * TValue2.v);
- _xy.Add(TValue1.v * TValue2.v);
- }
- if (_x.Count > this._p) { _x.RemoveAt(0); }
- if (_xx.Count > this._p) { _xx.RemoveAt(0); }
- if (_y.Count > this._p) { _y.RemoveAt(0); }
- if (_yy.Count > this._p) { _yy.RemoveAt(0); }
- if (_xy.Count > this._p) { _xy.RemoveAt(0); }
+ Add_Replace_Trim(_x, TValue1.v, _p, update);
+ Add_Replace_Trim(_y, TValue2.v, _p, update);
+ Add_Replace_Trim(_xy, TValue1.v * TValue2.v, _p, update);
- double _sumx = 0;
- for (int i = 0; i < _x.Count; i++) { _sumx += _x[i]; }
- double _sumxx = 0;
- for (int i = 0; i < _xx.Count; i++) { _sumxx += _xx[i]; }
- double _sumy = 0;
- for (int i = 0; i < _y.Count; i++) { _sumy += _y[i]; }
- double _sumyy = 0;
- for (int i = 0; i < _yy.Count; i++) { _sumyy += _yy[i]; }
- double _sumxy = 0;
- for (int i = 0; i < _xy.Count; i++) { _sumxy += _xy[i]; }
-
- double _covar = (_sumxy / _p) - ((_sumx / _p) * (_sumy / _p));
+ double _avgx = _x.Average();
+ double _avgy = _y.Average();
+ double _avgxy = _xy.Average();
+ double _covar = _avgxy - (_avgx * _avgy);
var result = (TValue1.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _covar);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
- }
+ }
}
\ No newline at end of file
diff --git a/Source/Statistics/ENTP_Series.cs b/Source/Statistics/ENTROPY_Series.cs
similarity index 52%
rename from Source/Statistics/ENTP_Series.cs
rename to Source/Statistics/ENTROPY_Series.cs
index a75af82f..f27ea6c7 100644
--- a/Source/Statistics/ENTP_Series.cs
+++ b/Source/Statistics/ENTROPY_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
ENTP: Entropy
@@ -16,9 +17,9 @@ Sources:
*/
-public class ENTP_Series : Single_TSeries_Indicator
+public class ENTROPY_Series : Single_TSeries_Indicator
{
- public ENTP_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN)
+ public ENTROPY_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN)
{
this._logbase = logbase;
if (base._data.Count > 0) { base.Add(base._data); }
@@ -29,24 +30,15 @@ public class ENTP_Series : Single_TSeries_Indicator
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._p != 0) { this._buffer.RemoveAt(0); }
-
- double _sum = 0;
- for (int i = 0; i < this._buffer.Count; i++) { _sum += this._buffer[i]; }
-
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sum = _buffer.Sum();
+
double _pp = this._buffer[this._buffer.Count - 1] / _sum;
double _ppp = -_pp * Math.Log(_pp) / Math.Log(this._logbase);
- if (update) { this._buff2[this._buff2.Count - 1] = _ppp; }
- else { this._buff2.Add(_ppp); }
- if (this._buff2.Count > this._p && this._p != 0) { this._buff2.RemoveAt(0); }
+ Add_Replace_Trim(_buff2, _ppp, _p, update);
+ double _entp = _buff2.Sum();
- double _entp = 0;
- for (int i = 0; i < this._buff2.Count; i++) { _entp += this._buff2[i]; }
-
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _entp);
- base.Add(result, update);
+ base.Add((TValue.t, _entp), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Statistics/KURT_Series.cs b/Source/Statistics/KURTOSIS_Series.cs
similarity index 69%
rename from Source/Statistics/KURT_Series.cs
rename to Source/Statistics/KURTOSIS_Series.cs
index 10b1242f..ae1c93b2 100644
--- a/Source/Statistics/KURT_Series.cs
+++ b/Source/Statistics/KURTOSIS_Series.cs
@@ -1,62 +1,57 @@
-namespace QuanTAlib;
-using System;
-
-/*
-KURT: Kurtosis of population
- Kurtosis characterizes the relative peakedness or flatness of a distribution
- compared with the normal distribution. Positive kurtosis indicates a relatively
- peaked distribution. Negative kurtosis indicates a relatively flat distribution.
-
- The normal curve is called Mesokurtic curve. If the curve of a distribution is
- more outlier prone (or heavier-tailed) than a normal or mesokurtic curve then
- it is referred to as a Leptokurtic curve. If a curve is less outlier prone (or
- lighter-tailed) than a normal curve, it is called as a platykurtic curve.
-
-Calculation:
- sum4 = Σ(close-SMA)^4
- sum2 = (Σ(close-SMA)^2)^2
- KURT = length * (sum4/sum2)
-
-Sources:
- https://en.wikipedia.org/wiki/Kurtosis
- https://stats.oarc.ucla.edu/other/mult-pkg/faq/general/faq-whats-with-the-different-formulas-for-kurtosis/
-
- */
-
-public class KURT_Series : Single_TSeries_Indicator
-{
- public KURT_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN)
- {
- this._logbase = logbase;
- if (base._data.Count > 0) { base.Add(base._data); }
- }
- protected double _logbase;
- private readonly System.Collections.Generic.List _buffer = new();
-
- 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._p != 0) { this._buffer.RemoveAt(0); }
-
- double _n = this._buffer.Count;
-
- double _avg = 0;
- for (int i = 0; i < this._buffer.Count; i++) { _avg += this._buffer[i]; }
- _avg /= _n;
-
- double _s2 = 0;
- double _s4 = 0;
- for (int i = 0; i < this._buffer.Count; i++)
- {
- _s2 += (this._buffer[i] - _avg) * (this._buffer[i] - _avg);
- _s4 += (this._buffer[i] - _avg) * (this._buffer[i] - _avg) * (this._buffer[i] - _avg) * (this._buffer[i] - _avg);
- }
-
- double _Vx = _s2 / (_n - 1);
- double _kurt = (_n > 3) ? ((((_n * (_n + 1)) / (((_n - 1) * (_n - 2)) * (_n - 3))) * (_s4 / (_Vx * _Vx))) - (3 * (((_n - 1) * (_n - 1)) / ((_n - 2) * (_n - 3))))) : Double.NaN;
-
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? Double.NaN : _kurt);
- base.Add(result, update);
- }
+namespace QuanTAlib;
+using System;
+using System.Linq;
+
+/*
+KURT: Kurtosis of population
+ Kurtosis characterizes the relative peakedness or flatness of a distribution
+ compared with the normal distribution. Positive kurtosis indicates a relatively
+ peaked distribution. Negative kurtosis indicates a relatively flat distribution.
+
+ The normal curve is called Mesokurtic curve. If the curve of a distribution is
+ more outlier prone (or heavier-tailed) than a normal or mesokurtic curve then
+ it is referred to as a Leptokurtic curve. If a curve is less outlier prone (or
+ lighter-tailed) than a normal curve, it is called as a platykurtic curve.
+
+Calculation:
+ sum4 = Σ(close-SMA)^4
+ sum2 = (Σ(close-SMA)^2)^2
+ KURT = length * (sum4/sum2)
+
+Sources:
+ https://en.wikipedia.org/wiki/Kurtosis
+ https://stats.oarc.ucla.edu/other/mult-pkg/faq/general/faq-whats-with-the-different-formulas-for-kurtosis/
+
+ */
+
+public class KURTOSIS_Series : Single_TSeries_Indicator
+{
+ public KURTOSIS_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN)
+ {
+ this._logbase = logbase;
+ if (base._data.Count > 0) { base.Add(base._data); }
+ }
+ protected double _logbase;
+ private readonly System.Collections.Generic.List _buffer = new();
+
+ public override void Add((System.DateTime t, double v) TValue, bool update)
+ {
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _n = this._buffer.Count;
+ double _avg = _buffer.Average();
+
+ double _s2 = 0;
+ double _s4 = 0;
+ for (int i = 0; i < this._buffer.Count; i++)
+ {
+ _s2 += (_buffer[i] - _avg) * (_buffer[i] - _avg);
+ _s4 += (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg);
+ }
+
+ double _Vx = _s2 / (_n - 1);
+ double _kurt = (_n > 3) ? ((((_n * (_n + 1)) / (((_n - 1) * (_n - 2)) * (_n - 3))) * (_s4 / (_Vx * _Vx))) - (3 * (((_n - 1) * (_n - 1)) / ((_n - 2) * (_n - 3))))) : Double.NaN;
+
+ var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? Double.NaN : _kurt);
+ base.Add(result, update);
+ }
}
\ No newline at end of file
diff --git a/Source/Statistics/LINREG_Series.cs b/Source/Statistics/LINREG_Series.cs
index 44e1bb2c..0987555c 100644
--- a/Source/Statistics/LINREG_Series.cs
+++ b/Source/Statistics/LINREG_Series.cs
@@ -34,9 +34,7 @@ public class LINREG_Series : Single_TSeries_Indicator
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); }
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
int _len = this._buffer.Count;
@@ -79,7 +77,7 @@ public class LINREG_Series : Single_TSeries_Indicator
double _RSquared = arrr * arrr;
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _slope);
- base.Add(ret, update);
+ base.Add(ret, update, _NaN);
ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _intercept);
Intercept.Add(ret, update);
diff --git a/Source/Statistics/MAD_Series.cs b/Source/Statistics/MAD_Series.cs
index 0c76fdaf..8a032e4a 100644
--- a/Source/Statistics/MAD_Series.cs
+++ b/Source/Statistics/MAD_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
MAD: Mean Absolute Deviation
@@ -24,19 +25,14 @@ public class MAD_Series : Single_TSeries_Indicator
public override void Add((System.DateTime t, double v) TValue, bool update)
{
- if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
- else { _buffer.Add(TValue.v); }
- if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
- double _sma = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
- _sma /= this._buffer.Count;
+ double _sma = _buffer.Average();
double _mad = 0;
for (int i = 0; i < _buffer.Count; i++) { _mad += Math.Abs(_buffer[i] - _sma); }
_mad /= this._buffer.Count;
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _mad);
- base.Add(result, update);
+ base.Add((TValue.t, _mad), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Statistics/MAPE_Series.cs b/Source/Statistics/MAPE_Series.cs
index 7b112aae..ca737cf1 100644
--- a/Source/Statistics/MAPE_Series.cs
+++ b/Source/Statistics/MAPE_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
MAPE: Mean Absolute Percentage Error
@@ -27,19 +28,15 @@ public class MAPE_Series : Single_TSeries_Indicator
public override void Add((System.DateTime t, double v) TValue, bool update)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else { _buffer.Add(TValue.v); }
- if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
-
- double _sma = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
- _sma /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Average();
double _mape = 0;
- for (int i = 0; i < _buffer.Count; i++) { _mape += (_buffer[i] != 0) ? Math.Abs(_buffer[i] - _sma) / Math.Abs(_buffer[i]) : double.PositiveInfinity; }
- _mape /= this._buffer.Count;
+ for (int i = 0; i < _buffer.Count; i++) {
+ _mape += (_buffer[i] != 0) ? Math.Abs(_buffer[i] - _sma) / Math.Abs(_buffer[i]) : double.PositiveInfinity;
+ }
+ _mape /= (_buffer.Count>0) ? _buffer.Count : 1;
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _mape);
- base.Add(result, update);
+ base.Add((TValue.t, _mape), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Statistics/MED_Series.cs b/Source/Statistics/MEDIAN_Series.cs
similarity index 70%
rename from Source/Statistics/MED_Series.cs
rename to Source/Statistics/MEDIAN_Series.cs
index bf5e6586..0bbd6948 100644
--- a/Source/Statistics/MED_Series.cs
+++ b/Source/Statistics/MEDIAN_Series.cs
@@ -1,47 +1,44 @@
-namespace QuanTAlib;
-using System;
-
-/*
-MED - Median value
- Median of numbers is the middlemost value of the given set of numbers.
- It separates the higher half and the lower half of a given data sample.
- At least half of the observations are smaller than or equal to median
- and at least half of the observations are greater than or equal to the median.
-
- If the number of values is odd, the middlemost observation of the sorted
- list is the median of the given data. If the number of values is even,
- median is the average of (n/2)th and [(n/2) + 1]th values of the sorted list.
-
- If period = 0 => period is max
-
-Sources:
- https://corporatefinanceinstitute.com/resources/knowledge/other/median/
- https://en.wikipedia.org/wiki/Median
-
- */
-
-public class MED_Series : Single_TSeries_Indicator
-{
- public MED_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
- {
- if (base._data.Count > 0) { base.Add(base._data); }
- }
- private readonly System.Collections.Generic.List _buffer = new();
-
- 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._p != 0) { this._buffer.RemoveAt(0); }
-
- System.Collections.Generic.List _s = new(this._buffer);
- _s.Sort();
- int _p1 = _s.Count / 2;
- int _p2 = Math.Max(0, (_s.Count / 2) - 1);
- double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2;
-
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _med);
-
- base.Add(result, update);
- }
-}
+namespace QuanTAlib;
+using System;
+using static System.Net.Mime.MediaTypeNames;
+
+/*
+MED - Median value
+ Median of numbers is the middlemost value of the given set of numbers.
+ It separates the higher half and the lower half of a given data sample.
+ At least half of the observations are smaller than or equal to median
+ and at least half of the observations are greater than or equal to the median.
+
+ If the number of values is odd, the middlemost observation of the sorted
+ list is the median of the given data. If the number of values is even,
+ median is the average of (n/2)th and [(n/2) + 1]th values of the sorted list.
+
+ If period = 0 => period is max
+
+Sources:
+ https://corporatefinanceinstitute.com/resources/knowledge/other/median/
+ https://en.wikipedia.org/wiki/Median
+
+ */
+
+public class MEDIAN_Series : Single_TSeries_Indicator
+{
+ public MEDIAN_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
+ {
+ if (base._data.Count > 0) { base.Add(base._data); }
+ }
+ private readonly System.Collections.Generic.List _buffer = new();
+
+ public override void Add((System.DateTime t, double v) TValue, bool update)
+ {
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+
+ System.Collections.Generic.List _s = new(this._buffer);
+ _s.Sort();
+ int _p1 = _s.Count / 2;
+ int _p2 = Math.Max(0, (_s.Count / 2) - 1);
+ double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2;
+
+ base.Add((TValue.t, _med), update, _NaN);
+ }
+}
diff --git a/Source/Statistics/MSE_Series.cs b/Source/Statistics/MSE_Series.cs
index 896dd8b9..1dcdd6a9 100644
--- a/Source/Statistics/MSE_Series.cs
+++ b/Source/Statistics/MSE_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
MSE: Mean Square Error
@@ -20,19 +21,13 @@ public class MSE_Series : Single_TSeries_Indicator
public override void Add((System.DateTime t, double v) TValue, bool update)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else { _buffer.Add(TValue.v); }
- if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
-
- double _sma = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
- _sma /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Average();
double _mse = 0;
for (int i = 0; i < _buffer.Count; i++) { _mse += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
_mse /= this._buffer.Count;
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _mse);
- base.Add(result, update);
+ base.Add((TValue.t, _mse), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Statistics/SDEV_Series.cs b/Source/Statistics/SDEV_Series.cs
index 0a0675e6..88f6ed8f 100644
--- a/Source/Statistics/SDEV_Series.cs
+++ b/Source/Statistics/SDEV_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
SDEV: Population Standard Deviation
@@ -25,20 +26,14 @@ public class SDEV_Series : Single_TSeries_Indicator
public override void Add((System.DateTime t, double v) TValue, bool update)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else { _buffer.Add(TValue.v); }
- if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
-
- double _sma = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
- _sma /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Average();
double _pvar = 0;
for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
_pvar /= this._buffer.Count;
double _psdev = Math.Sqrt(_pvar);
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _psdev);
- base.Add(result, update);
+ base.Add((TValue.t, _psdev), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Statistics/SMAPE_Series.cs b/Source/Statistics/SMAPE_Series.cs
index de371fbc..dc0eaaa5 100644
--- a/Source/Statistics/SMAPE_Series.cs
+++ b/Source/Statistics/SMAPE_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
SMAPE: Symmetric Mean Absolute Percentage Error
@@ -20,19 +21,13 @@ public class SMAPE_Series : Single_TSeries_Indicator
public override void Add((System.DateTime t, double v) TValue, bool update)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else { _buffer.Add(TValue.v); }
- if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
-
- double _sma = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
- _sma /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Average();
double _smape = 0;
for (int i = 0; i < _buffer.Count; i++) { _smape += Math.Abs(_buffer[i] - _sma) / (Math.Abs(_buffer[i]) + Math.Abs(_sma)); }
_smape /= this._buffer.Count;
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _smape);
- base.Add(result, update);
+ base.Add((TValue.t, _smape), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Statistics/SSDEV_Series.cs b/Source/Statistics/SSDEV_Series.cs
index 376ffa79..ab882476 100644
--- a/Source/Statistics/SSDEV_Series.cs
+++ b/Source/Statistics/SSDEV_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
SSDEV: (Corrected) Sample Standard Deviation
@@ -25,20 +26,14 @@ public class SSDEV_Series : Single_TSeries_Indicator
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._p != 0) { this._buffer.RemoveAt(0); }
-
- double _sma = 0;
- for (int i = 0; i < this._buffer.Count; i++) { _sma += this._buffer[i]; }
- _sma /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Average();
double _svar = 0;
- for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); }
- _svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction
+ for (int i = 0; i < this._buffer.Count; i++) { _svar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
+ _svar /= (_buffer.Count > 1) ? _buffer.Count - 1 : 1; // Bessel's correction
double _ssdev = Math.Sqrt(_svar);
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _ssdev);
- base.Add(result, update);
+ base.Add((TValue.t, _ssdev), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Statistics/SVAR_Series.cs b/Source/Statistics/SVAR_Series.cs
index 56f6d733..5f569081 100644
--- a/Source/Statistics/SVAR_Series.cs
+++ b/Source/Statistics/SVAR_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
SVAR: Sample Variance
@@ -25,19 +26,13 @@ public class SVAR_Series : Single_TSeries_Indicator
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._p != 0) { this._buffer.RemoveAt(0); }
-
- double _sma = 0;
- for (int i = 0; i < this._buffer.Count; i++) { _sma += this._buffer[i]; }
- _sma /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Average();
double _svar = 0;
for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); }
_svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _svar);
- base.Add(result, update);
+ base.Add((TValue.t, _svar), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Statistics/VAR_Series.cs b/Source/Statistics/VAR_Series.cs
index 9c3b3e63..2aebee3b 100644
--- a/Source/Statistics/VAR_Series.cs
+++ b/Source/Statistics/VAR_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
VAR: Population Variance
@@ -25,19 +26,13 @@ public class VAR_Series : Single_TSeries_Indicator
public override void Add((System.DateTime t, double v) TValue, bool update)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else { _buffer.Add(TValue.v); }
- if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
-
- double _sma = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
- _sma /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Average();
double _pvar = 0;
for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
_pvar /= this._buffer.Count;
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _pvar);
- base.Add(result, update);
+ base.Add((TValue.t, _pvar), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Statistics/WMAPE_Series.cs b/Source/Statistics/WMAPE_Series.cs
index 0d770358..ff2a112a 100644
--- a/Source/Statistics/WMAPE_Series.cs
+++ b/Source/Statistics/WMAPE_Series.cs
@@ -1,9 +1,12 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
WMAPE: Weighted Mean Absolute Percentage Error
- Measures the size of the error in percentage terms
+ Measures the size of the error in percentage terms. Improves problems with MAPE
+ when there are zero or close-to-zero values because there would be a division by zero
+ or values of MAPE tending to infinity.
Sources:
https://en.wikipedia.org/wiki/WMAPE
@@ -20,13 +23,8 @@ public class WMAPE_Series : Single_TSeries_Indicator
public override void Add((System.DateTime t, double v) TValue, bool update)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else { _buffer.Add(TValue.v); }
- if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
-
- double _sma = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
- _sma /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Average();
double _div = 0;
double _wmape = 0;
@@ -35,9 +33,8 @@ public class WMAPE_Series : Single_TSeries_Indicator
_wmape += Math.Abs(_buffer[i] - _sma);
_div += Math.Abs(_buffer[i]);
}
- _wmape /= _div;
+ _wmape = (_div!=0) ? _wmape/_div : double.PositiveInfinity;
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _wmape);
- base.Add(result, update);
+ base.Add((TValue.t, _wmape), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Statistics/ZSCORE_Series.cs b/Source/Statistics/ZSCORE_Series.cs
index 73034315..097482d9 100644
--- a/Source/Statistics/ZSCORE_Series.cs
+++ b/Source/Statistics/ZSCORE_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
ZSCORE: number of standard deviations from SMA
@@ -31,13 +32,8 @@ public class ZSCORE_Series : Single_TSeries_Indicator
public override void Add((System.DateTime t, double v) TValue, bool update)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else { _buffer.Add(TValue.v); }
- if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
-
- double _sma = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
- _sma /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Average();
double _pvar = 0;
for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); }
@@ -45,7 +41,6 @@ public class ZSCORE_Series : Single_TSeries_Indicator
double _psdev = Math.Sqrt(_pvar);
double _zscore = (_psdev == 0) ? double.NaN : (TValue.v - _sma) / _psdev;
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _zscore);
- base.Add(result, update);
+ base.Add((TValue.t, _zscore), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Trends/ALMA_Series.cs b/Source/Trends/ALMA_Series.cs
index 122cc2d4..39ff8101 100644
--- a/Source/Trends/ALMA_Series.cs
+++ b/Source/Trends/ALMA_Series.cs
@@ -19,49 +19,45 @@ TODO: Discrepancy with Pandas-TA (but passes the validation with Skender.GetAlma
*/
public class ALMA_Series : Single_TSeries_Indicator
-{
- private readonly System.Collections.Generic.List _buffer = new();
- private readonly double[] _weight;
- private double _norm;
- private readonly double _offset, _sigma;
-
- public ALMA_Series(TSeries source, int period, double offset = 0.85, double sigma = 6.0, bool useNaN = false)
- : base(source, period, useNaN)
- {
- _offset = offset;
- _sigma = sigma;
- _weight = new double[period];
-
- 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); }
-
- if (this._buffer.Count <= _p) { calc_weights(); }
-
- double _weightedSum = 0;
- for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; }
- double _alma = _weightedSum / _norm;
-
- var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _alma);
- base.Add(ret, update);
- }
-
- private void calc_weights()
- {
- int _len = this._buffer.Count;
- _norm = 0;
- double _m = _offset * (_len - 1);
- double _s = _len / _sigma;
- for (int i = 0; i < _len; i++)
- {
- double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
- _weight[i] = _wt;
- _norm += _wt;
- }
- }
+{
+ private readonly System.Collections.Generic.List _buffer = new();
+ private readonly double[] _weight;
+ private double _norm;
+ private readonly double _offset, _sigma;
+
+ public ALMA_Series(TSeries source, int period, double offset = 0.85, double sigma = 6.0, bool useNaN = false)
+ : base(source, period, useNaN)
+ {
+ _offset = offset;
+ _sigma = sigma;
+ _weight = new double[period];
+
+ if (this._data.Count > 0) { base.Add(this._data); }
+ }
+
+ public override void Add((System.DateTime t, double v) TValue, bool update)
+ {
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+
+ if (this._buffer.Count <= _p)
+ {
+ int _len = this._buffer.Count;
+ _norm = 0;
+ double _m = _offset * (_len - 1);
+ double _s = _len / _sigma;
+ for (int i = 0; i < _len; i++)
+ {
+ double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
+ _weight[i] = _wt;
+ _norm += _wt;
+ }
+ }
+
+ double _weightedSum = 0;
+ for (int i = 0; i < this._buffer.Count; i++)
+ { _weightedSum += _weight[i] * _buffer[i]; }
+ double _alma = _weightedSum / _norm;
+
+ base.Add((TValue.t, _alma), update, _NaN);
+ }
}
diff --git a/Source/Trends/DEMA_Series.cs b/Source/Trends/DEMA_Series.cs
index 5832b8eb..8a7d8e92 100644
--- a/Source/Trends/DEMA_Series.cs
+++ b/Source/Trends/DEMA_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
DEMA: Double Exponential Moving Average
@@ -41,16 +42,9 @@ public class DEMA_Series : Single_TSeries_Indicator
if (this.Count < this._p)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else
- {
- _buffer.Add(TValue.v);
- }
- if (_buffer.Count > this._p) { _buffer.RemoveAt(0); }
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Average();
- double _sma = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
- _sma /= this._buffer.Count;
_ema1 = _ema2 = _sma;
}
else
@@ -65,7 +59,6 @@ public class DEMA_Series : Single_TSeries_Indicator
this._lastema1 = _ema1;
this._lastema2 = _ema2;
- var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _dema);
- base.Add(ret, update);
+ base.Add((TValue.t, _dema), update, _NaN);
}
}
diff --git a/Source/Trends/EMA_Series.cs b/Source/Trends/EMA_Series.cs
index b3be32e4..aae20c2a 100644
--- a/Source/Trends/EMA_Series.cs
+++ b/Source/Trends/EMA_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
EMA: Exponential Moving Average
@@ -35,20 +36,13 @@ public class EMA_Series : Single_TSeries_Indicator
public override void Add((DateTime t, double v) TValue, bool update)
{
- double _ema = 0;
+ double _ema;
if (update) { this._lastema = this._lastlastema; }
if (this.Count < this._p)
{
- 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); }
-
- for (int i = 0; i < this._buffer.Count; i++) { _ema += this._buffer[i]; }
- _ema /= this._buffer.Count;
+ Add_Replace(_buffer, TValue.v, update);
+ _ema = _buffer.Average();
}
else
{
@@ -58,7 +52,6 @@ public class EMA_Series : Single_TSeries_Indicator
this._lastlastema = this._lastema;
this._lastema = _ema;
- var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema);
- base.Add(ret, update);
+ base.Add((TValue.t, _ema), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Trends/HEMA_Series.cs b/Source/Trends/HEMA_Series.cs
index 0ec45cf7..3f1678f5 100644
--- a/Source/Trends/HEMA_Series.cs
+++ b/Source/Trends/HEMA_Series.cs
@@ -2,8 +2,8 @@
using System;
/*
-HEMA: Hull-EMA Moving Average
- Modified HUll Moving Average; instead of using WMA (Weighted MA) for acalculation,
+HEMA: Hull-EMA Moving Average - a hybrid indicator
+ Modified HUll Moving Average; instead of using WMA (Weighted MA) for calculation,
HEMA uses EMA for Hull's formula:
EMA1 = EMA(n/2) of price - where k = 4/(n/2 +1)
@@ -39,17 +39,11 @@ public class HEMA_Series : Single_TSeries_Indicator
this._lastema2 = this._lastlastema2;
this._lastema3 = this._lastlastema3;
}
- double _ema1 = System.Double.IsNaN(this._lastema1)
- ? TValue.v
- : TValue.v * this._k1 + this._lastema1 * (1 - this._k1);
- double _ema2 = System.Double.IsNaN(this._lastema2)
- ? TValue.v
- : TValue.v * this._k2 + this._lastema2 * (1 - this._k2);
+ double _ema1 = System.Double.IsNaN(this._lastema1) ? TValue.v : TValue.v * this._k1 + this._lastema1 * (1 - this._k1);
+ double _ema2 = System.Double.IsNaN(this._lastema2) ? TValue.v : TValue.v * this._k2 + this._lastema2 * (1 - this._k2);
double _rawhema = (2 * _ema1) - _ema2;
- double _ema3 = System.Double.IsNaN(this._lastema3)
- ? _rawhema
- : _rawhema * this._k3 + this._lastema3 * (1 - this._k3);
+ double _ema3 = System.Double.IsNaN(this._lastema3) ? _rawhema : _rawhema * this._k3 + this._lastema3 * (1 - this._k3);
this._lastlastema1 = this._lastema1;
this._lastlastema2 = this._lastema2;
@@ -58,8 +52,6 @@ public class HEMA_Series : Single_TSeries_Indicator
this._lastema2 = _ema2;
this._lastema3 = _ema3;
- (System.DateTime t, double v) result =
- (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _ema3);
- base.Add(result, update);
+ base.Add((TValue.t, _ema3), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Trends/HMA_Series.cs b/Source/Trends/HMA_Series.cs
index b8acb657..ad6f30f8 100644
--- a/Source/Trends/HMA_Series.cs
+++ b/Source/Trends/HMA_Series.cs
@@ -73,7 +73,6 @@ public class HMA_Series : TSeries
{
this._wma1 += this._buf1[i] * this._weights[i];
}
-
this._wma1 /= (this._buf1.Count * (this._buf1.Count + 1)) * 0.5;
this._wma2 = 0;
@@ -81,7 +80,6 @@ public class HMA_Series : TSeries
{
this._wma2 += this._buf2[i] * this._weights[i];
}
-
this._wma2 /= (this._buf2.Count * (this._buf2.Count + 1)) * 0.5;
if (update)
@@ -92,6 +90,7 @@ public class HMA_Series : TSeries
{
this._buf3.Add(2 * this._wma1 - this._wma2);
}
+
if (this._buf3.Count > (int)Math.Sqrt(this._p))
{
this._buf3.RemoveAt(0);
diff --git a/Source/Trends/JMA_Series.cs b/Source/Trends/JMA_Series.cs
index b180d79d..54e588ee 100644
--- a/Source/Trends/JMA_Series.cs
+++ b/Source/Trends/JMA_Series.cs
@@ -150,12 +150,9 @@ public class JMA_Series : Single_TSeries_Indicator
double det1 = ((ma2 - this.prev_jma) * (1 - alpha) * (1 - alpha)) +
(this.prev_det1 * alpha * alpha);
this.prev_det1 = det1;
- var jma = this.prev_jma + det1;
- this.prev_jma = jma;
+ var _jma = this.prev_jma + det1;
+ this.prev_jma = _jma;
- (System.DateTime t, double v) result =
- (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : jma);
- base.Add(result, update);
-
- }
+ base.Add((TValue.t, _jma), update, _NaN);
+ }
}
\ No newline at end of file
diff --git a/Source/Trends/KAMA_Series.cs b/Source/Trends/KAMA_Series.cs
index 2f46e25d..01425f16 100644
--- a/Source/Trends/KAMA_Series.cs
+++ b/Source/Trends/KAMA_Series.cs
@@ -44,6 +44,7 @@ public class KAMA_Series : Single_TSeries_Indicator
_buffer.Add(TValue.v);
}
if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); }
+
double _kama = 0;
if (this.Count < this._p) {
for (int i = 0; i < this._buffer.Count; i++) { _kama += this._buffer[i]; }
@@ -59,7 +60,6 @@ public class KAMA_Series : Single_TSeries_Indicator
}
_lastlastkama = _lastkama;
_lastkama = _kama;
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _kama);
- base.Add(result, update);
- }
+ base.Add((TValue.t, _kama), update, _NaN);
+ }
}
\ No newline at end of file
diff --git a/Source/Trends/MACD_Series.cs b/Source/Trends/MACD_Series.cs
index 1050cd1f..ebe205f2 100644
--- a/Source/Trends/MACD_Series.cs
+++ b/Source/Trends/MACD_Series.cs
@@ -40,7 +40,6 @@ public class MACD_Series : Single_TSeries_Indicator
_TSfast.Add(TValue, true);
}
_macd = this._TSmacd[(this.Count < this._TSmacd.Count) ? this.Count : this._TSmacd.Count - 1].v;
- var result = (TValue.t, _macd);
- base.Add(result, update);
- }
+ base.Add((TValue.t, _macd), update, _NaN);
+ }
}
\ No newline at end of file
diff --git a/Source/Trends/MAMA_Series.cs b/Source/Trends/MAMA_Series.cs
new file mode 100644
index 00000000..20102431
--- /dev/null
+++ b/Source/Trends/MAMA_Series.cs
@@ -0,0 +1,131 @@
+namespace QuanTAlib;
+using System;
+
+/*
+MAMA: MESA Adaptive Moving Average
+ Created by John Ehlers, the MAMA indicator is a 5-period adaptive moving average of
+ high/low price that uses classic electrical radio-frequency signal processing algorithms
+ to reduce noise.
+
+ KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 )
+
+Sources:
+ https://mesasoftware.com/papers/MAMA.pdf
+ https://www.tradingview.com/script/foQxLbU3-Ehlers-MESA-Adaptive-Moving-Average-LazyBear/
+
+ */
+
+public class MAMA_Series : Single_TSeries_Indicator
+{
+ public MAMA_Series(TSeries source, double fastlimit = 0.5, double slowlimit = 0.05, bool useNaN = false) : base(source, period: 5, useNaN)
+ {
+ fastl = fastlimit;
+ slowl = slowlimit;
+ i = 0;
+ if (base._data.Count > 0) { base.Add(base._data); }
+ }
+
+ private int i;
+ private double sumPr, jI, jQ, fastl, slowl;
+ private (double i, double i1, double i2, double i3, double i4, double i5, double i6, double io) pr, i1, q1, sm, dt;
+ private (double i, double i1, double io) i2, q2, re, im, pd, ph, mama, fama;
+
+ public override void Add((System.DateTime t, double v) TValue, bool update)
+ {
+ if (update) {
+ i--;
+ pr.i = pr.i1; pr.i1 = pr.i2; pr.i2 = pr.i3; pr.i3 = pr.i4; pr.i4 = pr.i5; pr.i5 = pr.i6; pr.i6 = pr.io;
+ i1.i = i1.i1; i1.i1 = i1.i2; i1.i2 = i1.i3; i1.i3 = i1.i4; i1.i4 = i1.i5; i1.i5 = i1.i6; i1.i6 = i1.io;
+ q1.i = q1.i1; q1.i1 = q1.i2; q1.i2 = q1.i3; q1.i3 = q1.i4; q1.i4 = q1.i5; q1.i5 = q1.i6; q1.i6 = q1.io;
+ dt.i = dt.i1; dt.i1 = dt.i2; dt.i2 = dt.i3; dt.i3 = dt.i4; dt.i4 = dt.i5; dt.i5 = dt.i6; dt.i6 = dt.io;
+ sm.i = sm.i1; sm.i1 = sm.i2; sm.i2 = sm.i3; sm.i3 = sm.i4; dt.i4 = sm.i5; sm.i5 = sm.i6; sm.i6 = sm.io;
+ i2.i = i2.i1; i2.i1 = i2.io;
+ q2.i = q2.i1; q2.i1 = q2.io;
+ re.i = re.i1; re.i1 = re.io;
+ im.i = im.i1; im.i1 = im.io;
+ pd.i = pd.i1; pd.i1 = pd.io;
+ ph.i = ph.i1; ph.i1 = ph.io;
+ mama.i = mama.i1; mama.i1 = mama.io;
+ fama.i = fama.i1; fama.i1 = fama.io;
+ }
+
+ pr.i = TValue.v;
+ if (i > 5) {
+ double adj = (0.075 * pd.i1) + 0.54;
+
+ // smooth and detrender
+ sm.i = ((4 * pr.i) + (3 * pr.i1) + (2 * pr.i2) + pr.i3) / 10;
+ dt.i = ((0.0962 * sm.i) + (0.5769 * sm.i2) - (0.5769 * sm.i4) - (0.0962 * sm.i6)) * adj;
+
+ // in-phase and quadrature
+ q1.i = ((0.0962 * dt.i) + (0.5769 * dt.i2) - (0.5769 * dt.i4) - (0.0962 * dt.i6)) * adj;
+ i1.i = dt.i3;
+
+ // advance the phases by 90 degrees
+ jI = ((0.0962 * i1.i) + (0.5769 * i1.i2) - (0.5769 * i1.i4) - (0.0962 * i1.i6)) * adj;
+ jQ = ((0.0962 * q1.i) + (0.5769 * q1.i2) - (0.5769 * q1.i4) - (0.0962 * q1.i6)) * adj;
+
+ // phasor addition for 3-bar averaging
+ i2.i = i1.i - jQ;
+ q2.i = q1.i + jI;
+
+ i2.i = (0.2 * i2.i) + (0.8 * i2.i1); // smoothing it
+ q2.i = (0.2 * q2.i) + (0.8 * q2.i1);
+
+ // homodyne discriminator
+ re.i = (i2.i * i2.i1) + (q2.i * q2.i1);
+ im.i = (i2.i * q2.i1) - (q2.i * i2.i1);
+
+ re.i = (0.2 * re.i) + (0.8 * re.i1); // smoothing it
+ im.i = (0.2 * im.i) + (0.8 * im.i1);
+
+ // calculate period
+ pd.i = (im.i != 0 && re.i != 0) ? (6.283185307179586 / Math.Atan(im.i / re.i)) : 0d;
+
+ // adjust period to thresholds
+ pd.i = (pd.i > 1.5 * pd.i1) ? 1.5 * pd.i1 : pd.i;
+ pd.i = (pd.i < 0.67 * pd.i1) ? 0.67 * pd.i1 : pd.i;
+ pd.i = (pd.i < 6d) ? 6d : pd.i;
+ pd.i = (pd.i > 50d) ? 50d : pd.i;
+
+ // smooth the period
+ pd.i = (0.2 * pd.i) + (0.8 * pd.i1);
+
+ // determine phase position
+ ph.i = (i1.i != 0) ? Math.Atan(q1.i / i1.i) * 57.29577951308232 : 0;
+
+ // change in phase
+ double delta = Math.Max(ph.i1 - ph.i, 1d);
+
+ // adaptive alpha value
+ double alpha = Math.Max(fastl / delta, slowl);
+
+ // final indicators
+ mama.i = ((alpha * pr.i) + ((1d - alpha) * mama.i1));
+ fama.i = ((0.5d * alpha * mama.i) + ((1d - (0.5d * alpha)) * fama.i1));
+ }
+ else {
+ sumPr += pr.i;
+ pd.i = sm.i = dt.i = i1.i = q1.i = i2.i = q2.i = re.i = im.i = ph.i = 0;
+ mama.i = fama.i = sumPr / (i+1);
+ }
+ i++;
+ pr.io = pr.i6; pr.i6 = pr.i5; pr.i5 = pr.i4; pr.i4 = pr.i3; pr.i3 = pr.i2; pr.i2 = pr.i1; pr.i1 = pr.i;
+ i1.io = i1.i6; i1.i6 = i1.i5; i1.i5 = i1.i4; i1.i4 = i1.i3; i1.i3 = i1.i2; i1.i2 = i1.i1; i1.i1 = i1.i;
+ q1.io = q1.i6; q1.i6 = q1.i5; q1.i5 = q1.i4; q1.i4 = q1.i3; q1.i3 = q1.i2; q1.i2 = q1.i1; q1.i1 = q1.i;
+ dt.io = dt.i6; dt.i6 = dt.i5; dt.i5 = dt.i4; dt.i4 = dt.i3; dt.i3 = dt.i2; dt.i2 = dt.i1; dt.i1 = dt.i;
+ sm.io = sm.i6; sm.i6 = sm.i5; sm.i5 = sm.i4; sm.i4 = sm.i3; sm.i3 = sm.i2; sm.i2 = sm.i1; sm.i1 = sm.i;
+
+ i2.io = i2.i1; i2.i1 = i2.i;
+ q2.io = q2.i1; q2.i1 = q2.i;
+ re.io = re.i1; re.i1 = re.i;
+ im.io = im.i1; im.i1 = im.i;
+ pd.io = pd.i1; pd.i1 = pd.i;
+ ph.io = ph.i1; ph.i1 = ph.i;
+
+ mama.io = mama.i1; mama.i1 = mama.i;
+ fama.io = fama.i1; fama.i1 = fama.i;
+
+ base.Add((TValue.t, mama.i), update, _NaN);
+ }
+}
diff --git a/Source/Trends/RMA_Series.cs b/Source/Trends/RMA_Series.cs
index 66009437..e8b1ef63 100644
--- a/Source/Trends/RMA_Series.cs
+++ b/Source/Trends/RMA_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
RMA: wildeR Moving Average
@@ -34,20 +35,13 @@ public class RMA_Series : Single_TSeries_Indicator
public override void Add((DateTime t, double v) TValue, bool update)
{
- double _ema = 0;
+ double _ema;
if (update) { this._lastema = this._lastlastema; }
if (this.Count < this._p)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else
- {
- _buffer.Add(TValue.v);
- }
- if (_buffer.Count > this._p) { _buffer.RemoveAt(0); }
-
- for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; }
- _ema /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ _ema = _buffer.Average();
}
else
{
@@ -57,7 +51,6 @@ public class RMA_Series : Single_TSeries_Indicator
this._lastlastema = this._lastema;
this._lastema = _ema;
- var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema);
- base.Add(ret, update);
- }
+ base.Add((TValue.t, _ema), update, _NaN);
+ }
}
\ No newline at end of file
diff --git a/Source/Trends/SMA_Series.cs b/Source/Trends/SMA_Series.cs
index 6bbeb1fb..1f07a088 100644
--- a/Source/Trends/SMA_Series.cs
+++ b/Source/Trends/SMA_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
SMA: Simple Moving Average
@@ -26,16 +27,9 @@ public class SMA_Series : Single_TSeries_Indicator
public override void Add((System.DateTime t, double v) TValue, bool update)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else { _buffer.Add(TValue.v); }
- if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Sum() / _buffer.Count;
- double _sma = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
- _sma /= this._buffer.Count;
-
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _sma);
-
- base.Add(result, update);
+ base.Add((TValue.t, _sma), update, _NaN);
}
}
diff --git a/Source/Trends/SMMA_Series.cs b/Source/Trends/SMMA_Series.cs
index 2f31e824..08a22068 100644
--- a/Source/Trends/SMMA_Series.cs
+++ b/Source/Trends/SMMA_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
SMMA: Smoothed Moving Average
@@ -34,15 +35,8 @@ public class SMMA_Series : Single_TSeries_Indicator
if (this.Count < this._p)
{
- 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); }
-
- for (int i = 0; i < this._buffer.Count; i++) { _smma += this._buffer[i]; }
- _smma /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ _smma = _buffer.Average();
}
else
{
@@ -52,7 +46,6 @@ public class SMMA_Series : Single_TSeries_Indicator
this._lastlastsmma = this._lastsmma;
this._lastsmma = _smma;
- var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _smma);
- base.Add(ret, update);
- }
+ base.Add((TValue.t, _smma), update, _NaN);
+ }
}
\ No newline at end of file
diff --git a/Source/Trends/TEMA_Series.cs b/Source/Trends/TEMA_Series.cs
index ba61d6a0..3cb1aafc 100644
--- a/Source/Trends/TEMA_Series.cs
+++ b/Source/Trends/TEMA_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
TEMA: Triple Exponential Moving Average
@@ -44,16 +45,8 @@ public class TEMA_Series : Single_TSeries_Indicator
if (this.Count < this._p)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else
- {
- _buffer.Add(TValue.v);
- }
- if (_buffer.Count > this._p) { _buffer.RemoveAt(0); }
-
- double _sma = 0;
- for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
- _sma /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
+ double _sma = _buffer.Average();
_ema1 = _ema2 = _ema3 = _sma;
}
else
@@ -72,7 +65,6 @@ public class TEMA_Series : Single_TSeries_Indicator
this._lastema2 = _ema2;
this._lastema3 = _ema3;
- var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _tema);
- base.Add(ret, update);
- }
+ base.Add((TValue.t, _tema), update, _NaN);
+ }
}
\ No newline at end of file
diff --git a/Source/Trends/TRIMA_Series.cs b/Source/Trends/TRIMA_Series.cs
index e0fe6e9b..d0276359 100644
--- a/Source/Trends/TRIMA_Series.cs
+++ b/Source/Trends/TRIMA_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
TRIMA: Triangular Moving Average
@@ -31,19 +32,12 @@ public class TRIMA_Series : Single_TSeries_Indicator
{
if (update) { _buffer1[_buffer1.Count - 1] = TValue.v; } else { _buffer1.Add(TValue.v); }
if (_buffer1.Count > this._p1b && this._p1b != 0) { _buffer1.RemoveAt(0); }
-
- double _sma1 = 0;
- for (int i = 0; i < _buffer1.Count; i++) { _sma1 += _buffer1[i]; }
- _sma1 /= this._buffer1.Count;
+ double _sma1 = _buffer1.Average();
if (update) { _buffer2[_buffer2.Count - 1] = _sma1; } else { _buffer2.Add(_sma1); }
if (_buffer2.Count > this._p1a && this._p1a != 0) { _buffer2.RemoveAt(0); }
+ double _trima = _buffer2.Average();
- double _trima = 0;
- for (int i = 0; i < _buffer2.Count; i++) { _trima += _buffer2[i]; }
- _trima /= this._buffer2.Count;
-
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _trima);
- base.Add(result, update);
- }
+ base.Add((TValue.t, _trima), update, _NaN);
+ }
}
\ No newline at end of file
diff --git a/Source/Trends/WMA_Series.cs b/Source/Trends/WMA_Series.cs
index 6b182741..a6c4a1aa 100644
--- a/Source/Trends/WMA_Series.cs
+++ b/Source/Trends/WMA_Series.cs
@@ -24,16 +24,12 @@ public class WMA_Series : Single_TSeries_Indicator
public override void Add((System.DateTime t, double v) TValue, bool update)
{
- if (update) { _buffer[_buffer.Count - 1] = TValue.v; }
- else { _buffer.Add(TValue.v); }
- if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); }
+ Add_Replace_Trim(_buffer, TValue.v, _p, update);
double _wma = 0;
for (int i = 0; i < _buffer.Count; i++) { _wma += _buffer[i] * this._weights[i]; }
_wma /= (this._buffer.Count * (this._buffer.Count + 1)) * 0.5;
- var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _wma);
-
- base.Add(result, update);
+ base.Add((TValue.t, _wma), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Source/Trends/ZLEMA_Series.cs b/Source/Trends/ZLEMA_Series.cs
index ae4fef30..9855a550 100644
--- a/Source/Trends/ZLEMA_Series.cs
+++ b/Source/Trends/ZLEMA_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Linq;
/*
ZLEMA: Zero Lag Exponential Moving Average
@@ -45,18 +46,8 @@ public class ZLEMA_Series : Single_TSeries_Indicator
{ this._lastema = this._lastlastema; }
if (this.Count < this._p)
{
- if (update)
- { this._buffer[this._buffer.Count - 1] = _zl; }
- else
- {
- this._buffer.Add(_zl);
- }
- if (this._buffer.Count > this._p)
- { this._buffer.RemoveAt(0); }
-
- for (int i = 0; i < this._buffer.Count; i++)
- { _ema += this._buffer[i]; }
- _ema /= this._buffer.Count;
+ Add_Replace_Trim(_buffer, _zl, _p, update);
+ _ema = _buffer.Average();
}
else
{
@@ -66,7 +57,6 @@ public class ZLEMA_Series : Single_TSeries_Indicator
this._lastlastema = this._lastema;
this._lastema = _ema;
- var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema);
- base.Add(ret, update);
- }
+ base.Add((TValue.t, _ema), update, _NaN);
+ }
}
\ No newline at end of file
diff --git a/Source/Volatility/ADL_Series.cs b/Source/Volatility/ADL_Series.cs
index c2ae0cc4..72210268 100644
--- a/Source/Volatility/ADL_Series.cs
+++ b/Source/Volatility/ADL_Series.cs
@@ -37,7 +37,6 @@ public class ADL_Series : Single_TBars_Indicator
this._lastlastadl = this._lastadl;
this._lastadl = _adl;
- var ret = (TBar.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _adl);
- base.Add(ret, update);
- }
+ base.Add((TBar.t, _adl), update, _NaN);
+ }
}
\ No newline at end of file
diff --git a/Tests/Statistics/ENTP_Test.cs b/Tests/Statistics/ENTP_Test.cs
index 12098a8a..f7e8aa10 100644
--- a/Tests/Statistics/ENTP_Test.cs
+++ b/Tests/Statistics/ENTP_Test.cs
@@ -3,13 +3,13 @@ using System;
using QuanTAlib;
namespace Statistics;
-public class KURT_Test
+public class KURTOSIS_Test
{
[Fact]
public void Add_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
- KURT_Series c = new(a, 3);
+ KURTOSIS_Series c = new(a, 3);
Assert.Equal(6, c.Count);
a.Add(5);
Assert.Equal(a.Count, c.Count);
@@ -21,7 +21,7 @@ public class KURT_Test
public void Edge_Test()
{
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
- KURT_Series c = new(a, 3);
+ KURTOSIS_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count);
a.Add(double.NaN);
Assert.Equal(a.Count, c.Count);
diff --git a/Tests/Statistics/KURT_Test.cs b/Tests/Statistics/KURT_Test.cs
index 93b5220c..c594ff4b 100644
--- a/Tests/Statistics/KURT_Test.cs
+++ b/Tests/Statistics/KURT_Test.cs
@@ -9,7 +9,7 @@ public class ENTP_Test
public void Add_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
- ENTP_Series c = new(a, 3);
+ ENTROPY_Series c = new(a, 3);
Assert.Equal(6, c.Count);
a.Add(5);
Assert.Equal(a.Count, c.Count);
@@ -21,7 +21,7 @@ public class ENTP_Test
public void Edge_Test()
{
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
- ENTP_Series c = new(a, 3);
+ ENTROPY_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count);
a.Add(double.NaN);
Assert.Equal(a.Count, c.Count);
diff --git a/Tests/Statistics/MED_Test.cs b/Tests/Statistics/MED_Test.cs
index 778811a4..ccfc2bcc 100644
--- a/Tests/Statistics/MED_Test.cs
+++ b/Tests/Statistics/MED_Test.cs
@@ -9,7 +9,7 @@ public class MED_Test
public void Add_Test()
{
TSeries a = new() { 0, 1, 2, 3, 4, 5 };
- MED_Series c = new(a, 3);
+ MEDIAN_Series c = new(a, 3);
Assert.Equal(6, c.Count);
a.Add(5);
Assert.Equal(a.Count, c.Count);
@@ -21,7 +21,7 @@ public class MED_Test
public void Edge_Test()
{
TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue };
- MED_Series c = new(a, 3);
+ MEDIAN_Series c = new(a, 3);
Assert.Equal(a.Count, c.Count);
a.Add(double.NaN);
Assert.Equal(a.Count, c.Count);
diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj
index de0bdcd3..c584f538 100644
--- a/Tests/Tests.csproj
+++ b/Tests/Tests.csproj
@@ -15,10 +15,6 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
diff --git a/Tests/Validations/Pandas_TA.cs b/Tests/Validations/Pandas_TA.cs
index 2bc65c52..fb589b18 100644
--- a/Tests/Validations/Pandas_TA.cs
+++ b/Tests/Validations/Pandas_TA.cs
@@ -1,198 +1,206 @@
-using Xunit;
-using System;
-using QuanTAlib;
-using Python.Runtime;
-using Python.Included;
-
-namespace Validations;
-public class PandasTA : IDisposable
-{
- private readonly GBM_Feed bars;
- private readonly Random rnd = new();
- private readonly int period;
- private readonly string OStype;
- private dynamic np;
- private dynamic ta;
- private dynamic df;
-
- public PandasTA()
- {
- bars = new(5000);
- period = rnd.Next(28) + 3;
-
- // Checking the host OS and setting PythonDLL accordingly
- OStype = Environment.OSVersion.ToString();
- if (OStype == "Unix 13.1.0")
- {
- OStype = @"/usr/local/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/libpython3.10.dylib";
- }
- else
- {
- OStype = Path.GetFullPath(".") + @"\python-3.10.0-embed-amd64\python310.dll";
- }
-
- Installer.InstallPath = Path.GetFullPath(".");
- Installer.SetupPython().Wait();
- Installer.TryInstallPip();
- Installer.PipInstallModule("pandas-ta");
- //alternative: git+https://github.com/twopirllc/pandas-ta
-
- Runtime.PythonDLL = OStype;
- PythonEngine.Initialize();
- np = Py.Import("numpy");
- ta = Py.Import("pandas_ta");
-
- string[] cols = { "open", "high", "low", "close", "volume" };
- double[,] ary = new double[bars.Count, 5];
- for (int i = 0; i < bars.Count; i++)
- {
- ary[i, 0] = bars.Open[i].v;
- ary[i, 1] = bars.High[i].v;
- ary[i, 2] = bars.Low[i].v;
- ary[i, 3] = bars.Close[i].v;
- ary[i, 4] = bars.Volume[i].v;
- }
- df = ta.DataFrame(data: np.array(ary), index: np.array(bars.Close.t), columns: np.array(cols));
- }
-
- public void Dispose()
- {
+using Xunit;
+using System;
+using QuanTAlib;
+using Python.Runtime;
+using Python.Included;
+
+namespace Validations;
+public class PandasTA : IDisposable
+{
+ private readonly GBM_Feed bars;
+ private readonly Random rnd = new();
+ private readonly int period;
+ private readonly string OStype;
+ private readonly dynamic np;
+ private readonly dynamic ta;
+ private readonly dynamic df;
+
+ public PandasTA()
+ {
+ bars = new(5000);
+ period = rnd.Next(28) + 3;
+
+ // Checking the host OS and setting PythonDLL accordingly
+ OStype = Environment.OSVersion.ToString();
+ if (OStype == "Unix 13.1.0")
+ {
+ OStype = @"/usr/local/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/libpython3.10.dylib";
+ }
+ else
+ {
+ OStype = Path.GetFullPath(".") + @"\python-3.10.0-embed-amd64\python310.dll";
+ }
+
+ Installer.InstallPath = Path.GetFullPath(".");
+ Installer.SetupPython().Wait();
+ Installer.TryInstallPip();
+ Installer.PipInstallModule("pandas-ta");
+ //alternative: git+https://github.com/twopirllc/pandas-ta
+
+ Runtime.PythonDLL = OStype;
+ PythonEngine.Initialize();
+ np = Py.Import("numpy");
+ ta = Py.Import("pandas_ta");
+
+ string[] cols = { "open", "high", "low", "close", "volume" };
+ double[,] ary = new double[bars.Count, 5];
+ for (int i = 0; i < bars.Count; i++)
+ {
+ ary[i, 0] = bars.Open[i].v;
+ ary[i, 1] = bars.High[i].v;
+ ary[i, 2] = bars.Low[i].v;
+ ary[i, 3] = bars.Close[i].v;
+ ary[i, 4] = bars.Volume[i].v;
+ }
+ df = ta.DataFrame(data: np.array(ary), index: np.array(bars.Close.t), columns: np.array(cols));
+ }
+
+ public void Dispose()
+ {
PythonEngine.Shutdown();
GC.SuppressFinalize(this);
- }
-
- [Fact]
- void HL2()
- {
- var pta = df.ta.hl2(high: df.high, low: df.low);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(bars.HL2.Last().v, 4));
- }
-
- [Fact]
- void HLC3()
- {
- var pta = df.ta.hlc3(high: df.high, low: df.low, close: df.close);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(bars.HLC3.Last().v, 4));
- }
-
- [Fact]
- void OHLC4()
- {
- var pta = df.ta.ohlc4(open: df.open, high: df.high, low: df.low, close: df.close);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(bars.OHLC4.Last().v, 4));
- }
-
- [Fact]
- void MEDIAN()
- {
- MED_Series QL = new(bars.Close, period);
- var pta = df.ta.median(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void VARIANCE()
- {
- VAR_Series QL = new(bars.Close, period);
- var pta = df.ta.variance(close: df.close, length: period, ddof:0);
- Assert.Equal(Math.Round((double)pta.tail(1), 5), Math.Round(QL.Last().v, 5));
- }
-
- [Fact]
- void SVARIANCE()
- {
- SVAR_Series QL = new(bars.Close, period);
- var pta = df.ta.variance(close: df.close, length: period, ddof: 1);
- Assert.Equal(Math.Round((double)pta.tail(1), 5), Math.Round(QL.Last().v, 5));
- }
-
- [Fact]
- void ADL()
- {
- ADL_Series QL = new(bars);
- var pta = df.ta.ad(high: df.high, low: df.low, close:df.close, volume:df.volume);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void ADOSC()
- {
- ADOSC_Series QL = new(bars);
- var pta = df.ta.adosc(high: df.high, low: df.low, close: df.close, volume: df.volume);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void TR()
- {
- TR_Series QL = new(bars);
- var pta = df.ta.true_range(high: df.high, low: df.low, close: df.close);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void ATR()
- {
- ATR_Series QL = new(bars, period);
- var pta = df.ta.atr(high: df.high, low: df.low, close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void RSI()
- {
- RSI_Series QL = new(bars.Close, period);
- var pta = df.ta.rsi(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void TRIMA()
- {
- //TODO: return length to variable length (period) when Pandas-TA fixes trima
- TRIMA_Series QL = new(bars.Close, 11);
- var pta = df.ta.trima(close: df.close, length: 11);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void KAMA()
- {
- KAMA_Series QL = new(bars.Close, period);
- var pta = df.ta.kama(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void HMA()
- {
- HMA_Series QL = new(bars.Close, period, false);
- var pta = df.ta.hma(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void SMA()
- {
- SMA_Series QL = new(bars.Close, period, false);
- var pta = df.ta.sma(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void EMA()
- {
- EMA_Series QL = new(bars.Close, period, false);
- var pta = df.ta.ema(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void TEMA()
- {
- TEMA_Series QL = new(bars.Close, period, false);
- var pta = df.ta.tema(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
+ }
+
+ [Fact]
+ void HL2()
+ {
+ var pta = df.ta.hl2(high: df.high, low: df.low);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(bars.HL2.Last().v, 4));
+ }
+
+ [Fact]
+ void HLC3()
+ {
+ var pta = df.ta.hlc3(high: df.high, low: df.low, close: df.close);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(bars.HLC3.Last().v, 4));
+ }
+
+ [Fact]
+ void OHLC4()
+ {
+ var pta = df.ta.ohlc4(open: df.open, high: df.high, low: df.low, close: df.close);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(bars.OHLC4.Last().v, 4));
+ }
+
+ [Fact]
+ void MEDIAN()
+ {
+ MEDIAN_Series QL = new(bars.Close, period);
+ var pta = df.ta.median(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void VARIANCE()
+ {
+ VAR_Series QL = new(bars.Close, period);
+ var pta = df.ta.variance(close: df.close, length: period, ddof:0);
+ Assert.Equal(Math.Round((double)pta.tail(1), 5), Math.Round(QL.Last().v, 5));
+ }
+
+ [Fact]
+ void SVARIANCE()
+ {
+ SVAR_Series QL = new(bars.Close, period);
+ var pta = df.ta.variance(close: df.close, length: period, ddof: 1);
+ Assert.Equal(Math.Round((double)pta.tail(1), 5), Math.Round(QL.Last().v, 5));
+ }
+
+ [Fact]
+ void ADL()
+ {
+ ADL_Series QL = new(bars);
+ var pta = df.ta.ad(high: df.high, low: df.low, close:df.close, volume:df.volume);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void ADOSC()
+ {
+ ADOSC_Series QL = new(bars);
+ var pta = df.ta.adosc(high: df.high, low: df.low, close: df.close, volume: df.volume);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void TR()
+ {
+ TR_Series QL = new(bars);
+ var pta = df.ta.true_range(high: df.high, low: df.low, close: df.close);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void OBV()
+ {
+ OBV_Series QL = new(bars);
+ var pta = df.ta.obv(close: df.close, volume: df.volume);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void ATR()
+ {
+ ATR_Series QL = new(bars, period);
+ var pta = df.ta.atr(high: df.high, low: df.low, close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void RSI()
+ {
+ RSI_Series QL = new(bars.Close, period);
+ var pta = df.ta.rsi(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void TRIMA()
+ {
+ // TODO: return length to variable length (period) when Pandas-TA fixes trima
+ TRIMA_Series QL = new(bars.Close, 11);
+ var pta = df.ta.trima(close: df.close, length: 11);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void KAMA()
+ {
+ KAMA_Series QL = new(bars.Close, period);
+ var pta = df.ta.kama(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void HMA()
+ {
+ HMA_Series QL = new(bars.Close, period, false);
+ var pta = df.ta.hma(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void SMA()
+ {
+ SMA_Series QL = new(bars.Close, period, false);
+ var pta = df.ta.sma(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void EMA()
+ {
+ EMA_Series QL = new(bars.Close, period, false);
+ var pta = df.ta.ema(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void TEMA()
+ {
+ TEMA_Series QL = new(bars.Close, period, false);
+ var pta = df.ta.tema(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
}
[Fact]
@@ -219,67 +227,67 @@ public class PandasTA : IDisposable
Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
}
- [Fact]
- void ENTP()
- {
- ENTP_Series QL = new(bars.Close, period, useNaN: false);
- var pta = df.ta.entropy(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void WMA()
- {
- WMA_Series QL = new(bars.Close, period, false);
- var pta = df.ta.wma(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void RMA()
- {
- RMA_Series QL = new(bars.Close, period, false);
- var pta = df.ta.rma(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void ZLEMA()
- {
- ZLEMA_Series QL = new(bars.Close, period, false);
- var pta = df.ta.zlma(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void DEMA()
- {
- DEMA_Series QL = new(bars.Close, period, false);
- var pta = df.ta.dema(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void BIAS()
- {
- BIAS_Series QL = new(bars.Close, period, false);
- var pta = df.ta.bias(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void KURT()
- {
- KURT_Series QL = new(bars.Close, period, useNaN: false);
- var pta = df.ta.kurtosis(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- void MAD()
- {
- MAD_Series QL = new(bars.Close, period, useNaN: false);
- var pta = df.ta.mad(close: df.close, length: period);
- Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
- }
+ [Fact]
+ void ENTROPY()
+ {
+ ENTROPY_Series QL = new(bars.Close, period, useNaN: false);
+ var pta = df.ta.entropy(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void WMA()
+ {
+ WMA_Series QL = new(bars.Close, period, false);
+ var pta = df.ta.wma(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void RMA()
+ {
+ RMA_Series QL = new(bars.Close, period, false);
+ var pta = df.ta.rma(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void ZLEMA()
+ {
+ ZLEMA_Series QL = new(bars.Close, period, false);
+ var pta = df.ta.zlma(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void DEMA()
+ {
+ DEMA_Series QL = new(bars.Close, period, false);
+ var pta = df.ta.dema(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void BIAS()
+ {
+ BIAS_Series QL = new(bars.Close, period, false);
+ var pta = df.ta.bias(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void KURTOSIS()
+ {
+ KURTOSIS_Series QL = new(bars.Close, period, useNaN: false);
+ var pta = df.ta.kurtosis(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ void MAD()
+ {
+ MAD_Series QL = new(bars.Close, period, useNaN: false);
+ var pta = df.ta.mad(close: df.close, length: period);
+ Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4));
+ }
}
\ No newline at end of file
diff --git a/Tests/Validations/Skender_Stock.cs b/Tests/Validations/Skender_Stock.cs
index fcc27368..3e173138 100644
--- a/Tests/Validations/Skender_Stock.cs
+++ b/Tests/Validations/Skender_Stock.cs
@@ -5,314 +5,323 @@ using Xunit;
namespace Validations;
public class Skender_Stock
-{
- private readonly GBM_Feed bars;
- private readonly Random rnd = new();
- private readonly int period;
- private readonly IEnumerable quotes;
-
- public Skender_Stock()
- {
- bars = new(Bars: 5000, Volatility: 0.7, Drift: 0.0);
- period = rnd.Next(28) + 3;
- quotes = bars.Select(
- q => new Quote
- {
- Date = q.t,
- Open = (decimal)q.o,
- High = (decimal)q.h,
- Low = (decimal)q.l,
- Close = (decimal)q.c,
- Volume = (decimal)q.v
- });
- }
-
- [Fact]
- public void SMA()
- {
- SMA_Series QL = new(bars.Close, period, false);
- var SK = quotes.GetSma(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void EMA()
- {
- EMA_Series QL = new(bars.Close, period, false);
- var SK = quotes.GetEma(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Ema!, 6), Math.Round(QL.Last().v, 6));
- }
- [Fact]
- public void WMA()
- {
- WMA_Series QL = new(bars.Close, period, false);
- var SK = quotes.GetWma(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Wma!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void DEMA()
- {
- DEMA_Series QL = new(bars.Close, period, false);
- var SK = quotes.GetDema(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Dema!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void TEMA()
- {
- TEMA_Series QL = new(bars.Close, period, false);
- var SK = quotes.GetTema(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Tema!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void MAD()
- {
- MAD_Series QL = new(bars.Close, period, false);
- var SK = quotes.GetSmaAnalysis(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Mad!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void MSE()
- {
- MSE_Series QL = new(bars.Close, period, false);
- var SK = quotes.GetSmaAnalysis(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Mse!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void MAPE()
- {
- MAPE_Series QL = new(bars.Close, period, false);
- var SK = quotes.GetSmaAnalysis(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Mape!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void COVAR()
- {
- COVAR_Series QL = new(bars.High, bars.Low, period, false);
- var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period);
-
- Assert.Equal(Math.Round((double)SK.Last().Covariance!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void CORR()
- {
- CORR_Series QL = new(bars.High, bars.Low, period, false);
- var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period);
-
- Assert.Equal(Math.Round((double)SK.Last().Correlation!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void ATR()
- {
- ATR_Series QL = new(bars, period, false);
- var SK = quotes.GetAtr(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Atr!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void OBV()
- {
- OBV_Series QL = new(bars, period, false);
- var SK = quotes.GetObv(period);
-
- // adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB
- Assert.Equal(Math.Round(SK.Last().Obv! + (double)quotes.First().Volume!, 5),
- Math.Round(QL.Last().v, 5));
- }
-
- [Fact]
- public void ADL()
- {
- ADL_Series QL = new(bars, false);
- var SK = quotes.GetAdl();
-
- Assert.Equal(Math.Round(SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5));
- }
-
- [Fact]
- public void CCI()
- {
- CCI_Series QL = new(bars, period, false);
- var SK = quotes.GetCci(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Cci!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void ATRP()
- {
- ATRP_Series QL = new(bars, period, false);
- var SK = quotes.GetAtr(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Atrp!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void KAMA()
- {
- KAMA_Series QL = new(bars.Close, period, useNaN: false);
- var SK = quotes.GetKama(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Kama!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void HMA()
- {
- HMA_Series QL = new(bars.Close, period, useNaN: false);
- var SK = quotes.GetHma(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Hma!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void SMMA()
- {
- SMMA_Series QL = new(bars.Close, period, useNaN: false);
- var SK = quotes.GetSmma(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Smma!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void MACD()
- {
- MACD_Series QL = new(bars.Close, 26, 12, 9, useNaN: false);
- var SK = quotes.GetMacd(12, 26, 9);
-
- Assert.Equal(Math.Round((double)SK.Last().Macd!, 6), Math.Round(QL.Last().v, 6));
- Assert.Equal(Math.Round((double)SK.Last().Signal!, 6), Math.Round(QL.Signal.Last().v, 6));
- }
-
- [Fact]
- public void BBANDS()
- {
- BBANDS_Series QL = new(bars.Close, period, 2.0, useNaN: false);
- var SK = quotes.GetBollingerBands(period, 2.0);
-
- Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Mid.Last().v, 6));
- Assert.Equal(Math.Round((double)SK.Last().UpperBand!, 6), Math.Round(QL.Upper.Last().v, 6));
- Assert.Equal(Math.Round((double)SK.Last().LowerBand!, 6), Math.Round(QL.Lower.Last().v, 6));
- Assert.Equal(Math.Round((double)SK.Last().Width!, 6), Math.Round(QL.Bandwidth.Last().v, 6));
- Assert.Equal(Math.Round((double)SK.Last().PercentB!, 6), Math.Round(QL.PercentB.Last().v, 6));
- Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Zscore.Last().v, 6));
- }
-
- [Fact]
- public void RSI()
- {
- RSI_Series QL = new(bars.Close, period, useNaN: false);
- var SK = quotes.GetRsi(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Rsi!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void ALMA()
- {
- ALMA_Series QL = new(bars.Close, period, useNaN: false);
- var SK = quotes.GetAlma(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Alma!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void SDEV()
- {
- SDEV_Series QL = new(bars.Close, period, useNaN: false);
- var SK = quotes.GetStdDev(period);
-
- Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void ZSCORE()
- {
- ZSCORE_Series QL = new(bars.Close, period, useNaN: false);
- var SK = quotes.GetStdDev(period);
-
- Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void LINREG()
- {
- LINREG_Series QL = new(bars.Close, period, useNaN: false);
- var SK = quotes.GetSlope(period);
-
- Assert.Equal(Math.Round((double)SK.Last().Slope!, 6), Math.Round(QL.Last().v, 6));
- Assert.Equal(Math.Round((double)SK.Last().Intercept!, 6), Math.Round(QL.Intercept.Last().v, 6));
- Assert.Equal(Math.Round((double)SK.Last().RSquared!, 6), Math.Round(QL.RSquared.Last().v, 6));
- Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.StdDev.Last().v, 6));
- }
-
- [Fact]
- public void TR()
- {
- TR_Series QL = new(bars, useNaN: false);
- var SK = quotes.GetTr();
-
- Assert.Equal(Math.Round((double)SK.Last().Tr!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void HL2()
- {
- TSeries QL = bars.HL2;
- var SK = quotes.GetBaseQuote(CandlePart.HL2);
-
- Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void OC2()
- {
- TSeries QL = bars.OC2;
- var SK = quotes.GetBaseQuote(CandlePart.OC2);
-
- Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void HLC3()
- {
- TSeries QL = bars.HLC3;
- var SK = quotes.GetBaseQuote(CandlePart.HLC3);
-
- Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void OHL3()
- {
- TSeries QL = bars.OHL3;
- var SK = quotes.GetBaseQuote(CandlePart.OHL3);
-
- Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
- }
-
- [Fact]
- public void OHLC4()
- {
- TSeries QL = bars.OHLC4;
- var SK = quotes.GetBaseQuote(CandlePart.OHLC4);
-
- Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
+{
+ private readonly GBM_Feed bars;
+ private readonly Random rnd = new();
+ private readonly int period;
+ private readonly IEnumerable quotes;
+
+ public Skender_Stock()
+ {
+ bars = new(Bars: 5000, Volatility: 0.7, Drift: 0.0);
+ period = rnd.Next(28) + 3;
+ quotes = bars.Select(
+ q => new Quote
+ {
+ Date = q.t,
+ Open = (decimal)q.o,
+ High = (decimal)q.h,
+ Low = (decimal)q.l,
+ Close = (decimal)q.c,
+ Volume = (decimal)q.v
+ });
+ }
+
+ [Fact]
+ public void SMA()
+ {
+ SMA_Series QL = new(bars.Close, period, false);
+ var SK = quotes.GetSma(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void EMA()
+ {
+ EMA_Series QL = new(bars.Close, period, false);
+ var SK = quotes.GetEma(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Ema!, 6), Math.Round(QL.Last().v, 6));
+ }
+ [Fact]
+ public void WMA()
+ {
+ WMA_Series QL = new(bars.Close, period, false);
+ var SK = quotes.GetWma(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Wma!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void DEMA()
+ {
+ DEMA_Series QL = new(bars.Close, period, false);
+ var SK = quotes.GetDema(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Dema!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void TEMA()
+ {
+ TEMA_Series QL = new(bars.Close, period, false);
+ var SK = quotes.GetTema(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Tema!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+
+ [Fact]
+ public void MAMA() {
+ MAMA_Series QL = new(bars.HL2, fastlimit: 0.5, slowlimit: 0.05);
+ var SK = quotes.GetMama(fastLimit: 0.5, slowLimit: 0.05);
+
+ Assert.Equal(Math.Round((double)SK.Last().Mama!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void MAD()
+ {
+ MAD_Series QL = new(bars.Close, period, false);
+ var SK = quotes.GetSmaAnalysis(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Mad!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void MSE()
+ {
+ MSE_Series QL = new(bars.Close, period, false);
+ var SK = quotes.GetSmaAnalysis(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Mse!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void MAPE()
+ {
+ MAPE_Series QL = new(bars.Close, period, false);
+ var SK = quotes.GetSmaAnalysis(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Mape!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void COVAR()
+ {
+ COVAR_Series QL = new(bars.High, bars.Low, period, false);
+ var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Covariance!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void CORR()
+ {
+ CORR_Series QL = new(bars.High, bars.Low, period, false);
+ var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Correlation!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void ATR()
+ {
+ ATR_Series QL = new(bars, period, false);
+ var SK = quotes.GetAtr(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Atr!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void OBV()
+ {
+ OBV_Series QL = new(bars, period, false);
+ var SK = quotes.GetObv(period);
+
+ // adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB
+ Assert.Equal(Math.Round(SK.Last().Obv! + (double)quotes.First().Volume!, 5),
+ Math.Round(QL.Last().v, 5));
+ }
+
+ [Fact]
+ public void ADL()
+ {
+ ADL_Series QL = new(bars, false);
+ var SK = quotes.GetAdl();
+
+ Assert.Equal(Math.Round(SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5));
+ }
+
+ [Fact]
+ public void CCI()
+ {
+ CCI_Series QL = new(bars, period, false);
+ var SK = quotes.GetCci(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Cci!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void ATRP()
+ {
+ ATRP_Series QL = new(bars, period, false);
+ var SK = quotes.GetAtr(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Atrp!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void KAMA()
+ {
+ KAMA_Series QL = new(bars.Close, period, useNaN: false);
+ var SK = quotes.GetKama(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Kama!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void HMA()
+ {
+ HMA_Series QL = new(bars.Close, period, useNaN: false);
+ var SK = quotes.GetHma(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Hma!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void SMMA()
+ {
+ SMMA_Series QL = new(bars.Close, period, useNaN: false);
+ var SK = quotes.GetSmma(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Smma!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void MACD()
+ {
+ MACD_Series QL = new(bars.Close, 26, 12, 9, useNaN: false);
+ var SK = quotes.GetMacd(12, 26, 9);
+
+ Assert.Equal(Math.Round((double)SK.Last().Macd!, 6), Math.Round(QL.Last().v, 6));
+ Assert.Equal(Math.Round((double)SK.Last().Signal!, 6), Math.Round(QL.Signal.Last().v, 6));
+ }
+
+ [Fact]
+ public void BBANDS()
+ {
+ BBANDS_Series QL = new(bars.Close, period, 2.0, useNaN: false);
+ var SK = quotes.GetBollingerBands(period, 2.0);
+
+ Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Mid.Last().v, 6));
+ Assert.Equal(Math.Round((double)SK.Last().UpperBand!, 6), Math.Round(QL.Upper.Last().v, 6));
+ Assert.Equal(Math.Round((double)SK.Last().LowerBand!, 6), Math.Round(QL.Lower.Last().v, 6));
+ Assert.Equal(Math.Round((double)SK.Last().Width!, 6), Math.Round(QL.Bandwidth.Last().v, 6));
+ Assert.Equal(Math.Round((double)SK.Last().PercentB!, 6), Math.Round(QL.PercentB.Last().v, 6));
+ Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Zscore.Last().v, 6));
+ }
+
+ [Fact]
+ public void RSI()
+ {
+ RSI_Series QL = new(bars.Close, period, useNaN: false);
+ var SK = quotes.GetRsi(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Rsi!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void ALMA()
+ {
+ ALMA_Series QL = new(bars.Close, period, useNaN: false);
+ var SK = quotes.GetAlma(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Alma!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void SDEV()
+ {
+ SDEV_Series QL = new(bars.Close, period, useNaN: false);
+ var SK = quotes.GetStdDev(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void ZSCORE()
+ {
+ ZSCORE_Series QL = new(bars.Close, period, useNaN: false);
+ var SK = quotes.GetStdDev(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void LINREG()
+ {
+ LINREG_Series QL = new(bars.Close, period, useNaN: false);
+ var SK = quotes.GetSlope(period);
+
+ Assert.Equal(Math.Round((double)SK.Last().Slope!, 6), Math.Round(QL.Last().v, 6));
+ Assert.Equal(Math.Round((double)SK.Last().Intercept!, 6), Math.Round(QL.Intercept.Last().v, 6));
+ Assert.Equal(Math.Round((double)SK.Last().RSquared!, 6), Math.Round(QL.RSquared.Last().v, 6));
+ Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.StdDev.Last().v, 6));
+ }
+
+ [Fact]
+ public void TR()
+ {
+ TR_Series QL = new(bars, useNaN: false);
+ var SK = quotes.GetTr();
+
+ Assert.Equal(Math.Round((double)SK.Last().Tr!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void HL2()
+ {
+ TSeries QL = bars.HL2;
+ var SK = quotes.GetBaseQuote(CandlePart.HL2);
+
+ Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void OC2()
+ {
+ TSeries QL = bars.OC2;
+ var SK = quotes.GetBaseQuote(CandlePart.OC2);
+
+ Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void HLC3()
+ {
+ TSeries QL = bars.HLC3;
+ var SK = quotes.GetBaseQuote(CandlePart.HLC3);
+
+ Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void OHL3()
+ {
+ TSeries QL = bars.OHL3;
+ var SK = quotes.GetBaseQuote(CandlePart.OHL3);
+
+ Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
+ }
+
+ [Fact]
+ public void OHLC4()
+ {
+ TSeries QL = bars.OHLC4;
+ var SK = quotes.GetBaseQuote(CandlePart.OHLC4);
+
+ Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
}
}
diff --git a/Tests/Validations/TA_LIB.cs b/Tests/Validations/TA_LIB.cs
index ae900fbe..3e803230 100644
--- a/Tests/Validations/TA_LIB.cs
+++ b/Tests/Validations/TA_LIB.cs
@@ -1,318 +1,330 @@
-using Xunit;
-using System;
-using TALib;
-using QuanTAlib;
-
-namespace Validations;
-public class TA_LIB
-{
- private readonly GBM_Feed bars;
- private readonly Random rnd = new();
- private readonly int period;
- private readonly double[] TALIB;
- private readonly double[] inopen;
- private readonly double[] inhigh;
- private readonly double[] inlow;
- private readonly double[] inclose;
- private readonly double[] involume;
-
- public TA_LIB()
- {
- bars = new(5000);
- period = rnd.Next(28) + 3;
- TALIB = new double[bars.Count];
- inopen = bars.Open.v.ToArray();
- inhigh = bars.High.v.ToArray();
- inlow = bars.Low.v.ToArray();
- inclose = bars.Close.v.ToArray();
- involume = bars.Volume.v.ToArray();
- }
-
- /////////////////////////////////////////
-
- [Fact]
- public void ADD()
- {
- ADD_Series QL = new(bars.Open, bars.Close);
- Core.Add(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void SUB()
- {
- SUB_Series QL = new(bars.Open, bars.Close);
- Core.Sub(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void MUL()
- {
- MUL_Series QL = new(bars.Open, bars.Close);
- Core.Mult(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void DIV()
- {
- DIV_Series QL = new(bars.Open, bars.Close);
- Core.Div(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void CORR()
- {
- CORR_Series QL = new(bars.Open, bars.Close, period);
- Core.Correl(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, optInTimePeriod: period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void SDEV()
- {
- SDEV_Series QL = new(bars.Close, period, false);
- Core.StdDev(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void SMA()
- {
- SMA_Series QL = new(bars.Close, period, false);
- Core.Sma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void SUM()
- {
- SUM_Series QL = new(bars.Close, period, false);
- Core.Sum(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void MIDPRICE()
- {
- MIDPRICE_Series QL = new(bars, period, false);
- Core.MidPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
-
- [Fact]
- public void VAR()
- {
- VAR_Series QL = new(bars.Close, period, false);
- Core.Var(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 4, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 4));
- }
-
- [Fact]
- public void MIDPOINT()
- {
- MIDPOINT_Series QL = new(bars.Close, period, false);
- Core.MidPoint(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void TRIMA()
- {
- TRIMA_Series QL = new(bars.Close, period, false);
- Core.Trima(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void EMA()
- {
- EMA_Series QL = new(bars.Close, period, false);
- Core.Ema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void WMA()
- {
- WMA_Series QL = new(bars.Close, period, false);
- Core.Wma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void DEMA()
- {
- DEMA_Series QL = new(bars.Close, period, false);
- Core.Dema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void TEMA()
- {
- TEMA_Series QL = new(bars.Close, period, false);
- Core.Tema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void MAX()
- {
- MAX_Series QL = new(bars.Close, period, false);
- Core.Max(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void MIN()
- {
- MIN_Series QL = new(bars.Close, period, false);
- Core.Min(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void ADL()
- {
- ADL_Series QL = new(bars, false);
- Core.Ad(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void OBV()
- {
- OBV_Series QL = new(bars, period, false);
- Core.Obv(inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void ADOSC()
- {
- ADOSC_Series QL = new(bars, false);
- Core.AdOsc(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void ATR()
- {
- ATR_Series QL = new(bars, period, false);
- Core.Atr(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void CCI()
- {
- CCI_Series QL = new(bars, period, false);
- Core.Cci(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void RSI()
- {
- RSI_Series QL = new(bars.Close, period, false);
- Core.Rsi(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void TR()
- {
- TR_Series QL = new(bars, false);
- Core.TRange(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void MACD()
- {
- double[] macdSignal = new double[bars.Count];
- double[] macdHist = new double[bars.Count];
- MACD_Series QL = new(bars.Close, slow: 26, fast: 12, signal: 9, false);
- Core.Macd(inclose, 0, bars.Count - 1, outMacd: TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _);
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Signal.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void BBANDS()
- {
- double[] outMiddle = new double[bars.Count];
- double[] outUpper = new double[bars.Count];
- double[] outLower = new double[bars.Count];
- BBANDS_Series QL = new(bars.Close, period: 26, multiplier: 2.0, false);
- Core.Bbands(inclose, 0, bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod: 26, optInNbDevUp: 2.0, optInNbDevDn: 2.0);
- Assert.Equal(Math.Round(outUpper[outUpper.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Upper.Last().v, 6, MidpointRounding.AwayFromZero));
- Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Mid.Last().v, 6, MidpointRounding.AwayFromZero));
- Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Lower.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void HL2()
- {
- TSeries QL = bars.HL2;
- Core.MedPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void HLC3()
- {
- TSeries QL = bars.HLC3;
- Core.TypPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void OHLC4()
- {
- TSeries QL = bars.OHLC4;
- Core.AvgPrice(inopen, inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-
- [Fact]
- public void HLCC4()
- {
- TSeries QL = bars.HLCC4;
- Core.WclPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
-
- Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
- }
-}
+using Xunit;
+using System;
+using TALib;
+using QuanTAlib;
+
+namespace Validations;
+public class TA_LIB
+{
+ private readonly GBM_Feed bars;
+ private readonly Random rnd = new();
+ private readonly int period;
+ private readonly double[] TALIB;
+ private readonly double[] TALIB2;
+ private readonly double[] inopen;
+ private readonly double[] inhigh;
+ private readonly double[] inlow;
+ private readonly double[] inclose;
+ private readonly double[] involume;
+
+ public TA_LIB()
+ {
+ bars = new(5000);
+ period = rnd.Next(28) + 3;
+ TALIB = new double[bars.Count];
+ TALIB2 = new double[bars.Count];
+ inopen = bars.Open.v.ToArray();
+ inhigh = bars.High.v.ToArray();
+ inlow = bars.Low.v.ToArray();
+ inclose = bars.Close.v.ToArray();
+ involume = bars.Volume.v.ToArray();
+ }
+
+ /////////////////////////////////////////
+
+ [Fact]
+ public void ADD()
+ {
+ ADD_Series QL = new(bars.Open, bars.Close);
+ Core.Add(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void SUB()
+ {
+ SUB_Series QL = new(bars.Open, bars.Close);
+ Core.Sub(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void MUL()
+ {
+ MUL_Series QL = new(bars.Open, bars.Close);
+ Core.Mult(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void DIV()
+ {
+ DIV_Series QL = new(bars.Open, bars.Close);
+ Core.Div(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void CORR()
+ {
+ CORR_Series QL = new(bars.Open, bars.Close, period);
+ Core.Correl(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, optInTimePeriod: period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void SDEV()
+ {
+ SDEV_Series QL = new(bars.Close, period, false);
+ Core.StdDev(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void SMA()
+ {
+ SMA_Series QL = new(bars.Close, period, false);
+ Core.Sma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void SUM()
+ {
+ SUM_Series QL = new(bars.Close, period, false);
+ Core.Sum(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void MIDPRICE()
+ {
+ MIDPRICE_Series QL = new(bars, period, false);
+ Core.MidPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+
+ [Fact]
+ public void VAR()
+ {
+ VAR_Series QL = new(bars.Close, period, false);
+ Core.Var(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 4, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 4));
+ }
+
+ [Fact]
+ public void MIDPOINT()
+ {
+ MIDPOINT_Series QL = new(bars.Close, period, false);
+ Core.MidPoint(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+
+ [Fact]
+ public void MAMA() {
+ MAMA_Series QL = new(bars.Close, fastlimit: 0.5, slowlimit: 0.05);
+ Core.Mama(inReal: inclose, startIdx: 0, endIdx: bars.Count - 1, outMama: TALIB, outFama: TALIB2, outBegIdx: out int outBegIdx, outNbElement: out _, optInFastLimit: 0.5, optInSlowLimit: 0.05);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void TRIMA()
+ {
+ TRIMA_Series QL = new(bars.Close, period, false);
+ Core.Trima(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void EMA()
+ {
+ EMA_Series QL = new(bars.Close, period, false);
+ Core.Ema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void WMA()
+ {
+ WMA_Series QL = new(bars.Close, period, false);
+ Core.Wma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void DEMA()
+ {
+ DEMA_Series QL = new(bars.Close, period, false);
+ Core.Dema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void TEMA()
+ {
+ TEMA_Series QL = new(bars.Close, period, false);
+ Core.Tema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void MAX()
+ {
+ MAX_Series QL = new(bars.Close, period, false);
+ Core.Max(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void MIN()
+ {
+ MIN_Series QL = new(bars.Close, period, false);
+ Core.Min(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void ADL()
+ {
+ ADL_Series QL = new(bars, false);
+ Core.Ad(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void OBV()
+ {
+ OBV_Series QL = new(bars, period, false);
+ Core.Obv(inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void ADOSC()
+ {
+ ADOSC_Series QL = new(bars, false);
+ Core.AdOsc(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void ATR()
+ {
+ ATR_Series QL = new(bars, period, false);
+ Core.Atr(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void CCI()
+ {
+ CCI_Series QL = new(bars, period, false);
+ Core.Cci(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void RSI()
+ {
+ RSI_Series QL = new(bars.Close, period, false);
+ Core.Rsi(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void TR()
+ {
+ TR_Series QL = new(bars, false);
+ Core.TRange(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void MACD()
+ {
+ double[] macdSignal = new double[bars.Count];
+ double[] macdHist = new double[bars.Count];
+ MACD_Series QL = new(bars.Close, slow: 26, fast: 12, signal: 9, false);
+ Core.Macd(inclose, 0, bars.Count - 1, outMacd: TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _);
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Signal.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void BBANDS()
+ {
+ double[] outMiddle = new double[bars.Count];
+ double[] outUpper = new double[bars.Count];
+ double[] outLower = new double[bars.Count];
+ BBANDS_Series QL = new(bars.Close, period: 26, multiplier: 2.0, false);
+ Core.Bbands(inclose, 0, bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod: 26, optInNbDevUp: 2.0, optInNbDevDn: 2.0);
+ Assert.Equal(Math.Round(outUpper[outUpper.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Upper.Last().v, 6, MidpointRounding.AwayFromZero));
+ Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Mid.Last().v, 6, MidpointRounding.AwayFromZero));
+ Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Lower.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void HL2()
+ {
+ TSeries QL = bars.HL2;
+ Core.MedPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void HLC3()
+ {
+ TSeries QL = bars.HLC3;
+ Core.TypPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void OHLC4()
+ {
+ TSeries QL = bars.OHLC4;
+ Core.AvgPrice(inopen, inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+ [Fact]
+ public void HLCC4()
+ {
+ TSeries QL = bars.HLCC4;
+ Core.WclPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
+
+ Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
+ }
+
+}
diff --git a/docs/readme.md b/docs/readme.md
index 3ab89f97..4ff10d2f 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -17,7 +17,6 @@ Quantitative TA Library (**QuanTAlib**) is an easy-to-use C# library for quantit
**QuanTAlib** is written with some specific design criteria in mind - some reasons why there is '_yet another C# TA library_':
- Written in native C# - no code conversion from TA-LIB or other imported/converted TA libraries
-- No usage of Decimal datatypes, LINQ, interface abstractions, or static classes with tons of methods (all for performance reasons)
- Supports both **historical data analysis** (working on bulk of historical arrays) and **real-time analysis** (adding one data item at the time without the need to re-calculate the whole history)
- Calculate early data right - no hiding of incomplete calculations with NaN values (unless explicitly requested with useNan: true), data is as valid as mathematically possible from the first value
- Usage of events - each data series is an event publisher, each indicator is a subscriber - this allows seamless data flow between indicators)
@@ -57,8 +56,8 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
| ⭐ BIAS - Bias | `BIAS_Series` ||| bias |
| ⭐ CORR - Pearson's Correlation Coefficient | `CORR_Series` | CORREL | GetCorrelation ||
| ⭐ COVAR - Covariance | `COVAR_Series` || GetCorrelation ||
-| ⭐ ENTP - Entropy | `ENTP_Series` ||| entropy |
-| ⭐ KURT - Kurtosis | `KURT_Series` ||| kurtosis |
+| ⭐ ENTROPY - Entropy | `ENTROPY_Series` ||| entropy |
+| ⭐ KURTOSIS - Kurtosis | `KURT_Series` ||| kurtosis |
| ⭐ LINREG - Linear Regression | `LINREG_Series` || GetSlope ||
| ⭐ MAD - Mean Absolute Deviation | `MAD_Series` || GetSma | mad |
| ⭐ MAPE - Mean Absolute Percent Error | `MAPE_Series` || GetSma ||