using Xunit; using System; using TALib; using QuanTAlib; namespace Validations; public class Ta_Lib { private readonly GBM_Feed bars; private readonly Random rnd = new(); private readonly int period, digits, skip; 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(Bars: 5000, Volatility: 0.8, Drift: 0.0, Precision: 3); period = rnd.Next(28) + 3; skip = period+2; digits = 10; 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 _); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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 _); for (int i = QL.Length - 1; i > 0; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } [Fact] public void ADOSC() { ADOSC_Series QL = new(bars, 3, 10, false); Core.AdOsc(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); 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: 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 = 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)); } } [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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } [Fact] public void CMO() { CMO_Series QL = new(bars.Close, period, false); Core.Cmo(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } [Fact] public void DEMA() { 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 > period*10; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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 _); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } [Fact] public void HL2() { TSeries QL = bars.HL2; Core.MedPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } [Fact] public void HLC3() { TSeries QL = bars.HLC3; Core.TypPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } [Fact] public void HLCC4() { TSeries QL = bars.HLCC4; Core.WclPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } [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); // 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 = 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)); } } [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); for (int i = QL.Length - 1; i > skip * 15; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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 _); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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 _); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } [Fact] public void OHLC4() { TSeries QL = bars.OHLC4; Core.AvgPrice(inopen, inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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 _); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > period*10; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip * 15; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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 _); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } [Fact] public void TRIX() { TRIX_Series QL = new(bars.Close, period, useNaN: false, useSMA: true); Core.Trix(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); for (int i = QL.Length - 1; i > period*10; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip * 15; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-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); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = Math.Round(QL[i].v, digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); } } }