From f393ec336d1a2d963143ccfec7a9ad13543454b1 Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Fri, 18 Nov 2022 21:05:14 -0800 Subject: [PATCH] T3 --- Source/Basics/TR_Series.cs | 6 +- Source/Feeds/RND_Feed.cs | 14 +- Source/QuanTAlib.csproj | 5 +- Source/Trends/MAMA_Series.cs | 92 +++--- Source/Trends/T3_Series.cs | 117 +++++++ Source/Trends/ZLEMA_Series.cs | 38 +-- Source/Volatility/RSI_Series.cs | 39 ++- Tests/MovingAvg/ALMA_Test.cs | 2 +- Tests/Series/Update.cs | 501 ++++++++++++++++++++++++++++ Tests/Validations/Pandas_TA.cs | 414 +++++++++-------------- Tests/Validations/Skender_Stock.cs | 507 +++++++++++----------------- Tests/Validations/TA_LIB.cs | 510 +++++++++++------------------ docs/readme.md | 4 +- 13 files changed, 1264 insertions(+), 985 deletions(-) create mode 100644 Source/Trends/T3_Series.cs create mode 100644 Tests/Series/Update.cs diff --git a/Source/Basics/TR_Series.cs b/Source/Basics/TR_Series.cs index 65b1a54c..6f4c2391 100644 --- a/Source/Basics/TR_Series.cs +++ b/Source/Basics/TR_Series.cs @@ -19,14 +19,16 @@ Sources: public class TR_Series : Single_TBars_Indicator { - private double _cm1 = double.NaN; + 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 (_cm1 is double.NaN) { _cm1 = TBar.c; } + 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); diff --git a/Source/Feeds/RND_Feed.cs b/Source/Feeds/RND_Feed.cs index c30881e7..1d17840d 100644 --- a/Source/Feeds/RND_Feed.cs +++ b/Source/Feeds/RND_Feed.cs @@ -11,18 +11,18 @@ Random Bars generator - used for testing, validation and fun public class RND_Feed : TBars { - public RND_Feed(int bars, double volatility = 0.05, double startvalue = 100.0) + public RND_Feed(int Bars, double Volatility = 0.05, double Startvalue = 100.0) { Random rnd = new(); - double c = startvalue; - for (int i = 0; i < bars; i++) + double c = Startvalue; + for (int i = 0; i < Bars; i++) { - double o = Math.Round(c + (c * (((volatility * 0.1) * rnd.NextDouble()) - 0.005)), 2); - double h = Math.Round(o + (c * volatility * rnd.NextDouble()), 2); - double l = Math.Round(o - (c * volatility * rnd.NextDouble()), 2); + double o = Math.Round(c + (c * (((Volatility * 0.1) * rnd.NextDouble()) - 0.005)), 2); + double h = Math.Round(o + (c * Volatility * rnd.NextDouble()), 2); + double l = Math.Round(o - (c * Volatility * rnd.NextDouble()), 2); c = Math.Round(l + ((h - l) * rnd.NextDouble()), 2); double v = Math.Round(1000 * rnd.NextDouble(), 2); - this.Add(DateTime.Today.AddDays(i - bars), o, h, l, c, v); + this.Add(DateTime.Today.AddDays(i - Bars), o, h, l, c, v); } } } \ No newline at end of file diff --git a/Source/QuanTAlib.csproj b/Source/QuanTAlib.csproj index 3a18b409..be71640e 100644 --- a/Source/QuanTAlib.csproj +++ b/Source/QuanTAlib.csproj @@ -2,7 +2,7 @@ QuanTAlib - 0.1.21 + 0.1.22 Library of Technical Indicators for .NET Quantitative Technical Analysis library for both real-time (streaming) and historical data analysis git @@ -11,7 +11,7 @@ Miha Kralj Miha Kralj readme.md - net7.0; + net7.0;net6.0;netstandard2.1 disable preview disable @@ -66,6 +66,7 @@ False + \ No newline at end of file diff --git a/Source/Trends/MAMA_Series.cs b/Source/Trends/MAMA_Series.cs index 20102431..ae26f66c 100644 --- a/Source/Trends/MAMA_Series.cs +++ b/Source/Trends/MAMA_Series.cs @@ -3,8 +3,8 @@ 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 + 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 ) @@ -22,84 +22,87 @@ public class MAMA_Series : Single_TSeries_Indicator fastl = fastlimit; slowl = slowlimit; i = 0; + Fama = new(); if (base._data.Count > 0) { base.Add(base._data); } } - + private int i; private double sumPr, jI, jQ, fastl, slowl; private (double i, double i1, double i2, double i3, double i4, double i5, double i6, double io) pr, i1, q1, sm, dt; private (double i, double i1, double io) i2, q2, re, im, pd, ph, mama, fama; - + public TSeries Fama { get; } + public override void Add((System.DateTime t, double v) TValue, bool update) { - if (update) { - i--; - pr.i = pr.i1; pr.i1 = pr.i2; pr.i2 = pr.i3; pr.i3 = pr.i4; pr.i4 = pr.i5; pr.i5 = pr.i6; pr.i6 = pr.io; - i1.i = i1.i1; i1.i1 = i1.i2; i1.i2 = i1.i3; i1.i3 = i1.i4; i1.i4 = i1.i5; i1.i5 = i1.i6; i1.i6 = i1.io; - q1.i = q1.i1; q1.i1 = q1.i2; q1.i2 = q1.i3; q1.i3 = q1.i4; q1.i4 = q1.i5; q1.i5 = q1.i6; q1.i6 = q1.io; - dt.i = dt.i1; dt.i1 = dt.i2; dt.i2 = dt.i3; dt.i3 = dt.i4; dt.i4 = dt.i5; dt.i5 = dt.i6; dt.i6 = dt.io; - sm.i = sm.i1; sm.i1 = sm.i2; sm.i2 = sm.i3; sm.i3 = sm.i4; dt.i4 = sm.i5; sm.i5 = sm.i6; sm.i6 = sm.io; - i2.i = i2.i1; i2.i1 = i2.io; - q2.i = q2.i1; q2.i1 = q2.io; - re.i = re.i1; re.i1 = re.io; - im.i = im.i1; im.i1 = im.io; - pd.i = pd.i1; pd.i1 = pd.io; - ph.i = ph.i1; ph.i1 = ph.io; - mama.i = mama.i1; mama.i1 = mama.io; - fama.i = fama.i1; fama.i1 = fama.io; - } + + 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; + } pr.i = TValue.v; if (i > 5) { double adj = (0.075 * pd.i1) + 0.54; - + // smooth and detrender sm.i = ((4 * pr.i) + (3 * pr.i1) + (2 * pr.i2) + pr.i3) / 10; dt.i = ((0.0962 * sm.i) + (0.5769 * sm.i2) - (0.5769 * sm.i4) - (0.0962 * sm.i6)) * adj; - + // in-phase and quadrature q1.i = ((0.0962 * dt.i) + (0.5769 * dt.i2) - (0.5769 * dt.i4) - (0.0962 * dt.i6)) * adj; i1.i = dt.i3; - + // advance the phases by 90 degrees jI = ((0.0962 * i1.i) + (0.5769 * i1.i2) - (0.5769 * i1.i4) - (0.0962 * i1.i6)) * adj; jQ = ((0.0962 * q1.i) + (0.5769 * q1.i2) - (0.5769 * q1.i4) - (0.0962 * q1.i6)) * adj; - + // phasor addition for 3-bar averaging i2.i = i1.i - jQ; q2.i = q1.i + jI; - + i2.i = (0.2 * i2.i) + (0.8 * i2.i1); // smoothing it q2.i = (0.2 * q2.i) + (0.8 * q2.i1); - + // homodyne discriminator re.i = (i2.i * i2.i1) + (q2.i * q2.i1); im.i = (i2.i * q2.i1) - (q2.i * i2.i1); - + re.i = (0.2 * re.i) + (0.8 * re.i1); // smoothing it im.i = (0.2 * im.i) + (0.8 * im.i1); - + // calculate period pd.i = (im.i != 0 && re.i != 0) ? (6.283185307179586 / Math.Atan(im.i / re.i)) : 0d; - + // adjust period to thresholds pd.i = (pd.i > 1.5 * pd.i1) ? 1.5 * pd.i1 : pd.i; pd.i = (pd.i < 0.67 * pd.i1) ? 0.67 * pd.i1 : pd.i; pd.i = (pd.i < 6d) ? 6d : pd.i; pd.i = (pd.i > 50d) ? 50d : pd.i; - + // smooth the period pd.i = (0.2 * pd.i) + (0.8 * pd.i1); - + // determine phase position ph.i = (i1.i != 0) ? Math.Atan(q1.i / i1.i) * 57.29577951308232 : 0; - + // change in phase double delta = Math.Max(ph.i1 - ph.i, 1d); - + // adaptive alpha value double alpha = Math.Max(fastl / delta, slowl); - + // final indicators mama.i = ((alpha * pr.i) + ((1d - alpha) * mama.i1)); fama.i = ((0.5d * alpha * mama.i) + ((1d - (0.5d * alpha)) * fama.i1)); @@ -107,25 +110,12 @@ public class MAMA_Series : Single_TSeries_Indicator 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); + mama.i = fama.i = sumPr / (i+1); } - i++; - pr.io = pr.i6; pr.i6 = pr.i5; pr.i5 = pr.i4; pr.i4 = pr.i3; pr.i3 = pr.i2; pr.i2 = pr.i1; pr.i1 = pr.i; - i1.io = i1.i6; i1.i6 = i1.i5; i1.i5 = i1.i4; i1.i4 = i1.i3; i1.i3 = i1.i2; i1.i2 = i1.i1; i1.i1 = i1.i; - q1.io = q1.i6; q1.i6 = q1.i5; q1.i5 = q1.i4; q1.i4 = q1.i3; q1.i3 = q1.i2; q1.i2 = q1.i1; q1.i1 = q1.i; - dt.io = dt.i6; dt.i6 = dt.i5; dt.i5 = dt.i4; dt.i4 = dt.i3; dt.i3 = dt.i2; dt.i2 = dt.i1; dt.i1 = dt.i; - sm.io = sm.i6; sm.i6 = sm.i5; sm.i5 = sm.i4; sm.i4 = sm.i3; sm.i3 = sm.i2; sm.i2 = sm.i1; sm.i1 = sm.i; - - i2.io = i2.i1; i2.i1 = i2.i; - q2.io = q2.i1; q2.i1 = q2.i; - re.io = re.i1; re.i1 = re.i; - im.io = im.i1; im.i1 = im.i; - pd.io = pd.i1; pd.i1 = pd.i; - ph.io = ph.i1; ph.i1 = ph.i; - - mama.io = mama.i1; mama.i1 = mama.i; - fama.io = fama.i1; fama.i1 = fama.i; + if (!update) { i++; } base.Add((TValue.t, mama.i), update, _NaN); + var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : fama.i); + Fama.Add(result, update); } } diff --git a/Source/Trends/T3_Series.cs b/Source/Trends/T3_Series.cs new file mode 100644 index 00000000..46e4217a --- /dev/null +++ b/Source/Trends/T3_Series.cs @@ -0,0 +1,117 @@ +namespace QuanTAlib; +using System; +using System.Linq; +using System.Numerics; + +/* +T3: Triple Exponential Moving Average + TEMA uses EMA(EMA(EMA())) to calculate less laggy Exponential moving average. + +Sources: + https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triple-exponential-moving-average-tema/ + + + */ + +public class T3_Series : Single_TSeries_Indicator +{ + private int i; + private double k, a; + private double c1, c2, c3, c4; + private double o_c1, o_c2, o_c3, o_c4; + + private double e1, e2, e3, e4, e5, e6; + private double o_e1, o_e2, o_e3, o_e4, o_e5, o_e6; + + private double sum1, sum2, sum3, sum4, sum5, sum6; + private double o_sum1, o_sum2, o_sum3, o_sum4, o_sum5, o_sum6; + + public T3_Series(TSeries source, int period, double vfactor, bool useNaN = false) : base(source, period, useNaN) + { + i = 0; + k = 2.0 / (_p + 1); + a = vfactor; + c1 = -a * a * a; + c2 = (3 * a * a) + (3 * a * a * a); + c3 = (-6 * a * a) - (3 * a) - (3 * a * a * a); + c4 = 1 + (3 * a) + (3 * a * a) + (a * a * a) ; + e1 = e2 = e3 = e4 = e5 = e6 = 0; + sum1 = sum2 = sum3 = sum4 = sum5 = sum6 = 0; + + if (_data.Count > 0) { base.Add(data: _data); } + } + + public override void Add((DateTime t, double v) TValue, bool update) + { + if (update) { + // roll back (x = oldx) + c1 = o_c1; c2 = o_c2; c3 = o_c3; c4 = o_c4; + e1 = o_e1; e2 = o_e2; e3 = o_e3; e4 = o_e4; e5 = o_e5; e6 = o_e6; + sum1 = o_sum1; sum2 = o_sum2; sum3 = o_sum3; sum4 = o_sum4; sum5 = o_sum5; sum6 = o_sum6; + } else { + // roll forward (oldx = x) + o_c1 = c1; o_c2 = c2; o_c3 = c3; o_c4 = c4; + o_e1 = e1; o_e2 = e2; o_e3 = e3; o_e4 = e4; o_e5 = e5; o_e6 = e6; + o_sum1 = sum1; o_sum2 = sum2; o_sum3 = sum3; o_sum4 = sum4; o_sum5 = sum5; o_sum6 = sum6; + } + double v = TValue.v; + if (i > _p - 1) { + e1 += k * (v - e1); + if (i > 2 * (_p - 1)) { + e2 += k * (e1 - e2); + if (i > 3 * (_p - 1)) { + e3 += k * (e2 - e3); + if (i > 4 * (_p - 1)) { + e4 += k * (e3 - e4); + if (i > 5 * (_p - 1)) { + e5 += k * (e4 - e5); + if (i > 6 * (_p - 1)) { + e6 += k * (e5 - e6); + } + else { + sum6 += e5; + if (i == 6 * (_p - 1)) { + e6 = sum6 / _p; + } + } + } + else { + sum5 += e4; + if (i == 5 * (_p - 1)) { + sum6 = e5 = sum5 / _p; + } + } + } + else { + sum4 += e3; + if (i == 4 * (_p - 1)) { + sum5 = e4 = sum4 / _p; + } + } + } + else { + sum3 += e2; + if (i == 3 * (_p - 1)) { + sum4 = e3 = sum3 / _p; + } + } + } + else { + sum2 += e1; + if (i == 2 * (_p - 1)) { + sum3 = e2 = sum2 / _p; + } + } + } + else { + sum1 += v; + if (i == _p - 1) { + sum2 = e1 = sum1 / _p; + } + } + if (!update) { i++; } + + double t3 = (c1 * e6) + (c2 * e5) + (c3 * e4) + (c4 * e3); + base.Add(TValue: (TValue.t, t3), update: update, useNaN: _NaN); + } +} \ No newline at end of file diff --git a/Source/Trends/ZLEMA_Series.cs b/Source/Trends/ZLEMA_Series.cs index 9855a550..14f6605b 100644 --- a/Source/Trends/ZLEMA_Series.cs +++ b/Source/Trends/ZLEMA_Series.cs @@ -24,38 +24,36 @@ public class ZLEMA_Series : Single_TSeries_Indicator { private readonly System.Collections.Generic.List _buffer = new(); private readonly double _k, _k1m; - private double _lastema, _lastlastema; + private double _lastema, _lastema_o; + private int _llag; public ZLEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) { this._k = 2.0 / (this._p + 1); this._k1m = 1.0 - this._k; - this._lastema = this._lastlastema = double.NaN; - if (base._data.Count > 0) - { base.Add(base._data); } + this._lastema = this._lastema_o = double.NaN; + _llag = (int)((_p-1) * 0.5); + if (_data.Count > 0) { base.Add(_data); } } public override void Add((System.DateTime t, double v) TValue, bool update) { - int _lag = (int)((_p-1) * 0.5); - _lag = (this.Count-_lag < 0) ? 0 : this.Count-_lag; + int _lag = Math.Max(this.Count-_llag, 0); + if (update) { + _lastema = _lastema_o; _lag--; + } else { + _lastema_o = _lastema; + } double _zl = TValue.v + (TValue.v - _data[_lag].v); - double _ema = 0; - if (update) - { this._lastema = this._lastlastema; } - if (this.Count < this._p) - { - Add_Replace_Trim(_buffer, _zl, _p, update); - _ema = _buffer.Average(); - } - else - { - _ema = (_zl * this._k) + (this._lastema * this._k1m); - } - this._lastlastema = this._lastema; - this._lastema = _ema; + if (this.Count < this._p) { + Add_Replace_Trim(_buffer, _zl, _p, update); + _ema = _buffer.Average(); + } else { + _ema = (_zl * _k) + (_lastema * _k1m); + } + _lastema = _ema; base.Add((TValue.t, _ema), update, _NaN); } diff --git a/Source/Volatility/RSI_Series.cs b/Source/Volatility/RSI_Series.cs index f5717f73..e4f6a350 100644 --- a/Source/Volatility/RSI_Series.cs +++ b/Source/Volatility/RSI_Series.cs @@ -16,30 +16,34 @@ public class RSI_Series : Single_TSeries_Indicator { private readonly System.Collections.Generic.List _gain = new(); private readonly System.Collections.Generic.List _loss = new(); - private double _avgGain; - private double _avgLoss; - private double _lastValue; - private double _lastlastValue; + private double _avgGain, _avgLoss, _lastValue; + private double _avgGain_o, _avgLoss_o, _lastValue_o; + private int i; - public RSI_Series(TSeries source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) - { if (source.Count > 0) { base.Add(source); } } + public RSI_Series(TSeries source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) { + i = 0; + if (source.Count > 0) { base.Add(source); } + } - public override void Add((System.DateTime t, double v) TValue, bool update) - { - int i = this.Count; + public override void Add((System.DateTime t, double v) TValue, bool update) { double _rsi = 0; - if (update) { _lastValue = _lastlastValue; } + if (update) { + _lastValue = _lastValue_o; + _avgGain = _avgGain_o; + _avgLoss = _avgLoss_o; + } + else { + _lastValue_o = _lastValue; + _avgGain_o = _avgGain; + _avgLoss_o = _avgLoss; + } + if (i == 0) { _lastValue = TValue.v; } double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0; - if (update) { _gain[_gain.Count - 1] = _gainval; } else { _gain.Add(_gainval); } - if (_gain.Count > this._p) { _gain.RemoveAt(0); } - + Add_Replace_Trim(_gain, _gainval, _p, update); double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0; - if (update) { _loss[_loss.Count - 1] = _lossval; } else { _loss.Add(_lossval); } - if (_loss.Count > this._p) { _loss.RemoveAt(0); } - - _lastlastValue = _lastValue; + Add_Replace_Trim(_loss, _lossval, _p, update); _lastValue = TValue.v; // calculate RSI @@ -67,6 +71,7 @@ public class RSI_Series : Single_TSeries_Indicator _rsi = (_avgLoss > 0) ? 100 - (100 / (1 + (_avgGain / _avgLoss))) : 100; } + if (!update) { i++; } var result = (TValue.t, (this.Count < this._p && this._NaN) ? double.NaN : _rsi); base.Add(result, update); } diff --git a/Tests/MovingAvg/ALMA_Test.cs b/Tests/MovingAvg/ALMA_Test.cs index b0b2c297..589ab75e 100644 --- a/Tests/MovingAvg/ALMA_Test.cs +++ b/Tests/MovingAvg/ALMA_Test.cs @@ -3,7 +3,7 @@ using System; using QuanTAlib; namespace MovingAvg; -public class ALMA_Test +public class Update { [Fact] public void Add_Test() diff --git a/Tests/Series/Update.cs b/Tests/Series/Update.cs new file mode 100644 index 00000000..37d3f9a7 --- /dev/null +++ b/Tests/Series/Update.cs @@ -0,0 +1,501 @@ +using Xunit; +using System; +using QuanTAlib; +using Skender.Stock.Indicators; + +namespace Series; +public class Update { + private readonly GBM_Feed bars; + private readonly Random rnd = new(); + private readonly int period; + + public Update() { + bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0); + period = rnd.Next(28) + 3; + } + + [Fact] public void ADL() { + ADL_Series QL = new(bars); + var lastData = bars.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void ADOSC() { + ADOSC_Series QL = new(bars); + var lastData = bars.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void ALMA() { + ALMA_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void ATR() { + ATR_Series QL = new(bars, period: period); + var lastData = bars.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void ATRP() { + ATRP_Series QL = new(bars, period: period); + var lastData = bars.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void BBANDS() { + BBANDS_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void BIAS() { + BIAS_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void CCI() { + CCI_Series QL = new(bars, period: period); + var lastData = bars.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void CORR() { + CORR_Series QL = new(d1: bars.High, d2: bars.Low, period: period); + var lastData = bars.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), (DateTime.Today, 0), update: true); + QL.Add((lastData.t, lastData.h), (lastData.t, lastData.l), update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void COVAR() { + COVAR_Series QL = new(d1: bars.High, d2: bars.Low, period: period); + var lastData = bars.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), (DateTime.Today, 0), update: true); + QL.Add((lastData.t, lastData.h), (lastData.t, lastData.l), update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void DEMA() { + DEMA_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void ENTROPY() { + ENTROPY_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void EMA() { + EMA_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void HEMA() { + HEMA_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void HMA() { + HMA_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void JMA() { + JMA_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void KAMA() { + KAMA_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void KURTOSIS() { + KURTOSIS_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void LINREG() { + LINREG_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void MACD() { + MACD_Series QL = new(source: bars.Close); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + var lastC1 = QL.Signal.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + Assert.Equal(lastC1, QL.Signal.Last()); // same data + } + [Fact] public void MAD() { + MAD_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void MAMA() { + MAMA_Series QL = new(source: bars.Close); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + var lastC1 = QL.Fama.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + Assert.Equal(lastC1, QL.Fama.Last()); // same data + } + [Fact] public void MAPE() { + MAPE_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void MAX() { + MAX_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void MEDIAN() { + MEDIAN_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void MIDPOINT() { + MIDPOINT_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void MIDPRICE() { + MIDPRICE_Series QL = new(bars, period: period); + var lastData = bars.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void MIN() { + MAX_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void MSE() { + MSE_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void OBV() { + OBV_Series QL = new(bars, period: period); + var lastData = bars.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void RSI() { + RSI_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void RMA() { + RMA_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void SDEV() { + SDEV_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void SMA() { + SMA_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void SMAPE() { + SMAPE_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void SMMA() { + SMMA_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void SSDEV() { + SSDEV_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void SUM() { + SUM_Series QL = new(source: bars.Close, period: period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void SVAR() { + SVAR_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void T3() { + SMA_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void TEMA() { + TEMA_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void TR() { + TR_Series QL = new(bars); + var lastData = bars.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void TRIMA() { + TRIMA_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void VAR() { + VAR_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void WMA() { + WMA_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void WMAPE() { + WMAPE_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void ZLEMA() { + ZLEMA_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } + [Fact] public void ZSCORE() { + ZSCORE_Series QL = new(source: bars.Close, period); + var lastData = bars.Close.Last(); + var lastCalc = QL.Last(); + int lastLen = QL.Count; + QL.Add((DateTime.Today, 0), update: true); + QL.Add(lastData, update: true); + Assert.Equal(lastLen, QL.Count); // same size + Assert.Equal(lastCalc, QL.Last()); // same data + } +} diff --git a/Tests/Validations/Pandas_TA.cs b/Tests/Validations/Pandas_TA.cs index fb589b18..2a971df5 100644 --- a/Tests/Validations/Pandas_TA.cs +++ b/Tests/Validations/Pandas_TA.cs @@ -7,287 +7,197 @@ using Python.Included; namespace Validations; public class PandasTA : IDisposable { - private readonly GBM_Feed bars; - private readonly Random rnd = new(); - private readonly int period; - private readonly string OStype; - private readonly dynamic np; - private readonly dynamic ta; - private readonly dynamic df; + private readonly GBM_Feed bars; + private readonly Random rnd = new(); + private readonly int period; + private int digits; + private readonly string OStype; + private readonly dynamic np; + private readonly dynamic ta; + private readonly dynamic df; + + public PandasTA() { + bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0); + period = rnd.Next(maxValue: 28) + 3; + digits = 4; //minimizing rounding errors in type conversions - public PandasTA() - { - bars = new(5000); - period = rnd.Next(28) + 3; + // Checking the host OS and setting PythonDLL accordingly + OStype = Path.GetFullPath(path: ".") + @"\python-3.10.0-embed-amd64\python310.dll"; - // Checking the host OS and setting PythonDLL accordingly - OStype = Environment.OSVersion.ToString(); - if (OStype == "Unix 13.1.0") - { - OStype = @"/usr/local/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/libpython3.10.dylib"; - } - else - { - OStype = Path.GetFullPath(".") + @"\python-3.10.0-embed-amd64\python310.dll"; - } + Installer.InstallPath = Path.GetFullPath(path: "."); + Installer.SetupPython().Wait(); + Installer.TryInstallPip(); + Installer.PipInstallModule(module_name: "pandas-ta"); + Runtime.PythonDLL = OStype; + PythonEngine.Initialize(); + np = Py.Import(name: "numpy"); + ta = Py.Import(name: "pandas_ta"); - Installer.InstallPath = Path.GetFullPath("."); - Installer.SetupPython().Wait(); - Installer.TryInstallPip(); - Installer.PipInstallModule("pandas-ta"); - //alternative: git+https://github.com/twopirllc/pandas-ta - - Runtime.PythonDLL = OStype; - PythonEngine.Initialize(); - np = Py.Import("numpy"); - ta = Py.Import("pandas_ta"); - - string[] cols = { "open", "high", "low", "close", "volume" }; - double[,] ary = new double[bars.Count, 5]; - for (int i = 0; i < bars.Count; i++) - { - ary[i, 0] = bars.Open[i].v; - ary[i, 1] = bars.High[i].v; - ary[i, 2] = bars.Low[i].v; - ary[i, 3] = bars.Close[i].v; - ary[i, 4] = bars.Volume[i].v; - } - df = ta.DataFrame(data: np.array(ary), index: np.array(bars.Close.t), columns: np.array(cols)); - } - - public void Dispose() - { + string[] cols = { "open", "high", "low", "close", "volume" }; + double[,] ary = new double[bars.Count, 5]; + for (int i = 0; i < bars.Count; i++) { + ary[i, 0] = bars.Open[i].v; + ary[i, 1] = bars.High[i].v; + ary[i, 2] = bars.Low[i].v; + ary[i, 3] = bars.Close[i].v; + ary[i, 4] = bars.Volume[i].v; + } + df = ta.DataFrame(data: np.array(ary), index: np.array(bars.Close.t), columns: np.array(cols)); + } + public void Dispose() + { PythonEngine.Shutdown(); - GC.SuppressFinalize(this); + GC.SuppressFinalize(this); } - [Fact] - void HL2() - { - var pta = df.ta.hl2(high: df.high, low: df.low); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(bars.HL2.Last().v, 4)); - } - - [Fact] - void HLC3() - { - var pta = df.ta.hlc3(high: df.high, low: df.low, close: df.close); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(bars.HLC3.Last().v, 4)); - } - - [Fact] - void OHLC4() - { - var pta = df.ta.ohlc4(open: df.open, high: df.high, low: df.low, close: df.close); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(bars.OHLC4.Last().v, 4)); - } - - [Fact] - void MEDIAN() - { - MEDIAN_Series QL = new(bars.Close, period); - var pta = df.ta.median(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void VARIANCE() - { - VAR_Series QL = new(bars.Close, period); - var pta = df.ta.variance(close: df.close, length: period, ddof:0); - Assert.Equal(Math.Round((double)pta.tail(1), 5), Math.Round(QL.Last().v, 5)); - } - - [Fact] - void SVARIANCE() - { - SVAR_Series QL = new(bars.Close, period); - var pta = df.ta.variance(close: df.close, length: period, ddof: 1); - Assert.Equal(Math.Round((double)pta.tail(1), 5), Math.Round(QL.Last().v, 5)); - } - - [Fact] - void ADL() - { + [Fact] void ADL() { ADL_Series QL = new(bars); var pta = df.ta.ad(high: df.high, low: df.low, close:df.close, volume:df.volume); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); } - - [Fact] - void ADOSC() - { + [Fact] void ADOSC() { ADOSC_Series QL = new(bars); var pta = df.ta.adosc(high: df.high, low: df.low, close: df.close, volume: df.volume); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); } - - [Fact] - void TR() - { - TR_Series QL = new(bars); - var pta = df.ta.true_range(high: df.high, low: df.low, close: df.close); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void OBV() - { - OBV_Series QL = new(bars); - var pta = df.ta.obv(close: df.close, volume: df.volume); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void ATR() - { + [Fact] void ATR() { ATR_Series QL = new(bars, period); var pta = df.ta.atr(high: df.high, low: df.low, close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); } - - [Fact] - void RSI() - { - RSI_Series QL = new(bars.Close, period); - var pta = df.ta.rsi(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + [Fact] void BIAS() { + BIAS_Series QL = new(bars.Close, period, false); + var pta = df.ta.bias(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); } - - [Fact] - void TRIMA() - { - // TODO: return length to variable length (period) when Pandas-TA fixes trima - TRIMA_Series QL = new(bars.Close, 11); - var pta = df.ta.trima(close: df.close, length: 11); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + [Fact] void DEMA() { + DEMA_Series QL = new(bars.Close, period, false); + var pta = df.ta.dema(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); } - - [Fact] - void KAMA() - { + [Fact] void EMA() { + EMA_Series QL = new(bars.Close, period, false); + var pta = df.ta.ema(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void ENTROPY() { + ENTROPY_Series QL = new(bars.Close, period, useNaN: false); + var pta = df.ta.entropy(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void HL2() { + var pta = df.ta.hl2(high: df.high, low: df.low); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(bars.HL2.Last().v, digits: digits)); + } + [Fact] void HLC3() { + var pta = df.ta.hlc3(high: df.high, low: df.low, close: df.close); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(bars.HLC3.Last().v, digits: digits)); + } + [Fact] void HMA() { + HMA_Series QL = new(bars.Close, period, false); + var pta = df.ta.hma(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void KAMA() { KAMA_Series QL = new(bars.Close, period); var pta = df.ta.kama(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); } - - [Fact] - void HMA() - { - HMA_Series QL = new(bars.Close, period, false); - var pta = df.ta.hma(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void SMA() - { - SMA_Series QL = new(bars.Close, period, false); - var pta = df.ta.sma(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void EMA() - { - EMA_Series QL = new(bars.Close, period, false); - var pta = df.ta.ema(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void TEMA() - { - TEMA_Series QL = new(bars.Close, period, false); - var pta = df.ta.tema(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); - } - - [Fact] - void SDEV() - { - SDEV_Series QL = new(bars.Close, period, useNaN: false); - var pta = df.ta.stdev(close: df.close, length: period, ddof: 0); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + [Fact] void KURTOSIS() { + KURTOSIS_Series QL = new(bars.Close, period, useNaN: false); + var pta = df.ta.kurtosis(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); } - - [Fact] - void SSDEV() + [Fact] void MAD() { - SSDEV_Series QL = new(bars.Close, period, useNaN: false); - var pta = df.ta.stdev(close: df.close, length: period, ddof: 1); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + MAD_Series QL = new(bars.Close, period, useNaN: false); + var pta = df.ta.mad(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); } - - [Fact] - void ZSCORE() - { - ZSCORE_Series QL = new(bars.Close, period, useNaN: false); - var pta = df.ta.zscore(close: df.close, length: period, ddof: 0); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + [Fact] void MEDIAN() { + MEDIAN_Series QL = new(bars.Close, period); + var pta = df.ta.median(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); } - - [Fact] - void ENTROPY() - { - ENTROPY_Series QL = new(bars.Close, period, useNaN: false); - var pta = df.ta.entropy(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void WMA() - { - WMA_Series QL = new(bars.Close, period, false); - var pta = df.ta.wma(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void RMA() - { + [Fact] void OBV() { + OBV_Series QL = new(bars); + var pta = df.ta.obv(close: df.close, volume: df.volume); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void OHLC4() { + var pta = df.ta.ohlc4(open: df.open, high: df.high, low: df.low, close: df.close); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(bars.OHLC4.Last().v, digits: digits)); + } + [Fact] void RMA() { RMA_Series QL = new(bars.Close, period, false); var pta = df.ta.rma(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); } - - [Fact] - void ZLEMA() - { + [Fact] void RSI() { + RSI_Series QL = new(bars.Close, period); + var pta = df.ta.rsi(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void SDEV() { + SDEV_Series QL = new(bars.Close, period, useNaN: false); + var pta = df.ta.stdev(close: df.close, length: period, ddof: 0); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void SMA() { + SMA_Series QL = new(bars.Close, period, false); + var pta = df.ta.sma(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: 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); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void SVARIANCE() { + SVAR_Series QL = new(bars.Close, period); + var pta = df.ta.variance(close: df.close, length: period, ddof: 1); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void T3() { + T3_Series QL = new(source: bars.Close, period: period, vfactor: 0.7, useNaN: false); + var pta = df.ta.t3(close: df.close, length: period, a: 0.7); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void TEMA() { + TEMA_Series QL = new(bars.Close, period, false); + var pta = df.ta.tema(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void TR() { + TR_Series QL = new(bars); + var pta = df.ta.true_range(high: df.high, low: df.low, close: df.close); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void TRIMA() { + // TODO: return length to variable length (period) when Pandas-TA fixes trima to calculate even periods right + TRIMA_Series QL = new(bars.Close, 11); + var pta = df.ta.trima(close: df.close, length: 11); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void VARIANCE() { + VAR_Series QL = new(bars.Close, period); + var pta = df.ta.variance(close: df.close, length: period, ddof:0); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void WMA() { + WMA_Series QL = new(bars.Close, period, false); + var pta = df.ta.wma(close: df.close, length: period); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void ZLEMA() { ZLEMA_Series QL = new(bars.Close, period, false); var pta = df.ta.zlma(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] void ZSCORE() { + ZSCORE_Series QL = new(bars.Close, period, useNaN: false); + var pta = df.ta.zscore(close: df.close, length: period, ddof: 0); + Assert.Equal(Math.Round((double)pta.tail(1), digits: digits), Math.Round(QL.Last().v, digits: digits)); } - [Fact] - void DEMA() - { - DEMA_Series QL = new(bars.Close, period, false); - var pta = df.ta.dema(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void BIAS() - { - BIAS_Series QL = new(bars.Close, period, false); - var pta = df.ta.bias(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void KURTOSIS() - { - KURTOSIS_Series QL = new(bars.Close, period, useNaN: false); - var pta = df.ta.kurtosis(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } - - [Fact] - void MAD() - { - MAD_Series QL = new(bars.Close, period, useNaN: false); - var pta = df.ta.mad(close: df.close, length: period); - Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); - } } \ No newline at end of file diff --git a/Tests/Validations/Skender_Stock.cs b/Tests/Validations/Skender_Stock.cs index 3e173138..418f9611 100644 --- a/Tests/Validations/Skender_Stock.cs +++ b/Tests/Validations/Skender_Stock.cs @@ -4,324 +4,201 @@ using Skender.Stock.Indicators; using Xunit; namespace Validations; -public class Skender_Stock -{ - private readonly GBM_Feed bars; - private readonly Random rnd = new(); - private readonly int period; - private readonly IEnumerable quotes; +public class Skender_Stock { + private readonly GBM_Feed bars; + private readonly Random rnd = new(); + private readonly int period, digits; + private readonly IEnumerable quotes; - public Skender_Stock() - { - bars = new(Bars: 5000, Volatility: 0.7, Drift: 0.0); - period = rnd.Next(28) + 3; - quotes = bars.Select( - q => new Quote - { - Date = q.t, - Open = (decimal)q.o, - High = (decimal)q.h, - Low = (decimal)q.l, - Close = (decimal)q.c, - Volume = (decimal)q.v + public Skender_Stock() { + bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0); + period = rnd.Next(28) + 3; + digits = 4; //minimizing rounding errors in type conversions + + quotes = bars.Select(q => new Quote { + Date = q.t, + Open = (decimal)q.o, + High = (decimal)q.h, + Low = (decimal)q.l, + Close = (decimal)q.c, + Volume = (decimal)q.v }); - } - - [Fact] - public void SMA() - { - SMA_Series QL = new(bars.Close, period, false); - var SK = quotes.GetSma(period); - - Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void EMA() - { - EMA_Series QL = new(bars.Close, period, false); - var SK = quotes.GetEma(period); - - Assert.Equal(Math.Round((double)SK.Last().Ema!, 6), Math.Round(QL.Last().v, 6)); - } - [Fact] - public void WMA() - { - WMA_Series QL = new(bars.Close, period, false); - var SK = quotes.GetWma(period); - - Assert.Equal(Math.Round((double)SK.Last().Wma!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void DEMA() - { - DEMA_Series QL = new(bars.Close, period, false); - var SK = quotes.GetDema(period); - - Assert.Equal(Math.Round((double)SK.Last().Dema!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void TEMA() - { - TEMA_Series QL = new(bars.Close, period, false); - var SK = quotes.GetTema(period); - - Assert.Equal(Math.Round((double)SK.Last().Tema!, 6), Math.Round(QL.Last().v, 6)); - } - - - [Fact] - public void MAMA() { + } + [Fact] public void ADL() { + ADL_Series QL = new(bars, false); + var SK = quotes.GetAdl(); + Assert.Equal(Math.Round(SK.Last().Adl!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void ALMA() { + ALMA_Series QL = new(bars.Close, period, useNaN: false); + var SK = quotes.GetAlma(period); + Assert.Equal(Math.Round((double)SK.Last().Alma!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void ATR() { + ATR_Series QL = new(bars, period, false); + var SK = quotes.GetAtr(period); + Assert.Equal(Math.Round((double)SK.Last().Atr!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void ATRP() { + ATRP_Series QL = new(bars, period, false); + var SK = quotes.GetAtr(period); + Assert.Equal(Math.Round((double)SK.Last().Atrp!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void BBANDS() { + BBANDS_Series QL = new(bars.Close, period, 2.0, useNaN: false); + var SK = quotes.GetBollingerBands(period, 2.0); + Assert.Equal(Math.Round((double)SK.Last().Sma!, digits: digits), Math.Round(QL.Mid.Last().v, digits: digits)); + Assert.Equal(Math.Round((double)SK.Last().UpperBand!, digits: digits), Math.Round(QL.Upper.Last().v, digits: digits)); + Assert.Equal(Math.Round((double)SK.Last().LowerBand!, digits: digits), Math.Round(QL.Lower.Last().v, digits: digits)); + Assert.Equal(Math.Round((double)SK.Last().Width!, digits: digits), Math.Round(QL.Bandwidth.Last().v, digits: digits)); + Assert.Equal(Math.Round((double)SK.Last().PercentB!, digits: digits), Math.Round(QL.PercentB.Last().v, digits: digits)); + Assert.Equal(Math.Round((double)SK.Last().ZScore!, digits: digits), Math.Round(QL.Zscore.Last().v, digits: digits)); + } + [Fact] public void CCI() { + CCI_Series QL = new(bars, period, false); + var SK = quotes.GetCci(period); + Assert.Equal(Math.Round((double)SK.Last().Cci!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void CORR() { + CORR_Series QL = new(bars.High, bars.Low, period, false); + var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period); + Assert.Equal(Math.Round((double)SK.Last().Correlation!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void COVAR() { + COVAR_Series QL = new(bars.High, bars.Low, period, false); + var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period); + Assert.Equal(Math.Round((double)SK.Last().Covariance!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void DEMA() { + DEMA_Series QL = new(bars.Close, period, false); + var SK = quotes.GetDema(period); + Assert.Equal(Math.Round((double)SK.Last().Dema!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void EMA() { + EMA_Series QL = new(bars.Close, period, false); + var SK = quotes.GetEma(period); + Assert.Equal(Math.Round((double)SK.Last().Ema!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void HL2() { + TSeries QL = bars.HL2; + var SK = quotes.GetBaseQuote(CandlePart.HL2); + Assert.Equal(Math.Round(SK.Last().Value!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void HLC3() { + TSeries QL = bars.HLC3; + var SK = quotes.GetBaseQuote(CandlePart.HLC3); + Assert.Equal(Math.Round(SK.Last().Value!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void HMA() { + HMA_Series QL = new(bars.Close, period, useNaN: false); + var SK = quotes.GetHma(period); + Assert.Equal(Math.Round((double)SK.Last().Hma!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void KAMA() { + KAMA_Series QL = new(bars.Close, period, useNaN: false); + var SK = quotes.GetKama(period); + Assert.Equal(Math.Round((double)SK.Last().Kama!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void LINREG() { + LINREG_Series QL = new(bars.Close, period, useNaN: false); + var SK = quotes.GetSlope(period); + Assert.Equal(Math.Round((double)SK.Last().Slope!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + Assert.Equal(Math.Round((double)SK.Last().Intercept!, digits: digits), Math.Round(QL.Intercept.Last().v, digits: digits)); + Assert.Equal(Math.Round((double)SK.Last().RSquared!, digits: digits), Math.Round(QL.RSquared.Last().v, digits: digits)); + Assert.Equal(Math.Round((double)SK.Last().StdDev!, digits: digits), Math.Round(QL.StdDev.Last().v, digits: digits)); + } + [Fact] public void MACD() { + MACD_Series QL = new(bars.Close, 26, 12, 9, useNaN: false); + var SK = quotes.GetMacd(12, 26, 9); + Assert.Equal(Math.Round((double)SK.Last().Macd!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + Assert.Equal(Math.Round((double)SK.Last().Signal!, digits: digits), Math.Round(QL.Signal.Last().v, digits: digits)); + } + [Fact] public void MAD() { + MAD_Series QL = new(bars.Close, period, false); + var SK = quotes.GetSmaAnalysis(period); + Assert.Equal(Math.Round((double)SK.Last().Mad!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void MAMA() { MAMA_Series QL = new(bars.HL2, fastlimit: 0.5, slowlimit: 0.05); var SK = quotes.GetMama(fastLimit: 0.5, slowLimit: 0.05); + Assert.Equal(Math.Round((double)SK.Last().Mama!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + Assert.Equal(Math.Round((double)SK.Last().Fama!, digits: digits), Math.Round(QL.Fama.Last().v, digits: digits)); + } + [Fact] public void MAPE() { + MAPE_Series QL = new(bars.Close, period, false); + var SK = quotes.GetSmaAnalysis(period); + Assert.Equal(Math.Round((double)SK.Last().Mape!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void MSE() { + MSE_Series QL = new(bars.Close, period, false); + var SK = quotes.GetSmaAnalysis(period); + Assert.Equal(Math.Round((double)SK.Last().Mse!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void OBV() { + OBV_Series QL = new(bars, period, false); + var SK = quotes.GetObv(period); + // adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB + Assert.Equal(Math.Round(SK.Last().Obv! + (double)quotes.First().Volume!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void OC2() { + TSeries QL = bars.OC2; + var SK = quotes.GetBaseQuote(CandlePart.OC2); + Assert.Equal(Math.Round(SK.Last().Value!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void OHL3() { + TSeries QL = bars.OHL3; + var SK = quotes.GetBaseQuote(CandlePart.OHL3); + Assert.Equal(Math.Round(SK.Last().Value!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void OHLC4() { + TSeries QL = bars.OHLC4; + var SK = quotes.GetBaseQuote(CandlePart.OHLC4); + Assert.Equal(Math.Round(SK.Last().Value!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void RSI() { + RSI_Series QL = new(bars.Close, period, useNaN: false); + var SK = quotes.GetRsi(period); + Assert.Equal(Math.Round((double)SK.Last().Rsi!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void SDEV() { + SDEV_Series QL = new(bars.Close, period, useNaN: false); + var SK = quotes.GetStdDev(period); + Assert.Equal(Math.Round((double)SK.Last().StdDev!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void SMA() { + SMA_Series QL = new(bars.Close, period, false); + var SK = quotes.GetSma(period); + Assert.Equal(Math.Round((double)SK.Last().Sma!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void SMMA() { + SMMA_Series QL = new(bars.Close, period, useNaN: false); + var SK = quotes.GetSmma(period); + Assert.Equal(Math.Round((double)SK.Last().Smma!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void T3() { + T3_Series QL = new(source: bars.Close, period, vfactor: 0.7, false); + var SK = quotes.GetT3(lookbackPeriods: period, volumeFactor: 0.7); + Assert.Equal(Math.Round((double)SK.Last().T3!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void TEMA() { + TEMA_Series QL = new(bars.Close, period, false); + var SK = quotes.GetTema(period); + Assert.Equal(Math.Round((double)SK.Last().Tema!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void TR() { + TR_Series QL = new(bars, useNaN: false); + var SK = quotes.GetTr(); + Assert.Equal(Math.Round((double)SK.Last().Tr!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void WMA() { + WMA_Series QL = new(bars.Close, period, false); + var SK = quotes.GetWma(period); + Assert.Equal(Math.Round((double)SK.Last().Wma!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void ZSCORE() { + ZSCORE_Series QL = new(bars.Close, period, useNaN: false); + var SK = quotes.GetStdDev(period); + Assert.Equal(Math.Round((double)SK.Last().ZScore!, digits: digits), Math.Round(QL.Last().v, digits: digits)); + } - Assert.Equal(Math.Round((double)SK.Last().Mama!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void MAD() - { - MAD_Series QL = new(bars.Close, period, false); - var SK = quotes.GetSmaAnalysis(period); - - Assert.Equal(Math.Round((double)SK.Last().Mad!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void MSE() - { - MSE_Series QL = new(bars.Close, period, false); - var SK = quotes.GetSmaAnalysis(period); - - Assert.Equal(Math.Round((double)SK.Last().Mse!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void MAPE() - { - MAPE_Series QL = new(bars.Close, period, false); - var SK = quotes.GetSmaAnalysis(period); - - Assert.Equal(Math.Round((double)SK.Last().Mape!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void COVAR() - { - COVAR_Series QL = new(bars.High, bars.Low, period, false); - var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period); - - Assert.Equal(Math.Round((double)SK.Last().Covariance!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void CORR() - { - CORR_Series QL = new(bars.High, bars.Low, period, false); - var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period); - - Assert.Equal(Math.Round((double)SK.Last().Correlation!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void ATR() - { - ATR_Series QL = new(bars, period, false); - var SK = quotes.GetAtr(period); - - Assert.Equal(Math.Round((double)SK.Last().Atr!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void OBV() - { - OBV_Series QL = new(bars, period, false); - var SK = quotes.GetObv(period); - - // adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB - Assert.Equal(Math.Round(SK.Last().Obv! + (double)quotes.First().Volume!, 5), - Math.Round(QL.Last().v, 5)); - } - - [Fact] - public void ADL() - { - ADL_Series QL = new(bars, false); - var SK = quotes.GetAdl(); - - Assert.Equal(Math.Round(SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5)); - } - - [Fact] - public void CCI() - { - CCI_Series QL = new(bars, period, false); - var SK = quotes.GetCci(period); - - Assert.Equal(Math.Round((double)SK.Last().Cci!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void ATRP() - { - ATRP_Series QL = new(bars, period, false); - var SK = quotes.GetAtr(period); - - Assert.Equal(Math.Round((double)SK.Last().Atrp!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void KAMA() - { - KAMA_Series QL = new(bars.Close, period, useNaN: false); - var SK = quotes.GetKama(period); - - Assert.Equal(Math.Round((double)SK.Last().Kama!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void HMA() - { - HMA_Series QL = new(bars.Close, period, useNaN: false); - var SK = quotes.GetHma(period); - - Assert.Equal(Math.Round((double)SK.Last().Hma!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void SMMA() - { - SMMA_Series QL = new(bars.Close, period, useNaN: false); - var SK = quotes.GetSmma(period); - - Assert.Equal(Math.Round((double)SK.Last().Smma!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void MACD() - { - MACD_Series QL = new(bars.Close, 26, 12, 9, useNaN: false); - var SK = quotes.GetMacd(12, 26, 9); - - Assert.Equal(Math.Round((double)SK.Last().Macd!, 6), Math.Round(QL.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().Signal!, 6), Math.Round(QL.Signal.Last().v, 6)); - } - - [Fact] - public void BBANDS() - { - BBANDS_Series QL = new(bars.Close, period, 2.0, useNaN: false); - var SK = quotes.GetBollingerBands(period, 2.0); - - Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Mid.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().UpperBand!, 6), Math.Round(QL.Upper.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().LowerBand!, 6), Math.Round(QL.Lower.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().Width!, 6), Math.Round(QL.Bandwidth.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().PercentB!, 6), Math.Round(QL.PercentB.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Zscore.Last().v, 6)); - } - - [Fact] - public void RSI() - { - RSI_Series QL = new(bars.Close, period, useNaN: false); - var SK = quotes.GetRsi(period); - - Assert.Equal(Math.Round((double)SK.Last().Rsi!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void ALMA() - { - ALMA_Series QL = new(bars.Close, period, useNaN: false); - var SK = quotes.GetAlma(period); - - Assert.Equal(Math.Round((double)SK.Last().Alma!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void SDEV() - { - SDEV_Series QL = new(bars.Close, period, useNaN: false); - var SK = quotes.GetStdDev(period); - - Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void ZSCORE() - { - ZSCORE_Series QL = new(bars.Close, period, useNaN: false); - var SK = quotes.GetStdDev(period); - - Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void LINREG() - { - LINREG_Series QL = new(bars.Close, period, useNaN: false); - var SK = quotes.GetSlope(period); - - Assert.Equal(Math.Round((double)SK.Last().Slope!, 6), Math.Round(QL.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().Intercept!, 6), Math.Round(QL.Intercept.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().RSquared!, 6), Math.Round(QL.RSquared.Last().v, 6)); - Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.StdDev.Last().v, 6)); - } - - [Fact] - public void TR() - { - TR_Series QL = new(bars, useNaN: false); - var SK = quotes.GetTr(); - - Assert.Equal(Math.Round((double)SK.Last().Tr!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void HL2() - { - TSeries QL = bars.HL2; - var SK = quotes.GetBaseQuote(CandlePart.HL2); - - Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void OC2() - { - TSeries QL = bars.OC2; - var SK = quotes.GetBaseQuote(CandlePart.OC2); - - Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void HLC3() - { - TSeries QL = bars.HLC3; - var SK = quotes.GetBaseQuote(CandlePart.HLC3); - - Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void OHL3() - { - TSeries QL = bars.OHL3; - var SK = quotes.GetBaseQuote(CandlePart.OHL3); - - Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); - } - - [Fact] - public void OHLC4() - { - TSeries QL = bars.OHLC4; - var SK = quotes.GetBaseQuote(CandlePart.OHLC4); - - Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); - } } diff --git a/Tests/Validations/TA_LIB.cs b/Tests/Validations/TA_LIB.cs index 7dab5701..e6e87b71 100644 --- a/Tests/Validations/TA_LIB.cs +++ b/Tests/Validations/TA_LIB.cs @@ -4,327 +4,205 @@ using TALib; using QuanTAlib; namespace Validations; -public class TA_LIB +public class Ta_Lib { - private readonly GBM_Feed bars; - private readonly Random rnd = new(); - private readonly int period; - private readonly double[] TALIB; - private readonly double[] TALIB2; - private readonly double[] inopen; - private readonly double[] inhigh; - private readonly double[] inlow; - private readonly double[] inclose; - private readonly double[] involume; + private readonly GBM_Feed bars; + private readonly Random rnd = new(); + private readonly int period, digits; + private readonly double[] TALIB; + private readonly double[] TALIB2; + private readonly double[] inopen; + private readonly double[] inhigh; + private readonly double[] inlow; + private readonly double[] inclose; + private readonly double[] involume; - public TA_LIB() - { - bars = new(5000); - period = rnd.Next(28) + 3; - TALIB = new double[bars.Count]; - TALIB2 = new double[bars.Count]; - inopen = bars.Open.v.ToArray(); - inhigh = bars.High.v.ToArray(); - inlow = bars.Low.v.ToArray(); - inclose = bars.Close.v.ToArray(); - involume = bars.Volume.v.ToArray(); - } + public Ta_Lib() { + bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0); + period = rnd.Next(28) + 3; + digits = 6; - ///////////////////////////////////////// + TALIB = new double[bars.Count]; + TALIB2 = new double[bars.Count]; + inopen = bars.Open.v.ToArray(); + inhigh = bars.High.v.ToArray(); + inlow = bars.Low.v.ToArray(); + inclose = bars.Close.v.ToArray(); + involume = bars.Volume.v.ToArray(); + } - [Fact] - public void ADD() - { - ADD_Series QL = new(bars.Open, bars.Close); - Core.Add(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void SUB() - { - SUB_Series QL = new(bars.Open, bars.Close); - Core.Sub(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void MUL() - { - MUL_Series QL = new(bars.Open, bars.Close); - Core.Mult(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void DIV() - { - DIV_Series QL = new(bars.Open, bars.Close); - Core.Div(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void CORR() - { - CORR_Series QL = new(bars.Open, bars.Close, period); - Core.Correl(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, optInTimePeriod: period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void SDEV() - { - SDEV_Series QL = new(bars.Close, period, false); - Core.StdDev(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void SMA() - { - SMA_Series QL = new(bars.Close, period, false); - Core.Sma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void SUM() - { - SUM_Series QL = new(bars.Close, period, false); - Core.Sum(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void MIDPRICE() - { - MIDPRICE_Series QL = new(bars, period, false); - Core.MidPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - - [Fact] - public void VAR() - { - VAR_Series QL = new(bars.Close, period, false); - Core.Var(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 4, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 4)); - } - - [Fact] - public void MIDPOINT() - { - MIDPOINT_Series QL = new(bars.Close, period, false); - Core.MidPoint(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - - [Fact] - public void MAMA() { + [Fact] public void ADD() { + ADD_Series QL = new(bars.Open, bars.Close); + Core.Add(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void ADL() { + ADL_Series QL = new(bars, false); + Core.Ad(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void ADOSC() { + ADOSC_Series QL = new(bars, false); + Core.AdOsc(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void ATR() { + ATR_Series QL = new(bars, period, false); + Core.Atr(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void BBANDS() { + double[] outMiddle = new double[bars.Count]; + double[] outUpper = new double[bars.Count]; + double[] outLower = new double[bars.Count]; + BBANDS_Series QL = new(bars.Close, period: 26, multiplier: 2.0, false); + Core.Bbands(inclose, 0, bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod: 26, optInNbDevUp: 2.0, optInNbDevDn: 2.0); + Assert.Equal(Math.Round(outUpper[outUpper.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Upper.Last().v, digits: digits)); + Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Mid.Last().v, digits: digits)); + Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Lower.Last().v, digits: digits)); + } + [Fact] public void CCI() { + CCI_Series QL = new(bars, period, false); + Core.Cci(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void CORR() { + CORR_Series QL = new(bars.Open, bars.Close, period); + Core.Correl(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, optInTimePeriod: period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void DEMA() { + DEMA_Series QL = new(bars.Close, period, false); + Core.Dema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void DIV() { + DIV_Series QL = new(bars.Open, bars.Close); + Core.Div(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void EMA() { + EMA_Series QL = new(bars.Close, period, false); + Core.Ema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void HL2() { + TSeries QL = bars.HL2; + Core.MedPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void HLC3() { + TSeries QL = bars.HLC3; + Core.TypPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void HLCC4() { + TSeries QL = bars.HLCC4; + Core.WclPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void MACD() { + double[] macdSignal = new double[bars.Count]; + double[] macdHist = new double[bars.Count]; + MACD_Series QL = new(bars.Close, slow: 26, fast: 12, signal: 9, false); + Core.Macd(inclose, 0, bars.Count - 1, outMacd: TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Signal.Last().v, digits: digits)); + } + [Fact] public void MAMA() { MAMA_Series QL = new(bars.Close, fastlimit: 0.5, slowlimit: 0.05); Core.Mama(inReal: inclose, startIdx: 0, endIdx: bars.Count - 1, outMama: TALIB, outFama: TALIB2, outBegIdx: out int outBegIdx, outNbElement: out _, optInFastLimit: 0.5, optInSlowLimit: 0.05); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void TRIMA() - { - TRIMA_Series QL = new(bars.Close, period, false); - Core.Trima(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void EMA() - { - EMA_Series QL = new(bars.Close, period, false); - Core.Ema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void WMA() - { - WMA_Series QL = new(bars.Close, period, false); - Core.Wma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void DEMA() - { - DEMA_Series QL = new(bars.Close, period, false); - Core.Dema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void TEMA() - { - TEMA_Series QL = new(bars.Close, period, false); - Core.Tema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void MAX() - { - MAX_Series QL = new(bars.Close, period, false); - Core.Max(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void MIN() - { - MIN_Series QL = new(bars.Close, period, false); - Core.Min(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void ADL() - { - ADL_Series QL = new(bars, false); - Core.Ad(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void OBV() - { - OBV_Series QL = new(bars, period, false); - Core.Obv(inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void ADOSC() - { - ADOSC_Series QL = new(bars, false); - Core.AdOsc(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void ATR() - { - ATR_Series QL = new(bars, period, false); - Core.Atr(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void CCI() - { - CCI_Series QL = new(bars, period, false); - Core.Cci(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void RSI() - { - RSI_Series QL = new(bars.Close, period, false); - Core.Rsi(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void TR() - { - TR_Series QL = new(bars, false); - Core.TRange(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void MACD() - { - double[] macdSignal = new double[bars.Count]; - double[] macdHist = new double[bars.Count]; - MACD_Series QL = new(bars.Close, slow: 26, fast: 12, signal: 9, false); - Core.Macd(inclose, 0, bars.Count - 1, outMacd: TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _); - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Signal.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void BBANDS() - { - double[] outMiddle = new double[bars.Count]; - double[] outUpper = new double[bars.Count]; - double[] outLower = new double[bars.Count]; - BBANDS_Series QL = new(bars.Close, period: 26, multiplier: 2.0, false); - Core.Bbands(inclose, 0, bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod: 26, optInNbDevUp: 2.0, optInNbDevDn: 2.0); - Assert.Equal(Math.Round(outUpper[outUpper.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Upper.Last().v, 6, MidpointRounding.AwayFromZero)); - Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Mid.Last().v, 6, MidpointRounding.AwayFromZero)); - Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Lower.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void HL2() - { - TSeries QL = bars.HL2; - Core.MedPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void HLC3() - { - TSeries QL = bars.HLC3; - Core.TypPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void OHLC4() - { - TSeries QL = bars.OHLC4; - Core.AvgPrice(inopen, inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } - - [Fact] - public void HLCC4() - { - TSeries QL = bars.HLCC4; - Core.WclPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); - - Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); - } + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void MAX() { + MAX_Series QL = new(bars.Close, period, false); + Core.Max(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void MIDPOINT() { + MIDPOINT_Series QL = new(bars.Close, period, false); + Core.MidPoint(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void MIDPRICE() { + MIDPRICE_Series QL = new(bars, period, false); + Core.MidPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void MIN() { + MIN_Series QL = new(bars.Close, period, false); + Core.Min(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void MUL() { + MUL_Series QL = new(bars.Open, bars.Close); + Core.Mult(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void OBV() { + OBV_Series QL = new(bars, period, false); + Core.Obv(inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void OHLC4() { + TSeries QL = bars.OHLC4; + Core.AvgPrice(inopen, inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void RSI() { + RSI_Series QL = new(bars.Close, period, false); + Core.Rsi(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void SDEV() { + SDEV_Series QL = new(bars.Close, period, false); + Core.StdDev(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void SMA() { + SMA_Series QL = new(bars.Close, period, false); + Core.Sma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void SUB() { + SUB_Series QL = new(bars.Open, bars.Close); + Core.Sub(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void SUM() { + SUM_Series QL = new(bars.Close, period, false); + Core.Sum(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void T3() { + T3_Series QL = new(source: bars.Close, period: period, vfactor:0.7, useNaN: false); + Core.T3(inReal: inclose, startIdx: 0, endIdx: bars.Count - 1, outReal: TALIB, outBegIdx: out int outBegIdx, outNbElement: out _, optInTimePeriod: period, optInVFactor: 0.7); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void TEMA() { + TEMA_Series QL = new(bars.Close, period, false); + Core.Tema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void TR() { + TR_Series QL = new(bars, false); + Core.TRange(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void TRIMA() { + TRIMA_Series QL = new(bars.Close, period, false); + Core.Trima(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void VAR() { + VAR_Series QL = new(bars.Close, period, false); + Core.Var(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } + [Fact] public void WMA() { + WMA_Series QL = new(bars.Close, period, false); + Core.Wma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); + Assert.Equal(Math.Round(TALIB[TALIB.Length - outBegIdx - 1], digits: digits), Math.Round(QL.Last().v, digits: digits)); + } } diff --git a/docs/readme.md b/docs/readme.md index 4ff10d2f..224e2f64 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -92,7 +92,7 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett | ⛔ KDJ - KDJ Indicator (trend reversal) |||| kdj | | ⛔ LSMA - Least Squares Moving Average ||||| | ⭐ MACD - Moving Average Convergence/Divergence | `MACD_Series` | MACD | GetMacd | macd | -| ⛔ MAMA - MESA Adaptive Moving Average || MAMA | GetMama || +| ⭐ MAMA - MESA Adaptive Moving Average | `MAMA_Series` | MAMA | GetMama || | ⛔ MCGD - McGinley Dynamic |||| mcgd | | ⛔ MMA - Modified Moving Average ||||| | ⛔ PPMA - Pivot Point Moving Average ||||| @@ -104,7 +104,7 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett | ⛔ SSF - Ehler's Super Smoother Filter |||| ssf | | ⛔ SUPERTREND - Supertrend |||| supertrend | | ⛔ SWMA - Symmetric Weighted Moving Average |||| swma | -| ⛔ T3 - Tillson T3 Moving Average || T3 | GetT3 | t3 | +| ⭐ T3 - Tillson T3 Moving Average | `T3_Series` | T3 | GetT3 | t3 | | ⭐ TEMA - Triple EMA Average | `TEMA_Series` | TEMA | GetTema | tema | | ⭐ TRIMA - Triangular Moving Average | `TRIMA_Series` | TRIMA || trima | | ⛔ TSF - Time Series Forecast || TSF |||