diff --git a/.github/workflows/main_automation.yml b/.github/workflows/main_automation.yml
index 0f91fe12..85a883a4 100644
--- a/.github/workflows/main_automation.yml
+++ b/.github/workflows/main_automation.yml
@@ -65,7 +65,7 @@ jobs:
run: dotnet sonarscanner begin /o:"mihakralj" /k:"mihakralj_QuanTAlib"
/d:sonar.login="${{ secrets.SONAR_TOKEN }}"
/d:sonar.host.url="https://sonarcloud.io"
- /d:sonar.cs.dotcover.reportsPaths=./dotcover.xml
+ /d:sonar.cs.dotcover.reportsPaths=dotcover*
############# Build and test
@@ -80,8 +80,10 @@ jobs:
- name: Build Strategies DLL
run: dotnet build ./Strategies/Strategies.csproj --configuration Release --nologo
- - name: DotCover Test
- run: dotnet dotcover test Tests/Tests.csproj --dcReportType=DetailedXML --dcReportType=HTML --dcoutput=dotcover.xml --dcoutput=dotcover.html
+ - name: DotCover Test HTML
+ run: dotnet dotcover test Tests/Tests.csproj --dcReportType=HTML --dcoutput=./dotcover.html
+ - name: DotCover Test XML
+ run: dotnet dotcover test Tests/Tests.csproj --dcReportType=DetailedXML --dcoutput=./dotcover.xml --verbosity=Detailed
- name: Coverlet Test
run: dotnet test -p:CollectCoverage=true --collect:"XPlat Code Coverage" --results-directory "./"
diff --git a/Calculations/Statistics/CORR_Series.cs b/Calculations/Basics/CORR_Series.cs
similarity index 100%
rename from Calculations/Statistics/CORR_Series.cs
rename to Calculations/Basics/CORR_Series.cs
diff --git a/Calculations/Statistics/COVAR_Series.cs b/Calculations/Basics/COVAR_Series.cs
similarity index 77%
rename from Calculations/Statistics/COVAR_Series.cs
rename to Calculations/Basics/COVAR_Series.cs
index 8fd20b47..3826ee9d 100644
--- a/Calculations/Statistics/COVAR_Series.cs
+++ b/Calculations/Basics/COVAR_Series.cs
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
+using System.Collections.Generic;
using System.Linq;
/*
@@ -12,11 +13,16 @@ Sources:
*/
+
public class COVAR_Series : Pair_TSeries_Indicator
{
public COVAR_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); } }
+ 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();
@@ -25,9 +31,9 @@ public class COVAR_Series : Pair_TSeries_Indicator
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(_y, TValue2.v, _p, update);
- Add_Replace_Trim(_xy, TValue1.v * TValue2.v, _p, update);
+ BufferTrim(_x, TValue1.v, _p, update);
+ BufferTrim(_y, TValue2.v, _p, update);
+ BufferTrim(_xy, TValue1.v * TValue2.v, _p, update);
double _avgx = _x.Average();
double _avgy = _y.Average();
@@ -37,4 +43,4 @@ public class COVAR_Series : Pair_TSeries_Indicator
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/Calculations/Basics/MIDPRICE_Series.cs b/Calculations/Basics/MIDPRICE_Series.cs
deleted file mode 100644
index c3a3c444..00000000
--- a/Calculations/Basics/MIDPRICE_Series.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-namespace QuanTAlib;
-using System;
-using System.Linq;
-
-/*
-MIDPRICE: Midpoint price (highhest high + lowest low)/2 in the given period in the series.
- If period = 0 => period = full length of the series
-
- */
-
-public class MIDPRICE_Series : Single_TBars_Indicator
-{
- public MIDPRICE_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN)
- {
- if (base._bars.Count > 0)
- { base.Add(base._bars); }
- }
- private readonly System.Collections.Generic.List _bufferhi = new();
- private readonly System.Collections.Generic.List _bufferlo = new();
-
- public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
- {
- Add_Replace_Trim(_bufferhi, TBar.h, _p, update);
- Add_Replace_Trim(_bufferlo, TBar.l, _p, update);
-
- double _max = _bufferhi.Max();
- double _min = _bufferlo.Min();
- double _mid = (_max + _min) * 0.5;
-
- base.Add((TBar.t, _mid), update, _NaN);
- }
-}
\ No newline at end of file
diff --git a/Calculations/Basics/TR_Series.cs b/Calculations/Basics/TR_Series.cs
deleted file mode 100644
index 6f4c2391..00000000
--- a/Calculations/Basics/TR_Series.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-namespace QuanTAlib;
-using System;
-
-/*
-TR: True Range
- True Range was introduced by J. Welles Wilder in his book New Concepts in Technical Trading Systems.
- It measures the daily range plus any gap from the closing price of the preceding day.
-
-Calculation:
- d1 = ABS(High - Low)
- d2 = ABS(High - Previous close)
- d3 = ABS(Previous close - Low)
- TR = MAX(d1,d2,d3)
-
-Sources:
- https://www.macroption.com/true-range/
-
- */
-
-public class TR_Series : Single_TBars_Indicator
-{
- private double _cm1, _cm1_o;
- public TR_Series(TBars source, bool useNaN = false) : base(source, period:0, useNaN:useNaN) {
- _cm1 =_cm1_o = double.NaN;
- if (this._bars.Count > 0) { base.Add(this._bars); }
- }
-
- public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
- {
- if (update) {_cm1 = _cm1_o; } else { _cm1_o = _cm1; }
- if (_cm1 is double.NaN) { _cm1 = TBar.c; } //first bar
-
- double d1 = Math.Abs(TBar.h - TBar.l);
- double d2 = Math.Abs(_cm1 - TBar.h);
- double d3 = Math.Abs(_cm1 - TBar.l);
- var ret = (TBar.t, (base.Count==0 && base._NaN) ? double.NaN : Math.Max(d1,Math.Max(d2,d3)) );
- base.Add(ret, update);
- _cm1 = TBar.c;
- }
-}
\ No newline at end of file
diff --git a/Calculations/ClassStructures/Pair_TSeries_Abstract.cs b/Calculations/ClassStructures/Pair_TSeries_Abstract.cs
index 564a9e39..2203d3f1 100644
--- a/Calculations/ClassStructures/Pair_TSeries_Abstract.cs
+++ b/Calculations/ClassStructures/Pair_TSeries_Abstract.cs
@@ -16,97 +16,117 @@ Abstract classes with all scaffolding required to build indicators.
*/
+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;
-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) {
+ _p = period;
+ _NaN = useNaN;
+ _d1 = source1;
+ _d2 = source2;
+ _dd1 = double.NaN;
+ _dd2 = double.NaN;
+ _d1.Pub += Sub;
+ _d2.Pub += Sub;
+ }
- // 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;
- }
+ protected Pair_TSeries_Indicator(TSeries source1, TSeries source2) {
+ _d1 = source1;
+ _d2 = source2;
+ _dd1 = double.NaN;
+ _dd2 = double.NaN;
+ _d1.Pub += Sub;
+ _d2.Pub += 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
+ protected Pair_TSeries_Indicator(TSeries source1, double dd2) {
+ _d1 = source1;
+ _d2 = new TSeries();
+ _dd1 = double.NaN;
+ _dd2 = dd2;
+ _d1.Pub += Sub;
+ }
- // 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); }}
+ protected Pair_TSeries_Indicator(double dd1, TSeries source2) {
+ _d1 = new TSeries();
+ _d2 = source2;
+ _dd1 = dd1;
+ _dd2 = double.NaN;
+ _d2.Pub += Sub;
+ }
- public void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2) => this.Add(TValue1, TValue2, update: false);
+ // overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list
+ public virtual void Add((DateTime t, double v) TValue1, (DateTime t, double v) TValue2, bool update) {
+ base.Add((TValue1.t, 0), update);
+ // default inserts zeros
+ }
- 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);
+ // potentially overridable Add() bulk variations (could be replaced with faster bulk algos)
+ public virtual void Add(TSeries d1, TSeries d2) {
+ for (var i = 0; i < d1.Count; i++) {
+ Add(d1[i], d2[i], false);
}
}
- public void Add() => this.Add(update: false);
- public new void Sub(object source, TSeriesEventArgs e) => this.Add(e.update);
+ public virtual void Add(TSeries d1, double dd2) {
+ for (var i = 0; i < d1.Count; i++) {
+ Add(d1[i], (d1[i].t, dd2), false);
+ }
+ }
- 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); }
- }
+ public virtual void Add(double dd1, TSeries d2) {
+ for (var i = 0; i < d2.Count; i++) {
+ Add((d2[i].t, dd1), d2[i], false);
+ }
+ }
+
+ public void Add((DateTime t, double v) TValue1, (DateTime t, double v) TValue2) {
+ Add(TValue1, TValue2, false);
+ }
+
+ public void Add(bool update) {
+ if (_dd1 is double.NaN && _dd2 is double.NaN) {
+ // (Series, Series)
+ if (update || (_d1.Count > Count && _d2.Count > Count)) {
+ Add(_d1[_d1.Count - 1], _d2[_d2.Count - 1], update);
+ }
+ }
+ else if (_dd2 is not double.NaN && _dd1 is double.NaN) {
+ // (Series, Double)
+ Add(_d1[_d1.Count - 1], (_d1[_d1.Count - 1].t, _dd2), update);
+ }
+ else {
+ // (Double, Series)
+ Add((_d2[_d2.Count - 1].t, _dd1), _d2[_d2.Count - 1], update);
+ }
+ }
+
+ public void Add() {
+ Add(false);
+ }
+
+ public new void Sub(object source, TSeriesEventArgs e) {
+ 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/Calculations/ClassStructures/Single_TBars_Abstract.cs b/Calculations/ClassStructures/Single_TBars_Abstract.cs
deleted file mode 100644
index 1d3c8ac8..00000000
--- a/Calculations/ClassStructures/Single_TBars_Abstract.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-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 new 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/Calculations/ClassStructures/Single_TSeries_Abstract.cs b/Calculations/ClassStructures/Single_TSeries_Abstract.cs
deleted file mode 100644
index ca8d3d89..00000000
--- a/Calculations/ClassStructures/Single_TSeries_Abstract.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-namespace QuanTAlib;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-/*
-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 _period;
- protected readonly bool _NaN;
- protected readonly TSeries _data;
- protected int _p;
-
- // 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)
- {
- _data = source;
- _period = period;
- _p = _period;
- _NaN = useNaN;
- _data.Pub += Sub;
- }
-
- // overridable Add() method to add/update a single item at the end of the list
-
- public virtual void Add((DateTime t, double v) TValue, bool update, bool useNaN)
- {
- if (_period == 0) { _p = Length; }
- var res = (TValue.t, Count < _p - 1 && _NaN ? double.NaN : TValue.v);
- base.Add(res, update);
- }
- public new virtual void Add((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 new void Add(TSeries data)
- {
- foreach (var item in data) { Add(TValue: item, 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 double Add_Replace_Trim(List l, double v, int p, bool update)
- {
- Add_Replace(l, v, update);
- double ret = (l.Count > 0) ? l.First() : 0;
- if (l.Count > p && p != 0)
- {
- l.RemoveAt(0);
- }
- return ret;
- }
-}
diff --git a/Calculations/Logic/EQUITY_Series.cs b/Calculations/Logic/EQUITY_Series.cs
index 50313152..78e8fa0d 100644
--- a/Calculations/Logic/EQUITY_Series.cs
+++ b/Calculations/Logic/EQUITY_Series.cs
@@ -12,6 +12,8 @@ EQUITY - Generates P&L portfolio based on trades signals and equity prices
//optional: long, short, long&short
//optional: warmup period: warmup
+/*
+
public class EQUITY_Series : Single_TSeries_Indicator {
readonly TSeries inmarket; //for every bar
private readonly TSeries _price;
@@ -84,4 +86,6 @@ public class EQUITY_Series : Single_TSeries_Indicator {
inmarket.Add((TValue.t, (double)_inmarket));
base.Add((TValue.t, _equity), update, _NaN);
}
-}
\ No newline at end of file
+}
+
+*/
\ No newline at end of file
diff --git a/Calculations/ClassStructures/TOrders.cs b/Calculations/Logic/TOrders.cs
similarity index 100%
rename from Calculations/ClassStructures/TOrders.cs
rename to Calculations/Logic/TOrders.cs
diff --git a/Calculations/Statistics/LINREG_Series.cs b/Calculations/Statistics/LINREG_Series.cs
deleted file mode 100644
index 96458c54..00000000
--- a/Calculations/Statistics/LINREG_Series.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-namespace QuanTAlib;
-using System;
-
-/*
-LINREG: Linear Regression (using Least Square Method)
- Linear Regression provides a slope of a straight line that is the best approximation of the given set of data.
- The method of least squares is a standard approach in linear regression analysis to approximate the solution
- by minimizing the sum of the squares of the residuals made in the results of each individual equation.
-
-Additional outputs provided by LINREG:
- .Intercept - y-intercept point of the best fit line
- .RSquared - R-Squared (R²), Coefficient of Determination
- .StdDev - Standard Deviation of data over given periods
-
- y = Slope * x + Intercept
-
-Sources:
- https://en.wikipedia.org/wiki/Least_squares
-
- */
-
-public class LINREG_Series : Single_TSeries_Indicator
-{
- private readonly TSeries p_Intercept = new();
- private readonly TSeries p_RSquared = new();
- private readonly TSeries p_StdDev = new();
- private readonly System.Collections.Generic.List _buffer = new();
- public TSeries Intercept => p_Intercept;
- public TSeries RSquared => p_RSquared;
- public TSeries StdDev => p_StdDev;
-public LINREG_Series(TSeries source, int period, bool useNaN = false)
- : base(source, period, useNaN)
- {
- if (this._data.Count > 0) { base.Add(this._data); }
- }
-
- public override void Add((System.DateTime t, double v) TValue, bool update)
- {
- Add_Replace_Trim(_buffer, TValue.v, _p, update);
-
- int _len = this._buffer.Count;
-
- // get averages for period
- double sumX = 0;
- double sumY = 0;
-
- for (int p = 0; p < _len; p++)
- {
- sumX += this.Count - _len + 2 + p;
- sumY += _buffer[p];
- }
- double avgX = sumX / _len;
- double avgY = sumY / _len;
-
- // least squares method
- double sumSqX = 0;
- double sumSqY = 0;
- double sumSqXY = 0;
-
- for (int p = 0; p < _len; p++)
- {
- double devX = this.Count - _len + 2 + p - avgX;
- double devY = _buffer[p] - avgY;
-
- sumSqX += devX * devX;
- sumSqY += devY * devY;
- sumSqXY += devX * devY;
- }
-
- double _slope = sumSqXY / sumSqX;
- double _intercept = avgY - (_slope * avgX);
-
- // calculate Standard Deviation and R-Squared
- double stdDevX = Math.Sqrt(sumSqX / _len);
- double stdDevY = Math.Sqrt(sumSqY / _len);
- double _StdDev = stdDevY;
-
- double arrr = (stdDevX * stdDevY != 0) ? sumSqXY / (stdDevX * stdDevY) / _len : 0;
- double _RSquared = arrr * arrr;
-
- var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _slope);
- base.Add(ret, update, _NaN);
-
- ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _intercept);
- p_Intercept.Add(ret, update);
-
- ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _StdDev);
- p_StdDev.Add(ret, update);
-
- ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _RSquared);
- p_RSquared.Add(ret, update);
- }
-}
\ No newline at end of file
diff --git a/Calculations/Trends/CCI_Series.cs b/Calculations/Trends/CCI_Series.cs
deleted file mode 100644
index aa3505b3..00000000
--- a/Calculations/Trends/CCI_Series.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-namespace QuanTAlib;
-using System;
-using System.Linq;
-using static System.Net.Mime.MediaTypeNames;
-
-/*
-CCI: Commodity Channel Index
- Commodity Channel Index is a momentum oscillator used to primarily identify overbought
- and oversold levels relative to a mean. CCI measures the current price level relative
- to an average price level over a given period of time:
- - CCI is relatively high when prices are far above their average.
- - CCI is relatively low when prices are far below their average.
- Using this method, CCI can be used to identify overbought and oversold levels.
-
-Sources:
- https://www.investopedia.com/terms/c/commoditychannelindex.asp
- https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/cci
-
- */
-
-public class CCI_Series : Single_TBars_Indicator
-{
- private readonly System.Collections.Generic.List _tp = new();
-
- public CCI_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN)
- {
- if (_bars.Count > 0) { base.Add(_bars); }
- }
-
- public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
- {
- double _tpItem = (TBar.h + TBar.l + TBar.c) / 3.0;
- if (update) { this._tp[this._tp.Count - 1] = _tpItem; } else { this._tp.Add(_tpItem); }
- if (this._tp.Count > this._p) { this._tp.RemoveAt(0); }
-
- // average TP over _tp buffer
- 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);
-
- base.Add((TBar.t, _cci), update, _NaN);
- }
-}
\ No newline at end of file
diff --git a/Calculations/Trends/HWMA_Series.cs b/Calculations/Trends/HWMA_Series.cs
deleted file mode 100644
index f2ba9ae3..00000000
--- a/Calculations/Trends/HWMA_Series.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-namespace QuanTAlib;
-using System;
-
-/*
-HWMA: Holt-Winter Moving Average
- Indicator HWMA (Holt-Winter Moving Average) is a three-parameter moving
- average by the Holt-Winter method; Holt-Winters Exponential Smoothing is
- used for forecasting time series data that exhibits both a trend and a
- seasonal variation.
-
-
-Sources:
- https://timeseriesreasoning.com/contents/holt-winters-exponential-smoothing/
- https://www.mql5.com/en/code/20856
-
-nA - smoothed series (from 0 to 1)
-nB - assess the trend (from 0 to 1)
-nC - assess seasonality (from 0 to 1)
-
-F[i] = (1-nA) * (F[i-1] + V[i-1] + 0.5 * A[i-1]) + nA * Price[i]
-V[i] = (1-nB) * (V[i-1] + A[i-1]) + nB * (F[i] - F[i-1])
-A[i] = (1-nC) * A[i-1] + nC * (V[i] - V[i-1])
-HWMA[i] = F[i] + V[i] + 0.5 * A[i]
-
- */
-
-public class HWMA_Series : Single_TSeries_Indicator {
- readonly double _nA, _nB, _nC;
- double _pF, _pV, _pA;
- double _ppF, _ppV, _ppA;
-
- public HWMA_Series(TSeries source, double nA = 0.2, double nB = 0.1, double nC = 0.1, bool useNaN = false) : base(source, 0, useNaN) {
-
- _nA = nA;
- _nB = nB;
- _nC = nC;
- if (this._data.Count > 0) { base.Add(this._data); }
- }
- public override void Add((DateTime t, double v) TValue, bool update) {
- double _F, _V, _A;
- if (this.Count == 0) { _pF = TValue.v; _pA = _pV = 0; }
-
- if (update) { _pF = _ppF; _pV = _ppV; _pA = _ppA; }
- else { _ppF = _pF; _ppV = _pV; _ppA = _pA; }
-
- _F = (1 - _nA) * (_pF + _pV + 0.5 * _pA) + _nA * TValue.v;
- _V = (1 - _nB) * (_pV + _pA) + _nB * (_F - _pF);
- _A = (1 - _nC) * _pA + _nC * (_V - _pV);
-
- double _hwma = _F + _V + 0.5 * _A;
- _pF = _F;
- _pV = _V;
- _pA = _A;
-
- base.Add((TValue.t, _hwma), update, _NaN);
- }
-}
diff --git a/Calculations/Trends/MACD_Series.cs b/Calculations/Trends/MACD_Series.cs
deleted file mode 100644
index 02f9360c..00000000
--- a/Calculations/Trends/MACD_Series.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-namespace QuanTAlib;
-using System;
-
-/*
-MACD: Moving Average Convergence/Divergence
- Moving average convergence divergence (MACD) is a trend-following momentum
- indicator that shows the relationship between two moving averages of a series.
- The MACD is calculated by subtracting the 26-period exponential moving average (EMA)
- from the 12-period EMA. MACD Signal is 9-day EMA of MACD.
-
-Sources:
- https://www.investopedia.com/terms/m/macd.asp
- https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/macd
-
- */
-
-public class MACD_Series : Single_TSeries_Indicator
-{
- private readonly EMA_Series _TSslow;
- private readonly EMA_Series _TSfast;
- private readonly SUB_Series _TSmacd;
- public EMA_Series Signal { get; }
-
- public MACD_Series(TSeries source, int slow = 26, int fast = 12, int signal = 9, bool useNaN = false)
- : base(source, period: 0, useNaN)
- {
- _TSslow = new(source: source, period: slow, useNaN: false);
- _TSfast = new(source: source, period: fast, useNaN: false);
- _TSmacd = new(_TSfast, _TSslow);
- this.Signal = new(source: _TSmacd, period: signal, useNaN: useNaN);
-
- if (source.Count > 0) { base.Add(_TSmacd); }
- }
- public override void Add((System.DateTime t, double v) TValue, bool update)
- {
- double _macd;
- if (update)
- {
- _TSslow.Add(TValue, true);
- _TSfast.Add(TValue, true);
- }
- _macd = this._TSmacd[(this.Count < this._TSmacd.Count) ? this.Count : this._TSmacd.Count - 1].v;
- base.Add((TValue.t, _macd), update, _NaN);
- }
-}
\ No newline at end of file
diff --git a/Calculations/Trends/MAMA_Series.cs b/Calculations/Trends/MAMA_Series.cs
deleted file mode 100644
index 5a04d341..00000000
--- a/Calculations/Trends/MAMA_Series.cs
+++ /dev/null
@@ -1,158 +0,0 @@
-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, 5, useNaN) {
- fastl = fastlimit;
- slowl = slowlimit;
- Fama = new TSeries();
- if (_data.Count > 0) {
- base.Add(_data);
- }
- }
-
- private double sumPr, jI, jQ;
- private readonly double 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 TSeries Fama { get; }
-
- public override void Add((DateTime t, double v) TValue, bool update) {
- if (!update) {
- // roll forward (oldx = x)
- 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;
- }
-
- var i = Count;
- pr.i = TValue.v;
- if (i > 5) {
- var 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
- var delta = Math.Max(ph.i1 - ph.i, 1d);
-
- // adaptive alpha value
- var 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);
- }
-
- base.Add((TValue.t, mama.i), update, _NaN);
- var result = (TValue.t, Count < _p - 1 && _NaN ? double.NaN : fama.i);
- Fama.Add(result, update);
- }
-}
diff --git a/Calculations/Volatility/ADL_Series.cs b/Calculations/Volatility/ADL_Series.cs
deleted file mode 100644
index 0eb43ec2..00000000
--- a/Calculations/Volatility/ADL_Series.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-namespace QuanTAlib;
-using System;
-
-/*
-ADL: Chaikin Accumulation/Distribution Line
- ADL is a volume-based indicator that measures the cumulative Money Flow Volume:
-
- 1. Money Flow Multiplier = [(Close - Low) - (High - Close)] /(High - Low)
- 2. Money Flow Volume = Money Flow Multiplier x Volume for the Period
- 3. ADL = Previous ADL + Current Period's Money Flow Volume
-
-Sources:
- https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line
-
- */
-
-public class ADL_Series : Single_TBars_Indicator
-{
- private double _lastadl, _lastlastadl;
-
- public ADL_Series(TBars source, bool useNaN = false) : base(source, 0, useNaN)
- {
- _lastadl = _lastlastadl = 0;
- if (_bars.Count > 0) { base.Add(_bars); }
- }
-
- public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
- {
- if (update) { this._lastadl = this._lastlastadl; }
-
- double _adl = 0;
- double tmp = TBar.h - TBar.l;
- if (tmp > 0.0 ) { _adl = _lastadl + ((2*TBar.c - TBar.l - TBar.h) / tmp * TBar.v); }
-
- this._lastlastadl = this._lastadl;
- this._lastadl = _adl;
-
- base.Add((TBar.t, _adl), update, _NaN);
- }
-}
\ No newline at end of file
diff --git a/Calculations/Volatility/ADOSC_Series.cs b/Calculations/Volatility/ADOSC_Series.cs
deleted file mode 100644
index 797e1f85..00000000
--- a/Calculations/Volatility/ADOSC_Series.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-namespace QuanTAlib;
-using System;
-
-/*
-ADO: Chaikin Accumulation/Distribution Oscillator
- ADO measures the momentum of ADL using the difference between slow (10-day) EMA(ADL)
- and fast (3-day) EMA(ADL):
-
- Chaikin A/D Oscillator is defined as 3-day EMA of ADL minus 10-day EMA of ADL
-
-Sources:
- https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_oscillator
-
- */
-
-
-public class ADOSC_Series : Single_TBars_Indicator
-{
- private readonly double _k1, _k2;
- private double _lastema1, _lastlastema1, _lastema2, _lastlastema2;
- private double _lastadl, _lastlastadl;
-
- public ADOSC_Series(TBars source, int shortPeriod = 3, int longPeriod =10, bool useNaN = false) : base(source, period: 0, useNaN)
- {
- _k1 = 2.0 / (shortPeriod + 1);
- _k2 = 2.0 / (longPeriod + 1);
- _lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
- if (_bars.Count > 0) { base.Add(_bars); }
- }
-
- public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
- {
- if (update) {
- _lastadl = _lastlastadl;
- _lastema1 = _lastlastema1;
- _lastema2 = _lastlastema2;
- }
-
- double _adl = 0;
- double tmp = TBar.h - TBar.l;
- if (tmp > 0.0) { _adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v); }
- if (this.Count == 0) { _lastema1 = _lastema2 = _adl; }
-
- double _ema1 = (_adl - _lastema1) * _k1 + _lastema1;
- double _ema2 = (_adl - _lastema2) * _k2 + _lastema2;
-
- _lastlastadl = _lastadl; _lastadl = _adl;
- _lastlastema1 = _lastema1; _lastema1 = _ema1;
- _lastlastema2 = _lastema2; _lastema2 = _ema2;
-
- double _adosc = _ema1 - _ema2;
- base.Add((TBar.t, _adosc), update, _NaN);
- }
-
-}
diff --git a/Calculations/Volatility/ATRP_Series.cs b/Calculations/Volatility/ATRP_Series.cs
deleted file mode 100644
index 3f4457ea..00000000
--- a/Calculations/Volatility/ATRP_Series.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-namespace QuanTAlib;
-using System;
-
-/*
-ATRP: Average True Range Percent
- Average True Range Percent is (ATR/Close Price)*100.
- This normalizes so it can be compared to other stocks.
-
-Sources:
- https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/atrp
-
- */
-
-public class ATRP_Series : Single_TBars_Indicator {
- private readonly System.Collections.Generic.List _buffer = new();
- private readonly double _k;
- private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
- private readonly int _period;
-
- public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) {
- _period = period;
- _k = 1.0 / (double)(_period);
- _lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0;
- if (this._bars.Count > 0) { base.Add(this._bars); }
- }
-
- public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) {
- if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
- else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; }
-
- if (this.Count == 0) { _cm1 = TBar.c; }
- double d1 = Math.Abs(TBar.h - TBar.l);
- double d2 = Math.Abs(_cm1 - TBar.h);
- double d3 = Math.Abs(_cm1 - TBar.l);
- (DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
- _cm1 = TBar.c;
-
- double _atr = 0;
- if (this.Count == 0) { _atr = d.v; }
- else if (this.Count < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); }
- else { _atr = _k * (d.v - _lastatr) + _lastatr; }
- _lastatr = _atr;
-
- double _atrp = 100 * (_atr / TBar.c);
- var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atrp);
- base.Add(ret, update);
- }
-}
diff --git a/Calculations/Volatility/ATR_Series.cs b/Calculations/Volatility/ATR_Series.cs
deleted file mode 100644
index bc641e92..00000000
--- a/Calculations/Volatility/ATR_Series.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-namespace QuanTAlib;
-using System;
-
-/*
-ATR: wildeR Moving Average
- The average true range (ATR) is a price volatility indicator
- showing the average price variation of assets within a given time period.
-
-Sources:
- https://en.wikipedia.org/wiki/Average_true_range
- https://www.tradingview.com/wiki/Average_True_Range_(ATR)
- https://www.investopedia.com/terms/a/atr.asp
-
- */
-
-public class ATR_Series : Single_TBars_Indicator {
- private readonly System.Collections.Generic.List _buffer = new();
- private readonly double _k;
- private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
- private readonly int _period;
-
- public ATR_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) {
- _period = period;
- _k = 1.0 / (double)(_p);
- _lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0;
- if (this._bars.Count > 0) { base.Add(this._bars); }
- }
-
- public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) {
- if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
- else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; }
-
- if (this.Count == 0) { _cm1 = TBar.c; }
- double d1 = Math.Abs(TBar.h - TBar.l);
- double d2 = Math.Abs(_cm1 - TBar.h);
- double d3 = Math.Abs(_cm1 - TBar.l);
- (DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
- _cm1 = TBar.c;
-
- double _atr = 0;
- if (this.Count == 0) { _atr = d.v; }
- else if (this.Count < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); }
- else { _atr = _k * (d.v - _lastatr) + _lastatr; }
- _lastatr = _atr;
-
- var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atr);
- base.Add(ret, update);
- }
-}
\ No newline at end of file
diff --git a/Calculations/Volatility/BBANDS_Series.cs b/Calculations/Volatility/BBANDS_Series.cs
deleted file mode 100644
index 169f8f35..00000000
--- a/Calculations/Volatility/BBANDS_Series.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-namespace QuanTAlib;
-using System;
-
-/*
-BBANDS: Bollinger Bands®
- Price channels created by John Bollinger, depict volatility as standard deviation boundary
- line range from a moving average of price. The bands automatically widen when volatility
- increases and contract when volatility decreases. Their dynamic nature allows them to be
- used on different securities with the standard settings.
-
- Mid Band = simple moving average (SMA)
- Upper Band = SMA + (standard deviation of price x multiplier)
- Lower Band = SMA - (standard deviation of price x multiplier)
- Bandwidth = Width of the channel: (Upper-Lower)/SMA
- %B = The location of the data point within the channel: (Price-Lower)/(Upper/Lower)
- Z-Score = number of standard deviations of the data point from SMA
-
-Sources:
- https://www.investopedia.com/terms/b/bollingerbands.asp
- https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands
-
-Note:
- Bollinger Bands® is a registered trademark of John A. Bollinger.
-
- */
-
-public class BBANDS_Series : Single_TSeries_Indicator
-{
- public SMA_Series Mid { get; }
- public ADD_Series Upper { get; }
- public SUB_Series Lower { get; }
- public DIV_Series PercentB { get; }
- public DIV_Series Bandwidth { get; }
- public DIV_Series Zscore { get; }
-
- private readonly SDEV_Series _sdev;
- private readonly MUL_Series _mulsdev;
- private readonly SUB_Series _pbdnd;
- private readonly SUB_Series _pbdvr;
- private readonly SUB_Series _zdnd;
-
- public BBANDS_Series(TSeries source, int period = 26, double multiplier = 2.0, bool useNaN = false)
- : base(source, period: 0, useNaN)
- {
- this.Mid = new(source: source, period: period, useNaN: useNaN);
-
- _sdev = new(source, period, useNaN: useNaN);
- _mulsdev = new(_sdev, multiplier);
- this.Upper = new(Mid, _mulsdev);
- this.Lower = new(Mid, _mulsdev);
-
- _pbdnd = new(source, Lower);
- _pbdvr = new(Upper, Lower);
-
- this.PercentB = new(_pbdnd, _pbdvr);
- this.Bandwidth = new(_pbdvr, Mid);
-
- _zdnd = new(source, Mid);
- this.Zscore = new(_zdnd, _sdev);
-
- if (source.Count > 0)
- { base.Add(this.Bandwidth); }
- }
- public override void Add((System.DateTime t, double v) TValue, bool update)
- {
- double _bbandwidth;
- if (update)
- { _sdev.Add(TValue, true); }
- _bbandwidth = this.Bandwidth[(this.Count < this.Bandwidth.Count) ? this.Count : this.Bandwidth.Count - 1].v;
- var result = (TValue.t, _bbandwidth);
- base.Add(result, update);
- }
-}
\ No newline at end of file
diff --git a/Calculations/Volatility/OBV_Series.cs b/Calculations/Volatility/OBV_Series.cs
deleted file mode 100644
index 73d4e327..00000000
--- a/Calculations/Volatility/OBV_Series.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-namespace QuanTAlib;
-using System;
-
-/*
-OBV: On-Balance Volume
- On-balance volume (OBV) is a technical trading momentum indicator that uses volume flow to predict
- changes in stock price. Joseph Granville first developed the OBV metric in the 1963 book
- Granville's New Key to Stock Market Profits.
-
- | +volume; if close > close[previous]
- OBV = OBV[previous] + | 0; if close = close[previous]
- | -volume; if close < close[previous]
-
-Sources:
- https://www.investopedia.com/terms/o/onbalancevolume.asp
- https://www.tradingview.com/wiki/On_Balance_Volume_(OBV)
- https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/on-balance-volume-obv/
- https://www.motivewave.com/studies/on_balance_volume.htm
-
-Note:
- There is no consensus on what is the first OBV value in the series:
- - TA-LIB uses the first volume: OBV[0] = volume[0]
- - Skender stock library uses 0: OBV[0] = 0
-
- */
-
-public class OBV_Series : Single_TBars_Indicator
-{
- private double _lastobv, _lastlastobv;
- private double _lastclose, _lastlastclose;
- public OBV_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN)
- {
- this._lastobv = this._lastlastobv = 0;
- this._lastclose = this._lastlastclose = 0;
- if (_bars.Count > 0) { base.Add(_bars); }
- }
-
- public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
- {
- if (update)
- {
- this._lastobv = this._lastlastobv;
- this._lastclose = this._lastlastclose;
- }
-
- double _obv = this._lastobv;
- if (TBar.c > this._lastclose) { _obv += TBar.v; }
- if (TBar.c < this._lastclose) { _obv -= TBar.v; }
-
- this._lastlastobv = this._lastobv;
- this._lastobv = _obv;
-
- this._lastlastclose = this._lastclose;
- this._lastclose = TBar.c;
-
- var result = (TBar.t, (this.Count < this._p && this._NaN) ? double.NaN : _obv);
- base.Add(result, update);
- }
-}
diff --git a/Calculations/_Updated/ADL_Series.cs b/Calculations/_Updated/ADL_Series.cs
new file mode 100644
index 00000000..aa33c7b2
--- /dev/null
+++ b/Calculations/_Updated/ADL_Series.cs
@@ -0,0 +1,69 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+ADL: Chaikin Accumulation/Distribution Line
+ ADL is a volume-based indicator that measures the cumulative Money Flow Volume:
+
+ 1. Money Flow Multiplier = [(Close - Low) - (High - Close)] /(High - Low)
+ 2. Money Flow Volume = Money Flow Multiplier x Volume for the Period
+ 3. ADL = Previous ADL + Current Period's Money Flow Volume
+
+Sources:
+ https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line
+
+ */
+
+public class ADL_Series : TSeries {
+ protected readonly TBars _data;
+ private double _lastadl, _lastlastadl;
+
+ //core constructors
+ public ADL_Series() {
+ Name = $"ADL()";
+ _lastadl = _lastlastadl = 0;
+ }
+ public ADL_Series(TBars source) {
+ _data = source;
+ Name = $"ADL({(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _lastadl = _lastlastadl = 0;
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
+ if (update) { this._lastadl = this._lastlastadl; }
+ else { this._lastlastadl = this._lastadl; }
+
+ double _adl = 0;
+ double tmp = TBar.h - TBar.l;
+ if (tmp > 0.0) {
+ _adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v);
+ }
+ _lastadl = _adl;
+
+ var ret = (TBar.t, _adl);
+ return base.Add(ret, update);
+ }
+
+ public new void Add(TBars data) {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset() {
+ _lastadl = _lastlastadl = 0;
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/ADOSC_Series.cs b/Calculations/_Updated/ADOSC_Series.cs
new file mode 100644
index 00000000..63aa2104
--- /dev/null
+++ b/Calculations/_Updated/ADOSC_Series.cs
@@ -0,0 +1,90 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+ADOSC: Chaikin Accumulation/Distribution Oscillator
+ ADO measures the momentum of ADL using the difference between slow (10-day) EMA(ADL)
+ and fast (3-day) EMA(ADL):
+
+ Chaikin A/D Oscillator is defined as 3-day EMA of ADL minus 10-day EMA of ADL
+
+Sources:
+ https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_oscillator
+
+ */
+
+public class ADOSC_Series : TSeries {
+ protected readonly TBars _data;
+ private readonly double _k1, _k2;
+ private double _lastema1, _lastlastema1, _lastema2, _lastlastema2;
+ private double _lastadl, _lastlastadl;
+
+ //core constructors
+ public ADOSC_Series(int shortPeriod, int longPeriod, bool useNaN = false) {
+ Name = $"ADOSC()";
+ _k1 = 2.0 / (shortPeriod + 1);
+ _k2 = 2.0 / (longPeriod + 1);
+ _lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
+ }
+ public ADOSC_Series(TBars source, int shortPeriod, int longPeriod, bool useNaN = false) :this(shortPeriod, longPeriod, useNaN) {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _lastadl = _lastlastadl = 0;
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+
+ public ADOSC_Series() : this(shortPeriod: 3, longPeriod: 10, useNaN: false) {}
+
+ public ADOSC_Series(TBars source) : this(source, shortPeriod: 3, longPeriod:10, useNaN:false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update= false) {
+
+ if (update) {
+ _lastadl = _lastlastadl;
+ _lastema1 = _lastlastema1;
+ _lastema2 = _lastlastema2;
+ }
+
+ double _adl = 0;
+ double tmp = TBar.h - TBar.l;
+ if (tmp > 0.0) { _adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v); }
+ if (this.Count == 0) { _lastema1 = _lastema2 = _adl; }
+
+ double _ema1 = (_adl - _lastema1) * _k1 + _lastema1;
+ double _ema2 = (_adl - _lastema2) * _k2 + _lastema2;
+
+ _lastlastadl = _lastadl;
+ _lastadl = _adl;
+ _lastlastema1 = _lastema1;
+ _lastema1 = _ema1;
+ _lastlastema2 = _lastema2;
+ _lastema2 = _ema2;
+
+ double _adosc = _ema1 - _ema2;
+
+ var ret = (TBar.t, _adosc);
+ return base.Add(ret, update);
+ }
+
+ public new void Add(TBars data) {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset() {
+ _lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/ALMA_Series.cs b/Calculations/_Updated/ALMA_Series.cs
index 18ba3339..514e0e34 100644
--- a/Calculations/_Updated/ALMA_Series.cs
+++ b/Calculations/_Updated/ALMA_Series.cs
@@ -25,12 +25,12 @@ public class ALMA_Series : TSeries {
protected readonly TSeries _data;
private readonly System.Collections.Generic.List _buffer = new();
- private readonly System.Collections.Generic.List _weight = new();
+ private readonly System.Collections.Generic.List _weight;
private double _norm;
private readonly double _offset, _sigma;
//core constructors
- public ALMA_Series(int period, double offset, double sigma, bool useNaN) : base() {
+ public ALMA_Series(int period, double offset, double sigma, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"ALMA({period})";
@@ -55,36 +55,41 @@ public class ALMA_Series : TSeries {
public ALMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, offset: 0.85, sigma: 6.0, useNaN: useNaN) { }
// core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) {
- BufferTrim(_buffer, TValue.v, _period, update);
- if (_weight.Count < _buffer.Count) {
- for (int i = 0; i < (_buffer.Count - _weight.Count); i++) { _weight.Add(0.0); }
- }
- if (this._buffer.Count <= _period || _period ==0) {
- 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;
- }
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
+ if (double.IsNaN(TValue.v)) {
+ return base.Add((TValue.t, double.NaN), update);
}
- double _weightedSum = 0;
- for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; }
- double _alma = _weightedSum / _norm;
+ BufferTrim(_buffer, TValue.v, _period, update);
+ if (_weight.Count < _buffer.Count) {
+ for (var i = 0; i < _buffer.Count - _weight.Count; i++) {
+ _weight.Add(0.0);
+ }
+ }
+
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _alma);
- return base.Add(res, update);
- }
+ if (_buffer.Count <= _period || _period == 0) {
+ var _len = _buffer.Count;
+ _norm = 0;
+ var _m = _offset * (_len - 1);
+ var _s = _len / _sigma;
+ for (var i = 0; i < _len; i++) {
+ var _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
+ _weight[i] = _wt;
+ _norm += _wt;
+ }
+ }
- //reset calculation
- public override void Reset() {
- _buffer.Clear();
- _weight.Clear();
- }
+ double _weightedSum = 0;
+ for (var i = 0; i < _buffer.Count; i++) {
+ _weightedSum += _weight[i] * _buffer[i];
+ }
+
+ var _alma = _weightedSum / _norm;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _alma);
+ return base.Add(res, update);
+ }
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
@@ -92,9 +97,6 @@ public class ALMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
@@ -104,4 +106,9 @@ public class ALMA_Series : TSeries {
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
+ //reset calculation
+ public override void Reset() {
+ _buffer.Clear();
+ _weight.Clear();
+ }
}
\ No newline at end of file
diff --git a/Calculations/_Updated/ATRP_Series.cs b/Calculations/_Updated/ATRP_Series.cs
new file mode 100644
index 00000000..3ba2c1dc
--- /dev/null
+++ b/Calculations/_Updated/ATRP_Series.cs
@@ -0,0 +1,87 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+ATRP: Average True Range Percent
+ Average True Range Percent is (ATR/Close Price)*100.
+ This normalizes so it can be compared to other stocks.
+
+Sources:
+ https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/atrp
+
+ */
+
+public class ATRP_Series : TSeries {
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TBars _data;
+ private double _k;
+ private int _len;
+ private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
+
+ //core constructors
+ public ATRP_Series(int period, bool useNaN) {
+ _period = period;
+ _k = 1.0 / (double)(_period);
+ _NaN = useNaN;
+ _len = 0;
+ Name = $"ATRP({period})";
+ }
+ public ATRP_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+ public ATRP_Series() : this(period: 1, useNaN: false) { }
+ public ATRP_Series(int period) : this(period: period, useNaN: false) { }
+ public ATRP_Series(TBars source) : this(source, period: 1, useNaN: false) { }
+ public ATRP_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
+ if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
+ else {
+ _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum;
+ _k = (_period == 0) ? 1 / (double)_len : _k;
+ _len++;
+ }
+
+ if (_len == 1) { _cm1 = TBar.c; }
+ double d1 = Math.Abs(TBar.h - TBar.l);
+ double d2 = Math.Abs(_cm1 - TBar.h);
+ double d3 = Math.Abs(_cm1 - TBar.l);
+ (DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
+ _cm1 = TBar.c;
+
+ double _atr = 0;
+ if (this.Count == 0) { _atr = d.v; }
+ else if (this.Count < _period + 1) { _sum += d.v; _atr = _sum / (this.Count); }
+ else { _atr = _k * (d.v - _lastatr) + _lastatr; }
+ _lastatr = _atr;
+ double _atrp = 100 * (_atr / TBar.c);
+
+ var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _atrp);
+ return base.Add(res, update);
+ }
+
+ public new void Add(TBars data) {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset() {
+ _len = 0;
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/ATR_Series.cs b/Calculations/_Updated/ATR_Series.cs
new file mode 100644
index 00000000..9935f5c4
--- /dev/null
+++ b/Calculations/_Updated/ATR_Series.cs
@@ -0,0 +1,88 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+ATR: wildeR Moving Average
+ The average true range (ATR) is a price volatility indicator
+ showing the average price variation of assets within a given time period.
+
+Sources:
+ https://en.wikipedia.org/wiki/Average_true_range
+ https://www.tradingview.com/wiki/Average_True_Range_(ATR)
+ https://www.investopedia.com/terms/a/atr.asp
+
+ */
+
+public class ATR_Series : TSeries {
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TBars _data;
+ private double _k;
+ private int _len;
+ private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
+
+ //core constructors
+ public ATR_Series(int period, bool useNaN) {
+ _period = period;
+ _k = 1.0 / (double)(_period);
+ _NaN = useNaN;
+ _len = 0;
+ Name = $"ATR({period})";
+ }
+ public ATR_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+ public ATR_Series() : this(period: 1, useNaN: false) { }
+ public ATR_Series(int period) : this(period: period, useNaN: false) { }
+ public ATR_Series(TBars source) : this(source, period: 1, useNaN: false) { }
+ public ATR_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
+ if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
+ else {
+ _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum;
+ _k = (_period == 0) ? 1 / (double)_len : _k;
+ _len++;
+ }
+
+ if (_len == 1) { _cm1 = TBar.c; }
+ double d1 = Math.Abs(TBar.h - TBar.l);
+ double d2 = Math.Abs(_cm1 - TBar.h);
+ double d3 = Math.Abs(_cm1 - TBar.l);
+ (DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
+ _cm1 = TBar.c;
+
+ double _atr = 0;
+ if (this.Count == 0) { _atr = d.v; }
+ else if (this.Count < _period + 1) { _sum += d.v; _atr = _sum / (this.Count); }
+ else { _atr = _k * (d.v - _lastatr) + _lastatr; }
+ _lastatr = _atr;
+
+ var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _atr);
+ return base.Add(res, update);
+ }
+
+ public new void Add(TBars data) {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset() {
+ _len = 0;
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/BBANDS_Series.cs b/Calculations/_Updated/BBANDS_Series.cs
new file mode 100644
index 00000000..198b2a38
--- /dev/null
+++ b/Calculations/_Updated/BBANDS_Series.cs
@@ -0,0 +1,112 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+BBANDS: Bollinger Bands®
+ Price channels created by John Bollinger, depict volatility as standard deviation boundary
+ line range from a moving average of price. The bands automatically widen when volatility
+ increases and contract when volatility decreases. Their dynamic nature allows them to be
+ used on different securities with the standard settings.
+
+ Mid Band = simple moving average (SMA)
+ Upper Band = SMA + (standard deviation of price x multiplier)
+ Lower Band = SMA - (standard deviation of price x multiplier)
+ Bandwidth = Width of the channel: (Upper-Lower)/SMA
+ %B = The location of the data point within the channel: (Price-Lower)/(Upper/Lower)
+ Z-Score = number of standard deviations of the data point from SMA
+
+Sources:
+ https://www.investopedia.com/terms/b/bollingerbands.asp
+ https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands
+
+Note:
+ Bollinger Bands® is a registered trademark of John A. Bollinger.
+
+ */
+
+public class BBANDS_Series : TSeries {
+ protected readonly int _period;
+ protected readonly double _multiplier;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ public SMA_Series Mid { get; }
+ public TSeries Upper { get; }
+ public TSeries Lower { get; }
+ public TSeries PercentB { get; }
+ public TSeries Bandwidth { get; }
+ public TSeries Zscore { get; }
+ private readonly SDEV_Series _sdev;
+
+ //core constructors
+ public BBANDS_Series(int period, double multiplier, bool useNaN) {
+ _period = period;
+ _multiplier = multiplier;
+ _NaN = useNaN;
+ Name = $"BBANDS({period})";
+ }
+ public BBANDS_Series(TSeries source, int period, double multiplier, bool useNaN) : this(period, multiplier, useNaN) {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ Upper = new("BB_Up");
+ Lower = new("BB_Low");
+ Bandwidth = new("BBandwidth");
+ PercentB = new("%BBandwidth");
+ Zscore = new("Zscore");
+
+ Mid = new(period, false);
+ _sdev = new(period, false);
+
+ _data.Pub += Sub;
+ Add(_data);
+ }
+
+ public BBANDS_Series() : this(period:0, multiplier: 2.0, useNaN: false) { }
+ public BBANDS_Series(int period) : this(period: period, multiplier: 2.0, useNaN:false) { }
+ public BBANDS_Series(TBars source) : this(source:source.Close, period:0, multiplier: 2.0, useNaN:false) { }
+ public BBANDS_Series(TBars source, int period) : this(source:source.Close, period:period, multiplier: 2.0, useNaN: false) { }
+ public BBANDS_Series(TBars source, int period, double multiplier, bool useNaN) : this(source.Close, period:period, multiplier:multiplier, useNaN: false) { }
+ public BBANDS_Series(TSeries source) : this(source, period:0, useNaN:false) { }
+ public BBANDS_Series(TSeries source, int period) : this(source:source, period:period, useNaN:false) { }
+ public BBANDS_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, multiplier: 2.0, useNaN: useNaN) { }
+
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) {
+ var _mid = Mid.Add(TValue,update);
+ var _sd = this._sdev.Add(TValue, update);
+ var _upper = Upper.Add((TValue.t, _mid.v + _sd.v * _multiplier), update);
+ var _lower = Lower.Add((TValue.t, _mid.v - _sd.v * _multiplier), update);
+ double _pbdnd = TValue.v - _lower.v;
+ double _pbdvr = _upper.v - _lower.v;
+ PercentB.Add((TValue.t, _pbdnd/_pbdvr), update);
+ Zscore.Add((TValue.t, (TValue.v-_mid.v)/_sd.v), update);
+ Bandwidth.Add((TValue.t, _pbdvr / _mid.v), update);
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _pbdvr / _mid.v);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data) {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TValue: _data.Last, update: e.update);
+ }
+ //reset calculation
+ public override void Reset() {
+ Mid.Clear();
+ _sdev.Clear();
+ Upper.Clear();
+ Lower.Clear();
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/BIAS_Series.cs b/Calculations/_Updated/BIAS_Series.cs
index 8fa734d5..df9bc5a5 100644
--- a/Calculations/_Updated/BIAS_Series.cs
+++ b/Calculations/_Updated/BIAS_Series.cs
@@ -20,7 +20,7 @@ public class BIAS_Series : TSeries {
private readonly SMA_Series _sma;
//core constructors
- public BIAS_Series(int period, bool useNaN) : base() {
+ public BIAS_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"BIAS({period})";
@@ -55,9 +55,6 @@ public class BIAS_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/CCI_Series.cs b/Calculations/_Updated/CCI_Series.cs
new file mode 100644
index 00000000..3bf2e553
--- /dev/null
+++ b/Calculations/_Updated/CCI_Series.cs
@@ -0,0 +1,86 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+CCI: Commodity Channel Index
+ Commodity Channel Index is a momentum oscillator used to primarily identify overbought
+ and oversold levels relative to a mean. CCI measures the current price level relative
+ to an average price level over a given period of time:
+ - CCI is relatively high when prices are far above their average.
+ - CCI is relatively low when prices are far below their average.
+ Using this method, CCI can be used to identify overbought and oversold levels.
+
+Sources:
+ https://www.investopedia.com/terms/c/commoditychannelindex.asp
+ https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/cci
+
+ */
+
+public class CCI_Series : TSeries {
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TBars _data;
+ private readonly System.Collections.Generic.List _tp = new();
+
+ //core constructors
+ public CCI_Series(int period, bool useNaN) {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"CCI({period})";
+ }
+ public CCI_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+ public CCI_Series() : this(period: 2, useNaN: false) { }
+ public CCI_Series(int period) : this(period: period, useNaN: false) { }
+ public CCI_Series(TBars source) : this(source, period: 2, useNaN: false) { }
+ public CCI_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
+ double _tpItem = (TBar.h + TBar.l + TBar.c) / 3.0;
+ if (update) {
+ this._tp[this._tp.Count - 1] = _tpItem;
+ }
+ else {
+ this._tp.Add(_tpItem);
+ }
+ if (this._tp.Count > this._period) { this._tp.RemoveAt(0); }
+
+ // average TP over _tp buffer
+ 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) ? 0 : (this._tp[this._tp.Count - 1] - _avgTp) / (0.015 * _avgDv);
+ var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _cci);
+ return base.Add(res, update);
+ }
+
+ public new void Add(TBars data) {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset() {
+ _tp.Clear();
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/CMO_Series.cs b/Calculations/_Updated/CMO_Series.cs
index 6a7520b1..6906067a 100644
--- a/Calculations/_Updated/CMO_Series.cs
+++ b/Calculations/_Updated/CMO_Series.cs
@@ -27,7 +27,7 @@ public class CMO_Series : TSeries {
private double _plast_value, _last_value;
//core constructors
- public CMO_Series(int period, bool useNaN) : base() {
+ public CMO_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"CMO({period})";
@@ -71,9 +71,7 @@ public class CMO_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
+
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/CUSUM_Series.cs b/Calculations/_Updated/CUSUM_Series.cs
index 333a1466..e61d288d 100644
--- a/Calculations/_Updated/CUSUM_Series.cs
+++ b/Calculations/_Updated/CUSUM_Series.cs
@@ -19,7 +19,7 @@ public class CUSUM_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public CUSUM_Series(int period, bool useNaN) : base() {
+ public CUSUM_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"CUSUM({period})";
@@ -35,7 +35,7 @@ public class CUSUM_Series : TSeries {
public CUSUM_Series(TBars source) : this(source.Close, 0, false) { }
public CUSUM_Series(TBars source, int period) : this(source.Close, period, false) { }
public CUSUM_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public CUSUM_Series(TSeries source) : this(source, 0, false) { }
+ public CUSUM_Series(TSeries source) : this(source, period: 0, useNaN: false) { }
public CUSUM_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
@@ -54,9 +54,6 @@ public class CUSUM_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/DECAY_Series.cs b/Calculations/_Updated/DECAY_Series.cs
index 194f639a..a0193dc2 100644
--- a/Calculations/_Updated/DECAY_Series.cs
+++ b/Calculations/_Updated/DECAY_Series.cs
@@ -22,7 +22,7 @@ public class DECAY_Series : TSeries {
private readonly double _dfactor;
//core constructors
- public DECAY_Series(int period, bool exponential, bool useNaN) : base() {
+ public DECAY_Series(int period, bool exponential, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"DECAY({period})";
@@ -66,9 +66,6 @@ public class DECAY_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/DEMA_Series.cs b/Calculations/_Updated/DEMA_Series.cs
index afec6a2c..0cdac2b0 100644
--- a/Calculations/_Updated/DEMA_Series.cs
+++ b/Calculations/_Updated/DEMA_Series.cs
@@ -28,7 +28,7 @@ public class DEMA_Series : TSeries {
protected readonly TSeries _data;
//core constructor
- public DEMA_Series(int period, bool useNaN, bool useSMA) : base() {
+ public DEMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
@@ -107,10 +107,6 @@ public class DEMA_Series : TSeries {
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
-
public (DateTime t, double v) Add(bool update) {
return Add(_data.Last, update);
}
diff --git a/Calculations/_Updated/DWMA_Series.cs b/Calculations/_Updated/DWMA_Series.cs
index 91df946c..3e5f4808 100644
--- a/Calculations/_Updated/DWMA_Series.cs
+++ b/Calculations/_Updated/DWMA_Series.cs
@@ -13,14 +13,14 @@ DWMA: Double Weighted Moving Average
public class DWMA_Series : TSeries {
private readonly List _buffer = new();
- private List _weights = new();
+ private List _weights;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
protected int _len;
//core constructors
- public DWMA_Series(int period, bool useNaN) : base() {
+ public DWMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"DWMA({period})";
@@ -91,10 +91,6 @@ public class DWMA_Series : TSeries {
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
-
public (DateTime t, double v) Add(bool update) {
return Add(_data.Last, update);
}
diff --git a/Calculations/_Updated/EMA_Series.cs b/Calculations/_Updated/EMA_Series.cs
index 8136f7da..138f04ea 100644
--- a/Calculations/_Updated/EMA_Series.cs
+++ b/Calculations/_Updated/EMA_Series.cs
@@ -33,7 +33,7 @@ public class EMA_Series : TSeries {
//core constructors
- public EMA_Series(int period, bool useNaN, bool useSMA) : base() {
+ public EMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
@@ -59,7 +59,7 @@ public class EMA_Series : TSeries {
//////////////////
// core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
_lastema = _oldema;
_sum = _oldsum;
@@ -102,9 +102,6 @@ public class EMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/ENTROPY_Series.cs b/Calculations/_Updated/ENTROPY_Series.cs
index 4abd1239..23523a50 100644
--- a/Calculations/_Updated/ENTROPY_Series.cs
+++ b/Calculations/_Updated/ENTROPY_Series.cs
@@ -27,7 +27,7 @@ public class ENTROPY_Series : TSeries {
private readonly System.Collections.Generic.List _buff2 = new();
//core constructors
- public ENTROPY_Series(int period, double logbase, bool useNaN) : base() {
+ public ENTROPY_Series(int period, double logbase, bool useNaN) {
_period = period;
_NaN = useNaN;
_logbase = logbase;
@@ -69,9 +69,6 @@ public class ENTROPY_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/FWMA_Series.cs b/Calculations/_Updated/FWMA_Series.cs
index fb50117c..78cfef0e 100644
--- a/Calculations/_Updated/FWMA_Series.cs
+++ b/Calculations/_Updated/FWMA_Series.cs
@@ -12,13 +12,13 @@ FWMA: Fibonacci's Weighted Moving Average is similar to a Weighted Moving Averag
*/
public class FWMA_Series : TSeries {
private readonly List _buffer = new();
- private List _weights = new();
+ private List _weights;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
protected int _len;
- public FWMA_Series(int period, bool useNaN) : base() {
+ public FWMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"FWMA({period})";
@@ -65,12 +65,6 @@ public class FWMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
- public (DateTime t, double v) Add(bool update) {
- return this.Add(TValue: _data.Last, update: update);
- }
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
diff --git a/Calculations/_Updated/HEMA_Series.cs b/Calculations/_Updated/HEMA_Series.cs
index 84d292bf..b2f53114 100644
--- a/Calculations/_Updated/HEMA_Series.cs
+++ b/Calculations/_Updated/HEMA_Series.cs
@@ -24,11 +24,11 @@ public class HEMA_Series : TSeries {
private double _lasthema, _oldhema;
//core constructors
- public HEMA_Series(int period, bool useNaN) : base() {
+ public HEMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"HEMA({period})";
- CalculateK(_period, out _k1, out _k2, out _k3);
+ (_k1, _k2, _k3) = CalculateK(_period);
_len = 0;
_lastema1 = _oldema1 = _lastema2 = _oldema2 = _lasthema = _oldhema = 0;
}
@@ -62,7 +62,7 @@ public class HEMA_Series : TSeries {
double _ema1, _ema2, _hema;
if (_period == 0) {
_len++;
- CalculateK(_len, out _k1, out _k2, out _k3);
+ (_k1, _k2, _k3) = CalculateK(_len);
}
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, double.NaN), update);
@@ -88,9 +88,6 @@ public class HEMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
@@ -108,9 +105,12 @@ public class HEMA_Series : TSeries {
_len = 0;
}
- public static void CalculateK(int len, out double k1, out double k2, out double k3) {
- k1 = 8 / (double)(len + 7);
- k2 = 3 / (double)(len + 2);
- k3 = 2 / Math.Sqrt(len + 3);
+ public static (double k1, double k2, double k3) CalculateK(int len) {
+ double k1 = 8 / (double)(len + 7);
+ double k2 = 3 / (double)(len + 2);
+ double k3 = 2 / Math.Sqrt(len + 3);
+
+ return (k1, k2, k3);
}
+
}
\ No newline at end of file
diff --git a/Calculations/_Updated/HMA_Series.cs b/Calculations/_Updated/HMA_Series.cs
index 3631acf4..9230a76b 100644
--- a/Calculations/_Updated/HMA_Series.cs
+++ b/Calculations/_Updated/HMA_Series.cs
@@ -25,7 +25,7 @@ public class HMA_Series : TSeries {
protected WMA_Series _wma1, _wma2, _wma3;
//core constructors
- public HMA_Series(int period, bool useNaN) : base() {
+ public HMA_Series(int period, bool useNaN) {
_period = period;
_period2 = period /2;
_psqrt = (int)Math.Sqrt(period);
@@ -69,9 +69,6 @@ public class HMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/HWMA_Series.cs b/Calculations/_Updated/HWMA_Series.cs
new file mode 100644
index 00000000..f67249e2
--- /dev/null
+++ b/Calculations/_Updated/HWMA_Series.cs
@@ -0,0 +1,132 @@
+namespace QuanTAlib;
+
+using System;
+using System.Linq;
+
+/*
+HWMA: Holt-Winter Moving Average
+ Indicator HWMA (Holt-Winter Moving Average) is a three-parameter moving
+ average by the Holt-Winter method; Holt-Winters Exponential Smoothing is
+ used for forecasting time series data that exhibits both a trend and a
+ seasonal variation.
+
+
+Sources:
+ https://timeseriesreasoning.com/contents/holt-winters-exponential-smoothing/
+ https://www.mql5.com/en/code/20856
+
+nA - smoothed series (from 0 to 1)
+nB - assess the trend (from 0 to 1)
+nC - assess seasonality (from 0 to 1)
+
+Heuristic for determining alpha, beta, and gamma from period:
+ alpha = 2 / (1 + period)
+ beta = 1 / period
+ gamma = 1 / period
+
+F[i] = (1-nA) * (F[i-1] + V[i-1] + 0.5 * A[i-1]) + nA * Price[i]
+V[i] = (1-nB) * (V[i-1] + A[i-1]) + nB * (F[i] - F[i-1])
+A[i] = (1-nC) * A[i-1] + nC * (V[i] - V[i-1])
+HWMA[i] = F[i] + V[i] + 0.5 * A[i]
+
+ */
+
+public class HWMA_Series : TSeries {
+ private int _len;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ double _nA, _nB, _nC;
+ double _pF, _pV, _pA;
+ double _ppF, _ppV, _ppA;
+
+ //core constructors
+
+ public HWMA_Series(double nA, double nB, double nC, bool useNaN) {
+ _period = (int)((2 - nA) / nA);
+ _nA = nA;
+ _nB = nB;
+ _nC = nC;
+ _NaN = useNaN;
+ Name = $"HWMA({_period})";
+ _len = 0;
+ }
+ public HWMA_Series(TSeries source, double nA, double nB, double nC, bool useNaN = false) : this(nA, nB, nC, useNaN) {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public HWMA_Series() : this(period: 0, useNaN: false) { }
+ public HWMA_Series(int period) : this(period, useNaN: false) { }
+ public HWMA_Series(int period, bool useNaN) : this(nA: 2 / (1 + (double)period), nB: 1 / (double)period, nC: 1 / (double)period, useNaN) {
+ _period = period;
+ }
+ public HWMA_Series(TBars source) : this(source.Close, period: 0, useNaN: false) { }
+ public HWMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public HWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public HWMA_Series(TSeries source, int period) : this(source, period, false) { }
+ public HWMA_Series(TSeries source, int period, bool useNaN) : this(source, nA: 2 / (1 + (double)period), nB: 1 / (double)period, nC: 1 / (double)period, useNaN: useNaN) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
+ if (double.IsNaN(TValue.v)) {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+ double _F, _V, _A;
+ if (_len == 0) { _pF = TValue.v; _pA = _pV = 0; }
+
+ if (update) { _pF = _ppF; _pV = _ppV; _pA = _ppA; }
+ else {
+ _ppF = _pF;
+ _ppV = _pV;
+ _ppA = _pA;
+ _len++;
+ }
+
+ if (_period == 0) {
+ _nA = 2 / (1 + (double)_len);
+ _nB = 1 / (double)_len;
+ _nC = 1 / (double)_len;
+ }
+ if (_period == 1) {
+ _nA = 1;
+ _nB = 0;
+ _nC = 0;
+ }
+
+ _F = (1 - _nA) * (_pF + _pV + 0.5 * _pA) + _nA * TValue.v;
+ _V = (1 - _nB) * (_pV + _pA) + _nB * (_F - _pF);
+ _A = (1 - _nC) * _pA + _nC * (_V - _pV);
+
+ double _hwma = _F + _V + 0.5 * _A;
+ _pF = _F;
+ _pV = _V;
+ _pA = _A;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hwma);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data) {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset() {
+ _len = 0;
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/JMA_Series.cs b/Calculations/_Updated/JMA_Series.cs
index bfa9f445..13f16a81 100644
--- a/Calculations/_Updated/JMA_Series.cs
+++ b/Calculations/_Updated/JMA_Series.cs
@@ -34,7 +34,7 @@ public class JMA_Series : TSeries {
private readonly int _voltyS, _voltyL;
//core constructors
- public JMA_Series(int period, double phase, int vshort, int vlong, bool useNaN) : base() {
+ public JMA_Series(int period, double phase, int vshort, int vlong, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"JMA({period})";
@@ -147,9 +147,6 @@ public class JMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/KAMA_Series.cs b/Calculations/_Updated/KAMA_Series.cs
index 87200bef..a3bcf394 100644
--- a/Calculations/_Updated/KAMA_Series.cs
+++ b/Calculations/_Updated/KAMA_Series.cs
@@ -27,17 +27,15 @@ Remark:
public class KAMA_Series : TSeries {
private readonly System.Collections.Generic.List _buffer = new();
private double _lastkama, _lastlastkama;
- private int _len;
private readonly double _scFast, _scSlow;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
- public KAMA_Series(int period, int fast, int slow, bool useNaN) : base() {
+ public KAMA_Series(int period, int fast, int slow, bool useNaN) {
_period = period;
_NaN = useNaN;
- _len = 0;
_scFast = 2.0 / (((period < fast) ? period : fast) + 1);
_scSlow = 2.0 / (slow + 1);
_lastkama = _lastlastkama = 0;
@@ -81,7 +79,6 @@ public class KAMA_Series : TSeries {
double _sc = (_er * (_scFast - _scSlow)) + _scSlow;
_kama = (_lastkama + (_sc * _sc * (TValue.v - _lastkama)));
}
- _len++;
_lastkama = _kama;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kama);
return base.Add(res, update);
@@ -92,9 +89,6 @@ public class KAMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
@@ -108,7 +102,6 @@ public class KAMA_Series : TSeries {
//reset calculation
public override void Reset() {
_buffer.Clear();
- _len = 0;
_lastkama = _lastlastkama = 0;
}
}
\ No newline at end of file
diff --git a/Calculations/_Updated/KURTOSIS_Series.cs b/Calculations/_Updated/KURTOSIS_Series.cs
index 6c1b48c6..71b8cfba 100644
--- a/Calculations/_Updated/KURTOSIS_Series.cs
+++ b/Calculations/_Updated/KURTOSIS_Series.cs
@@ -32,7 +32,7 @@ public class KURTOSIS_Series : TSeries {
private readonly System.Collections.Generic.List _buffer = new();
//core constructors
- public KURTOSIS_Series(int period, bool useNaN) : base() {
+ public KURTOSIS_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"KURTOSIS({period})";
@@ -79,9 +79,6 @@ public class KURTOSIS_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/MACD_Series.cs b/Calculations/_Updated/MACD_Series.cs
new file mode 100644
index 00000000..a81ce1a9
--- /dev/null
+++ b/Calculations/_Updated/MACD_Series.cs
@@ -0,0 +1,78 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+MACD: Moving Average Convergence/Divergence
+ Moving average convergence divergence (MACD) is a trend-following momentum
+ indicator that shows the relationship between two moving averages of a series.
+ The MACD is calculated by subtracting the 26-period exponential moving average (EMA)
+ from the 12-period EMA. MACD Signal is 9-day EMA of MACD.
+
+ */
+
+public class MACD_Series : TSeries {
+ private readonly System.Collections.Generic.List _buffer = new();
+
+ protected readonly int _slow, _fast, _signal;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private readonly EMA_Series _TSlow;
+ private readonly EMA_Series _TFast;
+ public EMA_Series Signal { get; }
+
+ //core constructors
+ public MACD_Series(int slow = 26, int fast = 12, int signal = 9, bool useNaN = false) {
+ _slow = slow;
+ _fast = fast;
+ _signal = signal;
+ _NaN = useNaN;
+ Name = $"MACD({slow},{fast},{signal})";
+ _TSlow = new(slow, useNaN:false, useSMA:true);
+ _TFast = new(fast, useNaN: false, useSMA: true);
+ Signal = new(signal, useNaN: false, useSMA: true);
+ }
+ public MACD_Series(TSeries source, int slow, int fast, int signal, bool useNaN) : this(slow, fast, signal, useNaN) {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MACD_Series(TSeries source) : this(source:source, slow:26, fast:12, signal:9 , useNaN:false) { }
+ public MACD_Series(TSeries source, int slow, int fast, int signal) : this(source: source, slow: slow, fast:fast, signal:signal, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
+ if (double.IsNaN(TValue.v)) {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+
+ var _sslow = _TSlow.Add(TValue,update);
+ var _sfast = _TFast.Add(TValue, update);
+ Signal.Add((TValue.t, _sfast.v-_sslow.v));
+
+ var res = (TValue.t, Count < _fast - 1 && _NaN ? double.NaN : _sfast.v-_sslow.v);
+ return base.Add(res, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data) {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset() {
+ _buffer.Clear();
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/MAD_Series.cs b/Calculations/_Updated/MAD_Series.cs
index e1f358cd..0378f1c5 100644
--- a/Calculations/_Updated/MAD_Series.cs
+++ b/Calculations/_Updated/MAD_Series.cs
@@ -24,7 +24,7 @@ public class MAD_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public MAD_Series(int period, bool useNaN) : base() {
+ public MAD_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAD({period})";
@@ -62,9 +62,6 @@ public class MAD_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/zMA_Series.cs b/Calculations/_Updated/MAE_Series.cs
similarity index 59%
rename from Calculations/_Updated/zMA_Series.cs
rename to Calculations/_Updated/MAE_Series.cs
index c37a41e5..b01839d2 100644
--- a/Calculations/_Updated/zMA_Series.cs
+++ b/Calculations/_Updated/MAE_Series.cs
@@ -1,49 +1,57 @@
-namespace QuanTAlib;
+using System.Linq;
+
+namespace QuanTAlib;
using System;
using System.Collections.Generic;
/*
+MAE: Mean Absolute Error
+ Defined as a Mean (Average) of the absolute difference between actual and estimated values.
+ MAE = (1/n) * Σ|y_i - MA_i|
+
+Sources:
+ https://en.wikipedia.org/wiki/Mean_absolute_error
*/
-public class xMA_Series : TSeries {
+public class MAE_Series : TSeries {
private readonly System.Collections.Generic.List _buffer = new();
-
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
- public xMA_Series(int period, bool useNaN) : base() {
+ public MAE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
- Name = $"xMA({period})";
+ Name = $"MSE({period})";
}
- public xMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
+ public MAE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
- public xMA_Series() : this(period: 0, useNaN: false) { }
- public xMA_Series(int period) : this(period: period, useNaN: false) { }
- public xMA_Series(TBars source) : this(source.Close, 0, false) { }
- public xMA_Series(TBars source, int period) : this(source.Close, period, false) { }
- public xMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
- public xMA_Series(TSeries source) : this(source, 0, false) { }
- public xMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+ public MAE_Series() : this(period: 0, useNaN: false) { }
+ public MAE_Series(int period) : this(period: period, useNaN: false) { }
+ public MAE_Series(TBars source) : this(source.Close, 0, false) { }
+ public MAE_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public MAE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public MAE_Series(TSeries source) : this(source, 0, false) { }
+ public MAE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
- if (double.IsNaN(TValue.v)) {
- return base.Add((TValue.t, Double.NaN), update);
- }
-
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
- double _xma = 0;
- var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _xma);
+ double _sma = _buffer.Average();
+
+ double _mae = 0;
+ for (int i = 0; i < _buffer.Count; i++) { _mae += Math.Abs(_buffer[i] - _sma); }
+ _mae /= this._buffer.Count;
+
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mae);
return base.Add(res, update);
}
@@ -52,9 +60,6 @@ public class xMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/MAMA_Series.cs b/Calculations/_Updated/MAMA_Series.cs
new file mode 100644
index 00000000..52bd5d7b
--- /dev/null
+++ b/Calculations/_Updated/MAMA_Series.cs
@@ -0,0 +1,189 @@
+namespace QuanTAlib;
+
+using System;
+using System.Linq;
+
+/*
+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 : TSeries {
+ private int _len;
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+
+ private double sumPr;
+ private double 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 TSeries Fama { get; }
+ private double mamaseed, famaseed;
+
+ //core constructors
+
+ public MAMA_Series(double fastlimit, double slowlimit, bool useNaN) {
+ _period = (int)(2 / fastlimit) - 1;
+ fastl = fastlimit;
+ slowl = slowlimit;
+ Fama = new TSeries();
+ _NaN = useNaN;
+ Name = $"MAMA({_period})";
+ _len = 0;
+ }
+ public MAMA_Series(TSeries source, double fastlimit, double slowlimit, bool useNaN = false) : this(fastlimit, slowlimit, useNaN) {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public MAMA_Series() : this(period: 0, useNaN: false) { }
+ public MAMA_Series(int period) : this(period, useNaN: false) { }
+ public MAMA_Series(int period, bool useNaN) : this(fastlimit: 2 / (period + 1), slowlimit: 0.2 / (period + 1), useNaN) {
+ _period = period;
+ }
+ public MAMA_Series(TBars source) : this(source.Close, period: 0, useNaN: false) { }
+ public MAMA_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public MAMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public MAMA_Series(TSeries source, int period) : this(source, period, false) { }
+ public MAMA_Series(TSeries source, int period, bool useNaN) : this(source, fastlimit: 2 / ((double)period + 1), slowlimit: 0.2 / ((double)period + 1), useNaN: useNaN) { }
+
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
+ if (double.IsNaN(TValue.v)) {
+ return base.Add((TValue.t, Double.NaN), update);
+ }
+ if (!update) {
+ // roll forward (oldx = x)
+ 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;
+ _len++;
+ }
+ if (_period == 0) {
+ fastl = 2 / (double)_len;
+ slowl = fastl * 0.1;
+ }
+ if (_period == 1) {
+ fastl = 1;
+ slowl = 1;
+ }
+ var i = _len - 1;
+ pr.i = TValue.v;
+ if (i > 5) {
+ var 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
+ double jI = (0.0962 * i1.i + 0.5769 * i1.i2 - 0.5769 * i1.i4 - 0.0962 * i1.i6) * adj;
+ double 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
+ var delta = Math.Max(ph.i1 - ph.i, 1d);
+
+ // adaptive alpha value
+ var alpha = Math.Max(fastl / delta, slowl);
+
+ // final indicators
+ mama.i = alpha * (pr.i - mama.i1) + mama.i1;
+ fama.i = 0.5d * alpha * (mama.i - fama.i1) + 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);
+
+ if (_len == 1) {
+ mamaseed = famaseed = TValue.v;
+ }
+ else {
+ mamaseed = fastl * (TValue.v - mamaseed) + mamaseed;
+ famaseed = slowl * (TValue.v - famaseed) + famaseed;
+ }
+ }
+
+ double _fama = (i > 5) ? fama.i : famaseed;
+ var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _fama);
+ Fama.Add(res, update);
+ double _mama = (i > 5) ? mama.i : mamaseed;
+ res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mama);
+ return base.Add(res, update);
+ }
+
+ //variation of Add()
+ public override (DateTime t, double v) Add(TSeries data) {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TValue: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TValue: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TValue: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset() {
+ _len = 0;
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/MAPE_Series.cs b/Calculations/_Updated/MAPE_Series.cs
index 776a9a12..43a6a9c6 100644
--- a/Calculations/_Updated/MAPE_Series.cs
+++ b/Calculations/_Updated/MAPE_Series.cs
@@ -27,7 +27,7 @@ public class MAPE_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public MAPE_Series(int period, bool useNaN) : base() {
+ public MAPE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAPE({period})";
@@ -68,9 +68,6 @@ public class MAPE_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/MAX_Series.cs b/Calculations/_Updated/MAX_Series.cs
index 0eae2b6f..f199a329 100644
--- a/Calculations/_Updated/MAX_Series.cs
+++ b/Calculations/_Updated/MAX_Series.cs
@@ -17,7 +17,7 @@ public class MAX_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public MAX_Series(int period, bool useNaN) : base() {
+ public MAX_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAX({period})";
@@ -51,9 +51,6 @@ public class MAX_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/MEDIAN_Series.cs b/Calculations/_Updated/MEDIAN_Series.cs
index 18e46c67..0df36399 100644
--- a/Calculations/_Updated/MEDIAN_Series.cs
+++ b/Calculations/_Updated/MEDIAN_Series.cs
@@ -30,7 +30,7 @@ public class MEDIAN_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public MEDIAN_Series(int period, bool useNaN) : base() {
+ public MEDIAN_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MEDIAN({period})";
@@ -69,9 +69,6 @@ public class MEDIAN_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/MIDPOINT_Series.cs b/Calculations/_Updated/MIDPOINT_Series.cs
index 686f9825..46bdd221 100644
--- a/Calculations/_Updated/MIDPOINT_Series.cs
+++ b/Calculations/_Updated/MIDPOINT_Series.cs
@@ -20,7 +20,7 @@ public class MIDPOINT_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public MIDPOINT_Series(int period, bool useNaN) : base() {
+ public MIDPOINT_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MIDPOINT({period})";
@@ -55,9 +55,6 @@ public class MIDPOINT_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/MIDPRICE_Series.cs b/Calculations/_Updated/MIDPRICE_Series.cs
new file mode 100644
index 00000000..1bb914a8
--- /dev/null
+++ b/Calculations/_Updated/MIDPRICE_Series.cs
@@ -0,0 +1,65 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+MIDPRICE: Midpoint price (highhest high + lowest low)/2 in the given period in the series.
+ If period = 0 => period = full length of the series
+
+ */
+
+public class MIDPRICE_Series : TSeries {
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TBars _data;
+ private readonly System.Collections.Generic.List _bufferhi = new();
+ private readonly System.Collections.Generic.List _bufferlo = new();
+
+ //core constructors
+ public MIDPRICE_Series(int period, bool useNaN) {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"MIDPRICE({period})";
+ }
+ public MIDPRICE_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+ public MIDPRICE_Series() : this(period: 2, useNaN: false) { }
+ public MIDPRICE_Series(int period) : this(period: period, useNaN: false) { }
+ public MIDPRICE_Series(TBars source) : this(source, period: 2, useNaN: false) { }
+ public MIDPRICE_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
+ BufferTrim(_bufferhi, TBar.h, _period, update);
+ BufferTrim(_bufferlo, TBar.l, _period, update);
+ double _mid = (_bufferhi.Max() + _bufferlo.Min()) * 0.5;
+
+ var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _mid);
+ return base.Add(res, update);
+ }
+
+ public new void Add(TBars data) {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset() {
+ _bufferhi.Clear();
+ _bufferlo.Clear();
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/MIN_Series.cs b/Calculations/_Updated/MIN_Series.cs
index 30b68fae..3f30ffbe 100644
--- a/Calculations/_Updated/MIN_Series.cs
+++ b/Calculations/_Updated/MIN_Series.cs
@@ -17,7 +17,7 @@ public class MIN_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public MIN_Series(int period, bool useNaN) : base() {
+ public MIN_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAX({period})";
@@ -51,9 +51,6 @@ public class MIN_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/MSE_Series.cs b/Calculations/_Updated/MSE_Series.cs
index 18406554..262cbd6a 100644
--- a/Calculations/_Updated/MSE_Series.cs
+++ b/Calculations/_Updated/MSE_Series.cs
@@ -20,7 +20,7 @@ public class MSE_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public MSE_Series(int period, bool useNaN) : base() {
+ public MSE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MSE({period})";
@@ -59,9 +59,6 @@ public class MSE_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/OBV_Series.cs b/Calculations/_Updated/OBV_Series.cs
new file mode 100644
index 00000000..57531bdd
--- /dev/null
+++ b/Calculations/_Updated/OBV_Series.cs
@@ -0,0 +1,96 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+/*
+OBV: On-Balance Volume
+ On-balance volume (OBV) is a technical trading momentum indicator that uses volume flow to predict
+ changes in stock price. Joseph Granville first developed the OBV metric in the 1963 book
+ Granville's New Key to Stock Market Profits.
+
+ | +volume; if close > close[previous]
+ OBV = OBV[previous] + | 0; if close = close[previous]
+ | -volume; if close < close[previous]
+
+Sources:
+ https://www.investopedia.com/terms/o/onbalancevolume.asp
+ https://www.tradingview.com/wiki/On_Balance_Volume_(OBV)
+ https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/on-balance-volume-obv/
+ https://www.motivewave.com/studies/on_balance_volume.htm
+
+Note:
+ There is no consensus on what is the first OBV value in the series:
+ - TA-LIB uses the first volume: OBV[0] = volume[0]
+ - Skender stock library uses 0: OBV[0] = 0
+
+ */
+
+public class OBV_Series : TSeries {
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TBars _data;
+ private double _lastobv, _lastlastobv;
+ private double _lastclose, _lastlastclose;
+
+ //core constructors
+ public OBV_Series(int period, bool useNaN) {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"OBV({period})";
+ this._lastobv = this._lastlastobv = 0;
+ this._lastclose = this._lastlastclose = 0;
+ }
+ public OBV_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+ public OBV_Series() : this(period: 2, useNaN: false) { }
+ public OBV_Series(int period) : this(period: period, useNaN: false) { }
+ public OBV_Series(TBars source) : this(source, period: 2, useNaN: false) { }
+ public OBV_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
+
+ if (update) {
+ this._lastobv = this._lastlastobv;
+ this._lastclose = this._lastlastclose;
+ }
+
+ double _obv = this._lastobv;
+ if (TBar.c > this._lastclose) { _obv += TBar.v; }
+ if (TBar.c < this._lastclose) { _obv -= TBar.v; }
+
+ this._lastlastobv = this._lastobv;
+ this._lastobv = _obv;
+
+ this._lastlastclose = this._lastclose;
+ this._lastclose = TBar.c;
+
+ var res = (TBar.t, (this.Count < this._period && this._NaN) ? double.NaN : _obv);
+ return base.Add(res, update);
+ }
+
+ public new void Add(TBars data) {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset() {
+ this._lastobv = this._lastlastobv = 0;
+ this._lastclose = this._lastlastclose = 0;
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/RMA_Series.cs b/Calculations/_Updated/RMA_Series.cs
index b5be9d9c..bd84105f 100644
--- a/Calculations/_Updated/RMA_Series.cs
+++ b/Calculations/_Updated/RMA_Series.cs
@@ -31,7 +31,7 @@ public class RMA_Series : TSeries {
protected readonly TSeries _data;
//core constructor
- public RMA_Series(int period, bool useNaN, bool useSMA) : base() {
+ public RMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
@@ -57,7 +57,7 @@ public class RMA_Series : TSeries {
}
// core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
_lastrma = _oldrma;
_sum = _oldsum;
@@ -98,9 +98,6 @@ public class RMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/RSI_Series.cs b/Calculations/_Updated/RSI_Series.cs
index a1cd561e..7acb6daa 100644
--- a/Calculations/_Updated/RSI_Series.cs
+++ b/Calculations/_Updated/RSI_Series.cs
@@ -26,7 +26,7 @@ public class RSI_Series : TSeries {
private int i;
//core constructors
- public RSI_Series(int period, bool useNaN) : base() {
+ public RSI_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"RSI({period})";
@@ -103,9 +103,6 @@ public class RSI_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/SDEV_Series.cs b/Calculations/_Updated/SDEV_Series.cs
index 90d269cd..4b5a91be 100644
--- a/Calculations/_Updated/SDEV_Series.cs
+++ b/Calculations/_Updated/SDEV_Series.cs
@@ -25,7 +25,7 @@ public class SDEV_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public SDEV_Series(int period, bool useNaN) : base() {
+ public SDEV_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SDEV({period})";
@@ -65,9 +65,6 @@ public class SDEV_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/SLOPE_Series.cs b/Calculations/_Updated/SLOPE_Series.cs
new file mode 100644
index 00000000..c9fc3eae
--- /dev/null
+++ b/Calculations/_Updated/SLOPE_Series.cs
@@ -0,0 +1,122 @@
+using System.Linq;
+
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+SLOPE: Slope of linear regression (using Least Square Method)
+ Linear Regression provides a slope of a straight line that is the best approximation of the given set of data.
+ The method of least squares is a standard approach in linear regression analysis to approximate the solution
+ by minimizing the sum of the squares of the residuals made in the results of each individual equation.
+
+Additional outputs provided by LINREG:
+ .Intercept - y-intercept point of the best fit line
+ .RSquared - R-Squared (R²), Coefficient of Determination
+ .StdDev - Standard Deviation of data over given periods
+
+ y = Slope * x + Intercept
+
+Sources:
+ https://en.wikipedia.org/wiki/Least_squares
+
+ */
+
+public class SLOPE_Series : TSeries {
+ protected readonly int _period;
+ protected readonly bool _NaN;
+ protected readonly TSeries _data;
+ private readonly TSeries p_Intercept = new();
+ private readonly TSeries p_RSquared = new();
+ private readonly TSeries p_StdDev = new();
+ private readonly System.Collections.Generic.List _buffer = new();
+ public TSeries Intercept => p_Intercept;
+ public TSeries RSquared => p_RSquared;
+ public TSeries StdDev => p_StdDev;
+ //core constructors
+ public SLOPE_Series(int period, bool useNaN) {
+ _period = period;
+ _NaN = useNaN;
+ Name = $"SLOPE({period})";
+ }
+ public SLOPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
+ _data = source;
+ Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _data.Pub += Sub;
+ Add(_data);
+ }
+ public SLOPE_Series() : this(period: 0, useNaN: false) { }
+ public SLOPE_Series(int period) : this(period: period, useNaN: false) { }
+ public SLOPE_Series(TBars source) : this(source.Close, 0, false) { }
+ public SLOPE_Series(TBars source, int period) : this(source.Close, period, false) { }
+ public SLOPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
+ public SLOPE_Series(TSeries source) : this(source, 0, false) { }
+ public SLOPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
+ BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
+
+ int _len = this._buffer.Count;
+
+ // get averages for period
+ double sumX = 0;
+ double sumY = 0;
+
+ for (int p = 0; p < _len; p++) {
+ sumX += this.Count - _len + 2 + p;
+ sumY += _buffer[p];
+ }
+ double avgX = sumX / _len;
+ double avgY = sumY / _len;
+
+ // least squares method
+ double sumSqX = 0;
+ double sumSqY = 0;
+ double sumSqXY = 0;
+
+ for (int p = 0; p < _len; p++) {
+ double devX = this.Count - _len + 2 + p - avgX;
+ double devY = _buffer[p] - avgY;
+
+ sumSqX += devX * devX;
+ sumSqY += devY * devY;
+ sumSqXY += devX * devY;
+ }
+
+ double _slope = sumSqXY / sumSqX;
+ double _intercept = avgY - (_slope * avgX);
+
+ // calculate Standard Deviation and R-Squared
+ double stdDevX = Math.Sqrt(sumSqX / _len);
+ double stdDevY = Math.Sqrt(sumSqY / _len);
+ double _StdDev = stdDevY;
+
+ double arrr = (stdDevX * stdDevY != 0) ? sumSqXY / (stdDevX * stdDevY) / _len : 0;
+ double _RSquared = arrr * arrr;
+
+ var ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _intercept);
+ p_Intercept.Add(ret, update);
+
+ ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _StdDev);
+ p_StdDev.Add(ret, update);
+
+ ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _RSquared);
+ p_RSquared.Add(ret, update);
+
+ ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _slope);
+ return base.Add(ret, update);
+ }
+
+ public override (DateTime t, double v) Add(TSeries data) {
+ if (data == null) { return (DateTime.Today, Double.NaN); }
+ foreach (var item in data) { Add(item, false); }
+ return _data.Last;
+ }
+
+ //reset calculation
+ public override void Reset() {
+ _buffer.Clear();
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/SMAPE_Series.cs b/Calculations/_Updated/SMAPE_Series.cs
index 7ab08d6a..00ff1237 100644
--- a/Calculations/_Updated/SMAPE_Series.cs
+++ b/Calculations/_Updated/SMAPE_Series.cs
@@ -20,7 +20,7 @@ public class SMAPE_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public SMAPE_Series(int period, bool useNaN) : base() {
+ public SMAPE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SMAPE({period})";
@@ -45,8 +45,6 @@ public class SMAPE_Series : TSeries {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: 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;
@@ -60,9 +58,6 @@ public class SMAPE_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/SMA_Series.cs b/Calculations/_Updated/SMA_Series.cs
index 30ccc4ba..ba25a3f6 100644
--- a/Calculations/_Updated/SMA_Series.cs
+++ b/Calculations/_Updated/SMA_Series.cs
@@ -25,7 +25,7 @@ public class SMA_Series : TSeries {
protected readonly bool _NaN;
//core constructor
- public SMA_Series(int period, bool useNaN) : base() {
+ public SMA_Series(int period, bool useNaN) {
_period = Math.Max(0, period);
_NaN = useNaN;
Name = $"SMA({period})";
@@ -47,7 +47,7 @@ public class SMA_Series : TSeries {
//////////////////
// core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) { return (TValue.t, double.NaN);
} else {
if (update && _buffer.Count > 0) {
@@ -77,9 +77,6 @@ public class SMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/SMMA_Series.cs b/Calculations/_Updated/SMMA_Series.cs
index 50bed0ba..f653eab3 100644
--- a/Calculations/_Updated/SMMA_Series.cs
+++ b/Calculations/_Updated/SMMA_Series.cs
@@ -27,7 +27,7 @@ public class SMMA_Series : TSeries {
private double _lastsmma, _lastlastsmma;
//core constructors
- public SMMA_Series(int period, bool useNaN) : base() {
+ public SMMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SMMA({period})";
@@ -75,9 +75,6 @@ public class SMMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/SSDEV_Series.cs b/Calculations/_Updated/SSDEV_Series.cs
index e295199a..20d41b95 100644
--- a/Calculations/_Updated/SSDEV_Series.cs
+++ b/Calculations/_Updated/SSDEV_Series.cs
@@ -25,7 +25,7 @@ public class SSDEV_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public SSDEV_Series(int period, bool useNaN) : base() {
+ public SSDEV_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SSDEV({period})";
@@ -65,9 +65,6 @@ public class SSDEV_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/SVAR_Series.cs b/Calculations/_Updated/SVAR_Series.cs
index 4c4e0c8a..b121fe8b 100644
--- a/Calculations/_Updated/SVAR_Series.cs
+++ b/Calculations/_Updated/SVAR_Series.cs
@@ -25,7 +25,7 @@ public class SVAR_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public SVAR_Series(int period, bool useNaN) : base() {
+ public SVAR_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SVAR({period})";
@@ -64,9 +64,6 @@ public class SVAR_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/T3_Series.cs b/Calculations/_Updated/T3_Series.cs
index d9abbb65..1ffac970 100644
--- a/Calculations/_Updated/T3_Series.cs
+++ b/Calculations/_Updated/T3_Series.cs
@@ -31,7 +31,7 @@ public class T3_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public T3_Series(int period, double vfactor, bool useSMA, bool useNaN) : base() {
+ public T3_Series(int period, double vfactor, bool useSMA, bool useNaN) {
_period = period;
_len = 0;
_NaN = useNaN;
@@ -137,9 +137,6 @@ public class T3_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/TBars.cs b/Calculations/_Updated/TBars.cs
index 8387219d..920dd17c 100644
--- a/Calculations/_Updated/TBars.cs
+++ b/Calculations/_Updated/TBars.cs
@@ -84,16 +84,16 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub
};
}
- public virtual (DateTime t, double o, double h, double l, double c, double v) Add((double o, double h, double l, double c, double v) p, bool update = false) =>
+ public virtual (DateTime t, double v) Add((double o, double h, double l, double c, double v) p, bool update = false) =>
Add((t: (this.Count == 0) ? DateTime.Today : this[^1].t.AddDays(1),p.o,p.h,p.l,p.c,p.v),update);
- public virtual (DateTime t, double o, double h, double l, double c, double v) Add(double o, double h, double l, double c, double v, bool update = false) =>
+ public virtual (DateTime t, double v) Add(double o, double h, double l, double c, double v, bool update = false) =>
Add((o,h,l,c,v),update);
- public virtual (DateTime t, double o, double h, double l, double c, double v) Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) =>
+ public virtual (DateTime t, double v) Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) =>
this.Add((t, o, h, l, c, v), update);
- public virtual (DateTime t, double o, double h, double l, double c, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
+ public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) { this[^1] = TBar; } else { base.Add(TBar); }
_open.Add((TBar.t, TBar.o), update);
@@ -109,8 +109,8 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub
_hlcc4.Add((TBar.t, (TBar.h + TBar.l + TBar.c + TBar.c) * 0.25), update);
this.OnEvent(update);
- return TBar;
- }
+ return (TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25);
+ }
public delegate void NewDataEventHandler(object source, TSeriesEventArgs args);
public event NewDataEventHandler Pub;
@@ -120,7 +120,19 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub
public void Sub(object source, TSeriesEventArgs e) { TBars ss = (TBars)source; if (ss.Count > 1) {
for (int i = 0; i < ss.Count; i++) { this.Add(ss[i]); }
} else {
- this.Add(ss[ss.Count - 1], e.update);
+ this.Add(ss[^1], e.update);
}
}
+
+ /// common helpers
+ public static void BufferTrim(System.Collections.Generic.List buffer, double value, int period, bool update) {
+ if (!update) {
+ buffer.Add(value);
+ if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); }
+ return;
+ }
+ buffer[^1] = value;
+ }
+ public virtual void Reset() {
+ }
}
diff --git a/Calculations/_Updated/TEMA_Series.cs b/Calculations/_Updated/TEMA_Series.cs
index b109995b..a9653f6b 100644
--- a/Calculations/_Updated/TEMA_Series.cs
+++ b/Calculations/_Updated/TEMA_Series.cs
@@ -29,7 +29,7 @@ public class TEMA_Series : TSeries {
protected readonly TSeries _data;
//core constructor
- public TEMA_Series(int period, bool useNaN, bool useSMA) : base() {
+ public TEMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
@@ -102,9 +102,6 @@ public class TEMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/TRIMA_Series.cs b/Calculations/_Updated/TRIMA_Series.cs
index 70313693..210be772 100644
--- a/Calculations/_Updated/TRIMA_Series.cs
+++ b/Calculations/_Updated/TRIMA_Series.cs
@@ -17,13 +17,13 @@ Remark:
public class TRIMA_Series : TSeries {
private readonly int _p1a, _p1b;
- private SMA_Series sma, trima;
+ private readonly SMA_Series sma, trima;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
- public TRIMA_Series(int period, bool useNaN) : base() {
+ public TRIMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"xMA({period})";
@@ -66,9 +66,6 @@ public class TRIMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/TRIX_Series.cs b/Calculations/_Updated/TRIX_Series.cs
index 243dba19..30d9f58e 100644
--- a/Calculations/_Updated/TRIX_Series.cs
+++ b/Calculations/_Updated/TRIX_Series.cs
@@ -21,7 +21,7 @@ public class TRIX_Series : TSeries {
private readonly System.Collections.Generic.List _buffer3 = new();
private double _lastema1, _lastema2, _lastema3;
private double _llastema1, _llastema2, _llastema3;
-
+ private int _len;
private readonly bool _useSMA;
protected readonly int _period;
protected readonly bool _NaN;
@@ -29,12 +29,13 @@ public class TRIX_Series : TSeries {
//core constructors
- public TRIX_Series(int period, bool useNaN, bool useSMA) : base() {
+ public TRIX_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
Name = $"TRIX({period})";
_k = 2.0 / (_period + 1);
+ _len = 0;
_lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = 0;
}
public TRIX_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
@@ -54,13 +55,14 @@ public class TRIX_Series : TSeries {
//////////////////
// core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
- if (this.Count == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; }
+ if (_len == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; }
if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; }
- else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; }
+ else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _len++;
+ }
double _ema1, _ema2, _ema3;
if ((this.Count < _period) && _useSMA) {
@@ -99,9 +101,6 @@ public class TRIX_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
@@ -114,6 +113,6 @@ public class TRIX_Series : TSeries {
//reset calculation
public override void Reset() {
-
+ _len = 0;
}
}
\ No newline at end of file
diff --git a/Calculations/_Updated/TR_Series.cs b/Calculations/_Updated/TR_Series.cs
new file mode 100644
index 00000000..e3c61058
--- /dev/null
+++ b/Calculations/_Updated/TR_Series.cs
@@ -0,0 +1,79 @@
+namespace QuanTAlib;
+using System;
+using System.Collections.Generic;
+
+/*
+TR: True Range
+ True Range was introduced by J. Welles Wilder in his book New Concepts in Technical Trading Systems.
+ It measures the daily range plus any gap from the closing price of the preceding day.
+
+Calculation:
+ d1 = ABS(High - Low)
+ d2 = ABS(High - Previous close)
+ d3 = ABS(Previous close - Low)
+ TR = MAX(d1,d2,d3)
+
+Sources:
+ https://www.macroption.com/true-range/
+
+ */
+
+public class TR_Series : TSeries {
+ protected readonly TBars _data;
+ private double _cm1, _cm1_o;
+
+ //core constructors
+ public TR_Series() {
+ Name = $"TR()";
+ _cm1 = _cm1_o = double.NaN;
+ }
+ public TR_Series(TBars source) {
+ _data = source;
+ Name = $"TR({(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
+ _cm1 = _cm1_o = double.NaN;
+ _data.Pub += Sub;
+ Add(data: _data);
+ }
+
+ //////////////////
+ // core Add() algo
+ public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
+
+ if (update) {
+ _cm1 = _cm1_o;
+ }
+ else {
+ _cm1_o = _cm1;
+ }
+
+ if (_cm1 is double.NaN) {
+ _cm1 = TBar.c;
+ }
+
+ double d1 = Math.Abs(TBar.h - TBar.l);
+ double d2 = Math.Abs(_cm1 - TBar.h);
+ double d3 = Math.Abs(_cm1 - TBar.l);
+ _cm1 = TBar.c;
+ var ret = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
+ return base.Add(ret, update);
+
+ }
+
+ public new void Add(TBars data) {
+ foreach (var item in data) { Add(item, false); }
+ }
+ public (DateTime t, double v) Add(bool update) {
+ return this.Add(TBar: _data.Last, update: update);
+ }
+ public (DateTime t, double v) Add() {
+ return Add(TBar: _data.Last, update: false);
+ }
+ private new void Sub(object source, TSeriesEventArgs e) {
+ Add(TBar: _data.Last, update: e.update);
+ }
+
+ //reset calculation
+ public override void Reset() {
+ _cm1 = _cm1_o = double.NaN;
+ }
+}
\ No newline at end of file
diff --git a/Calculations/_Updated/TSeries.cs b/Calculations/_Updated/TSeries.cs
index 65c09886..f7becdb3 100644
--- a/Calculations/_Updated/TSeries.cs
+++ b/Calculations/_Updated/TSeries.cs
@@ -22,7 +22,7 @@ public class TSeriesEventArgs : EventArgs {
public class TSeries : List<(DateTime t, double v)> {
public List t => this.Select(item => item.t).ToList();
public List v => this.Select(item => item.v).ToList();
- public (DateTime t, double v) Last => this[^1];
+ public (DateTime t, double v) Last => this[this.Count - 1];
public int Length => Count;
public string Name { get; set; }
@@ -35,13 +35,13 @@ public class TSeries : List<(DateTime t, double v)> {
}
public virtual (DateTime t, double v) Add(double v, bool update = false) {
- var Value = (t: Count == 0 ? DateTime.Today : this[^1].t.AddDays(1), v);
+ var Value = (t: Count == 0 ? DateTime.Today : this[this.Count-1].t.AddDays(1), v);
return Add(Value, update);
}
public virtual (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
- this[^1] = TValue;
+ this[this.Count-1] = TValue;
}
else {
base.Add(TValue);
@@ -51,15 +51,32 @@ public class TSeries : List<(DateTime t, double v)> {
return TValue;
}
+ public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
+ if (update) {
+ this[this.Count - 1] = (TBar.t, TBar.c);
+ }
+ else {
+ base.Add((TBar.t, TBar.c));
+ }
+
+ OnEvent(update);
+ return (TBar.t, TBar.c);
+ }
+
public virtual (DateTime t, double v) Add(TSeries data) {
- foreach (var item in data) { Add(item, false); }
+ foreach (var item in data) { Add(item); }
return data.Last;
}
+ public virtual (DateTime t, double v) Add(TBars data) {
+ foreach (var item in data) { Add(item.c, false); }
+ return (data.Last.t, data.Last.c);
+ }
+
public void Sub(object source, TSeriesEventArgs e) {
var data = (TSeries) source;
if (data == null) { return; }
- foreach (var item in data) { Add(item, update: false); }
+ foreach (var item in data) { Add(item); }
}
public delegate void NewEventHandler(object source, TSeriesEventArgs args);
diff --git a/Calculations/_Updated/VAR_Series.cs b/Calculations/_Updated/VAR_Series.cs
index 97ad50c3..72562277 100644
--- a/Calculations/_Updated/VAR_Series.cs
+++ b/Calculations/_Updated/VAR_Series.cs
@@ -25,7 +25,7 @@ public class VAR_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public VAR_Series(int period, bool useNaN) : base() {
+ public VAR_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"VAR({period})";
@@ -64,9 +64,6 @@ public class VAR_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/WMAPE_Series.cs b/Calculations/_Updated/WMAPE_Series.cs
index b7254958..b0479cb8 100644
--- a/Calculations/_Updated/WMAPE_Series.cs
+++ b/Calculations/_Updated/WMAPE_Series.cs
@@ -22,7 +22,7 @@ public class WMAPE_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public WMAPE_Series(int period, bool useNaN) : base() {
+ public WMAPE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"WMAPE({period})";
@@ -65,9 +65,6 @@ public class WMAPE_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/WMA_Series.cs b/Calculations/_Updated/WMA_Series.cs
index f8d8bb39..48679fe4 100644
--- a/Calculations/_Updated/WMA_Series.cs
+++ b/Calculations/_Updated/WMA_Series.cs
@@ -19,7 +19,7 @@ Sources:
public class WMA_Series : TSeries {
private readonly System.Collections.Generic.List _buffer = new();
- private System.Collections.Generic.List _weights = new();
+ private System.Collections.Generic.List _weights;
protected int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
@@ -30,7 +30,7 @@ public class WMA_Series : TSeries {
}
//core constructors
- public WMA_Series(int period, bool useNaN) : base() {
+ public WMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"WMA({period})";
@@ -76,9 +76,6 @@ public class WMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/ZLEMA_Series.cs b/Calculations/_Updated/ZLEMA_Series.cs
index 81ad2d67..512b5cc0 100644
--- a/Calculations/_Updated/ZLEMA_Series.cs
+++ b/Calculations/_Updated/ZLEMA_Series.cs
@@ -30,7 +30,7 @@ public class ZLEMA_Series : TSeries {
private readonly EMA_Series _ema;
//core constructor
- public ZLEMA_Series(int period, bool useNaN, bool useSMA) : base() {
+ public ZLEMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
Name = $"ZLEMA({period})";
@@ -54,7 +54,7 @@ public class ZLEMA_Series : TSeries {
}
// core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
int _lag;
if (_period == 0) {
@@ -76,9 +76,7 @@ public class ZLEMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
+
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/ZL_Series.cs b/Calculations/_Updated/ZL_Series.cs
index cfb71d20..0f6af1aa 100644
--- a/Calculations/_Updated/ZL_Series.cs
+++ b/Calculations/_Updated/ZL_Series.cs
@@ -26,7 +26,7 @@ public class ZL_Series: TSeries {
private readonly EMA_Series _ema;
//core constructor
- public ZL_Series(int period, bool useNaN, bool useSMA) : base() {
+ public ZL_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
Name = $"ZL({period})";
@@ -50,7 +50,7 @@ public class ZL_Series: TSeries {
}
// core Add() algo
- public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
+ public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
int _lag;
if (_period == 0) {
@@ -72,9 +72,6 @@ public class ZL_Series: TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Calculations/_Updated/ZSCORE_Series.cs b/Calculations/_Updated/ZSCORE_Series.cs
index 8b213c04..c3ab4288 100644
--- a/Calculations/_Updated/ZSCORE_Series.cs
+++ b/Calculations/_Updated/ZSCORE_Series.cs
@@ -31,7 +31,7 @@ public class ZSCORE_Series : TSeries {
protected readonly TSeries _data;
//core constructors
- public ZSCORE_Series(int period, bool useNaN) : base() {
+ public ZSCORE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"ZSCORE({period})";
@@ -71,9 +71,6 @@ public class ZSCORE_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
- public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
- return Add(TValue, false);
- }
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
diff --git a/Indicators/Charts/2MASlope_chart.cs b/Indicators/Charts/2MASlope_chart.cs
index 360af677..547dc860 100644
--- a/Indicators/Charts/2MASlope_chart.cs
+++ b/Indicators/Charts/2MASlope_chart.cs
@@ -39,7 +39,7 @@ public class MovingAverageSlope_chart : Indicator {
private bool LongTrades = true;
[InputParameter("Short trades", 8)]
- private bool ShortTrades = false;
+ private bool ShortTrades;
#endregion Parameters
@@ -48,7 +48,7 @@ public class MovingAverageSlope_chart : Indicator {
///////
private TSeries MA1, MA2;
- private LINREG_Series sMA1, sMA2;
+ private SLOPE_Series sMA1, sMA2;
private CROSS_Series sig1, sig2;
private bool inLong, inShort;
@@ -276,11 +276,12 @@ public class MovingAverageSlope_chart : Indicator {
Graphics graphics = args.Graphics;
var mainWindow = this.CurrentChart.MainWindow;
int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
- int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
+ int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
+/*
int historycount = HistoricalData.Count;
int ymax = mainWindow.ClientRectangle.Height;
-/*
+
for (int i = leftIndex; i <= rightIndex; i++) {
int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
int width = this.CurrentChart.BarsWidth;
diff --git a/Indicators/Charts/JMA_chart.cs b/Indicators/Charts/JMA_chart.cs
index 9390ea59..7d5e5341 100644
--- a/Indicators/Charts/JMA_chart.cs
+++ b/Indicators/Charts/JMA_chart.cs
@@ -24,7 +24,7 @@ public class JMA_chart : Indicator {
private int Vlong = 65;
[InputParameter("Phase", 4, -100, 100, 1, 2)]
- private double Jphase = 0.0;
+ private double Jphase;
#endregion Parameters
@@ -38,7 +38,7 @@ public class JMA_chart : Indicator {
protected int firstOnScreenBarIndex, lastOnScreenBarIndex;
protected HistoricalData History;
protected int HistPeriod;
- public JMA_chart() :base() {
+ public JMA_chart() {
Name = "JMA - Jurik Moving Avg";
Description = "Jurik Moving Average description";
AddLineSeries(lineName: "JMA", lineColor: Color.Yellow, lineWidth: 3,lineStyle: LineStyle.Solid);
@@ -80,8 +80,10 @@ public class JMA_chart : Indicator {
}
public override void OnPaintChart(PaintChartEventArgs args) {
base.OnPaintChart(args);
- if (this.CurrentChart == null)
+ if (this.CurrentChart == null) {
return;
+ }
+
graphics = args.Graphics;
mainWindow = this.CurrentChart.MainWindow;
diff --git a/Indicators/Charts/TrailingStop.cs b/Indicators/Charts/TrailingStop.cs
index 2f20542e..29aee917 100644
--- a/Indicators/Charts/TrailingStop.cs
+++ b/Indicators/Charts/TrailingStop.cs
@@ -30,7 +30,7 @@ public class TrailingStop_chart : Indicator {
///////
- public TrailingStop_chart() :base() {
+ public TrailingStop_chart() {
Name = $"ATR Trailing Stop";
AddLineSeries(lineName: "TrailingATR Long", lineColor: Color.Yellow, lineWidth: 1,lineStyle: LineStyle.Dot);
AddLineSeries(lineName: "Ratchet Long", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
@@ -91,30 +91,5 @@ public class TrailingStop_chart : Indicator {
this.SetValue(_tslineS, lineIndex: 2);
this.SetValue(_ratchetS, lineIndex: 3);
}
-
- public override void OnPaintChart(PaintChartEventArgs args) {
- base.OnPaintChart(args);
- if (this.CurrentChart == null) { return; }
- Graphics graphics = args.Graphics;
- var mainWindow = this.CurrentChart.MainWindow;
- int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
- int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
- int historycount = HistoricalData.Count;
- int ymax = mainWindow.ClientRectangle.Height;
-
- /*
- for (int i = leftIndex; i <= rightIndex; i++) {
- int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
- int width = this.CurrentChart.BarsWidth;
- int height = (int)((equity[i+historycount].v) *proportion);
-
- Brush bb = Brushes.DarkSlateGray;
- bb = (overunder[i+historycount].v>0 && LongTrades)? Brushes.Green : bb;
- bb = (overunder[i + historycount].v < 0 && ShortTrades) ? Brushes.Red : bb;
-
- graphics.FillRectangle(bb, xi, ymax - height, width, height);
- }
- */
- }
}
diff --git a/Strategies/SimpleMACross1.cs b/Strategies/SimpleMACross1.cs
index f6ffaeb6..ffefdb15 100644
--- a/Strategies/SimpleMACross1.cs
+++ b/Strategies/SimpleMACross1.cs
@@ -14,16 +14,16 @@ namespace SimpleMACross {
public Account CurrentAccount { get; set; }
[InputParameter("Fast MA", 2, minimum: 1, maximum: 100, increment: 1, decimalPlaces: 0)]
- public int FastMA = 5;
+ private int FastMA = 5;
[InputParameter("Slow MA", 3, minimum: 1, maximum: 100, increment: 1, decimalPlaces: 0)]
- public int SlowMA = 10;
+ private int SlowMA = 10;
[InputParameter("Quantity", 4, 0.1, 99999, 0.1, 2)]
- public double Quantity = 1.0;
+ private double Quantity = 1.0;
[InputParameter("Period", 5)]
- public Period period = Period.MIN1;
+ private Period period = Period.MIN1;
public override string[] MonitoringConnectionsIds => new string[] { this.CurrentSymbol?.ConnectionId, this.CurrentAccount?.ConnectionId };
@@ -31,9 +31,8 @@ namespace SimpleMACross {
private DateTime prev_time;
private readonly TBars bars = new();
- public SimpleMACross1()
- : base() {
- this.Name = "Miha MA Cross strategy 3";
+ public SimpleMACross1() {
+ this.Name = "MA Cross strategy 3";
this.Description = "Raw strategy without any additional functional";
}
@@ -73,24 +72,7 @@ namespace SimpleMACross {
// An example of adding custom strategy metrics:
result.Add("Bars processed", this.bars.Count.ToString());
- /*
- result.Add("Trades [#]", "0");
- result.Add("Long trades [#]", this.longPositionsCount.ToString());
- result.Add("Short trades [#]", this.shortPositionsCount.ToString());
- result.Add("Profitable trades [#]", "0");
- result.Add("Win Rate [%]", "0");
- result.Add("Best Trade [%]", "0");
- result.Add("Worst Trade[%]", "0");
- result.Add("Avg Winning Trade [%]", "0");
- result.Add("Avg Losing Trade [%]", "0");
- result.Add("Profit Factor", "0");
- result.Add("Sharpe Ratio", "0");
- result.Add("Sortino Ratio", "0");
- result.Add("Omega Ratio", "0");
- result.Add("Calmar Ratio", "0");
- result.Add("Beta", "0");
- result.Add("Alpha", "0");
- */
+
return result;
}
diff --git a/Strategies/Strategies.csproj b/Strategies/Strategies.csproj
index 08f3bcdf..78d3a39f 100644
--- a/Strategies/Strategies.csproj
+++ b/Strategies/Strategies.csproj
@@ -34,9 +34,6 @@
True
anycpu
-
-
-
diff --git a/Tests/Basic tests/Indicators.cs b/Tests/Basic tests/Indicators.cs
index 29476d01..de49baae 100644
--- a/Tests/Basic tests/Indicators.cs
+++ b/Tests/Basic tests/Indicators.cs
@@ -26,6 +26,8 @@ public class Indicators
typeof(T3_Series),
typeof(KAMA_Series),
typeof(TRIMA_Series),
+ typeof(MAMA_Series),
+ typeof(HWMA_Series),
};
[Theory]
diff --git a/Tests/Basic tests/Oscillators.cs b/Tests/Basic tests/Oscillators.cs
index 458386fb..7d87e784 100644
--- a/Tests/Basic tests/Oscillators.cs
+++ b/Tests/Basic tests/Oscillators.cs
@@ -7,7 +7,7 @@ namespace Basics;
#nullable disable
public class Oscillators
{
- private static Type[] maSeriesTypes = new Type[]
+ private static Type[] maSeriesTypes = new[]
{
typeof(BIAS_Series),
typeof(MAX_Series),
@@ -19,7 +19,8 @@ public class Oscillators
typeof(KURTOSIS_Series),
typeof(MAD_Series),
typeof(MAPE_Series),
- typeof(MSE_Series),
+ typeof(MAE_Series),
+ typeof(MSE_Series),
typeof(SDEV_Series),
typeof(SMAPE_Series),
typeof(WMAPE_Series),
@@ -31,6 +32,7 @@ public class Oscillators
typeof(CMO_Series),
typeof(RSI_Series),
typeof(TRIX_Series),
+ typeof(BBANDS_Series),
};
[Theory]
diff --git a/Tests/Basic tests/TBars_input.cs b/Tests/Basic tests/TBars_input.cs
new file mode 100644
index 00000000..f3ee38b2
--- /dev/null
+++ b/Tests/Basic tests/TBars_input.cs
@@ -0,0 +1,96 @@
+using Xunit;
+using System;
+using System.Runtime.InteropServices;
+using QuanTAlib;
+
+namespace Basics;
+#nullable disable
+public class TBars
+{
+ private static Type[] maSeriesTypes = new Type[]
+ {
+ typeof(ATR_Series),
+ typeof(ATRP_Series),
+ typeof(TR_Series),
+ typeof(ADL_Series),
+ typeof(CCI_Series),
+ typeof(OBV_Series),
+ typeof(ADOSC_Series),
+ typeof(MIDPRICE_Series),
+};
+
+ [Theory]
+ [MemberData(nameof(MASeriesData))]
+ public void Name_exists(Type classType)
+ {
+ GBM_Feed data = new(10);
+
+ var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
+ Assert.NotEmpty(MA_Series.Name);
+ }
+
+ [Theory]
+ [MemberData(nameof(MASeriesData))]
+ public void Series_Length(Type classType)
+ {
+ GBM_Feed data = new(1000);
+
+ var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
+ Assert.Equal(1000, MA_Series.Count);
+ }
+
+ [Theory]
+ [MemberData(nameof(MASeriesData))]
+ public void Return_data(Type classType)
+ {
+ GBM_Feed data = new(10);
+ var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
+ var result = MA_Series.Add((DateTime.Today, 1,2,3,4,5));
+ Assert.Equal(result.v, MA_Series.Last.v);
+ }
+
+ [Theory]
+ [MemberData(nameof(MASeriesData))]
+ public void Update(Type classType)
+ {
+ GBM_Feed data = new(10);
+ var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
+ var pre_update = MA_Series.Last;
+
+ var pre_data = data.Last;
+ data.Add((DateTime.Today, 1, 2, 3, 4, 5), true);
+ data.Add(pre_data, true);
+
+ Assert.Equal(pre_update.v, MA_Series.Last.v);
+ Assert.Equal(data.Count, MA_Series.Count);
+}
+
+ [Theory]
+ [MemberData(nameof(MASeriesData))]
+ public void Reset(Type classType)
+ {
+ GBM_Feed data = new(10);
+ var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
+ MA_Series.Reset();
+ data.Add();
+ Assert.False(double.IsNaN(MA_Series.Last.v));
+}
+
+ [Theory]
+ [MemberData(nameof(MASeriesData))]
+ public void Period_default(Type classType) {
+ GBM_Feed data = new(100);
+
+ var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
+ Assert.False(double.IsNaN(MA_Series.Last.v));
+ }
+
+ public static IEnumerable