using Skender.Stock.Indicators; using OoplesFinance.StockIndicators; using OoplesFinance.StockIndicators.Models; using QuanTAlib.Tests; namespace QuanTAlib; public sealed class AoValidationTests : IDisposable { private readonly ValidationTestData _data; public AoValidationTests() { _data = new ValidationTestData(); } public void Dispose() { _data.Dispose(); } [Fact] public void MatchesSkender() { var ao = new Ao(5, 34); var results = new List(); for (int i = 0; i < _data.Bars.Count; i++) { var res = ao.Update(_data.Bars[i]); results.Add(res.Value); } var skenderResults = _data.SkenderQuotes.GetAwesome(5, 34).ToList(); Assert.Equal(_data.Bars.Count, skenderResults.Count); for (int i = 0; i < _data.Bars.Count; i++) { // Skender returns null for warmup if (skenderResults[i].Oscillator == null) { continue; } Assert.Equal((double)skenderResults[i].Oscillator!, results[i], ValidationHelper.SkenderTolerance); } } [Fact] public void MatchesTulip() { var ao = new Ao(5, 34); var results = new List(); for (int i = 0; i < _data.Bars.Count; i++) { var res = ao.Update(_data.Bars[i]); results.Add(res.Value); } var high = _data.Bars.High.Select(x => x.Value).ToArray(); var low = _data.Bars.Low.Select(x => x.Value).ToArray(); var tulipIndicator = Tulip.Indicators.ao; double[][] inputs = { high, low }; double[] options = Array.Empty(); const int lookback = 33; double[][] outputs = [new double[_data.Bars.Count - lookback]]; tulipIndicator.Run(inputs, options, outputs); var tulipResults = outputs[0]; for (int i = 0; i < tulipResults.Length; i++) { Assert.Equal(tulipResults[i], results[i + lookback], ValidationHelper.TulipTolerance); } } [Fact] public void MatchesOoples() { var ao = new Ao(5, 34); var results = new List(); for (int i = 0; i < _data.Bars.Count; i++) { var res = ao.Update(_data.Bars[i]); results.Add(res.Value); } var ooplesData = _data.SkenderQuotes.Select(q => new TickerData { Date = q.Date, Open = (double)q.Open, High = (double)q.High, Low = (double)q.Low, Close = (double)q.Close, Volume = (double)q.Volume }).ToList(); var stockData = new StockData(ooplesData); var oResult = stockData.CalculateAwesomeOscillator(fastLength: 5, slowLength: 34); var oValues = oResult.OutputValues["Ao"]; Assert.Equal(_data.Bars.Count, oValues.Count); for (int i = 0; i < _data.Bars.Count; i++) { // Ooples might return 0 for warmup if (i < 33) { continue; // Skip warmup } Assert.Equal(oValues[i], results[i], ValidationHelper.OoplesTolerance); } } }