mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-24 05:28:05 +00:00
Refactor validation tests for various indicators to utilize shared test data structure
This commit is contained in:
@@ -1,32 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Skender.Stock.Indicators;
|
||||
using TALib;
|
||||
using Tulip;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using QuanTAlib.Tests;
|
||||
|
||||
namespace QuanTAlib;
|
||||
|
||||
public class DwmaValidationTests
|
||||
public class DwmaValidationTests : IDisposable
|
||||
{
|
||||
private readonly ValidationTestData _testData;
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public DwmaValidationTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
_testData = new ValidationTestData(count: 1000, seed: 42);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_testData.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_Against_DoubleWma()
|
||||
{
|
||||
// DWMA should be exactly WMA(WMA(source, period), period)
|
||||
|
||||
int period = 10;
|
||||
int count = 1000;
|
||||
var source = new TSeries();
|
||||
var rnd = new Random(42);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
source.Add(new TValue(DateTime.UtcNow.AddMinutes(i), rnd.NextDouble() * 100));
|
||||
}
|
||||
|
||||
var dwma = new Dwma(period);
|
||||
var wma1 = new Wma(period);
|
||||
var wma2 = new Wma(period);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
for (int i = 0; i < _testData.Data.Count; i++)
|
||||
{
|
||||
var val = source[i];
|
||||
var val = _testData.Data[i];
|
||||
|
||||
// Calculate DWMA
|
||||
var dwmaVal = dwma.Update(val);
|
||||
@@ -35,7 +57,125 @@ public class DwmaValidationTests
|
||||
var wma1Val = wma1.Update(val);
|
||||
var wma2Val = wma2.Update(wma1Val);
|
||||
|
||||
Assert.Equal(wma2Val.Value, dwmaVal.Value, 10);
|
||||
Assert.Equal(wma2Val.Value, dwmaVal.Value, 1e-9);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_Against_Ooples()
|
||||
{
|
||||
// Ooples Finance does not have a specific DWMA indicator, but it can be calculated
|
||||
// by chaining two Weighted Moving Averages
|
||||
|
||||
int period = 14;
|
||||
|
||||
var dwma = new Dwma(period);
|
||||
var wma1 = new Wma(period); // Simulates first CalculateWeightedMovingAverage
|
||||
var wma2 = new Wma(period); // Simulates second CalculateWeightedMovingAverage
|
||||
|
||||
for (int i = 0; i < _testData.Data.Count; i++)
|
||||
{
|
||||
var val = _testData.Data[i];
|
||||
|
||||
// QuanTAlib DWMA
|
||||
var qVal = dwma.Update(val);
|
||||
|
||||
// Ooples Logic (Chained WMA)
|
||||
var w1 = wma1.Update(val);
|
||||
var w2 = wma2.Update(w1);
|
||||
|
||||
Assert.Equal(w2.Value, qVal.Value, 1e-9);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_Against_Tulip()
|
||||
{
|
||||
// Tulip does not have DWMA, so we chain two WMAs
|
||||
int[] periods = { 10, 20 };
|
||||
foreach (var period in periods)
|
||||
{
|
||||
var dwma = new Dwma(period);
|
||||
var qResult = dwma.Update(_testData.Data);
|
||||
|
||||
// Tulip WMA 1
|
||||
var wmaIndicator = Tulip.Indicators.wma;
|
||||
double[][] inputs1 = { _testData.RawData.ToArray() };
|
||||
double[] options = { period };
|
||||
int lookback1 = period - 1;
|
||||
double[][] outputs1 = { new double[_testData.RawData.Length - lookback1] };
|
||||
wmaIndicator.Run(inputs1, options, outputs1);
|
||||
|
||||
// Tulip WMA 2
|
||||
double[][] inputs2 = { outputs1[0] };
|
||||
int lookback2 = period - 1;
|
||||
double[][] outputs2 = { new double[inputs2[0].Length - lookback2] };
|
||||
wmaIndicator.Run(inputs2, options, outputs2);
|
||||
|
||||
var tResult = outputs2[0];
|
||||
int totalLookback = lookback1 + lookback2;
|
||||
|
||||
ValidationHelper.VerifyData(qResult, tResult, totalLookback, tolerance: 1e-6);
|
||||
}
|
||||
_output.WriteLine("DWMA validated against Tulip (Chained WMA)");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_Against_Skender()
|
||||
{
|
||||
// Skender does not have DWMA, so we chain two WMAs
|
||||
int[] periods = { 10, 20 };
|
||||
foreach (var period in periods)
|
||||
{
|
||||
var dwma = new Dwma(period);
|
||||
var qResult = dwma.Update(_testData.Data);
|
||||
|
||||
// Skender WMA 1
|
||||
var wma1Results = _testData.SkenderQuotes.GetWma(period)
|
||||
.Where(x => x.Wma.HasValue)
|
||||
.Select(x => new Quote { Date = x.Date, Close = (decimal)x.Wma!.Value })
|
||||
.ToList();
|
||||
|
||||
// Skender WMA 2
|
||||
var wma2Results = wma1Results.GetWma(period)
|
||||
.Where(x => x.Wma.HasValue)
|
||||
.Select(x => x.Wma!.Value)
|
||||
.ToArray();
|
||||
|
||||
int totalLookback = (period - 1) * 2;
|
||||
ValidationHelper.VerifyData(qResult, wma2Results, totalLookback, tolerance: 1e-6);
|
||||
}
|
||||
_output.WriteLine("DWMA validated against Skender (Chained WMA)");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_Against_Talib()
|
||||
{
|
||||
// TA-Lib does not have DWMA, so we chain two WMAs
|
||||
int[] periods = { 10, 20 };
|
||||
foreach (var period in periods)
|
||||
{
|
||||
var dwma = new Dwma(period);
|
||||
var qResult = dwma.Update(_testData.Data);
|
||||
|
||||
// TA-Lib WMA 1
|
||||
double[] wma1Output = new double[_testData.RawData.Length];
|
||||
var retCode1 = TALib.Functions.Wma(_testData.RawData.Span, 0..^0, wma1Output, out var outRange1, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode1);
|
||||
|
||||
// Prepare input for WMA 2 (only valid data from WMA 1)
|
||||
int count1 = outRange1.End.Value - outRange1.Start.Value;
|
||||
double[] wma1Valid = new double[count1];
|
||||
Array.Copy(wma1Output, 0, wma1Valid, 0, count1);
|
||||
|
||||
// TA-Lib WMA 2
|
||||
double[] dwmaOutput = new double[wma1Valid.Length];
|
||||
var retCode2 = TALib.Functions.Wma(wma1Valid, 0..^0, dwmaOutput, out _, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode2);
|
||||
|
||||
int totalLookback = (period - 1) * 2;
|
||||
ValidationHelper.VerifyData(qResult, dwmaOutput, totalLookback, tolerance: 1e-6);
|
||||
}
|
||||
_output.WriteLine("DWMA validated against TA-Lib (Chained WMA)");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user