diff --git a/.vscode/settings.json b/.vscode/settings.json
index 335e6e7c..e27b36ee 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -7,11 +7,17 @@
}
],
"sarif-viewer.connectToGithubCodeScanning": "on",
- "dotnet.dotnetPath": "/opt/homebrew/bin/",
"omnisharp.useModernNet": true,
- "omnisharp.sdkPath": "/opt/homebrew/bin/dotnet",
"sonarlint.connectedMode.project": {
"connectionId": "mihakralj",
"projectKey": "mihakralj_QuanTAlib"
- }
-}
\ No newline at end of file
+ },
+ "dotnet.backgroundAnalysis.analyzerDiagnosticsScope": "fullSolution",
+ "dotnet.completion.showCompletionItemsFromUnimportedNamespaces": true,
+ "dotnetAcquisitionExtension.enableTelemetry": false,
+ "dotnet-test-explorer.testProjectPath": "Tests",
+ "dotnet-test-explorer.autoWatch": true,
+ "dotnet-test-explorer.showCodeLens": true,
+ "dotnet-test-explorer.testArguments": "/p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=./TestResults/coverage.cobertura.xml"
+
+}
diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj
index 11c1e048..31f09837 100644
--- a/Tests/Tests.csproj
+++ b/Tests/Tests.csproj
@@ -2,15 +2,16 @@
QuanTAlib.Tests
QuanTAlib.Tests
+ false
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Tests/test_eventing.cs b/Tests/test_eventing.cs
index 57f519ca..5b0d6db4 100644
--- a/Tests/test_eventing.cs
+++ b/Tests/test_eventing.cs
@@ -51,12 +51,37 @@ public class EventingTests
("Tema", new Tema(p), new Tema(input, p)),
("Kama", new Kama(2, 30, 6), new Kama(input, 2, 30, 6)),
("Zlema", new Zlema(p), new Zlema(input, p)),
+ // Added missing averages
+ ("Sinema", new Sinema(p), new Sinema(input, p)),
+ ("Smma", new Smma(p), new Smma(input, p)),
+ ("T3", new T3(p), new T3(input, p)),
+ ("Trima", new Trima(p), new Trima(input, p)),
+ ("Vidya", new Vidya(p), new Vidya(input, p)),
+ // momentum indicators
+ ("Apo", new Apo(12, 26), new Apo(input, 12, 26)),
// oscillators
("Rsi", new Rsi(p), new Rsi(input, p)),
("Rsx", new Rsx(p), new Rsx(input, p)),
("Cmo", new Cmo(p), new Cmo(input, p)),
+ // statistics
+ ("Curvature", new Curvature(p), new Curvature(input, p)),
+ ("Entropy", new Entropy(p), new Entropy(input, p)),
+ ("Kurtosis", new Kurtosis(p), new Kurtosis(input, p)),
+ ("Max", new Max(p), new Max(input, p)),
+ ("Median", new Median(p), new Median(input, p)),
+ ("Min", new Min(p), new Min(input, p)),
+ ("Mode", new Mode(p), new Mode(input, p)),
+ ("Percentile", new Percentile(p, 0.5), new Percentile(input, p, 0.5)),
+ ("Skew", new Skew(p), new Skew(input, p)),
+ ("Slope", new Slope(p), new Slope(input, p)),
+ ("Stddev", new Stddev(p), new Stddev(input, p)),
+ ("Variance", new Variance(p), new Variance(input, p)),
+ ("Zscore", new Zscore(p), new Zscore(input, p)),
// volatility
+ ("Hv", new Hv(p), new Hv(input, p)),
+ ("Jvolty", new Jvolty(p), new Jvolty(input, p)),
("Rv", new Rv(p), new Rv(input, p)),
+ ("Rvi", new Rvi(p), new Rvi(input, p)),
// error classes
("Mae", new Mae(p), new Mae(input, p)),
("Mapd", new Mapd(p), new Mapd(input, p)),
diff --git a/Tests/test_updates_momentum.cs b/Tests/test_updates_momentum.cs
new file mode 100644
index 00000000..a94d2386
--- /dev/null
+++ b/Tests/test_updates_momentum.cs
@@ -0,0 +1,91 @@
+using Xunit;
+using System.Security.Cryptography;
+
+namespace QuanTAlib.Tests;
+
+public class MomentumUpdateTests
+{
+ private readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
+ private const int RandomUpdates = 100;
+ private const double ReferenceValue = 100.0;
+ private const int precision = 8;
+
+ private double GetRandomDouble()
+ {
+ byte[] bytes = new byte[8];
+ rng.GetBytes(bytes);
+ return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200 - 100; // Range: -100 to 100
+ }
+
+ private TBar GetRandomBar(bool IsNew)
+ {
+ double open = GetRandomDouble();
+ double high = open + Math.Abs(GetRandomDouble());
+ double low = open - Math.Abs(GetRandomDouble());
+ double close = low + (high - low) * GetRandomDouble();
+ return new TBar(DateTime.Now, open, high, low, close, 1000, IsNew);
+ }
+
+ [Fact]
+ public void Adx_Update()
+ {
+ var indicator = new Adx(period: 14);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Adxr_Update()
+ {
+ var indicator = new Adxr(period: 14);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Apo_Update()
+ {
+ var indicator = new Apo(fastPeriod: 12, slowPeriod: 26);
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Dmi_Update()
+ {
+ var indicator = new Dmi(period: 14);
+ TBar r = GetRandomBar(true);
+ double initialValue = indicator.Calc(r);
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(GetRandomBar(IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+}
diff --git a/Tests/test_updates_oscillators.cs b/Tests/test_updates_oscillators.cs
new file mode 100644
index 00000000..297f0ebd
--- /dev/null
+++ b/Tests/test_updates_oscillators.cs
@@ -0,0 +1,64 @@
+using Xunit;
+using System.Security.Cryptography;
+
+namespace QuanTAlib.Tests;
+
+public class OscillatorsUpdateTests
+{
+ private readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
+ private const int RandomUpdates = 100;
+ private const double ReferenceValue = 100.0;
+ private const int precision = 8;
+
+ private double GetRandomDouble()
+ {
+ byte[] bytes = new byte[8];
+ rng.GetBytes(bytes);
+ return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200 - 100; // Range: -100 to 100
+ }
+
+ [Fact]
+ public void Rsi_Update()
+ {
+ var indicator = new Rsi(period: 14);
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Rsx_Update()
+ {
+ var indicator = new Rsx(period: 14);
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Cmo_Update()
+ {
+ var indicator = new Cmo(period: 14);
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+}
diff --git a/Tests/test_updates_volatility.cs b/Tests/test_updates_volatility.cs
index 5a041c26..f8877a8e 100644
--- a/Tests/test_updates_volatility.cs
+++ b/Tests/test_updates_volatility.cs
@@ -46,13 +46,28 @@ public class VolatilityUpdateTests
public void Historical_Update()
{
var indicator = new Hv(period: 14);
- double initialValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true));
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
- indicator.Calc(GetRandomBar(false));
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
- double finalValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: false));
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
+
+ Assert.Equal(initialValue, finalValue, precision);
+ }
+
+ [Fact]
+ public void Jvolty_Update()
+ {
+ var indicator = new Jvolty(period: 14);
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
+
+ for (int i = 0; i < RandomUpdates; i++)
+ {
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
+ }
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
@@ -61,13 +76,13 @@ public class VolatilityUpdateTests
public void Realized_Update()
{
var indicator = new Rv(period: 14);
- double initialValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true));
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
- indicator.Calc(GetRandomBar(false));
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
- double finalValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: false));
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
@@ -76,13 +91,13 @@ public class VolatilityUpdateTests
public void Rvi_Update()
{
var indicator = new Rvi(period: 14);
- double initialValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true));
+ double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
- indicator.Calc(GetRandomBar(false));
+ indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
}
- double finalValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: false));
+ double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
diff --git a/benchmark/benchmark.csproj b/benchmark/benchmark.csproj
deleted file mode 100644
index 0940953e..00000000
--- a/benchmark/benchmark.csproj
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- Exe
- net8.0
- false
- enable
- latest
- false
-
-
-
-
-
-
-
-
-
-
-
- true
- AnyCPU
- pdbonly
- true
- true
-
-
-
\ No newline at end of file
diff --git a/benchmark/growthBench.cs b/benchmark/growthBench.cs
deleted file mode 100644
index 6dd123e4..00000000
--- a/benchmark/growthBench.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using BenchmarkDotNet.Attributes;
-using BenchmarkDotNet.Configs;
-using BenchmarkDotNet.Jobs;
-using BenchmarkDotNet.Running;
-
-namespace QuanTAlib;
-
-public class Program
-{
- public static void Main(string[] args)
- {
- var config = DefaultConfig.Instance
- .WithOption(ConfigOptions.DisableOptimizationsValidator, true);
- BenchmarkRunner.Run(config);
- }
-}
-
-[MemoryDiagnoser]
-[SimpleJob(RuntimeMoniker.Net80, launchCount: 1, warmupCount: 3, iterationCount: 5)]
-public class EmaBenchmark
-{
- private const int Period = 10;
- private const int Length = 100_000;
- private GbmFeed gbm = null!;
- private TSeries inputs = null!;
-
- [GlobalSetup]
- public void Setup()
- {
- gbm = new GbmFeed();
- inputs = new();
-
- for (int i = 0; i < Length; i++)
- {
- TBar item = gbm.Generate(DateTime.Now);
- inputs.Add(new TValue(item.Time, item.Close, true, true));
- }
- }
-
- [Benchmark]
- public void Ema_bench()
- {
- Ema ma1 = new(Period);
- for (int i = 0; i < Length; i++)
- {
- TValue item = gbm.Generate(DateTime.Now).Close;
- ma1.Calc(item);
- }
-
- }
-
- [Benchmark]
- public void Alma_bench()
- {
- Alma ma1 = new(Period);
- for (int i = 0; i < Length; i++)
- {
- TValue item = gbm.Generate(DateTime.Now).Close;
- ma1.Calc(item);
- }
- }
-
- [Benchmark]
- public void Dema_bench()
- {
- Dema ma1 = new(Period);
- for (int i = 0; i < Length; i++)
- {
- TValue item = gbm.Generate(DateTime.Now).Close;
- ma1.Calc(item);
- }
- }
-}
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
index c98425ed..eb060953 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -63,11 +63,11 @@
-
-
-
-
-
+
+
+
+
+