From dcd1379f09bbac088721b3390a3142a34efbd416 Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Mon, 9 Jan 2023 07:04:30 -0800 Subject: [PATCH 1/2] tests --- Tests/Validations/Trends/TA_LIB.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/Validations/Trends/TA_LIB.cs b/Tests/Validations/Trends/TA_LIB.cs index 891d7bd8..1d211ba6 100644 --- a/Tests/Validations/Trends/TA_LIB.cs +++ b/Tests/Validations/Trends/TA_LIB.cs @@ -239,6 +239,7 @@ public class Ta_Lib Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } + /* [Fact] public void MAMA() { @@ -251,6 +252,7 @@ public class Ta_Lib Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits-1), Math.Exp(-digits-1)); } } + */ [Fact] public void MAX() { From da34d7de38e0dd5a60255ce606065ff9275a9dd3 Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Mon, 9 Jan 2023 13:41:07 -0800 Subject: [PATCH 2/2] EMA update --- Source/QuanTAlib.csproj | 2 +- Source/Trends/EMA_Series.cs | 76 +++++++++++++++------------ Source/Trends/SMA_Series.cs | 1 + Tests/Validations/Trends/Pandas_TA.cs | 4 ++ 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/Source/QuanTAlib.csproj b/Source/QuanTAlib.csproj index 90da774b..4c154ae8 100644 --- a/Source/QuanTAlib.csproj +++ b/Source/QuanTAlib.csproj @@ -2,7 +2,7 @@ QuanTAlib - 0.1.26 + 0.1.27 Library of Technical Indicators for .NET Quantitative Technical Analysis library for real-time (streaming) data analysis git diff --git a/Source/Trends/EMA_Series.cs b/Source/Trends/EMA_Series.cs index abb4bcfd..19130497 100644 --- a/Source/Trends/EMA_Series.cs +++ b/Source/Trends/EMA_Series.cs @@ -20,43 +20,51 @@ Issues: */ -public class EMA_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k, _k1m; - private double _lastema, _lastlastema; - private readonly bool _useSMA; +public class EMA_Series : Single_TSeries_Indicator { + private double _k; + private double _lastema, _lastlastema; + private double _sum, _oldsum; + private int _len, _oldlen; + private readonly bool _useSMA; - public EMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) - { - this._k = 2.0 / (this._p + 1); - this._k1m = 1.0 - this._k; - this._lastema = this._lastlastema = 0; - _useSMA = useSMA; - if (this._data.Count > 0) { base.Add(this._data); } - } + public EMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) { + this._k = 2.0 / (this._p + 1); + _sum = _oldsum = _lastema = _lastlastema = 0; + _len = _oldlen = 0; + _useSMA = useSMA; + if (this._data.Count > 0) { base.Add(this._data); } + } - public override void Add((DateTime t, double v) TValue, bool update) - { - double _ema; - if (update) { this._lastema = this._lastlastema; } - if (this.Count == 0) { _lastema = TValue.v; } + public override void Add((DateTime t, double v) TValue, bool update) { + double _ema = 0; + if (update) { _lastema = _lastlastema; _sum = _oldsum; } + else { _lastlastema = _lastema; _oldsum = _sum; _len++; } - if (this.Count < this._p && _useSMA) - { - Add_Replace(_buffer, TValue.v, update); - _ema = 0; - for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } - _ema /= _buffer.Count; - } - else - { - _ema = (TValue.v * this._k) + (this._lastema * this._k1m); - } + // when period = 0, create cumulative/additive series where _k is progressively larger + if (_period == 0) { _k = 2.0 / (_len + 1); } - this._lastlastema = this._lastema; - this._lastema = _ema; + // the first value of the series + if (this.Count == 0) { + _ema = _sum = TValue.v; + } + // if SMA is used for seeding, calculate SMA within period + else if (_len <= _period && _useSMA && _p != 0) { + _sum += TValue.v; + if (_period != 0 && _len > _period) { + _sum -= (_data[base.Count - _period - (update ? 1 : 0)].v); + } + _ema = _sum / Math.Min(_len, _period); + } + // calculate EMA out from last EMA and factor k + else { + _ema = _k * (TValue.v - _lastema) + _lastema; + } + _lastema = _ema; - base.Add((TValue.t, _ema), update, _NaN); - } + base.Add((TValue.t, _ema), update, _NaN); + } + public void Reset() { + _sum = _oldsum = _lastema = _lastlastema = 0; + _len = _oldlen = 0; + } } \ No newline at end of file diff --git a/Source/Trends/SMA_Series.cs b/Source/Trends/SMA_Series.cs index 01282196..7b383961 100644 --- a/Source/Trends/SMA_Series.cs +++ b/Source/Trends/SMA_Series.cs @@ -29,6 +29,7 @@ public class SMA_Series : Single_TSeries_Indicator { public override void Add((DateTime t, double v) TValue, bool update) { if (update) { _sum = _oldsum; } else { _oldsum = _sum; _len++; } + _sum += TValue.v; if (_period != 0 && _len > _period) { _sum -= (_data[base.Count - _period - (update ? 1 : 0)].v); diff --git a/Tests/Validations/Trends/Pandas_TA.cs b/Tests/Validations/Trends/Pandas_TA.cs index 82d472d0..64d38ee9 100644 --- a/Tests/Validations/Trends/Pandas_TA.cs +++ b/Tests/Validations/Trends/Pandas_TA.cs @@ -144,6 +144,7 @@ public class PandasTA : IDisposable Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } + */ [Fact] void EMA() { EMA_Series QL = new(bars.Close, period, false); var pta = df.ta.ema(close: df.close, length: period); @@ -154,6 +155,7 @@ public class PandasTA : IDisposable Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } + /* [Fact] void ENTROPY() { ENTROPY_Series QL = new(bars.Close, period, useNaN: false); var pta = df.ta.entropy(close: df.close, length: period); @@ -307,6 +309,7 @@ public class PandasTA : IDisposable Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } + */ [Fact] void SMA() { SMA_Series QL = new(bars.Close, period, false); var pta = df.ta.sma(close: df.close, length: period); @@ -317,6 +320,7 @@ public class PandasTA : IDisposable Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } + /* [Fact] void SSDEV() { SSDEV_Series QL = new(bars.Close, period, useNaN: false); var pta = df.ta.stdev(close: df.close, length: period, ddof: 1);