diff --git a/.github/workflows/Publish.yml b/.github/workflows/Publish.yml
index 4be1d359..ada29549 100644
--- a/.github/workflows/Publish.yml
+++ b/.github/workflows/Publish.yml
@@ -215,7 +215,7 @@ jobs:
sarif_file: results.sarif
build_publish:
- needs: [SonarCloud, Code_Coverage, CodeQL, Codacy_Scan]
+ needs: [SonarCloud, Code_Coverage, CodeQL, Codacy_Scan, SecurityCodeScan]
if: success()
runs-on: ubuntu-latest
steps:
diff --git a/Directory.Build.props b/Directory.Build.props
index 6ee76064..d9353501 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -2,7 +2,7 @@
net8.0
preview
-
+ $(NoWarn);NU1903;NU5104
enable
enable
true
@@ -49,6 +49,8 @@
+
+
D:\Quantower
$([System.IO.Directory]::GetDirectories("$(QuantowerRoot)\TradingPlatform", "v1*")[0])
diff --git a/Tests/test_Trady.cs b/Tests/test_Trady.cs
index 44451a2a..5d2f356c 100644
--- a/Tests/test_Trady.cs
+++ b/Tests/test_Trady.cs
@@ -3,16 +3,16 @@ using Trady.Analysis.Indicator;
using Trady.Core;
using Trady.Core.Infrastructure;
using System.Diagnostics.CodeAnalysis;
+using System.Security.Cryptography;
namespace QuanTAlib;
[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")]
-
public class TradyTests
{
private readonly TBarSeries bars;
private readonly GbmFeed feed;
- private readonly Random rnd;
+ private readonly RandomNumberGenerator rng;
private readonly double range;
private readonly int iterations;
private readonly int skip;
@@ -20,7 +20,7 @@ public class TradyTests
public TradyTests()
{
- rnd = new((int)DateTime.Now.Ticks);
+ rng = RandomNumberGenerator.Create();
feed = new(sigma: 0.5, mu: 0.0);
bars = new(feed);
range = 1e-9;
@@ -37,12 +37,20 @@ public class TradyTests
)).ToList();
}
+ private int GetRandomNumber(int minValue, int maxValue)
+ {
+ byte[] randomBytes = new byte[4];
+ rng.GetBytes(randomBytes);
+ int randomInt = BitConverter.ToInt32(randomBytes, 0);
+ return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
+ }
+
[Fact]
public void SMA()
{
for (int run = 0; run < iterations; run++)
{
- int period = rnd.Next(50) + 5;
+ int period = GetRandomNumber(5, 55);
Sma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -72,7 +80,7 @@ public class TradyTests
{
for (int run = 0; run < iterations; run++)
{
- int period = rnd.Next(50) + 5;
+ int period = GetRandomNumber(5, 55);
Ema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -96,6 +104,4 @@ public class TradyTests
}
}
}
-
-
}
\ No newline at end of file
diff --git a/Tests/test_Tulip.cs b/Tests/test_Tulip.cs
index 623f0595..c9d686b8 100644
--- a/Tests/test_Tulip.cs
+++ b/Tests/test_Tulip.cs
@@ -1,15 +1,15 @@
using Xunit;
using Tulip;
using System.Diagnostics.CodeAnalysis;
+using System.Security.Cryptography;
namespace QuanTAlib;
[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")]
public class TulipTests
{
- private readonly TBarSeries bars;
private readonly GbmFeed feed;
- private readonly Random rnd;
+ private readonly RandomNumberGenerator rng;
private readonly double range;
private readonly int iterations;
private readonly double[] data;
@@ -18,9 +18,8 @@ public class TulipTests
public TulipTests()
{
- rnd = new((int)DateTime.Now.Ticks);
+ rng = RandomNumberGenerator.Create();
feed = new(sigma: 0.5, mu: 0.0);
- bars = new(feed);
range = 1e-9;
feed.Add(10000);
iterations = 3;
@@ -29,12 +28,20 @@ public class TulipTests
outdata = new double[data.Count()];
}
+ private int GetRandomNumber(int minValue, int maxValue)
+ {
+ byte[] randomBytes = new byte[4];
+ rng.GetBytes(randomBytes);
+ int randomInt = BitConverter.ToInt32(randomBytes, 0);
+ return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
+ }
+
[Fact]
public void SMA()
{
for (int run = 0; run < iterations; run++)
{
- int period = rnd.Next(50) + 5;
+ int period = GetRandomNumber(5, 55);
Sma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -58,7 +65,7 @@ public class TulipTests
{
for (int run = 0; run < iterations; run++)
{
- int period = rnd.Next(30) + 5;
+ int period = GetRandomNumber(5, 35);
Ema ma = new(period, useSma: false);
TSeries QL = new();
foreach (TBar item in feed)
diff --git a/Tests/test_eventing.cs b/Tests/test_eventing.cs
index dd8063f3..582517f7 100644
--- a/Tests/test_eventing.cs
+++ b/Tests/test_eventing.cs
@@ -1,4 +1,5 @@
using Xunit;
+using System.Security.Cryptography;
namespace QuanTAlib;
@@ -7,8 +8,8 @@ public class EventingTests
[Fact]
public void VerifyEventBasedCalculations()
{
- // Create a random number generator with a fixed seed for reproducibility
- var random = new Random(42);
+ // Create a cryptographically secure random number generator
+ using var rng = RandomNumberGenerator.Create();
// Create an input series to hold our random values
var input = new TSeries();
@@ -16,59 +17,63 @@ public class EventingTests
// Create a list of indicator pairs (direct calculation and event-based)
var indicators = new List<(AbstractBase Direct, AbstractBase EventBased)>
- {
- (new Afirma(p,p,Afirma.WindowType.BlackmanHarris), new Afirma(input, p,p,Afirma.WindowType.BlackmanHarris)),
- (new Alma(p), new Alma(input, p)),
- (new Convolution([1,2,3,2,1]), new Convolution(input, [1,2,3,2,1])),
- (new Dema(p), new Dema(input, p)),
- (new Dsma(p), new Dsma(input, p)),
- (new Dwma(p), new Dwma(input, p)),
- (new Ema(p), new Ema(input, p)),
- (new Epma(p), new Epma(input, p)),
- (new Frama(p), new Frama(input, p)),
- (new Fwma(p), new Fwma(input, p)),
- (new Gma(p), new Gma(input, p)),
- (new Hma(p), new Hma(input, p)),
- (new Htit(), new Htit(input)),
- (new Hwma(p), new Hwma(input, p)),
- (new Jma(p), new Jma(input, p)),
- (new Kama(p), new Kama(input, p)),
- (new Ltma(gamma: 0.2), new Ltma(input, gamma: 0.2)),
- (new Maaf(p), new Maaf(input, p)),
- (new Mama(p), new Mama(input, p)),
- (new Mgdi(p), new Mgdi(input, p)),
- (new Mma(p), new Mma(input, p)),
- (new Qema(k1: 0.2, k2: 0.2, k3: 0.2, k4: 0.2), new Qema(input, k1: 0.2, k2: 0.2, k3: 0.2, k4: 0.2)),
- (new Rema(p), new Rema(input, p)),
- (new Rma(p), new Rma(input, p)),
-
- (new Sma(p), new Sma(input, p)),
- (new Wma(p), new Wma(input, p)),
- (new Rma(p), new Rma(input, p)),
-
- (new Tema(p), new Tema(input, p)),
- (new Kama(2, 30, 6), new Kama(input, 2, 30, 6)),
-
- (new Zlema(p), new Zlema(input, p))
- };
+ {
+ (new Afirma(p,p,Afirma.WindowType.BlackmanHarris), new Afirma(input, p,p,Afirma.WindowType.BlackmanHarris)),
+ (new Alma(p), new Alma(input, p)),
+ (new Convolution([1,2,3,2,1]), new Convolution(input, [1,2,3,2,1])),
+ (new Dema(p), new Dema(input, p)),
+ (new Dsma(p), new Dsma(input, p)),
+ (new Dwma(p), new Dwma(input, p)),
+ (new Ema(p), new Ema(input, p)),
+ (new Epma(p), new Epma(input, p)),
+ (new Frama(p), new Frama(input, p)),
+ (new Fwma(p), new Fwma(input, p)),
+ (new Gma(p), new Gma(input, p)),
+ (new Hma(p), new Hma(input, p)),
+ (new Htit(), new Htit(input)),
+ (new Hwma(p), new Hwma(input, p)),
+ (new Jma(p), new Jma(input, p)),
+ (new Kama(p), new Kama(input, p)),
+ (new Ltma(gamma: 0.2), new Ltma(input, gamma: 0.2)),
+ (new Maaf(p), new Maaf(input, p)),
+ (new Mama(p), new Mama(input, p)),
+ (new Mgdi(p), new Mgdi(input, p)),
+ (new Mma(p), new Mma(input, p)),
+ (new Qema(k1: 0.2, k2: 0.2, k3: 0.2, k4: 0.2), new Qema(input, k1: 0.2, k2: 0.2, k3: 0.2, k4: 0.2)),
+ (new Rema(p), new Rema(input, p)),
+ (new Rma(p), new Rma(input, p)),
+ (new Sma(p), new Sma(input, p)),
+ (new Wma(p), new Wma(input, p)),
+ (new Rma(p), new Rma(input, p)),
+ (new Tema(p), new Tema(input, p)),
+ (new Kama(2, 30, 6), new Kama(input, 2, 30, 6)),
+ (new Zlema(p), new Zlema(input, p))
+ };
// Generate 200 random values and feed them to both direct and event-based indicators
- for (int i = 0; i< 200; i++)
+ for (int i = 0; i < 200; i++)
{
- double randomValue = random.NextDouble() * 100;
- input.Add(randomValue);
+ double randomValue = GetRandomDouble(rng) * 100;
+ input.Add(randomValue);
// Calculate direct indicators
foreach (var (direct, _) in indicators)
{
direct.Calc(randomValue);
}
-}
+ }
-// Compare the results of direct and event-based calculations
-foreach (var (direct, eventBased) in indicators)
-{
- Assert.Equal(direct.Value, eventBased.Value, 9);
-}
+ // Compare the results of direct and event-based calculations
+ foreach (var (direct, eventBased) in indicators)
+ {
+ Assert.Equal(direct.Value, eventBased.Value, 9);
+ }
+ }
+
+ private static double GetRandomDouble(RandomNumberGenerator rng)
+ {
+ byte[] bytes = new byte[8];
+ rng.GetBytes(bytes);
+ return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue;
}
}
diff --git a/Tests/test_iTBar.cs b/Tests/test_iTBar.cs
index 79c8563c..32ec7c37 100644
--- a/Tests/test_iTBar.cs
+++ b/Tests/test_iTBar.cs
@@ -1,16 +1,16 @@
using Xunit;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
+using System.Security.Cryptography;
namespace QuanTAlib;
///
/// Contains unit tests for bar-based indicators in QuanTAlib.
///
-[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")]
public class BarIndicatorTests
{
- private readonly Random rnd;
+ private readonly RandomNumberGenerator rng;
private const int SeriesLen = 1000;
private const int Corrections = 100;
@@ -19,7 +19,7 @@ public class BarIndicatorTests
///
public BarIndicatorTests()
{
- rnd = new Random((int)DateTime.Now.Ticks);
+ rng = RandomNumberGenerator.Create();
}
private static readonly ITValue[] indicators = new ITValue[]
@@ -124,15 +124,40 @@ public class BarIndicatorTests
/// A randomly generated TBar.
private TBar GenerateRandomBar(bool isNew)
{
- double open = rnd.NextDouble() * 200 - 100;
- double close = rnd.NextDouble() * 200 - 100;
- double high = Math.Max(open, close) + rnd.NextDouble() * 10;
- double low = Math.Min(open, close) - rnd.NextDouble() * 10;
- long volume = rnd.Next(0, 10000);
+ double open = GetRandomDouble() * 200 - 100;
+ double close = GetRandomDouble() * 200 - 100;
+ double high = Math.Max(open, close) + GetRandomDouble() * 10;
+ double low = Math.Min(open, close) - GetRandomDouble() * 10;
+ long volume = GetRandomNumber(0, 10000);
return new TBar(Time: DateTime.Now, Open: open, High: high, Low: low, Close: close, Volume: volume, IsNew: isNew);
}
+ ///
+ /// Generates a random double between 0 and 1.
+ ///
+ /// A random double between 0 and 1.
+ private double GetRandomDouble()
+ {
+ byte[] bytes = new byte[8];
+ rng.GetBytes(bytes);
+ return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue;
+ }
+
+ ///
+ /// Generates a random integer between minValue (inclusive) and maxValue (exclusive).
+ ///
+ /// The minimum value (inclusive).
+ /// The maximum value (exclusive).
+ /// A random integer between minValue and maxValue.
+ private int GetRandomNumber(int minValue, int maxValue)
+ {
+ byte[] randomBytes = new byte[4];
+ rng.GetBytes(randomBytes);
+ int randomInt = BitConverter.ToInt32(randomBytes, 0);
+ return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
+ }
+
///
/// Provides the list of indicators for parameterized tests.
///
diff --git a/Tests/test_iTValue.cs b/Tests/test_iTValue.cs
index f36bec3e..887c78cf 100644
--- a/Tests/test_iTValue.cs
+++ b/Tests/test_iTValue.cs
@@ -1,19 +1,27 @@
using Xunit;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
+using System.Security.Cryptography;
namespace QuanTAlib;
-[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")]
public class IndicatorTests
{
- private readonly Random rnd;
+ private readonly RandomNumberGenerator rng;
private const int SeriesLen = 1000;
private const int Corrections = 100;
public IndicatorTests()
{
- rnd = new Random((int)DateTime.Now.Ticks);
+ rng = RandomNumberGenerator.Create();
+ }
+
+ private int GetRandomNumber(int minValue, int maxValue)
+ {
+ byte[] randomBytes = new byte[4];
+ rng.GetBytes(randomBytes);
+ int randomInt = BitConverter.ToInt32(randomBytes, 0);
+ return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
}
// skipcq: CS-R1055
@@ -83,12 +91,12 @@ public class IndicatorTests
for (int i = 0; i < SeriesLen; i++)
{
- TValue item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: true);
+ TValue item1 = new(Time: DateTime.Now, Value: GetRandomNumber(-100, 100), IsNew: true);
InvokeCalc(indicator1, calcMethod, item1);
for (int j = 0; j < Corrections; j++)
{
- item1 = new(Time: DateTime.Now, Value: rnd.Next(-100, 100), IsNew: false);
+ item1 = new(Time: DateTime.Now, Value: GetRandomNumber(-100, 100), IsNew: false);
InvokeCalc(indicator1, calcMethod, item1);
}
diff --git a/Tests/test_skender.stock.cs b/Tests/test_skender.stock.cs
index fabc63db..fd1fcca1 100644
--- a/Tests/test_skender.stock.cs
+++ b/Tests/test_skender.stock.cs
@@ -1,16 +1,15 @@
using Xunit;
using Skender.Stock.Indicators;
using System.Diagnostics.CodeAnalysis;
+using System.Security.Cryptography;
namespace QuanTAlib;
-[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")]
-
public class SkenderTests
{
private readonly TBarSeries bars;
private readonly GbmFeed feed;
- private readonly Random rnd;
+ private readonly RandomNumberGenerator rng;
private readonly double range;
private int period;
private readonly int iterations = 3; // Initialized directly at declaration
@@ -18,7 +17,7 @@ public class SkenderTests
public SkenderTests()
{
- rnd = new((int)DateTime.Now.Ticks);
+ rng = RandomNumberGenerator.Create();
feed = new(sigma: 0.5, mu: 0.0);
bars = new(feed);
range = 1e-9;
@@ -34,12 +33,20 @@ public class SkenderTests
});
}
+ private int GetRandomNumber(int minValue, int maxValue)
+ {
+ byte[] randomBytes = new byte[4];
+ rng.GetBytes(randomBytes);
+ int randomInt = BitConverter.ToInt32(randomBytes, 0);
+ return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
+ }
+
[Fact]
public void SMA()
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Sma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -58,7 +65,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Ema ma = new(period, useSma: true);
TSeries QL = new();
foreach (TBar item in feed)
@@ -77,7 +84,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Ema ma = new(period, useSma: false);
TSeries QL = new();
foreach (TBar item in feed)
@@ -96,7 +103,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Dema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -115,7 +122,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Tema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -134,7 +141,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
double[] kernel = Enumerable.Repeat(1.0, period).ToArray();
Convolution ma = new(kernel);
TSeries QL = new();
@@ -154,7 +161,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Wma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -173,7 +180,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Hma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -192,7 +199,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Epma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -211,7 +218,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Alma ma = new(period, offset: 0.85, sigma: 6);
TSeries QL = new();
foreach (TBar item in feed)
@@ -230,7 +237,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
T3 ma = new(period, vfactor: 0.7, useSma: false);
TSeries QL = new();
foreach (TBar item in feed)
@@ -249,7 +256,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Smma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -268,7 +275,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Kama ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -307,7 +314,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Mgdi ma = new(period: period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -328,7 +335,7 @@ public class SkenderTests
{
for (int run = 0; run < iterations; run++)
{
- period = rnd.Next(50) + 5;
+ period = GetRandomNumber(5, 55);
Atr ma = new(period: period);
TSeries QL = new();
foreach (TBar item in bars) { QL.Add(ma.Calc(item)); }
@@ -342,5 +349,4 @@ public class SkenderTests
}
}
}
-
}
diff --git a/Tests/test_talib.cs b/Tests/test_talib.cs
index 5b0f23fa..b071a3a6 100644
--- a/Tests/test_talib.cs
+++ b/Tests/test_talib.cs
@@ -1,33 +1,36 @@
using Xunit;
using TALib;
using System.Diagnostics.CodeAnalysis;
+using System.Security.Cryptography;
namespace QuanTAlib;
-[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")]
-
public class TAlibTests
{
- private readonly TBarSeries bars;
private readonly GbmFeed feed;
- private readonly Random rnd;
+ private readonly RandomNumberGenerator rng;
private readonly double range;
private readonly int iterations;
private readonly double[] data;
private readonly double[] TALIB;
-
public TAlibTests()
{
- rnd = new((int)DateTime.Now.Ticks);
+ rng = RandomNumberGenerator.Create();
feed = new(sigma: 0.5, mu: 0.0);
- bars = new(feed);
range = 1e-9;
feed.Add(10000);
iterations = 3;
data = feed.Close.v.ToArray();
TALIB = new double[data.Count()];
+ }
+ private int GetRandomNumber(int minValue, int maxValue)
+ {
+ byte[] randomBytes = new byte[4];
+ rng.GetBytes(randomBytes);
+ int randomInt = BitConverter.ToInt32(randomBytes, 0);
+ return Math.Abs(randomInt % (maxValue - minValue)) + minValue;
}
[Fact]
@@ -35,7 +38,7 @@ public class TAlibTests
{
for (int run = 0; run < iterations; run++)
{
- int period = rnd.Next(50) + 5;
+ int period = GetRandomNumber(5, 55);
Sma ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -44,7 +47,6 @@ public class TAlibTests
Assert.Equal(QL.Length, TALIB.Count());
for (int i = QL.Length - 1; i > period; i--)
{
- double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
@@ -55,7 +57,7 @@ public class TAlibTests
{
for (int run = 0; run < iterations; run++)
{
- int period = rnd.Next(50) + 5;
+ int period = GetRandomNumber(5, 55);
Ema ma = new(period, useSma: true);
TSeries QL = new();
foreach (TBar item in feed)
@@ -64,7 +66,6 @@ public class TAlibTests
Assert.Equal(QL.Length, TALIB.Count());
for (int i = QL.Length - 1; i > period; i--)
{
- double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
@@ -75,7 +76,7 @@ public class TAlibTests
{
for (int run = 0; run < iterations; run++)
{
- int period = rnd.Next(50) + 5;
+ int period = GetRandomNumber(5, 55);
Dema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -84,7 +85,6 @@ public class TAlibTests
Assert.Equal(QL.Length, TALIB.Length);
for (int i = QL.Length - 1; i > period * 20; i--)
{
- double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
@@ -95,7 +95,7 @@ public class TAlibTests
{
for (int run = 0; run < iterations; run++)
{
- int period = rnd.Next(50) + 5;
+ int period = GetRandomNumber(5, 55);
Tema ma = new(period);
TSeries QL = new();
foreach (TBar item in feed)
@@ -104,41 +104,37 @@ public class TAlibTests
Assert.Equal(QL.Length, TALIB.Length);
for (int i = QL.Length - 1; i > period * 20; i--)
{
- double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
}
- //TODO fix WMA
- /*
- [Fact]
- public void WMA()
+ [Fact]
+ public void WMA()
+ {
+ for (int run = 0; run < iterations; run++)
{
- for (int run = 0; run < iterations; run++)
+ int period = GetRandomNumber(5, 55);
+ Wma ma = new(period);
+ TSeries QL = new();
+ foreach (TBar item in feed)
+ { QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
+ Core.Wma(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period);
+ Assert.Equal(QL.Length, TALIB.Count());
+ for (int i = QL.Length - 1; i > period * 10; i--)
{
- period = rnd.Next(50) + 5;
- Wma ma = new(period);
- TSeries QL = new();
- foreach (TBar item in feed)
- { QL.Add(ma.Calc(new TValue(item.Time, item.Close))); }
- Core.Wma(data, 0, QL.Length - 1, TALIB, out int outBegIdx, out _, period);
- Assert.Equal(QL.Length, TALIB.Count());
- for (int i = QL.Length - 1; i > period*3; i--)
- {
- double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
- Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
- }
+ Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
- */
+ }
+
[Fact]
public void T3()
{
for (int run = 0; run < iterations; run++)
{
- int period = rnd.Next(50) + 5;
+ int period = GetRandomNumber(5, 55);
T3 ma = new(period, vfactor: 0.7, useSma: false);
TSeries QL = new();
foreach (TBar item in feed)
@@ -147,10 +143,8 @@ public class TAlibTests
Assert.Equal(QL.Length, TALIB.Length);
for (int i = QL.Length - 1; i > period * 20; i--)
{
- double TL = i < outBegIdx ? double.NaN : TALIB[i - outBegIdx];
Assert.InRange(TALIB[i - outBegIdx] - QL[i].Value, -range, range);
}
}
}
-
}
\ No newline at end of file
diff --git a/lib/feeds/GbmFeed.cs b/lib/feeds/GbmFeed.cs
index f4c69a0e..5b2edd2f 100644
--- a/lib/feeds/GbmFeed.cs
+++ b/lib/feeds/GbmFeed.cs
@@ -1,11 +1,11 @@
-using System.CommandLine.Rendering.Views;
+using System.Security.Cryptography;
namespace QuanTAlib;
public class GbmFeed : TBarSeries
{
private readonly double _mu, _sigma;
- private readonly Random _random;
+ private readonly RandomNumberGenerator _rng;
private double _lastClose, _lastHigh, _lastLow;
public GbmFeed(double initialPrice = 100.0, double mu = 0.05, double sigma = 0.2)
@@ -13,7 +13,7 @@ public class GbmFeed : TBarSeries
_lastClose = _lastHigh = _lastLow = initialPrice;
_mu = mu;
_sigma = sigma;
- _random = new Random((int)DateTime.Now.Ticks);
+ _rng = RandomNumberGenerator.Create();
this.Name = $"GBM({_sigma:F2})";
}
@@ -39,9 +39,9 @@ public class GbmFeed : TBarSeries
double newClose = _lastClose * Math.Exp(drift + diffusion);
double open = _lastClose;
- double high = Math.Max(_lastHigh, Math.Max(open, newClose) * (1 + _random.NextDouble() * 0.01));
- double low = Math.Min(_lastLow, Math.Min(open, newClose) * (1 - _random.NextDouble() * 0.01));
- double volume = 1000 + _random.NextDouble() * 1000;
+ double high = Math.Max(_lastHigh, Math.Max(open, newClose) * (1 + GenerateRandomDouble() * 0.01));
+ double low = Math.Min(_lastLow, Math.Min(open, newClose) * (1 - GenerateRandomDouble() * 0.01));
+ double volume = 1000 + GenerateRandomDouble() * 1000;
if (isNew)
{
@@ -62,8 +62,15 @@ public class GbmFeed : TBarSeries
private double GenerateNormalRandom()
{
// Box-Muller transform to generate standard normal random variable
- double u1 = 1.0 - _random.NextDouble(); // Uniform(0,1] random doubles
- double u2 = 1.0 - _random.NextDouble();
+ double u1 = 1.0 - GenerateRandomDouble(); // Uniform(0,1] random doubles
+ double u2 = 1.0 - GenerateRandomDouble();
return Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
}
+
+ private double GenerateRandomDouble()
+ {
+ byte[] bytes = new byte[8];
+ _rng.GetBytes(bytes);
+ return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue;
+ }
}
\ No newline at end of file
diff --git a/lib/quantalib.csproj b/lib/quantalib.csproj
index f5e03213..2ca3d6ba 100644
--- a/lib/quantalib.csproj
+++ b/lib/quantalib.csproj
@@ -18,36 +18,24 @@
full
True
True
-
+ QuanTAlib2.png
+ readme.md
+ Apache-2.0
+
Indicators;Stock;Market;Technical;Analysis;Algorithmic;Trading;Trade;Trend;Momentum;Finance;Algorithm;Algo;
AlgoTrading;Financial;Strategy;Chart;Charting;Oscillator;Overlay;Equity;Bitcoin;Crypto;Cryptocurrency;Forex;
Quantitative;Historical;Quotes;
- $(NoWarn);NU5104
- QuanTAlib2.png
- Apache-2.0
- True
- https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png
- True
-
- Indicators;Stock;Market;Technical;Analysis;Algorithmic;Trading;Trade;Trend;Momentum;Finance;Algorithm;Algo;
- AlgoTrading;Financial;Strategy;Chart;Charting;Oscillator;Overlay;Equity;Bitcoin;Crypto;Cryptocurrency;Forex;
- Quantitative;Historical;Quotes;
-
QuanTAlib2.png
https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png
True
-
- QuanTAlib2.png
- https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png
- True
-
+
-
+
..\.github\TradingPlatform.BusinessLayer.dll