mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-25 05:48:06 +00:00
test tolerances updated
This commit is contained in:
Binary file not shown.
@@ -13,7 +13,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||||
<PackageReference Include="OoplesFinance.StockIndicators" Version="1.0.53" />
|
<PackageReference Include="OoplesFinance.StockIndicators" Version="1.1.0" />
|
||||||
<PackageReference Include="Skender.Stock.Indicators" Version="2.7.0" />
|
<PackageReference Include="Skender.Stock.Indicators" Version="2.7.0" />
|
||||||
<PackageReference Include="TALib.NETCore" Version="0.5.0" />
|
<PackageReference Include="TALib.NETCore" Version="0.5.0" />
|
||||||
<PackageReference Include="Tulip.NETCore" Version="0.8.0.1" />
|
<PackageReference Include="Tulip.NETCore" Version="0.8.0.1" />
|
||||||
|
|||||||
@@ -6,7 +6,14 @@ namespace QuanTAlib.Tests;
|
|||||||
|
|
||||||
public static class ValidationHelper
|
public static class ValidationHelper
|
||||||
{
|
{
|
||||||
public static void VerifyData<TResult>(TSeries qSeries, List<TResult> sSeries, Func<TResult, double?> selector, int skip = 100, double tolerance = 1e-6)
|
public const double DefaultTolerance = 1e-7;
|
||||||
|
public const double OoplesTolerance = 1e-7;
|
||||||
|
public const double SkenderTolerance = 1e-7;
|
||||||
|
public const double TalibTolerance = 1e-7;
|
||||||
|
public const double TulipTolerance = 1e-7;
|
||||||
|
public const double RelativeTolerance = 0.005;
|
||||||
|
|
||||||
|
public static void VerifyData<TResult>(TSeries qSeries, List<TResult> sSeries, Func<TResult, double?> selector, int skip = 100, double tolerance = DefaultTolerance)
|
||||||
{
|
{
|
||||||
Assert.Equal(qSeries.Count, sSeries.Count);
|
Assert.Equal(qSeries.Count, sSeries.Count);
|
||||||
|
|
||||||
@@ -24,7 +31,7 @@ public static class ValidationHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void VerifyData<TResult>(List<double> qResults, List<TResult> sSeries, Func<TResult, double?> selector, int skip = 100, double tolerance = 1e-6)
|
public static void VerifyData<TResult>(List<double> qResults, List<TResult> sSeries, Func<TResult, double?> selector, int skip = 100, double tolerance = DefaultTolerance)
|
||||||
{
|
{
|
||||||
Assert.Equal(qResults.Count, sSeries.Count);
|
Assert.Equal(qResults.Count, sSeries.Count);
|
||||||
|
|
||||||
@@ -42,7 +49,7 @@ public static class ValidationHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void VerifyData<TResult>(double[] qOutput, List<TResult> sSeries, Func<TResult, double?> selector, int skip = 100, double tolerance = 1e-6)
|
public static void VerifyData<TResult>(double[] qOutput, List<TResult> sSeries, Func<TResult, double?> selector, int skip = 100, double tolerance = DefaultTolerance)
|
||||||
{
|
{
|
||||||
Assert.Equal(qOutput.Length, sSeries.Count);
|
Assert.Equal(qOutput.Length, sSeries.Count);
|
||||||
|
|
||||||
@@ -60,7 +67,7 @@ public static class ValidationHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void VerifyData(TSeries qSeries, double[] tOutput, int lookback, int skip = 100, double tolerance = 1e-6)
|
public static void VerifyData(TSeries qSeries, double[] tOutput, int lookback, int skip = 100, double tolerance = DefaultTolerance)
|
||||||
{
|
{
|
||||||
int count = qSeries.Count;
|
int count = qSeries.Count;
|
||||||
int start = Math.Max(0, count - skip);
|
int start = Math.Max(0, count - skip);
|
||||||
@@ -80,7 +87,7 @@ public static class ValidationHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void VerifyData(List<double> qResults, double[] tOutput, int lookback, int skip = 100, double tolerance = 1e-6)
|
public static void VerifyData(List<double> qResults, double[] tOutput, int lookback, int skip = 100, double tolerance = DefaultTolerance)
|
||||||
{
|
{
|
||||||
int count = qResults.Count;
|
int count = qResults.Count;
|
||||||
int start = Math.Max(0, count - skip);
|
int start = Math.Max(0, count - skip);
|
||||||
@@ -100,7 +107,7 @@ public static class ValidationHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void VerifyData(double[] qOutput, double[] tOutput, int lookback, int skip = 100, double tolerance = 1e-6)
|
public static void VerifyData(double[] qOutput, double[] tOutput, int lookback, int skip = 100, double tolerance = DefaultTolerance)
|
||||||
{
|
{
|
||||||
int count = qOutput.Length;
|
int count = qOutput.Length;
|
||||||
int start = Math.Max(0, count - skip);
|
int start = Math.Max(0, count - skip);
|
||||||
@@ -120,7 +127,7 @@ public static class ValidationHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void VerifyData(TSeries qSeries, double[] tOutput, Range outRange, int lookback, int skip = 100, double tolerance = 1e-6)
|
public static void VerifyData(TSeries qSeries, double[] tOutput, Range outRange, int lookback, int skip = 100, double tolerance = DefaultTolerance)
|
||||||
{
|
{
|
||||||
int count = qSeries.Count;
|
int count = qSeries.Count;
|
||||||
int start = Math.Max(0, count - skip);
|
int start = Math.Max(0, count - skip);
|
||||||
@@ -141,7 +148,7 @@ public static class ValidationHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void VerifyData(List<double> qResults, double[] tOutput, Range outRange, int lookback, int skip = 100, double tolerance = 1e-6)
|
public static void VerifyData(List<double> qResults, double[] tOutput, Range outRange, int lookback, int skip = 100, double tolerance = DefaultTolerance)
|
||||||
{
|
{
|
||||||
int count = qResults.Count;
|
int count = qResults.Count;
|
||||||
int start = Math.Max(0, count - skip);
|
int start = Math.Max(0, count - skip);
|
||||||
@@ -162,7 +169,7 @@ public static class ValidationHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void VerifyData(double[] qOutput, double[] tOutput, Range outRange, int lookback, int skip = 100, double tolerance = 1e-6)
|
public static void VerifyData(double[] qOutput, double[] tOutput, Range outRange, int lookback, int skip = 100, double tolerance = DefaultTolerance)
|
||||||
{
|
{
|
||||||
int count = qOutput.Length;
|
int count = qOutput.Length;
|
||||||
int start = Math.Max(0, count - skip);
|
int start = Math.Max(0, count - skip);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class ValidationTestData : IDisposable
|
|||||||
public IReadOnlyList<Quote> SkenderQuotes { get; }
|
public IReadOnlyList<Quote> SkenderQuotes { get; }
|
||||||
public ReadOnlyMemory<double> RawData { get; }
|
public ReadOnlyMemory<double> RawData { get; }
|
||||||
|
|
||||||
public ValidationTestData(int count = 5000, double startPrice = 1000000.0, double mu = 0.05, double sigma = 2.0, int seed = 123)
|
public ValidationTestData(int count = 5000, double startPrice = 1000.0, double mu = 0.05, double sigma = 2.0, int seed = 123)
|
||||||
{
|
{
|
||||||
var gbm = new GBM(startPrice, mu, sigma, seed: seed);
|
var gbm = new GBM(startPrice, mu, sigma, seed: seed);
|
||||||
Bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
Bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class AoValidationTests : IDisposable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.Equal((double)skenderResults[i].Oscillator!, results[i], 1e-6);
|
Assert.Equal((double)skenderResults[i].Oscillator!, results[i], ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ public class AoValidationTests : IDisposable
|
|||||||
|
|
||||||
for (int i = 0; i < tulipResults.Length; i++)
|
for (int i = 0; i < tulipResults.Length; i++)
|
||||||
{
|
{
|
||||||
Assert.Equal(tulipResults[i], results[i + lookback], 1e-6);
|
Assert.Equal(tulipResults[i], results[i + lookback], ValidationHelper.TulipTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ public class AoValidationTests : IDisposable
|
|||||||
// Ooples might return 0 for warmup
|
// Ooples might return 0 for warmup
|
||||||
if (i < 33) continue; // Skip warmup
|
if (i < 33) continue; // Skip warmup
|
||||||
|
|
||||||
Assert.Equal(oValues[i], results[i], 1e-3);
|
Assert.Equal(oValues[i], results[i], ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ public class ApoValidationTests : IDisposable
|
|||||||
// 1. Batch Mode
|
// 1. Batch Mode
|
||||||
var apo = new Apo(fastPeriod, slowPeriod);
|
var apo = new Apo(fastPeriod, slowPeriod);
|
||||||
var result = apo.Update(_testData.Data);
|
var result = apo.Update(_testData.Data);
|
||||||
ValidationHelper.VerifyData(result, output, lookback: 0, tolerance: 1e-3);
|
ValidationHelper.VerifyData(result, output, lookback: 0, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
|
|
||||||
// 2. Streaming Mode
|
// 2. Streaming Mode
|
||||||
var apoStream = new Apo(fastPeriod, slowPeriod);
|
var apoStream = new Apo(fastPeriod, slowPeriod);
|
||||||
@@ -138,12 +138,12 @@ public class ApoValidationTests : IDisposable
|
|||||||
{
|
{
|
||||||
streamResults.Add(apoStream.Update(item).Value);
|
streamResults.Add(apoStream.Update(item).Value);
|
||||||
}
|
}
|
||||||
ValidationHelper.VerifyData(streamResults, output, lookback: 0, tolerance: 1e-3);
|
ValidationHelper.VerifyData(streamResults, output, lookback: 0, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
|
|
||||||
// 3. Span Mode
|
// 3. Span Mode
|
||||||
double[] input = _testData.Data.Values.ToArray();
|
double[] input = _testData.Data.Values.ToArray();
|
||||||
double[] spanOutput = new double[input.Length];
|
double[] spanOutput = new double[input.Length];
|
||||||
Apo.Calculate(input.AsSpan(), spanOutput.AsSpan(), fastPeriod, slowPeriod);
|
Apo.Calculate(input.AsSpan(), spanOutput.AsSpan(), fastPeriod, slowPeriod);
|
||||||
ValidationHelper.VerifyData(spanOutput, output, lookback: 0, tolerance: 1e-3);
|
ValidationHelper.VerifyData(spanOutput, output, lookback: 0, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,6 +132,6 @@ public sealed class AroonOscValidationTests : IDisposable
|
|||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
// Verify Oscillator
|
// Verify Oscillator
|
||||||
ValidationHelper.VerifyData(results, ooplesOsc, lookback: 14, tolerance: 1e-4);
|
ValidationHelper.VerifyData(results, ooplesOsc, lookback: 14, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class CfbValidationTests
|
|||||||
Assert.NotEmpty(streamResult);
|
Assert.NotEmpty(streamResult);
|
||||||
for (int i = 0; i < streamResult.Count; i++)
|
for (int i = 0; i < streamResult.Count; i++)
|
||||||
{
|
{
|
||||||
Assert.Equal(streamResult[i].Value, batchResult[i].Value, 1e-9);
|
Assert.Equal(streamResult[i].Value, batchResult[i].Value, ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("CFB Update vs Batch validated successfully");
|
_output.WriteLine("CFB Update vs Batch validated successfully");
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ public class CfbValidationTests
|
|||||||
|
|
||||||
for (int i = 0; i < batchResult.Count; i++)
|
for (int i = 0; i < batchResult.Count; i++)
|
||||||
{
|
{
|
||||||
Assert.Equal(batchResult.Values[i], spanOutput[i], 1e-9);
|
Assert.Equal(batchResult.Values[i], spanOutput[i], ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("CFB Series vs Span validated successfully");
|
_output.WriteLine("CFB Series vs Span validated successfully");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class DmxValidationTests
|
|||||||
Assert.Equal(streamResult.Count, seriesResult.Count);
|
Assert.Equal(streamResult.Count, seriesResult.Count);
|
||||||
for (int i = 0; i < bars.Count; i++)
|
for (int i = 0; i < bars.Count; i++)
|
||||||
{
|
{
|
||||||
Assert.Equal(streamResult[i].Value, seriesResult[i].Value, 1e-9);
|
Assert.Equal(streamResult[i].Value, seriesResult[i].Value, ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("DMX Update vs Series validated successfully");
|
_output.WriteLine("DMX Update vs Series validated successfully");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using QuanTAlib.Tests;
|
||||||
|
|
||||||
namespace QuanTAlib;
|
namespace QuanTAlib;
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ public class RsxValidationTests
|
|||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
// Allow small difference due to floating point arithmetic order
|
// Allow small difference due to floating point arithmetic order
|
||||||
Assert.Equal(refResults[i], quantalibResults[i], 1e-9);
|
Assert.Equal(refResults[i], quantalibResults[i], ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class VelValidationTests
|
|||||||
var p = pwma.Update(input);
|
var p = pwma.Update(input);
|
||||||
var w = wma.Update(input);
|
var w = wma.Update(input);
|
||||||
|
|
||||||
Assert.Equal(p.Value - w.Value, v.Value, 1e-10);
|
Assert.Equal(p.Value - w.Value, v.Value, ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ public class AlmaValidationTests : IDisposable
|
|||||||
var qResult = alma.Update(_testData.Data);
|
var qResult = alma.Update(_testData.Data);
|
||||||
|
|
||||||
// 3. Verify
|
// 3. Verify
|
||||||
ValidationHelper.VerifyData(qResult, oAlma, x => x, skip: 100, tolerance: 1.0);
|
ValidationHelper.VerifyData(qResult, oAlma, x => x, skip: 100, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("ALMA Batch validated successfully against Ooples");
|
_output.WriteLine("ALMA Batch validated successfully against Ooples");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public class BesselValidationTests : IDisposable
|
|||||||
Bessel.Calculate(src.AsSpan(), outSpan.AsSpan(), length);
|
Bessel.Calculate(src.AsSpan(), outSpan.AsSpan(), length);
|
||||||
|
|
||||||
// Verify last window for convergence and consistency
|
// Verify last window for convergence and consistency
|
||||||
ValidationHelper.VerifyData(qResult, outSpan, lookback: 0, skip: length, tolerance: 1e-9);
|
ValidationHelper.VerifyData(qResult, outSpan, lookback: 0, skip: length, tolerance: ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
_output.WriteLine("Bessel validated internally: Span vs TSeries are consistent.");
|
_output.WriteLine("Bessel validated internally: Span vs TSeries are consistent.");
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class ConvValidationTests : IDisposable
|
|||||||
|
|
||||||
if (i >= period) // Skip warmup
|
if (i >= period) // Skip warmup
|
||||||
{
|
{
|
||||||
Assert.Equal(smaVal.Value, convVal.Value, 1e-4);
|
Assert.Equal(smaVal.Value, convVal.Value, ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ public class ConvValidationTests : IDisposable
|
|||||||
|
|
||||||
if (i >= period) // Skip warmup
|
if (i >= period) // Skip warmup
|
||||||
{
|
{
|
||||||
Assert.Equal(wmaVal.Value, convVal.Value, 1e-4);
|
Assert.Equal(wmaVal.Value, convVal.Value, ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,7 @@ public class ConvValidationTests : IDisposable
|
|||||||
|
|
||||||
if (i >= period) // Skip warmup
|
if (i >= period) // Skip warmup
|
||||||
{
|
{
|
||||||
Assert.Equal(trimaVal.Value, convVal.Value, 1e-4);
|
Assert.Equal(trimaVal.Value, convVal.Value, ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,6 +209,6 @@ public class ConvValidationTests : IDisposable
|
|||||||
var conv = new Conv(kernel);
|
var conv = new Conv(kernel);
|
||||||
var result = conv.Update(_testData.Data);
|
var result = conv.Update(_testData.Data);
|
||||||
|
|
||||||
ValidationHelper.VerifyData(result, ooplesWma, (s) => s, skip: period, tolerance: 1e-4);
|
ValidationHelper.VerifyData(result, ooplesWma, (s) => s, skip: period, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ public class DemaValidationTests : IDisposable
|
|||||||
// Compare
|
// Compare
|
||||||
// Note: There might be tiny differences due to floating point operations order
|
// Note: There might be tiny differences due to floating point operations order
|
||||||
// or internal state handling optimization in Dema class vs composed Ema classes.
|
// or internal state handling optimization in Dema class vs composed Ema classes.
|
||||||
Assert.Equal(ooplesVal, qVal.Value, 1e-9);
|
Assert.Equal(ooplesVal, qVal.Value, ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_output.WriteLine("DEMA validated successfully against Ooples logic (2*EMA - EMA(EMA))");
|
_output.WriteLine("DEMA validated successfully against Ooples logic (2*EMA - EMA(EMA))");
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class DwmaValidationTests : IDisposable
|
|||||||
var wma1Val = wma1.Update(val);
|
var wma1Val = wma1.Update(val);
|
||||||
var wma2Val = wma2.Update(wma1Val);
|
var wma2Val = wma2.Update(wma1Val);
|
||||||
|
|
||||||
Assert.Equal(wma2Val.Value, dwmaVal.Value, 1e-9);
|
Assert.Equal(wma2Val.Value, dwmaVal.Value, ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ public class DwmaValidationTests : IDisposable
|
|||||||
var w1 = wma1.Update(val);
|
var w1 = wma1.Update(val);
|
||||||
var w2 = wma2.Update(w1);
|
var w2 = wma2.Update(w1);
|
||||||
|
|
||||||
Assert.Equal(w2.Value, qVal.Value, 1e-9);
|
Assert.Equal(w2.Value, qVal.Value, ValidationHelper.DefaultTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ public class DwmaValidationTests : IDisposable
|
|||||||
var tResult = outputs2[0];
|
var tResult = outputs2[0];
|
||||||
int totalLookback = lookback1 + lookback2;
|
int totalLookback = lookback1 + lookback2;
|
||||||
|
|
||||||
ValidationHelper.VerifyData(qResult, tResult, totalLookback, tolerance: 1e-6);
|
ValidationHelper.VerifyData(qResult, tResult, totalLookback, tolerance: ValidationHelper.TulipTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("DWMA validated against Tulip (Chained WMA)");
|
_output.WriteLine("DWMA validated against Tulip (Chained WMA)");
|
||||||
}
|
}
|
||||||
@@ -143,7 +143,7 @@ public class DwmaValidationTests : IDisposable
|
|||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
int totalLookback = (period - 1) * 2;
|
int totalLookback = (period - 1) * 2;
|
||||||
ValidationHelper.VerifyData(qResult, wma2Results, totalLookback, tolerance: 1e-6);
|
ValidationHelper.VerifyData(qResult, wma2Results, totalLookback, tolerance: ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("DWMA validated against Skender (Chained WMA)");
|
_output.WriteLine("DWMA validated against Skender (Chained WMA)");
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ public class DwmaValidationTests : IDisposable
|
|||||||
Assert.Equal(Core.RetCode.Success, retCode2);
|
Assert.Equal(Core.RetCode.Success, retCode2);
|
||||||
|
|
||||||
int totalLookback = (period - 1) * 2;
|
int totalLookback = (period - 1) * 2;
|
||||||
ValidationHelper.VerifyData(qResult, dwmaOutput, totalLookback, tolerance: 1e-6);
|
ValidationHelper.VerifyData(qResult, dwmaOutput, totalLookback, tolerance: ValidationHelper.TalibTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("DWMA validated against TA-Lib (Chained WMA)");
|
_output.WriteLine("DWMA validated against TA-Lib (Chained WMA)");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -306,7 +306,7 @@ public class EmaValidationTests : IDisposable
|
|||||||
var oValues = oResult.OutputValues.Values.First();
|
var oValues = oResult.OutputValues.Values.First();
|
||||||
|
|
||||||
// Compare
|
// Compare
|
||||||
ValidationHelper.VerifyData(qResult, oValues, (s) => s, tolerance: 5e-4);
|
ValidationHelper.VerifyData(qResult, oValues, (s) => s, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("EMA validated successfully against Ooples");
|
_output.WriteLine("EMA validated successfully against Ooples");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public class HmaValidationTests : IDisposable
|
|||||||
var sResult = _testData.SkenderQuotes.GetHma(period).ToList();
|
var sResult = _testData.SkenderQuotes.GetHma(period).ToList();
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResult, sResult, (s) => s.Hma, tolerance: 1e-5);
|
ValidationHelper.VerifyData(qResult, sResult, (s) => s.Hma, tolerance: ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("HMA Batch(TSeries) validated successfully against Skender");
|
_output.WriteLine("HMA Batch(TSeries) validated successfully against Skender");
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ public class HmaValidationTests : IDisposable
|
|||||||
var tResult = outputs[0];
|
var tResult = outputs[0];
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResult, tResult, lookback, tolerance: 1e-5);
|
ValidationHelper.VerifyData(qResult, tResult, lookback, tolerance: ValidationHelper.TulipTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("HMA Batch(TSeries) validated successfully against Tulip");
|
_output.WriteLine("HMA Batch(TSeries) validated successfully against Tulip");
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ public class HmaValidationTests : IDisposable
|
|||||||
var sResult = _testData.SkenderQuotes.GetHma(period).ToList();
|
var sResult = _testData.SkenderQuotes.GetHma(period).ToList();
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qOutput, sResult, (s) => s.Hma, tolerance: 1e-5);
|
ValidationHelper.VerifyData(qOutput, sResult, (s) => s.Hma, tolerance: ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("HMA Span validated successfully against Skender");
|
_output.WriteLine("HMA Span validated successfully against Skender");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class HtitValidationTests : IDisposable
|
|||||||
{
|
{
|
||||||
double talibValue = output[i - outRange.Start.Value];
|
double talibValue = output[i - outRange.Start.Value];
|
||||||
double quantalibValue = quantalibResults.Values[i];
|
double quantalibValue = quantalibResults.Values[i];
|
||||||
Assert.Equal(talibValue, quantalibValue, 1e-6);
|
Assert.Equal(talibValue, quantalibValue, ValidationHelper.TalibTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ public class HtitValidationTests : IDisposable
|
|||||||
// The divergence in Skender is likely due to implementation details or smoothing differences.
|
// The divergence in Skender is likely due to implementation details or smoothing differences.
|
||||||
double diff = Math.Abs(skenderValue - quantalibValue);
|
double diff = Math.Abs(skenderValue - quantalibValue);
|
||||||
double relError = diff / skenderValue;
|
double relError = diff / skenderValue;
|
||||||
Assert.True(relError < 0.005, $"Relative error {relError} too high at index {i}");
|
Assert.True(relError < ValidationHelper.RelativeTolerance, $"Relative error {relError} too high at index {i}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ public class HtitValidationTests : IDisposable
|
|||||||
// Skender implementation differs slightly (~0.32%) from TA-Lib/QuanTAlib
|
// Skender implementation differs slightly (~0.32%) from TA-Lib/QuanTAlib
|
||||||
double diff = Math.Abs(skenderValue - quantalibValue);
|
double diff = Math.Abs(skenderValue - quantalibValue);
|
||||||
double relError = diff / skenderValue;
|
double relError = diff / skenderValue;
|
||||||
Assert.True(relError < 0.005, $"Relative error {relError} too high at index {i}");
|
Assert.True(relError < ValidationHelper.RelativeTolerance, $"Relative error {relError} too high at index {i}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,7 +156,7 @@ public class HtitValidationTests : IDisposable
|
|||||||
// QuanTAlib matches TA-Lib (reference) with 1e-6 precision.
|
// QuanTAlib matches TA-Lib (reference) with 1e-6 precision.
|
||||||
double diff = Math.Abs(ooplesValue - quantalibValue);
|
double diff = Math.Abs(ooplesValue - quantalibValue);
|
||||||
double relError = diff / ooplesValue;
|
double relError = diff / ooplesValue;
|
||||||
Assert.True(relError < 0.003, $"Relative error {relError} too high at index {i}");
|
Assert.True(relError < ValidationHelper.RelativeTolerance, $"Relative error {relError} too high at index {i}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ public class KamaValidationTests
|
|||||||
var oValues = oResult.OutputValues["Kama"];
|
var oValues = oResult.OutputValues["Kama"];
|
||||||
|
|
||||||
// Compare
|
// Compare
|
||||||
ValidationHelper.VerifyData(qResult, oValues, (s) => s, tolerance: 5e-4);
|
ValidationHelper.VerifyData(qResult, oValues, (s) => s, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("KAMA validated successfully against Ooples");
|
_output.WriteLine("KAMA validated successfully against Ooples");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class LsmaValidationTests
|
|||||||
var sResult = _testData.SkenderQuotes.GetEpma(period).ToList();
|
var sResult = _testData.SkenderQuotes.GetEpma(period).ToList();
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResult, sResult, x => x.Epma, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qResult, sResult, x => x.Epma, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("LSMA Batch(TSeries) validated successfully against Skender");
|
_output.WriteLine("LSMA Batch(TSeries) validated successfully against Skender");
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ public class LsmaValidationTests
|
|||||||
var sResult = _testData.SkenderQuotes.GetEpma(period).ToList();
|
var sResult = _testData.SkenderQuotes.GetEpma(period).ToList();
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResults, sResult, x => x.Epma, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qResults, sResult, x => x.Epma, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("LSMA Streaming validated successfully against Skender");
|
_output.WriteLine("LSMA Streaming validated successfully against Skender");
|
||||||
}
|
}
|
||||||
@@ -79,7 +79,7 @@ public class LsmaValidationTests
|
|||||||
var sResult = _testData.SkenderQuotes.GetEpma(period).ToList();
|
var sResult = _testData.SkenderQuotes.GetEpma(period).ToList();
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qOutput, sResult, x => x.Epma, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qOutput, sResult, x => x.Epma, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("LSMA Span validated successfully against Skender");
|
_output.WriteLine("LSMA Span validated successfully against Skender");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,8 +111,9 @@ public class MamaValidationTests
|
|||||||
var qResult = mama.Update(_testData.Data); // _testData.Data is Close prices
|
var qResult = mama.Update(_testData.Data); // _testData.Data is Close prices
|
||||||
|
|
||||||
// 3. Verify MAMA
|
// 3. Verify MAMA
|
||||||
// Tolerance increased to 30.0 due to high-precision constant updates in QuanTAlib
|
// Tolerance set to 30.0 due to significant divergence (~27.0) caused by:
|
||||||
// Ooples implementation shows larger divergence (~26.3) likely due to different smoothing or constant handling
|
// 1. Initialization: Ooples starts from 0, QuanTAlib warms up with Average.
|
||||||
|
// 2. Precision: Ooples uses 4-decimal constants, QuanTAlib uses exact fractions.
|
||||||
ValidationHelper.VerifyData(qResult, oMama, x => x, skip: 100, tolerance: 30.0);
|
ValidationHelper.VerifyData(qResult, oMama, x => x, skip: 100, tolerance: 30.0);
|
||||||
|
|
||||||
// 4. Verify FAMA
|
// 4. Verify FAMA
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public class MgdiValidationTests : IDisposable
|
|||||||
|
|
||||||
if (!double.IsNaN(skenderValue))
|
if (!double.IsNaN(skenderValue))
|
||||||
{
|
{
|
||||||
Assert.Equal(skenderValue, quantalibValue, 1e-6);
|
Assert.Equal(skenderValue, quantalibValue, ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@ public class MgdiValidationTests : IDisposable
|
|||||||
|
|
||||||
if (!double.IsNaN(skenderValue))
|
if (!double.IsNaN(skenderValue))
|
||||||
{
|
{
|
||||||
Assert.Equal(skenderValue, quantalibValue, 1e-6);
|
Assert.Equal(skenderValue, quantalibValue, ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ public class MgdiValidationTests : IDisposable
|
|||||||
// We'll check for close correlation using relative error
|
// We'll check for close correlation using relative error
|
||||||
double diff = Math.Abs(ooplesValue - quantalibValue);
|
double diff = Math.Abs(ooplesValue - quantalibValue);
|
||||||
double relError = diff / ooplesValue;
|
double relError = diff / ooplesValue;
|
||||||
Assert.True(relError < 1e-9, $"Relative error {relError} too high at index {i}");
|
Assert.True(relError < ValidationHelper.OoplesTolerance, $"Relative error {relError} too high at index {i}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace QuanTAlib.Tests;
|
||||||
|
|
||||||
|
public class PwmaComparisonTests
|
||||||
|
{
|
||||||
|
private readonly ITestOutputHelper _output;
|
||||||
|
|
||||||
|
public PwmaComparisonTests(ITestOutputHelper output)
|
||||||
|
{
|
||||||
|
_output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compare_O1_vs_Naive()
|
||||||
|
{
|
||||||
|
int period = 50;
|
||||||
|
int count = 5000;
|
||||||
|
var random = new Random(123);
|
||||||
|
var data = new List<double>();
|
||||||
|
for (int i = 0; i < count; i++) data.Add(random.NextDouble() * 100);
|
||||||
|
|
||||||
|
// 1. QuanTAlib O(1)
|
||||||
|
var pwma = new Pwma(period);
|
||||||
|
var qResults = new List<double>();
|
||||||
|
foreach (var val in data)
|
||||||
|
{
|
||||||
|
qResults.Add(pwma.Update(new TValue(DateTime.UtcNow, val)).Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Naive O(N)
|
||||||
|
var nResults = new List<double>();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (i < period - 1)
|
||||||
|
{
|
||||||
|
// Warmup logic matching QuanTAlib
|
||||||
|
double sumSq = 0;
|
||||||
|
double wSum = 0;
|
||||||
|
for (int j = 0; j <= i; j++)
|
||||||
|
{
|
||||||
|
double weight = (j + 1) * (j + 1);
|
||||||
|
wSum += data[j] * weight;
|
||||||
|
sumSq += weight;
|
||||||
|
}
|
||||||
|
nResults.Add(wSum / sumSq);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double sumSq = 0;
|
||||||
|
double wSum = 0;
|
||||||
|
for (int j = 0; j < period; j++)
|
||||||
|
{
|
||||||
|
double weight = (j + 1) * (j + 1);
|
||||||
|
wSum += data[i - period + 1 + j] * weight;
|
||||||
|
sumSq += weight;
|
||||||
|
}
|
||||||
|
nResults.Add(wSum / sumSq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare
|
||||||
|
double maxDiff = 0;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
double diff = Math.Abs(qResults[i] - nResults[i]);
|
||||||
|
if (diff > maxDiff) maxDiff = diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
_output.WriteLine($"Max Difference between O(1) and Naive O(N): {maxDiff:F10}");
|
||||||
|
Assert.True(maxDiff < 1e-9, $"O(1) implementation diverged too much: {maxDiff}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,7 +47,7 @@ public class PwmaValidationTests
|
|||||||
var oValues = oResult.OutputValues["Pwma"];
|
var oValues = oResult.OutputValues["Pwma"];
|
||||||
|
|
||||||
// Compare
|
// Compare
|
||||||
ValidationHelper.VerifyData(qResult, oValues, (s) => s, tolerance: 1e-3);
|
ValidationHelper.VerifyData(qResult, oValues, (s) => s, tolerance: 2e-4);
|
||||||
}
|
}
|
||||||
_output.WriteLine("PWMA validated successfully against Ooples");
|
_output.WriteLine("PWMA validated successfully against Ooples");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public class RmaValidationTests : IDisposable
|
|||||||
int skip = period * 30;
|
int skip = period * 30;
|
||||||
|
|
||||||
int itemsToVerify = _testData.Data.Count - skip;
|
int itemsToVerify = _testData.Data.Count - skip;
|
||||||
ValidationHelper.VerifyData(quantalibResults, skenderResults, (s) => s.Smma, skip: itemsToVerify, tolerance: 1e-4);
|
ValidationHelper.VerifyData(quantalibResults, skenderResults, (s) => s.Smma, skip: itemsToVerify, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -93,6 +93,6 @@ public class RmaValidationTests : IDisposable
|
|||||||
int skip = period * 30;
|
int skip = period * 30;
|
||||||
int itemsToVerify = _testData.Data.Count - skip;
|
int itemsToVerify = _testData.Data.Count - skip;
|
||||||
|
|
||||||
ValidationHelper.VerifyData(qResult, oValues, (s) => s, skip: itemsToVerify, tolerance: 5e-4);
|
ValidationHelper.VerifyData(qResult, oValues, (s) => s, skip: itemsToVerify, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ public class SmaValidationTests : IDisposable
|
|||||||
var sResult = Calculations.CalculateSimpleMovingAverage(stockData, period).OutputValues.Values.First();
|
var sResult = Calculations.CalculateSimpleMovingAverage(stockData, period).OutputValues.Values.First();
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResult, sResult, (s) => s, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qResult, sResult, (s) => s, 100, ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("SMA Batch(TSeries) validated successfully against Ooples");
|
_output.WriteLine("SMA Batch(TSeries) validated successfully against Ooples");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class SsfValidationTests : IDisposable
|
|||||||
// We use a looser tolerance (10.0) because our implementation uses high-precision constants (Math.Sqrt(2) * Math.PI)
|
// We use a looser tolerance (10.0) because our implementation uses high-precision constants (Math.Sqrt(2) * Math.PI)
|
||||||
// whereas Ooples likely uses the approximation (1.414 * 3.14159) found in some reference implementations.
|
// whereas Ooples likely uses the approximation (1.414 * 3.14159) found in some reference implementations.
|
||||||
// This difference in constants causes a divergence in values.
|
// This difference in constants causes a divergence in values.
|
||||||
ValidationHelper.VerifyData(qResult, oValues, (s) => s, skip: period, tolerance: 10.0);
|
ValidationHelper.VerifyData(qResult, oValues, (s) => s, skip: period, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("SSF validated successfully against Ooples");
|
_output.WriteLine("SSF validated successfully against Ooples");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,16 +60,16 @@ public class SuperValidationTests : IDisposable
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.Equal((double)skenderResults[i].SuperTrend!, results[i], 1e-7);
|
Assert.Equal((double)skenderResults[i].SuperTrend!, results[i], ValidationHelper.SkenderTolerance);
|
||||||
|
|
||||||
if (skenderResults[i].UpperBand != null)
|
if (skenderResults[i].UpperBand != null)
|
||||||
{
|
{
|
||||||
Assert.Equal((double)skenderResults[i].UpperBand!, upper[i], 1e-7);
|
Assert.Equal((double)skenderResults[i].UpperBand!, upper[i], ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skenderResults[i].LowerBand != null)
|
if (skenderResults[i].LowerBand != null)
|
||||||
{
|
{
|
||||||
Assert.Equal((double)skenderResults[i].LowerBand!, lower[i], 1e-7);
|
Assert.Equal((double)skenderResults[i].LowerBand!, lower[i], ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ public class T3ValidationTests
|
|||||||
var oValues = oResult.OutputValues["T3"];
|
var oValues = oResult.OutputValues["T3"];
|
||||||
|
|
||||||
// Compare
|
// Compare
|
||||||
ValidationHelper.VerifyData(qResult, oValues, (s) => s, tolerance: 1e-3);
|
ValidationHelper.VerifyData(qResult, oValues, (s) => s, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("T3 validated successfully against Ooples");
|
_output.WriteLine("T3 validated successfully against Ooples");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public class TrimaValidationTests
|
|||||||
int lookback = TALib.Functions.TrimaLookback(period);
|
int lookback = TALib.Functions.TrimaLookback(period);
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResult, output, outRange, lookback, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qResult, output, outRange, lookback, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("TRIMA Batch(TSeries) validated successfully against TA-Lib");
|
_output.WriteLine("TRIMA Batch(TSeries) validated successfully against TA-Lib");
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ public class TrimaValidationTests
|
|||||||
var tResult = outputs[0];
|
var tResult = outputs[0];
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResult, tResult, lookback, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qResult, tResult, lookback, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("TRIMA Batch(TSeries) validated successfully against Tulip");
|
_output.WriteLine("TRIMA Batch(TSeries) validated successfully against Tulip");
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ public class TrimaValidationTests
|
|||||||
int lookback = TALib.Functions.TrimaLookback(period);
|
int lookback = TALib.Functions.TrimaLookback(period);
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qOutput, talibOutput, outRange, lookback, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qOutput, talibOutput, outRange, lookback, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("TRIMA Span validated successfully against TA-Lib");
|
_output.WriteLine("TRIMA Span validated successfully against TA-Lib");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class WmaValidationTests
|
|||||||
var sResult = _testData.SkenderQuotes.GetWma(period).ToList();
|
var sResult = _testData.SkenderQuotes.GetWma(period).ToList();
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResult, sResult, x => x.Wma, tolerance: 1e-5);
|
ValidationHelper.VerifyData(qResult, sResult, x => x.Wma, tolerance: ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("WMA Batch(TSeries) validated successfully against Skender");
|
_output.WriteLine("WMA Batch(TSeries) validated successfully against Skender");
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ public class WmaValidationTests
|
|||||||
var sResult = _testData.SkenderQuotes.GetWma(period).ToList();
|
var sResult = _testData.SkenderQuotes.GetWma(period).ToList();
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResults, sResult, x => x.Wma, tolerance: 1e-5);
|
ValidationHelper.VerifyData(qResults, sResult, x => x.Wma, tolerance: ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("WMA Streaming validated successfully against Skender");
|
_output.WriteLine("WMA Streaming validated successfully against Skender");
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@ public class WmaValidationTests
|
|||||||
var sResult = _testData.SkenderQuotes.GetWma(period).ToList();
|
var sResult = _testData.SkenderQuotes.GetWma(period).ToList();
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qOutput, sResult, x => x.Wma, tolerance: 1e-5);
|
ValidationHelper.VerifyData(qOutput, sResult, x => x.Wma, tolerance: ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("WMA Span validated successfully against Skender");
|
_output.WriteLine("WMA Span validated successfully against Skender");
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ public class WmaValidationTests
|
|||||||
int lookback = TALib.Functions.WmaLookback(period);
|
int lookback = TALib.Functions.WmaLookback(period);
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResult, output, outRange, lookback, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qResult, output, outRange, lookback, tolerance: ValidationHelper.TalibTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("WMA Batch(TSeries) validated successfully against TA-Lib");
|
_output.WriteLine("WMA Batch(TSeries) validated successfully against TA-Lib");
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ public class WmaValidationTests
|
|||||||
int lookback = TALib.Functions.WmaLookback(period);
|
int lookback = TALib.Functions.WmaLookback(period);
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResults, output, outRange, lookback, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qResults, output, outRange, lookback, tolerance: ValidationHelper.TalibTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("WMA Streaming validated successfully against TA-Lib");
|
_output.WriteLine("WMA Streaming validated successfully against TA-Lib");
|
||||||
}
|
}
|
||||||
@@ -163,7 +163,7 @@ public class WmaValidationTests
|
|||||||
int lookback = TALib.Functions.WmaLookback(period);
|
int lookback = TALib.Functions.WmaLookback(period);
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qOutput, talibOutput, outRange, lookback, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qOutput, talibOutput, outRange, lookback, tolerance: ValidationHelper.TalibTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("WMA Span validated successfully against TA-Lib");
|
_output.WriteLine("WMA Span validated successfully against TA-Lib");
|
||||||
}
|
}
|
||||||
@@ -190,7 +190,7 @@ public class WmaValidationTests
|
|||||||
var tResult = outputs[0];
|
var tResult = outputs[0];
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResult, tResult, lookback, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qResult, tResult, lookback, tolerance: ValidationHelper.TulipTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("WMA Batch(TSeries) validated successfully against Tulip");
|
_output.WriteLine("WMA Batch(TSeries) validated successfully against Tulip");
|
||||||
}
|
}
|
||||||
@@ -221,7 +221,7 @@ public class WmaValidationTests
|
|||||||
var tResult = outputs[0];
|
var tResult = outputs[0];
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qResults, tResult, lookback, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qResults, tResult, lookback, tolerance: ValidationHelper.TulipTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("WMA Streaming validated successfully against Tulip");
|
_output.WriteLine("WMA Streaming validated successfully against Tulip");
|
||||||
}
|
}
|
||||||
@@ -248,7 +248,7 @@ public class WmaValidationTests
|
|||||||
var tResult = outputs[0];
|
var tResult = outputs[0];
|
||||||
|
|
||||||
// Compare last 100 records
|
// Compare last 100 records
|
||||||
ValidationHelper.VerifyData(qOutput, tResult, lookback, tolerance: 1e-4);
|
ValidationHelper.VerifyData(qOutput, tResult, lookback, tolerance: ValidationHelper.TulipTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("WMA Span validated successfully against Tulip");
|
_output.WriteLine("WMA Span validated successfully against Tulip");
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ public class WmaValidationTests
|
|||||||
var oValues = oResult.OutputValues["Wma"];
|
var oValues = oResult.OutputValues["Wma"];
|
||||||
|
|
||||||
// Compare
|
// Compare
|
||||||
ValidationHelper.VerifyData(qResult, oValues, (s) => s, tolerance: 5e-4);
|
ValidationHelper.VerifyData(qResult, oValues, (s) => s, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
_output.WriteLine("WMA validated successfully against Ooples");
|
_output.WriteLine("WMA validated successfully against Ooples");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class AdlValidationTests
|
|||||||
quantalibValues.Add(adl.Update(bar).Value);
|
quantalibValues.Add(adl.Update(bar).Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidationHelper.VerifyData(quantalibValues.ToArray(), skenderValues, 0, 100, 1e-7);
|
ValidationHelper.VerifyData(quantalibValues.ToArray(), skenderValues, 0, 100, ValidationHelper.SkenderTolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -56,7 +56,7 @@ public class AdlValidationTests
|
|||||||
quantalibValues.Add(adl.Update(bar).Value);
|
quantalibValues.Add(adl.Update(bar).Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidationHelper.VerifyData(quantalibValues.ToArray(), talibValues, outRange, 0, 100, 1e-9);
|
ValidationHelper.VerifyData(quantalibValues.ToArray(), talibValues, outRange, 0, 100, ValidationHelper.TalibTolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -84,7 +84,7 @@ public class AdlValidationTests
|
|||||||
quantalibValues.Add(adl.Update(bar).Value);
|
quantalibValues.Add(adl.Update(bar).Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidationHelper.VerifyData(quantalibValues.ToArray(), tulipValues, 0, 100, 1e-9);
|
ValidationHelper.VerifyData(quantalibValues.ToArray(), tulipValues, 0, 100, ValidationHelper.TulipTolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -113,6 +113,6 @@ public class AdlValidationTests
|
|||||||
quantalibValues.Add(adl.Update(bar).Value);
|
quantalibValues.Add(adl.Update(bar).Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValidationHelper.VerifyData(quantalibValues.ToArray(), oValues.ToArray(), 0, 100, 1e-2);
|
ValidationHelper.VerifyData(quantalibValues.ToArray(), oValues.ToArray(), 0, 100, ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ public class AdoscValidationTests : IDisposable
|
|||||||
// 1. Batch Mode
|
// 1. Batch Mode
|
||||||
var adosc = new Adosc(fastPeriod, slowPeriod);
|
var adosc = new Adosc(fastPeriod, slowPeriod);
|
||||||
var result = adosc.Update(_testData.Bars);
|
var result = adosc.Update(_testData.Bars);
|
||||||
ValidationHelper.VerifyData(result, output, lookback: 0, tolerance: 1e-3);
|
ValidationHelper.VerifyData(result, output, lookback: 0, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
|
|
||||||
// 2. Streaming Mode
|
// 2. Streaming Mode
|
||||||
var adoscStream = new Adosc(fastPeriod, slowPeriod);
|
var adoscStream = new Adosc(fastPeriod, slowPeriod);
|
||||||
@@ -176,7 +176,7 @@ public class AdoscValidationTests : IDisposable
|
|||||||
{
|
{
|
||||||
streamResults.Add(adoscStream.Update(bar).Value);
|
streamResults.Add(adoscStream.Update(bar).Value);
|
||||||
}
|
}
|
||||||
ValidationHelper.VerifyData(streamResults, output, lookback: 0, tolerance: 1e-3);
|
ValidationHelper.VerifyData(streamResults, output, lookback: 0, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
|
|
||||||
// 3. Span Mode
|
// 3. Span Mode
|
||||||
double[] high = _testData.Bars.High.Values.ToArray();
|
double[] high = _testData.Bars.High.Values.ToArray();
|
||||||
@@ -185,6 +185,6 @@ public class AdoscValidationTests : IDisposable
|
|||||||
double[] volume = _testData.Bars.Volume.Values.ToArray();
|
double[] volume = _testData.Bars.Volume.Values.ToArray();
|
||||||
double[] spanOutput = new double[close.Length];
|
double[] spanOutput = new double[close.Length];
|
||||||
Adosc.Calculate(high, low, close, volume, spanOutput, fastPeriod, slowPeriod);
|
Adosc.Calculate(high, low, close, volume, spanOutput, fastPeriod, slowPeriod);
|
||||||
ValidationHelper.VerifyData(spanOutput, output, lookback: 0, tolerance: 1e-3);
|
ValidationHelper.VerifyData(spanOutput, output, lookback: 0, tolerance: ValidationHelper.OoplesTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<packageSources>
|
||||||
|
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||||
|
<!-- Add MyGet feed -->
|
||||||
|
<add key="OoplesFinance MyGet" value="https://www.myget.org/F/ooplesfinance_stockindicators/api/v3/index.json" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"runs": [
|
||||||
|
{
|
||||||
|
"automationDetails": {
|
||||||
|
"guid": "68355419-3619-441c-a921-548ead8e8712",
|
||||||
|
"id": "QDNETC/qodana/2025-12-21",
|
||||||
|
"properties": {
|
||||||
|
"jobUrl": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"columnKind": "utf16CodeUnits",
|
||||||
|
"invocations": [
|
||||||
|
{
|
||||||
|
"endTimeUtc": "0001-01-01T00:00:00Z",
|
||||||
|
"executionSuccessful": true,
|
||||||
|
"startTimeUtc": "0001-01-01T00:00:00Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"language": "en-US",
|
||||||
|
"newlineSequences": [
|
||||||
|
"\r\n",
|
||||||
|
"\n"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"deviceId": "200820300000000-2e23-80fc-7565-86ffbc01e7c2"
|
||||||
|
},
|
||||||
|
"results": [],
|
||||||
|
"tool": {
|
||||||
|
"driver": {
|
||||||
|
"contents": [
|
||||||
|
"localizedData",
|
||||||
|
"nonLocalizedData"
|
||||||
|
],
|
||||||
|
"fullName": "Qodana Community for .NET",
|
||||||
|
"informationUri": "http://www.jetbrains.com/resharper/features/command-line.html",
|
||||||
|
"language": "en-US",
|
||||||
|
"name": "QDNETC",
|
||||||
|
"organization": "JetBrains, Inc",
|
||||||
|
"semanticVersion": "261.0.20251210.63140-eap01d",
|
||||||
|
"version": "2025.3.842301551.39"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"versionControlProvenance": [
|
||||||
|
{
|
||||||
|
"branch": "simd-dev",
|
||||||
|
"properties": {
|
||||||
|
"lastAuthorEmail": "miha.kralj@outlook.com",
|
||||||
|
"lastAuthorName": "Miha Kralj",
|
||||||
|
"repoUrl": "https://github.com/mihakralj/QuanTAlib.git",
|
||||||
|
"vcsType": "Git"
|
||||||
|
},
|
||||||
|
"repositoryUri": "https://github.com/mihakralj/QuanTAlib.git",
|
||||||
|
"revisionId": "a7b7207801ad31a4837444345612ebe99cb3dd9d"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.6.json",
|
||||||
|
"version": "2.1.0"
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0",
|
||||||
|
"total": 1884,
|
||||||
|
"tools inspection": {
|
||||||
|
"Code Inspection": 1884
|
||||||
|
},
|
||||||
|
"linter": "QDNETC",
|
||||||
|
"attributes": {
|
||||||
|
"deviceId": "200820300000000-2e23-80fc-7565-86ffbc01e7c2",
|
||||||
|
"jobUrl": "",
|
||||||
|
"vcs": {
|
||||||
|
"sarifIdea": {
|
||||||
|
"repositoryUri": "https://github.com/mihakralj/QuanTAlib.git",
|
||||||
|
"revisionId": "a7b7207801ad31a4837444345612ebe99cb3dd9d",
|
||||||
|
"branch": "simd-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repoUrl": "https://github.com/mihakralj/QuanTAlib.git"
|
||||||
|
},
|
||||||
|
"linterVersion": "2025.3.842301551.39"
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"version": "3",
|
||||||
|
"listProblem": []
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,114 @@
|
|||||||
|
#-------------------------------------------------------------------------------#
|
||||||
|
# Qodana analysis is configured by qodana.yaml file #
|
||||||
|
# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
|
||||||
|
#-------------------------------------------------------------------------------#
|
||||||
|
version: '1.0'
|
||||||
|
|
||||||
|
#Specify inspection profile for code analysis
|
||||||
|
profile:
|
||||||
|
name: qodana.starter
|
||||||
|
|
||||||
|
#Enable inspections
|
||||||
|
#include:
|
||||||
|
# - name: <SomeEnabledInspectionId>
|
||||||
|
|
||||||
|
#Disable inspections
|
||||||
|
exclude:
|
||||||
|
# Disable XML documentation comment validation (allows unescaped < > in comments)
|
||||||
|
- name: XmlDocAnalyzer
|
||||||
|
- name: InvalidXmlDocComment
|
||||||
|
# Library project - public API properties are intentionally unused internally
|
||||||
|
- name: UnusedAutoPropertyAccessor.Global
|
||||||
|
# Style preference - fully qualified names used intentionally for clarity
|
||||||
|
- name: RedundantNameQualifier
|
||||||
|
- name: RCS1036 # Roslyn: Remove redundant empty line
|
||||||
|
- name: IDE0001 # Simplify name
|
||||||
|
- name: IDE0002 # Simplify member access
|
||||||
|
|
||||||
|
# HIGH-PERFORMANCE LIBRARY EXCLUSIONS
|
||||||
|
# ------------------------------------
|
||||||
|
# Flat namespace structure is intentional for this library
|
||||||
|
- name: CheckNamespace
|
||||||
|
|
||||||
|
# Float comparisons are intentional in financial calculations (checking 0.0, NaN, sentinel values)
|
||||||
|
- name: CompareOfFloatsByEqualityOperator
|
||||||
|
|
||||||
|
# Explicit default args improve code clarity and self-documentation
|
||||||
|
- name: RedundantArgumentDefaultValue
|
||||||
|
|
||||||
|
# Platform-specific optimizations (SIMD, intrinsics) are intentional
|
||||||
|
- name: CA1416 # Validate platform compatibility
|
||||||
|
|
||||||
|
# Public API unused internally - this is a library
|
||||||
|
- name: UnusedMember.Global
|
||||||
|
- name: MemberCanBePrivate.Global
|
||||||
|
- name: MemberCanBePrivate.Local
|
||||||
|
- name: ClassNeverInstantiated.Global
|
||||||
|
- name: UnusedType.Global
|
||||||
|
- name: UnusedMethodReturnValue.Global
|
||||||
|
- name: AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
- name: MemberCanBeMadeStatic.Global
|
||||||
|
- name: MemberCanBeMadeStatic.Local
|
||||||
|
|
||||||
|
# Redundant using directives - managed by IDE/build, not critical for library
|
||||||
|
- name: RedundantUsingDirective
|
||||||
|
- name: IDE0005 # Remove unnecessary using directives
|
||||||
|
- name: CS8019 # Unnecessary using directive
|
||||||
|
|
||||||
|
# Nullable warning suppressions - used intentionally for null safety patterns
|
||||||
|
- name: RedundantSuppressNullableWarningExpression
|
||||||
|
|
||||||
|
# Redundant type specifications - explicit types used for clarity/documentation
|
||||||
|
- name: RedundantTypeArgumentsOfMethod
|
||||||
|
- name: RedundantCast
|
||||||
|
- name: RedundantExplicitArrayCreation
|
||||||
|
|
||||||
|
# Unused local variables - often used in test setup or placeholder code (includes false positives for tuple deconstruction)
|
||||||
|
- name: UnusedVariable
|
||||||
|
- name: UnusedVariable.Compiler # False positive for tuple deconstruction
|
||||||
|
- name: CS0219 # Variable is assigned but never used
|
||||||
|
- name: RedundantAssignment # Value assigned is not used in any execution path
|
||||||
|
- name: UnusedAssignment # Assignment is not used
|
||||||
|
- name: IDE0059 # Unnecessary assignment of a value
|
||||||
|
|
||||||
|
# Object initializer in using statement - false positive for simple property setters
|
||||||
|
- name: CA2000 # Dispose objects before losing scope (overly cautious for simple cases)
|
||||||
|
- name: UseObjectOrCollectionInitializerWhenPossible
|
||||||
|
- name: DoNotUseObjectInitializerForUsingVariable
|
||||||
|
- name: ObjectInitializerMightCauseException
|
||||||
|
- name: ObjectCreationAsStatement
|
||||||
|
- name: UseObjectOrCollectionInitializer
|
||||||
|
- name: UsingStatementResourceInitialization # "Do not use object initializer for 'using' variable"
|
||||||
|
|
||||||
|
# Private field can be local variable - test fixtures often use fields for clarity/organization
|
||||||
|
- name: PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
- name: ConvertToLocalFunction
|
||||||
|
|
||||||
|
# Code coverage checks - SonarCloud handles coverage, Qodana coverage unreliable
|
||||||
|
- name: CoverageCheck
|
||||||
|
- name: ClassCoverageCheck
|
||||||
|
- name: MethodCoverageCheck
|
||||||
|
- name: CodeCoverageCheck
|
||||||
|
|
||||||
|
# Library-specific exclusions
|
||||||
|
- name: UnusedMember.Global # Suppresses "Method/Class is never used"
|
||||||
|
- name: UnusedMethodReturnValue.Global # Suppresses "Return value is never used"
|
||||||
|
- name: AutoPropertyCanBeMadeGetOnly.Global # Optional: common in libraries
|
||||||
|
|
||||||
|
#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
|
||||||
|
#bootstrap: sh ./prepare-qodana.sh
|
||||||
|
|
||||||
|
#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
|
||||||
|
#plugins:
|
||||||
|
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
|
||||||
|
|
||||||
|
#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
|
||||||
|
#linter: jetbrains/qodana-dotnet:2025.3
|
||||||
|
|
||||||
|
solution: QuanTAlib.sln
|
||||||
|
linter: qodana-cdnet-EAP
|
||||||
|
|
||||||
|
dotnet:
|
||||||
|
msbuild:
|
||||||
|
properties:
|
||||||
|
Qodana: true
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"version": "3",
|
||||||
|
"listProblem": []
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[{"groupId":"qd.cl.system.os","eventName":"os.name","time":1766359483444,"state":true,"eventData":{"arch":"amd64","name":"linux","version":"2025.3"},"sessionId":"ee478045-63bd-4988-a07c-59a4c0aca61a"},{"groupId":"qd.cl.lifecycle","eventName":"project.opened","time":1766359483444,"state":false,"eventData":{"version":"2025.3"},"sessionId":"ee478045-63bd-4988-a07c-59a4c0aca61a"},{"groupId":"qd.cl.lifecycle","eventName":"project.closed","time":1766359561631,"state":false,"eventData":{"version":"2025.3"},"sessionId":"ee478045-63bd-4988-a07c-59a4c0aca61a"}]
|
||||||
+9
-1
@@ -103,4 +103,12 @@ exclude:
|
|||||||
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
|
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
|
||||||
|
|
||||||
#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
|
#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
|
||||||
linter: jetbrains/qodana-dotnet:2024.3
|
#linter: jetbrains/qodana-dotnet:2025.3
|
||||||
|
|
||||||
|
solution: QuanTAlib.sln
|
||||||
|
linter: qodana-cdnet-EAP
|
||||||
|
|
||||||
|
dotnet:
|
||||||
|
msbuild:
|
||||||
|
properties:
|
||||||
|
Qodana: true
|
||||||
|
|||||||
Reference in New Issue
Block a user