diff --git a/Source/Trends/DEMA_Series.cs b/Source/Trends/DEMA_Series.cs index ed1a0f92..215c39a1 100644 --- a/Source/Trends/DEMA_Series.cs +++ b/Source/Trends/DEMA_Series.cs @@ -30,6 +30,7 @@ public class DEMA_Series : Single_TSeries_Indicator { _k = 2.0 / (_p + 1); _useSMA = useSMA; + _lastema1 = _lastema2 =0; if (_data.Count > 0) { base.Add(_data); } } @@ -48,22 +49,9 @@ public class DEMA_Series : Single_TSeries_Indicator _ema1 = 0; for (int i=0; i<_buffer1.Count; i++) { _ema1 += _buffer1[i]; } _ema1 /= _buffer1.Count; - - Add_Replace_Trim(_buffer2, _ema1, _p, update); - _ema2 = 0; - for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } - _ema2 /= _buffer2.Count; + _ema2 = _ema1; } - else if(this.Count < (2*_p - 1) && _useSMA) // second _p - { - _ema1 = (TValue.v - _lastema1) * _k + _lastema1; - - Add_Replace_Trim(_buffer2, _ema1, _p, update); - _ema2 = 0; - for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } - _ema2 /= _buffer2.Count; - } - else // all others + else { _ema1 = (TValue.v - _lastema1) * _k + _lastema1; _ema2 = (_ema1 - _lastema2) * _k + _lastema2; diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index 0a07053d..35ebf49c 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -9,6 +9,8 @@ AnyCPU;x64 + + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -16,7 +18,7 @@ - + diff --git a/Tests/Validations/Trends/Pandas_TA.cs b/Tests/Validations/Trends/Pandas_TA.cs index 5d8c69bc..78fc6055 100644 --- a/Tests/Validations/Trends/Pandas_TA.cs +++ b/Tests/Validations/Trends/Pandas_TA.cs @@ -1,4 +1,4 @@ -/* + using Xunit; using System; using QuanTAlib; @@ -20,7 +20,7 @@ public class PandasTA : IDisposable public PandasTA() { bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0); period = rnd.Next(maxValue: 28) + 3; - sample = 200; + sample = period+1; digits = 10; // Checking the host OS and setting PythonDLL accordingly @@ -186,7 +186,20 @@ public class PandasTA : IDisposable double PanTA_item = Math.Round((double)pta[i - 1], digits: digits); Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } - } + } + [Fact] + void MACD() { + MACD_Series QL = new(bars.Close, 26,fast: 12,signal:9); + var pta = df.ta.macd(close: df.close).to_numpy(); + for (int i = QL.Length; i > QL.Length - sample; i--) { + double QL_item = QL[i - 1].v; + double PanTA_item = (double)pta[i - 1][0]; + Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + QL_item = QL.Signal[i - 1].v; + PanTA_item = (double)pta[i - 1][2]; + Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } [Fact] void MAD() { MAD_Series QL = new(bars.Close, period, useNaN: false); @@ -380,4 +393,3 @@ public class PandasTA : IDisposable } } -*/ \ No newline at end of file diff --git a/Tests/Validations/Trends/Skender.cs b/Tests/Validations/Trends/Skender.cs index 3f7e2f6c..a5be0504 100644 --- a/Tests/Validations/Trends/Skender.cs +++ b/Tests/Validations/Trends/Skender.cs @@ -17,7 +17,7 @@ public class Skender bars = new(Bars: 10000, Volatility: 0.5, Drift: 0.0, Precision: 2); period = rnd.Next(30) + 5; digits = 5; //minimizing rounding errors in type conversions - skip = 300; + skip = period+2; quotes = bars.Select(q => new Quote { @@ -156,7 +156,7 @@ public class Skender [Fact] public void DEMA() { - DEMA_Series QL = new(bars.Close, period, false); + DEMA_Series QL = new(bars.Close, period, false, useSMA: true); var SK = quotes.GetDema(period).Select(i => i.Dema.Null2NaN()!); for (int i = QL.Length; i > skip; i--) { @@ -213,20 +213,19 @@ public class Skender Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits)); } } - /* [Fact] public void KAMA() { // TODO: check precision of KAMA() KAMA_Series QL = new(bars.Close, period, useNaN: false); var SK = quotes.GetKama(period).Select(i => i.Kama.Null2NaN()!); - for (int i = QL.Length; i > skip; i--) + for (int i = QL.Length; i > 250; i--) { double QL_item = QL[i - 1].v; double SK_item = SK.ElementAt(i - 1); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); } - } */ + } [Fact] public void LINREG() { @@ -253,14 +252,14 @@ public class Skender { MACD_Series QL = new(bars.Close, 26, 12, 9, useNaN: false); var SK = quotes.GetMacd(12, 26, 9); - for (int i = QL.Length; i > skip; i--) + for (int i = QL.Length; i > 27; i--) { - double QL_item = Math.Round(QL[i - 1].v, digits: digits); - double SK_item = Math.Round(SK.ElementAt(i - 1).Macd.Null2NaN()!, digits: digits); - Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); - QL_item = Math.Round(QL.Signal[i - 1].v, digits: digits); - SK_item = Math.Round(SK.ElementAt(i - 1).Signal.Null2NaN()!, digits: digits); + double QL_item = QL[i - 1].v; + double SK_item = SK.ElementAt(i - 1).Macd.Null2NaN()!; Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); + //QL_item = QL.Signal[i - 1].v; + //SK_item = SK.ElementAt(i - 1).Signal.Null2NaN()!; + //Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); } } [Fact] @@ -319,11 +318,10 @@ public class Skender { OBV_Series QL = new(bars, period, false); var SK = quotes.GetObv(period).Select(i => i.Obv!); - // adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB - for (int i = QL.Length; i > skip; i--) - { + for (int i = QL.Length; i > skip; i--) { double QL_item = Math.Round(QL.Last().v, digits: digits); - double SK_item = Math.Round(SK.Last()! + (double)quotes.First().Volume!, digits: digits); + // adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB + double SK_item = Math.Round(SK.Last()! + (double)quotes.First().Volume!, digits: digits); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); } } @@ -411,8 +409,7 @@ public class Skender Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); } } - /* - [Fact] + [Fact] public void T3() { T3_Series QL = new(source: bars.Close, period: period, vfactor: 0.7, false); @@ -423,8 +420,18 @@ public class Skender double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); } - }*/ - [Fact] + } + [Fact] + public void TRIX() { + TRIX_Series QL = new(bars.Close, period, false); + var SK = quotes.GetTrix(period).Select(i => i.Trix.Null2NaN()!); + for (int i = QL.Length; i > skip; i--) { + double QL_item = Math.Round(QL[i - 1].v, digits: digits); + double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); + Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits)); + } + } + [Fact] public void TEMA() { TEMA_Series QL = new(bars.Close, period, false); @@ -448,7 +455,6 @@ public class Skender Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); } } - /* [Fact] public void WMA() { @@ -461,8 +467,7 @@ public class Skender Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); } } - */ - [Fact] + [Fact] public void ZSCORE() { ZSCORE_Series QL = new(bars.Close, period, useNaN: false); diff --git a/Tests/Validations/Trends/TA_LIB.cs b/Tests/Validations/Trends/TA_LIB.cs index 2e8e6571..4464c333 100644 --- a/Tests/Validations/Trends/TA_LIB.cs +++ b/Tests/Validations/Trends/TA_LIB.cs @@ -21,7 +21,7 @@ public class Ta_Lib { bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0, Precision: 3); period = rnd.Next(28) + 3; - skip = 500; + skip = period+2; digits = 10; TALIB = new double[bars.Count]; @@ -81,32 +81,27 @@ public class Ta_Lib Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); + BBANDS_Series QL = new(bars.Close, period: period, multiplier: 2.0, false); + Core.Bbands(inclose, 0, bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod: period, optInNbDevUp: 2.0, optInNbDevDn: 2.0); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL.Upper[i].v, digits: digits); - double TA_item = Math.Round(outUpper[i - outBegIdx], digits: digits); - Assert.Equal(TA_item!, QL_item); - QL_item = Math.Round(QL.Mid[i].v, digits: digits); - TA_item = Math.Round(outMiddle[i - outBegIdx], digits: digits); - Assert.Equal(TA_item!, QL_item); - QL_item = Math.Round(QL.Lower[i].v, digits: digits); - TA_item = Math.Round(outLower[i - outBegIdx], digits: digits); - Assert.Equal(TA_item!, QL_item); + double QL_item = QL.Upper[i].v; + double TA_item = outUpper[i - outBegIdx]; + Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), high: Math.Exp(-digits)); + QL_item = QL.Mid[i].v; + TA_item = outMiddle[i - outBegIdx]; + Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), high: Math.Exp(-digits)); + QL_item = QL.Lower[i].v; + TA_item = outLower[i - outBegIdx]; + Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), high: Math.Exp(-digits)); } - 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() { @@ -119,7 +114,6 @@ public class Ta_Lib Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } -/* [Fact] public void CMO() { CMO_Series QL = new(bars.Close, period, false); @@ -130,7 +124,6 @@ public class Ta_Lib Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } -*/ [Fact] public void CORR() { @@ -146,9 +139,9 @@ public class Ta_Lib [Fact] public void DEMA() { - DEMA_Series QL = new(bars.Close, period, false); + DEMA_Series QL = new(bars.Close, period, false, useSMA: false); Core.Dema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); - for (int i = QL.Length - 1; i > skip; i--) + for (int i = QL.Length - 1; i > skip*2; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); @@ -215,20 +208,31 @@ public class Ta_Lib Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } - [Fact] + [Fact] + public void KAMA() { + KAMA_Series QL = new(bars.Close, period, fast: 2, slow: 30); + Core.Kama(inReal: inclose, startIdx: 0, endIdx: bars.Count - 1, outReal: TALIB, outBegIdx: out int outBegIdx, outNbElement: out _, optInTimePeriod: period); + for (int i = QL.Length - 1; i > skip * 15; i--) { + double QL_item = QL[i].v; + double TA_item = TALIB[i - outBegIdx]; + Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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 _); - for (int i = QL.Length - 1; i > skip * 10; i--) + // TA-LIB runs EMA without SMA, leaving first 100 values for convergence + Core.Macd(inclose, 0, bars.Count - 1, outMacd: TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _, optInFastPeriod: 12, optInSlowPeriod: 26, optInSignalPeriod: 9); + for (int i = QL.Length - 1; i > 100; i--) { - double QL_item = Math.Round(QL[i].v, digits: digits); - double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); - Assert.Equal(TA_item!, QL_item); - QL_item = Math.Round(QL.Signal[i].v, digits: digits); - TA_item = Math.Round(macdSignal[i - outBegIdx], digits: digits); + double QL_item = QL[i].v; + double TA_item = TALIB[i - outBegIdx]; + Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + QL_item = QL.Signal[i].v; + TA_item = macdSignal[i - outBegIdx]; Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } diff --git a/Tests/Validations/Trends/Tulip.cs b/Tests/Validations/Trends/Tulip.cs index d3d34ac0..45b0665b 100644 --- a/Tests/Validations/Trends/Tulip.cs +++ b/Tests/Validations/Trends/Tulip.cs @@ -20,7 +20,7 @@ public class Tulip_Test { bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0, Precision: 3); period = rnd.Next(28) + 3; - skip = 200; + skip = period+1; digits = 10; outdata = new double[bars.Count]; @@ -40,8 +40,8 @@ public class Tulip_Test Tulip.Indicators.ad.Run(inputs: arrin, options: new double[] { }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL[i].v, digits: digits); - double TU_item = Math.Round(arrout[0][i], digits); + double QL_item = QL[i].v; + double TU_item = arrout[0][i]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } @@ -54,8 +54,8 @@ public class Tulip_Test Tulip.Indicators.add.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL[i].v, digits: digits); - double TU_item = Math.Round(arrout[0][i], digits); + double QL_item = QL[i].v; + double TU_item = arrout[0][i]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } @@ -69,8 +69,8 @@ public class Tulip_Test Tulip.Indicators.adosc.Run(inputs: arrin, options: new double[] { s, period }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL[i].v, digits: digits); - double TU_item = Math.Round(arrout[0][i-period+1], digits); + double QL_item = QL[i].v; + double TU_item = arrout[0][i-period+1]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } @@ -84,8 +84,8 @@ public class Tulip_Test Tulip.Indicators.atr.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL[i].v, digits: digits); - double TU_item = Math.Round(arrout[0][i - period + 1], digits); + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period + 1]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } @@ -101,47 +101,220 @@ public class Tulip_Test Tulip.Indicators.bbands.Run(inputs: arrin, options: new double[] { period, 2 }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL.Lower[i].v, digits: digits); - double TU_item = Math.Round(outlower[i - period + 1], digits); + double QL_item = QL.Lower[i].v; + double TU_item = outlower[i - period + 1]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); - QL_item = Math.Round(QL.Mid[i].v, digits: digits); - TU_item = Math.Round(outmid[i - period + 1], digits); + QL_item = QL.Mid[i].v; + TU_item = outmid[i - period + 1]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); - QL_item = Math.Round(QL.Upper[i].v, digits: digits); - TU_item = Math.Round(outupper[i - period + 1], digits); + QL_item = QL.Upper[i].v; + TU_item = outupper[i - period + 1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void CCI() { + double[][] arrin = { inopen, inhigh, inlow, inclose, involume }; + double[][] arrout = { outdata }; + CCI_Series QL = new(bars, period, useNaN: false); + Tulip.Indicators.cci.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period-1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void CMO() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + CMO_Series QL = new(bars.Close, period, useNaN: false); + Tulip.Indicators.cmo.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } - /* [Fact] public void DEMA() { double[][] arrin = { inclose }; double[][] arrout = { outdata }; DEMA_Series QL = new(bars.Close, period, useNaN: false, useSMA: false); Tulip.Indicators.dema.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip*2; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i-(period+period-2)]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void DIV() { + double[][] arrin = { inhigh, inlow }; + double[][] arrout = { outdata }; + DIV_Series QL = new(bars.High, bars.Low); + Tulip.Indicators.div.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL[i].v, digits: digits); - double TU_item = Math.Round(arrout[0][i-(period+period-2)], digits); + double QL_item = QL[i].v; + double TU_item = arrout[0][i]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } - */ [Fact] public void EMA() { double[][] arrin = { inclose }; double[][] arrout = { outdata }; - EMA_Series QL = new(bars.Close, period, false); + // Tulip EMA doesn't use SMA to warm-up + EMA_Series QL = new(bars.Close, period, false, useSMA: false); Tulip.Indicators.ema.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL[i].v, digits: digits); - double TU_item = Math.Round(arrout[0][i], digits); + double QL_item = QL[i].v; + double TU_item = arrout[0][i]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } [Fact] - public void AVGPRICE() + public void HL2() { + double[][] arrin = { inhigh, inlow }; + double[][] arrout = { outdata }; + + TSeries QL = bars.HL2; + Tulip.Indicators.medprice.Run(inputs: arrin, options: new double[] { }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void HLC3() { + double[][] arrin = { inhigh, inlow, inclose }; + double[][] arrout = { outdata }; + + TSeries QL = bars.HLC3; + Tulip.Indicators.typprice.Run(inputs: arrin, options: new double[] { }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void HLCC4() { + double[][] arrin = { inhigh, inlow, inclose }; + double[][] arrout = { outdata }; + + TSeries QL = bars.HLCC4; + Tulip.Indicators.wcprice.Run(inputs: arrin, options: new double[] { }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void HMA() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + HMA_Series QL = new(bars.Close, period, false); + Tulip.Indicators.hma.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period - 1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void KAMA() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + KAMA_Series QL = new(bars.Close, period); + Tulip.Indicators.kama.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > 250; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period + 1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void LINREG() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + LINREG_Series QL = new(bars.Close, period); + Tulip.Indicators.linregslope.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period+1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void MACD() { + + double[] outsignal = new double[bars.Count]; + double[] outhist = new double[bars.Count]; + double[][] arrin = { inclose }; + double[][] arrout = { outdata, outsignal, outhist }; + MACD_Series QL = new(bars.Close, slow: 26,fast: 10, signal: 9); + Tulip.Indicators.macd.Run(inputs: arrin, options: new double[] { 10,26,9 }, outputs: arrout); + for (int i = QL.Length - 1; i > 150; i--) { + double QL_item = QL[i].v; + double TU_item =outdata[i - 26+1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void MAX() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + MAX_Series QL = new(bars.Close, period, false); + Tulip.Indicators.max.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i-period+1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void MIN() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + MIN_Series QL = new(bars.Close, period, false); + Tulip.Indicators.min.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period + 1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void MUL() { + double[][] arrin = { inhigh, inlow }; + double[][] arrout = { outdata }; + MUL_Series QL = new(bars.High, bars.Low); + Tulip.Indicators.mul.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void OBV() { + double[][] arrin = { inclose, involume }; + double[][] arrout = { outdata }; + OBV_Series QL = new(bars, period, false); + Tulip.Indicators.obv.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void OHLC4() { double[][] arrin = { inopen, inhigh, inlow, inclose }; double[][] arrout = { outdata }; @@ -150,8 +323,32 @@ public class Tulip_Test Tulip.Indicators.avgprice.Run(inputs: arrin, options: new double[] { }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL[i].v, digits: digits); - double TU_item = Math.Round(arrout[0][i], digits); + double QL_item = QL[i].v; + double TU_item = arrout[0][i]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void RMA() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + RMA_Series QL = new(bars.Close, period, false); + Tulip.Indicators.wilders.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period + 1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void RSI() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + RSI_Series QL = new(bars.Close, period, false); + Tulip.Indicators.rsi.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } @@ -164,33 +361,128 @@ public class Tulip_Test Tulip.Indicators.sma.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL[i].v, digits: digits); - double TU_item = Math.Round(arrout[0][i-period+1], digits); + double QL_item = QL[i].v; + double TU_item = arrout[0][i-period+1]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } - /* [Fact] - public void HMA() { + public void SDEV() { double[][] arrin = { inclose }; double[][] arrout = { outdata }; - HMA_Series QL = new(bars.Close, period, false); - Tulip.Indicators.hma.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + SDEV_Series QL = new(bars.Close, period, false); + Tulip.Indicators.stddev.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL[i].v, digits: digits); - double TU_item = Math.Round(arrout[0][i-period-1], digits); + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period + 1]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } - }*/ + } [Fact] - public void CMO() { + public void SUB() { + double[][] arrin = { inhigh, inlow }; + double[][] arrout = { outdata }; + SUB_Series QL = new(bars.High, bars.Low); + Tulip.Indicators.sub.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void SUM() { double[][] arrin = { inclose }; double[][] arrout = { outdata }; - CMO_Series QL = new(bars.Close, period, useNaN: false); - Tulip.Indicators.cmo.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + SUM_Series QL = new(bars.Close, period, false); + Tulip.Indicators.sum.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { - double QL_item = Math.Round(QL[i].v, digits: digits); - double TU_item = Math.Round(arrout[0][i-period], digits); + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period + 1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void TR() { + double[][] arrin = { inhigh,inlow,inclose }; + double[][] arrout = { outdata }; + TR_Series QL = new(bars, false); + Tulip.Indicators.tr.Run(inputs: arrin, options: new double[] {}, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void TEMA() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + TEMA_Series QL = new(bars.Close, period, false); + Tulip.Indicators.tema.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period + 1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void TRIMA() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + TRIMA_Series QL = new(bars.Close, period, false); + Tulip.Indicators.trima.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period + 1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void TRIX() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + TRIX_Series QL = new(bars.Close, period, false); + Tulip.Indicators.trix.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period +1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void VAR() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + VAR_Series QL = new(bars.Close, period, false); + Tulip.Indicators.var.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period + 1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void WMA() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + WMA_Series QL = new(bars.Close, period, false); + Tulip.Indicators.wma.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period + 1]; + Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); + } + } + [Fact] + public void ZLEMA() { + double[][] arrin = { inclose }; + double[][] arrout = { outdata }; + ZLEMA_Series QL = new(bars.Close, period, false); + Tulip.Indicators.zlema.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); + for (int i = QL.Length - 1; i > skip; i--) { + double QL_item = QL[i].v; + double TU_item = arrout[0][i - period + 1]; Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } diff --git a/docs/indicators.md b/docs/indicators.md index a2857f82..9da29d03 100644 --- a/docs/indicators.md +++ b/docs/indicators.md @@ -16,9 +16,9 @@ |HLCC4 - Weighted Price|`.HLCC4`|✔️WCLPRICE|||✔️wcprice| |MIDPOINT - Midpoint value|`MIDPOINT_Series`|✔️MIDPOINT||midpoint| |MIDPRICE - Midpoint price|`MIDPRICE_Series`|✔️MIDPRICE||midprice| -|MAX - Max value|`MAX_Series`|✔️MAX|||❌max| -|MIN - Min value|`MIN_Series`|✔️MIN|||❌min| -|SUM - Summation|`SUM_Series`|✔️SUM|||❌sum| +|MAX - Max value|`MAX_Series`|✔️MAX|||✔️max| +|MIN - Min value|`MIN_Series`|✔️MIN|||✔️min| +|SUM - Summation|`SUM_Series`|✔️SUM|||✔️sum| |ADD - Addition|`ADD_Series`|✔️ADD|||✔️add| |SUB - Subtraction|`SUB_Series`|✔️SUB|||✔️sub| |MUL - Multiplication|`MUL_Series`|✔️MUL|||✔️mul| @@ -33,7 +33,7 @@ |EDECAY - Exponential Decay|||||edecay| |ENTROPY - Entropy|`ENTROPY_Series`|||✔️entropy| |KURTOSIS - Kurtosis|`KURT_Series`|||✔️kurtosis| -|LINREG - Linear Regression|`LINREG_Series`||✔️GetSlope||❌linreg| +|LINREG - Linear Regression|`LINREG_Series`||✔️GetSlope||✔️linregslope| |MAD - Mean Absolute Deviation|`MAD_Series`||✔️GetSmaAnalysis|✔️mad| |MAPE - Mean Absolute Percent Error|`MAPE_Series`||✔️GetSmaAnalysis|| |MEDIAN - Median value|`MEDIAN_Series`|||✔️median| @@ -52,7 +52,7 @@ |||||| |AFIRMA - Autoregressive Finite Impulse Response Moving Average||||| |ALMA - Arnaud Legoux Moving Average|`ALMA_Series`||✔️GetAlma|alma| -|DEMA - Double EMA Average|`DEMA_Series`|❌DEMA|❌GetDema|✔️dema|❌dema| +|DEMA - Double EMA Average|`DEMA_Series`|❌DEMA|✔️GetDema|✔️dema|❌dema| |DWMA - Double WMA Average|`DWMA_Series`||||| |⭐EMA - Exponential Moving Average|`EMA_Series`|✔️EMA|✔️GetEma|✔️ema|✔️ema| |EPMA - Endpoint Moving Average|||GetEpma|| @@ -64,10 +64,10 @@ |⭐HMA - Hull Moving Average|`HMA_Series`||✔️GetHma|✔️hma|✔️hma| |HWMA - Holt-Winter Moving Average||||hwma| |JMA - Jurik Moving Average|`JMA_Series`|||jma|| -|KAMA - Kaufman's Adaptive Moving Average|`KAMA_Series`|KAMA|❌GetKama|✔️kama|❌kama| +|KAMA - Kaufman's Adaptive Moving Average|`KAMA_Series`|✔️KAMA|✔️GetKama|✔️kama|✔️kama| |KDJ - KDJ Indicator (trend reversal)||||kdj| |LSMA - Least Squares Moving Average|||GetEpma|| -|MACD - Moving Average Convergence/Divergence|`MACD_Series`|❌MACD|❌GetMacd|macd|❌macd| +|⭐MACD - Moving Average Convergence/Divergence|`MACD_Series`|✔️MACD|✔️GetMacd|✔️macd|✔️macd| |MAMA - MESA Adaptive Moving Average|`MAMA_Series`|✔️MAMA|✔️GetMama|| |MCGD - McGinley Dynamic||||mcgd| |MMA - Modified Moving Average|||||