using Xunit; using TALib; using System.Diagnostics.CodeAnalysis; namespace QuanTAlib; [SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")] public class TAlibTests { private readonly TBarSeries bars; private readonly GbmFeed feed; private readonly Random rnd; private readonly double range; private readonly int iterations; private readonly double[] data; private readonly double[] TALIB; public TAlibTests() { rnd = new((int)DateTime.Now.Ticks); feed = new(sigma: 0.5, mu: 0.0); bars = new(feed); range = 1e-9; feed.Add(10000); iterations = 3; data = feed.Close.v.ToArray(); TALIB = new double[data.Count()]; } [Fact] public void SMA() { for (int run = 0; run < iterations; run++) { int period = rnd.Next(50) + 5; Sma ma = new(period); TSeries QL = new(); foreach (TBar item in feed) { QL.Add(ma.Calc(new TValue(item.Time, item.Close))); } Core.Sma(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period); Assert.Equal(QL.Length, TALIB.Count()); for (int i = QL.Length - 1; i > period; i--) { double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx]; Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range); } } } [Fact] public void EMA() { for (int run = 0; run < iterations; run++) { int period = rnd.Next(50) + 5; Ema ma = new(period, useSma: true); TSeries QL = new(); foreach (TBar item in feed) { QL.Add(ma.Calc(new TValue(item.Time, item.Close))); } Core.Ema(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period); Assert.Equal(QL.Length, TALIB.Count()); for (int i = QL.Length - 1; i > period; i--) { double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx]; Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range); } } } [Fact] public void DEMA() { for (int run = 0; run < iterations; run++) { int period = rnd.Next(50) + 5; Dema ma = new(period); TSeries QL = new(); foreach (TBar item in feed) { QL.Add(ma.Calc(new TValue(item.Time, item.Close))); } Core.Dema(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period); Assert.Equal(QL.Length, TALIB.Length); for (int i = QL.Length - 1; i > period * 20; i--) { double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx]; Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range); } } } [Fact] public void TEMA() { for (int run = 0; run < iterations; run++) { int period = rnd.Next(50) + 5; Tema ma = new(period); TSeries QL = new(); foreach (TBar item in feed) { QL.Add(ma.Calc(new TValue(item.Time, item.Close))); } Core.Tema(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period); Assert.Equal(QL.Length, TALIB.Length); for (int i = QL.Length - 1; i > period * 20; i--) { double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx]; Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range); } } } //TODO fix WMA /* [Fact] public void WMA() { for (int run = 0; run < iterations; run++) { period = rnd.Next(50) + 5; Wma ma = new(period); TSeries QL = new(); foreach (TBar item in feed) { QL.Add(ma.Calc(new TValue(item.Time, item.Close))); } Core.Wma(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period); Assert.Equal(QL.Length, TALIB.Count()); for (int i = QL.Length - 1; i > period*3; i--) { double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx]; Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range); } } } */ [Fact] public void T3() { for (int run = 0; run < iterations; run++) { int period = rnd.Next(50) + 5; T3 ma = new(period, vfactor: 0.7, useSma: false); TSeries QL = new(); foreach (TBar item in feed) { QL.Add(ma.Calc(new TValue(item.Time, item.Close))); } Core.T3(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, optInTimePeriod: period, optInVFactor: 0.7); Assert.Equal(QL.Length, TALIB.Length); for (int i = QL.Length - 1; i > period * 20; i--) { double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx]; Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range); } } } }