mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-28 01:37:43 +00:00
Merging dev into main (#34)
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
|
||||
<NoWarn>$(NoWarn);NU1903;NU5104</NoWarn>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Deterministic>true</Deterministic>
|
||||
@@ -49,6 +49,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(IsLocalBuild)' == 'true'">
|
||||
|
||||
<!-- Set the correct path to Quantower here -->
|
||||
<QuantowerRoot>D:\Quantower</QuantowerRoot>
|
||||
<QuantowerPath>$([System.IO.Directory]::GetDirectories("$(QuantowerRoot)\TradingPlatform", "v1*")[0])</QuantowerPath>
|
||||
</PropertyGroup>
|
||||
|
||||
+13
-7
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+13
-6
@@ -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)
|
||||
|
||||
+43
-38
@@ -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,46 +17,43 @@ 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++)
|
||||
{
|
||||
double randomValue = random.NextDouble() * 100;
|
||||
double randomValue = GetRandomDouble(rng) * 100;
|
||||
input.Add(randomValue);
|
||||
|
||||
// Calculate direct indicators
|
||||
@@ -71,4 +69,11 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
+33
-8
@@ -1,16 +1,16 @@
|
||||
using Xunit;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
/// Contains unit tests for bar-based indicators in QuanTAlib.
|
||||
/// </summary>
|
||||
[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
|
||||
/// </summary>
|
||||
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
|
||||
/// <returns>A randomly generated TBar.</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random double between 0 and 1.
|
||||
/// </summary>
|
||||
/// <returns>A random double between 0 and 1.</returns>
|
||||
private double GetRandomDouble()
|
||||
{
|
||||
byte[] bytes = new byte[8];
|
||||
rng.GetBytes(bytes);
|
||||
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random integer between minValue (inclusive) and maxValue (exclusive).
|
||||
/// </summary>
|
||||
/// <param name="minValue">The minimum value (inclusive).</param>
|
||||
/// <param name="maxValue">The maximum value (exclusive).</param>
|
||||
/// <returns>A random integer between minValue and maxValue.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides the list of indicators for parameterized tests.
|
||||
/// </summary>
|
||||
|
||||
+13
-5
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+26
-20
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+30
-36
@@ -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 * 3; 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+15
-8
@@ -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;
|
||||
}
|
||||
}
|
||||
+6
-18
@@ -18,36 +18,24 @@
|
||||
<DebugType>full</DebugType>
|
||||
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<PackageTags>
|
||||
<PackageIcon>QuanTAlib2.png</PackageIcon>
|
||||
<PackageReadmeFile>readme.md</PackageReadmeFile>
|
||||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
||||
<PackageTags>
|
||||
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;
|
||||
</PackageTags>
|
||||
<NoWarn>$(NoWarn);NU5104</NoWarn>
|
||||
<PackageIcon>QuanTAlib2.png</PackageIcon>
|
||||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
||||
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
|
||||
<PackageIconUrl>https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png</PackageIconUrl>
|
||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||
<PackageTags>
|
||||
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;
|
||||
</PackageTags>
|
||||
<PackageIcon>QuanTAlib2.png</PackageIcon>
|
||||
<PackageIconUrl>https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png</PackageIconUrl>
|
||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PackageIcon>QuanTAlib2.png</PackageIcon>
|
||||
<PackageIconUrl>https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png</PackageIconUrl>
|
||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\docs\readme.md" Pack="true" PackagePath=""/>
|
||||
<None Include="..\.github\QuanTAlib2.png" Pack="true" Visible="false" PackagePath=""/>
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.0-rc.1.24431.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="TradingPlatform.BusinessLayer">
|
||||
<HintPath>..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
||||
|
||||
Reference in New Issue
Block a user