mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-19 19:18:05 +00:00
code reviews
This commit is contained in:
@@ -26,6 +26,7 @@ public sealed class CsvFeedTests : IDisposable
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
foreach (var file in _tempFiles)
|
||||
{
|
||||
@@ -882,4 +883,4 @@ public sealed class CsvFeedTests : IDisposable
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -666,14 +666,33 @@ public class GBMTests
|
||||
[Fact]
|
||||
public void ImplementsIFeed()
|
||||
{
|
||||
GBM feed = new GBM(startPrice: 100.0, seed: 42);
|
||||
// Verify GBM implements IFeed interface
|
||||
Assert.True(typeof(IFeed).IsAssignableFrom(typeof(GBM)));
|
||||
|
||||
// Use IFeed reference to verify interface contract
|
||||
IFeed feed = new GBM(startPrice: 100.0, seed: 42);
|
||||
|
||||
// Test Next(bool) overload via interface
|
||||
var bar1 = feed.Next(isNew: true);
|
||||
Assert.True(bar1.Time > 0);
|
||||
|
||||
var bar2 = feed.Next(isNew: true);
|
||||
Assert.True(bar2.Time > bar1.Time);
|
||||
|
||||
// Test Next(ref bool) overload via interface - verify ref parameter behavior
|
||||
bool isNew = true;
|
||||
var bar3 = feed.Next(ref isNew);
|
||||
Assert.True(bar3.Time > bar2.Time);
|
||||
Assert.True(isNew, "GBM should honor isNew=true request and keep it true");
|
||||
|
||||
// Test with isNew=false via interface
|
||||
bool isNewFalse = false;
|
||||
long bar3Time = bar3.Time;
|
||||
var bar3Updated = feed.Next(ref isNewFalse);
|
||||
Assert.Equal(bar3Time, bar3Updated.Time); // Same bar when isNew=false
|
||||
Assert.False(isNewFalse, "GBM should honor isNew=false request and keep it false");
|
||||
|
||||
// Test Fetch via interface
|
||||
long startTime = DateTime.UtcNow.Ticks;
|
||||
var series = feed.Fetch(5, startTime, TimeSpan.FromMinutes(1));
|
||||
Assert.Equal(5, series.Count);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace QuanTAlib.Tests;
|
||||
|
||||
/// <summary>
|
||||
|
||||
+77
-16
@@ -1,3 +1,4 @@
|
||||
using System.Buffers;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
@@ -262,6 +263,7 @@ public sealed class GBM : IFeed
|
||||
|
||||
/// <summary>
|
||||
/// Generates a batch of bars using optimized batch processing with explicit time parameters.
|
||||
/// Uses stackalloc for small batches to avoid heap allocations.
|
||||
/// </summary>
|
||||
/// <param name="count">Number of bars to generate (must be positive)</param>
|
||||
/// <param name="startTime">Starting timestamp in ticks</param>
|
||||
@@ -279,14 +281,81 @@ public sealed class GBM : IFeed
|
||||
|
||||
var series = new TBarSeries(count);
|
||||
|
||||
// Pre-allocate arrays for SoA layout
|
||||
long[] t = new long[count];
|
||||
double[] o = new double[count];
|
||||
double[] h = new double[count];
|
||||
double[] l = new double[count];
|
||||
double[] c = new double[count];
|
||||
double[] v = new double[count];
|
||||
// Threshold for stackalloc: 64 bars * (8 bytes for long + 5*8 bytes for doubles) = 64 * 48 = 3KB
|
||||
// Stay well under typical stack limit; use 64 as safe threshold
|
||||
const int StackAllocThreshold = 64;
|
||||
|
||||
// Use stackalloc for small batches to avoid heap allocations
|
||||
if (count <= StackAllocThreshold)
|
||||
{
|
||||
Span<long> t = stackalloc long[count];
|
||||
Span<double> o = stackalloc double[count];
|
||||
Span<double> h = stackalloc double[count];
|
||||
Span<double> l = stackalloc double[count];
|
||||
Span<double> c = stackalloc double[count];
|
||||
Span<double> v = stackalloc double[count];
|
||||
|
||||
FetchCore(count, startTime, interval, t, o, h, l, c, v);
|
||||
|
||||
// Bulk add to series using ReadOnlySpan overload
|
||||
series.AddRange(t, o, h, l, c, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use ArrayPool for larger batches to avoid heap allocations
|
||||
long[]? rentedT = null;
|
||||
double[]? rentedO = null;
|
||||
double[]? rentedH = null;
|
||||
double[]? rentedL = null;
|
||||
double[]? rentedC = null;
|
||||
double[]? rentedV = null;
|
||||
|
||||
try
|
||||
{
|
||||
rentedT = ArrayPool<long>.Shared.Rent(count);
|
||||
rentedO = ArrayPool<double>.Shared.Rent(count);
|
||||
rentedH = ArrayPool<double>.Shared.Rent(count);
|
||||
rentedL = ArrayPool<double>.Shared.Rent(count);
|
||||
rentedC = ArrayPool<double>.Shared.Rent(count);
|
||||
rentedV = ArrayPool<double>.Shared.Rent(count);
|
||||
|
||||
// Use only the first 'count' elements (rented arrays may be larger)
|
||||
var t = rentedT.AsSpan(0, count);
|
||||
var o = rentedO.AsSpan(0, count);
|
||||
var h = rentedH.AsSpan(0, count);
|
||||
var l = rentedL.AsSpan(0, count);
|
||||
var c = rentedC.AsSpan(0, count);
|
||||
var v = rentedV.AsSpan(0, count);
|
||||
|
||||
FetchCore(count, startTime, interval, t, o, h, l, c, v);
|
||||
|
||||
// Bulk add to series using ReadOnlySpan overload
|
||||
series.AddRange(t, o, h, l, c, v);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (rentedT != null) ArrayPool<long>.Shared.Return(rentedT);
|
||||
if (rentedO != null) ArrayPool<double>.Shared.Return(rentedO);
|
||||
if (rentedH != null) ArrayPool<double>.Shared.Return(rentedH);
|
||||
if (rentedL != null) ArrayPool<double>.Shared.Return(rentedL);
|
||||
if (rentedC != null) ArrayPool<double>.Shared.Return(rentedC);
|
||||
if (rentedV != null) ArrayPool<double>.Shared.Return(rentedV);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset streaming state after batch
|
||||
_hasCurrentBar = false;
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Core generation logic shared between stackalloc and heap-allocated paths.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void FetchCore(int count, long startTime, TimeSpan interval,
|
||||
Span<long> t, Span<double> o, Span<double> h, Span<double> l, Span<double> c, Span<double> v)
|
||||
{
|
||||
const double minutesPerYear = 252.0 * 6.5 * 60.0;
|
||||
double dt = interval.TotalMinutes / minutesPerYear;
|
||||
double drift = (Mu - 0.5 * Sigma * Sigma) * dt;
|
||||
@@ -335,14 +404,6 @@ public sealed class GBM : IFeed
|
||||
// Update internal state to continue from end of batch
|
||||
_lastPrice = currentPrice;
|
||||
_lastTime = currentTime - timeStep; // Last bar time, not next bar time
|
||||
|
||||
// Bulk add to series
|
||||
series.Add(t, o, h, l, c, v);
|
||||
|
||||
// Reset streaming state after batch
|
||||
_hasCurrentBar = false;
|
||||
|
||||
return series;
|
||||
}
|
||||
}
|
||||
#pragma warning restore S2245
|
||||
#pragma warning restore S2245
|
||||
|
||||
Reference in New Issue
Block a user