From fd3065e7b9743140433a6cd1743228acdc5f94ff Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Sat, 13 Dec 2025 22:51:26 -0800 Subject: [PATCH] fix: add validation for empty span in MinScalar and MaxScalar methods; ensure valid OHLC values in GBM calculations --- lib/core/simd/SimdExtensions.cs | 6 ++++++ lib/feeds/gbm/ValidationHelper.cs | 21 +++++++++------------ lib/feeds/gbm/gbm.cs | 22 ++++++++++++++++++---- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/lib/core/simd/SimdExtensions.cs b/lib/core/simd/SimdExtensions.cs index c5acede7..63674ed8 100644 --- a/lib/core/simd/SimdExtensions.cs +++ b/lib/core/simd/SimdExtensions.cs @@ -37,6 +37,9 @@ public static class SimdExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static double MinScalar(ReadOnlySpan span) { + if (span.Length == 0) + throw new ArgumentException("Span must not be empty", nameof(span)); + double min = span[0]; for (int i = 1; i < span.Length; i++) { @@ -49,6 +52,9 @@ public static class SimdExtensions [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static double MaxScalar(ReadOnlySpan span) { + if (span.Length == 0) + throw new ArgumentException("Span must not be empty", nameof(span)); + double max = span[0]; for (int i = 1; i < span.Length; i++) { diff --git a/lib/feeds/gbm/ValidationHelper.cs b/lib/feeds/gbm/ValidationHelper.cs index db635aaa..80a78f10 100644 --- a/lib/feeds/gbm/ValidationHelper.cs +++ b/lib/feeds/gbm/ValidationHelper.cs @@ -124,8 +124,7 @@ public static class ValidationHelper { int count = qSeries.Count; int start = Math.Max(0, count - skip); - var (_, length) = outRange.GetOffsetAndLength(tOutput.Length); - int validCount = length; + var (offset, length) = outRange.GetOffsetAndLength(tOutput.Length); for (int i = start; i < count; i++) { @@ -133,8 +132,8 @@ public static class ValidationHelper if (i < lookback) continue; - int tIndex = i - lookback; - if (tIndex >= validCount) continue; + int tIndex = i - offset; + if (tIndex < 0 || tIndex >= length) continue; double tValue = tOutput[tIndex]; @@ -146,8 +145,7 @@ public static class ValidationHelper { int count = qResults.Count; int start = Math.Max(0, count - skip); - var (_, length) = outRange.GetOffsetAndLength(tOutput.Length); - int validCount = length; + var (offset, length) = outRange.GetOffsetAndLength(tOutput.Length); for (int i = start; i < count; i++) { @@ -155,8 +153,8 @@ public static class ValidationHelper if (i < lookback) continue; - int tIndex = i - lookback; - if (tIndex >= validCount) continue; + int tIndex = i - offset; + if (tIndex < 0 || tIndex >= length) continue; double tValue = tOutput[tIndex]; @@ -168,8 +166,7 @@ public static class ValidationHelper { int count = qOutput.Length; int start = Math.Max(0, count - skip); - var (_, length) = outRange.GetOffsetAndLength(tOutput.Length); - int validCount = length; + var (offset, length) = outRange.GetOffsetAndLength(tOutput.Length); for (int i = start; i < count; i++) { @@ -177,8 +174,8 @@ public static class ValidationHelper if (i < lookback) continue; - int tIndex = i - lookback; - if (tIndex >= validCount) continue; + int tIndex = i - offset; + if (tIndex < 0 || tIndex >= length) continue; double tValue = tOutput[tIndex]; diff --git a/lib/feeds/gbm/gbm.cs b/lib/feeds/gbm/gbm.cs index 755e1ad4..7799bae6 100644 --- a/lib/feeds/gbm/gbm.cs +++ b/lib/feeds/gbm/gbm.cs @@ -132,8 +132,13 @@ public class GBM : IFeed double open = _lastPrice; double close = price; - double high = Math.Max(open, close) * (1.0 + NextDouble() * 0.01); - double low = Math.Min(open, close) * (1.0 - NextDouble() * 0.01); + double high = Math.Max(open, close) * (1.0 + Math.Abs(NextDouble()) * 0.01); + double low = Math.Min(open, close) * (1.0 - Math.Abs(NextDouble()) * 0.01); + + // Ensure valid OHLC + high = Math.Max(high, Math.Max(open, close)); + low = Math.Min(low, Math.Min(open, close)); + low = Math.Max(0.0, low); _currentBar = new TBar(currentTime, open, high, low, close, volume); _hasCurrentBar = true; @@ -215,8 +220,17 @@ public class GBM : IFeed t[i] = currentTime; o[i] = open; c[i] = close; - h[i] = Math.Max(open, close) * (1.0 + rnd1 * 0.01); - l[i] = Math.Min(open, close) * (1.0 - rnd2 * 0.01); + + double high = Math.Max(open, close) * (1.0 + Math.Abs(rnd1) * 0.01); + double low = Math.Min(open, close) * (1.0 - Math.Abs(rnd2) * 0.01); + + // Ensure valid OHLC + high = Math.Max(high, Math.Max(open, close)); + low = Math.Min(low, Math.Min(open, close)); + low = Math.Max(0.0, low); + + h[i] = high; + l[i] = low; v[i] = 1000 + rnd3 * 1000; currentPrice = price;