mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-19 02:58:05 +00:00
normalization of methods
This commit is contained in:
@@ -20,4 +20,4 @@ Basic mathematical transforms and utility functions for time series. These build
|
||||
| [SIGMOID](sigmoid/Sigmoid.md) | Logistic Function | 1/(1+e^-x); bounded [0,1] transform. |
|
||||
| [SLOPE](slope/Slope.md) | Rate of Change | First derivative; velocity of price movement. |
|
||||
| [SQRTTRANS](sqrttrans/Sqrttrans.md) | Square Root Transform | Variance-stabilizing transformation. |
|
||||
| [STANDARDIZE](standardize/Standardize.md) | Z-Score Normalization | (x - mean) / stddev; zero-mean unit-variance transform. |
|
||||
| [STANDARDIZE](standardize/Standardize.cs) | Z-Score Normalization | (x - mean) / stddev; zero-mean unit-variance transform. |
|
||||
|
||||
@@ -97,7 +97,7 @@ public class AccelTests
|
||||
|
||||
// Output must be same length as source
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
Accel.Calculate(source.AsSpan(), wrongSizeOutput.AsSpan()));
|
||||
Accel.Batch(source.AsSpan(), wrongSizeOutput.AsSpan()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -110,7 +110,7 @@ public class AccelTests
|
||||
// 1. Batch Mode (static span)
|
||||
var tValues = series.Values.ToArray();
|
||||
var batchOutput = new double[tValues.Length];
|
||||
Accel.Calculate(tValues, batchOutput);
|
||||
Accel.Batch(tValues, batchOutput);
|
||||
double expected = batchOutput[^1];
|
||||
|
||||
// 2. Streaming Mode
|
||||
@@ -122,7 +122,7 @@ public class AccelTests
|
||||
double streamingResult = streamingInd.Last.Value;
|
||||
|
||||
// 3. TSeries Batch Mode
|
||||
var batchSeriesResult = Accel.Calculate(series);
|
||||
var batchSeriesResult = Accel.Batch(series);
|
||||
double tseriesResult = batchSeriesResult.Last.Value;
|
||||
|
||||
Assert.Equal(expected, streamingResult, precision: 9);
|
||||
@@ -207,7 +207,7 @@ public class AccelTests
|
||||
|
||||
// Batch
|
||||
var batchResults = new double[count];
|
||||
Accel.Calculate(data, batchResults);
|
||||
Accel.Batch(data, batchResults);
|
||||
|
||||
// Compare
|
||||
for (int i = 0; i < count; i++)
|
||||
|
||||
@@ -109,7 +109,7 @@ public class AccelValidationTests
|
||||
double[] expected = [0, 0, 2, 2, 2, 2];
|
||||
double[] output = new double[data.Length];
|
||||
|
||||
Accel.Calculate(data, output);
|
||||
Accel.Batch(data, output);
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
|
||||
@@ -129,7 +129,7 @@ public sealed class Accel : AbstractBase
|
||||
var tSpan = CollectionsMarshal.AsSpan(t);
|
||||
var vSpan = CollectionsMarshal.AsSpan(v);
|
||||
|
||||
Calculate(sourceValues, vSpan);
|
||||
Batch(sourceValues, vSpan);
|
||||
sourceTimes.CopyTo(tSpan);
|
||||
|
||||
// Prime state with last two values using cached span
|
||||
@@ -176,7 +176,7 @@ public sealed class Accel : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source)
|
||||
public static TSeries Batch(TSeries source)
|
||||
{
|
||||
var accel = new Accel();
|
||||
return accel.Update(source);
|
||||
@@ -187,7 +187,7 @@ public sealed class Accel : AbstractBase
|
||||
/// accel[i] = source[i] - 2*source[i-1] + source[i-2]
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output)
|
||||
{
|
||||
if (source.Length != output.Length)
|
||||
{
|
||||
@@ -314,6 +314,13 @@ public sealed class Accel : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Accel Indicator) Calculate(TSeries source)
|
||||
{
|
||||
var indicator = new Accel();
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static double FindFinite(double a, double b, double c)
|
||||
{
|
||||
@@ -334,4 +341,4 @@ public sealed class Accel : AbstractBase
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,7 @@ public class ChangeTests
|
||||
public void Change_Batch_MatchesStreaming()
|
||||
{
|
||||
int period = 5;
|
||||
var batchResult = Change.Calculate(_source, period);
|
||||
var batchResult = Change.Batch(_source, period);
|
||||
var indicator = new Change(period);
|
||||
|
||||
for (int i = 0; i < _source.Count; i++)
|
||||
@@ -185,8 +185,8 @@ public class ChangeTests
|
||||
var values = _source.Values.ToArray();
|
||||
var output = new double[values.Length];
|
||||
|
||||
Change.Calculate(values, output, period);
|
||||
var batchResult = Change.Calculate(_source, period);
|
||||
Change.Batch(values, output, period);
|
||||
var batchResult = Change.Batch(_source, period);
|
||||
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
@@ -200,9 +200,9 @@ public class ChangeTests
|
||||
var source = new double[10];
|
||||
var output = new double[5];
|
||||
|
||||
Assert.Throws<ArgumentException>(() => Change.Calculate(ReadOnlySpan<double>.Empty, output, 1));
|
||||
Assert.Throws<ArgumentException>(() => Change.Calculate(source, output, 1));
|
||||
Assert.Throws<ArgumentException>(() => Change.Calculate(source, new double[10], 0));
|
||||
Assert.Throws<ArgumentException>(() => Change.Batch(ReadOnlySpan<double>.Empty, output, 1));
|
||||
Assert.Throws<ArgumentException>(() => Change.Batch(source, output, 1));
|
||||
Assert.Throws<ArgumentException>(() => Change.Batch(source, new double[10], 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -18,7 +18,7 @@ public class ChangeValidationTests
|
||||
var series = bars.Close;
|
||||
int period = 10;
|
||||
|
||||
var result = Change.Calculate(series, period);
|
||||
var result = Change.Batch(series, period);
|
||||
|
||||
for (int i = period; i < series.Count; i++)
|
||||
{
|
||||
@@ -63,7 +63,7 @@ public class ChangeValidationTests
|
||||
var output = new double[values.Length];
|
||||
int period = 10;
|
||||
|
||||
Change.Calculate(values, output, period);
|
||||
Change.Batch(values, output, period);
|
||||
|
||||
for (int i = period; i < values.Length; i++)
|
||||
{
|
||||
@@ -83,7 +83,7 @@ public class ChangeValidationTests
|
||||
int period = 10;
|
||||
|
||||
// Calculate QuanTAlib Change
|
||||
var qResult = Change.Calculate(source, period);
|
||||
var qResult = Change.Batch(source, period);
|
||||
|
||||
// Calculate Tulip ROC (returns percentage)
|
||||
var rocIndicator = Tulip.Indicators.roc;
|
||||
@@ -171,7 +171,7 @@ public class ChangeValidationTests
|
||||
var source = bars.Close;
|
||||
|
||||
// Batch
|
||||
var batchResult = Change.Calculate(source, period);
|
||||
var batchResult = Change.Batch(source, period);
|
||||
|
||||
// Streaming
|
||||
var streamingIndicator = new Change(period);
|
||||
@@ -185,7 +185,7 @@ public class ChangeValidationTests
|
||||
// Span
|
||||
var values = source.Values.ToArray();
|
||||
var spanOutput = new double[count];
|
||||
Change.Calculate(values, spanOutput, period);
|
||||
Change.Batch(values, spanOutput, period);
|
||||
|
||||
// Event-driven
|
||||
var eventIndicator = new Change(period);
|
||||
@@ -215,7 +215,7 @@ public class ChangeValidationTests
|
||||
|
||||
foreach (int period in new[] { 1, 5, 10, 20 })
|
||||
{
|
||||
var result = Change.Calculate(source, period);
|
||||
var result = Change.Batch(source, period);
|
||||
|
||||
// Calculate Tulip ROC
|
||||
var rocIndicator = Tulip.Indicators.roc;
|
||||
|
||||
@@ -28,7 +28,7 @@ public sealed class Change : AbstractBase
|
||||
public override bool IsHot => _buffer.Count > _period;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Initializes a new Change indicator with the specified lookback period.
|
||||
/// </summary>
|
||||
/// <param name="period">Lookback period (must be >= 1)</param>
|
||||
public Change(int period = 1)
|
||||
@@ -45,7 +45,7 @@ public sealed class Change : AbstractBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Initializes a new Change indicator chained to a source publisher.
|
||||
/// </summary>
|
||||
/// <param name="source">Source indicator for chaining</param>
|
||||
/// <param name="period">Lookback period</param>
|
||||
@@ -116,7 +116,7 @@ public sealed class Change : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source, int period = 1)
|
||||
public static TSeries Batch(TSeries source, int period = 1)
|
||||
{
|
||||
var indicator = new Change(period);
|
||||
return indicator.Update(source);
|
||||
@@ -125,7 +125,7 @@ public sealed class Change : AbstractBase
|
||||
/// <summary>
|
||||
/// Calculates relative change over a span of values.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output, int period = 1)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output, int period = 1)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
{
|
||||
@@ -204,6 +204,13 @@ public sealed class Change : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Change Indicator) Calculate(TSeries source, int period = 1)
|
||||
{
|
||||
var indicator = new Change(period);
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_buffer.Clear();
|
||||
@@ -211,4 +218,4 @@ public sealed class Change : AbstractBase
|
||||
_p_state = default;
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,7 +187,7 @@ public class ExptransTests
|
||||
var gbm = new GBM(startPrice: 100, mu: 0.05, sigma: 0.2, seed: 40000);
|
||||
var bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
// Use log of close prices to stay in reasonable exp range
|
||||
var logSource = Logtrans.Calculate(bars.Close);
|
||||
var logSource = Logtrans.Batch(bars.Close);
|
||||
|
||||
// Streaming
|
||||
var streaming = new Exptrans();
|
||||
@@ -199,7 +199,7 @@ public class ExptransTests
|
||||
}
|
||||
|
||||
// Batch
|
||||
var batch = Exptrans.Calculate(logSource);
|
||||
var batch = Exptrans.Batch(logSource);
|
||||
|
||||
// Compare all values
|
||||
for (int i = 0; i < logSource.Count; i++)
|
||||
@@ -214,15 +214,15 @@ public class ExptransTests
|
||||
int count = 50;
|
||||
var gbm = new GBM(startPrice: 100, mu: 0.05, sigma: 0.2, seed: 40001);
|
||||
var bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var logSource = Logtrans.Calculate(bars.Close);
|
||||
var logSource = Logtrans.Batch(bars.Close);
|
||||
|
||||
// TSeries batch
|
||||
var batchResult = Exptrans.Calculate(logSource);
|
||||
var batchResult = Exptrans.Batch(logSource);
|
||||
|
||||
// Span calculation
|
||||
var values = logSource.Values.ToArray();
|
||||
var output = new double[count];
|
||||
Exptrans.Calculate(values, output);
|
||||
Exptrans.Batch(values, output);
|
||||
|
||||
for (int i = 0; i < logSource.Count; i++)
|
||||
{
|
||||
@@ -236,14 +236,14 @@ public class ExptransTests
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
Span<double> output = stackalloc double[10];
|
||||
Exptrans.Calculate(ReadOnlySpan<double>.Empty, output);
|
||||
Exptrans.Batch(ReadOnlySpan<double>.Empty, output);
|
||||
});
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
ReadOnlySpan<double> source = stackalloc double[10];
|
||||
Span<double> output = stackalloc double[5];
|
||||
Exptrans.Calculate(source, output);
|
||||
Exptrans.Batch(source, output);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ public class ExptransValidationTests
|
||||
// Use log-transformed prices to keep exp in reasonable range
|
||||
var gbm = new GBM(startPrice: 100, mu: 0.05, sigma: 0.2, seed: 50000);
|
||||
var bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var logSource = Logtrans.Calculate(bars.Close);
|
||||
var logSource = Logtrans.Batch(bars.Close);
|
||||
|
||||
var result = Exptrans.Calculate(logSource);
|
||||
var result = Exptrans.Batch(logSource);
|
||||
|
||||
for (int i = 0; i < logSource.Count; i++)
|
||||
{
|
||||
@@ -33,7 +33,7 @@ public class ExptransValidationTests
|
||||
int count = 100;
|
||||
var gbm = new GBM(startPrice: 100, mu: 0.05, sigma: 0.2, seed: 50001);
|
||||
var bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var logSource = Logtrans.Calculate(bars.Close);
|
||||
var logSource = Logtrans.Batch(bars.Close);
|
||||
|
||||
var indicator = new Exptrans();
|
||||
|
||||
@@ -51,11 +51,11 @@ public class ExptransValidationTests
|
||||
int count = 100;
|
||||
var gbm = new GBM(startPrice: 100, mu: 0.05, sigma: 0.2, seed: 50002);
|
||||
var bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var logSource = Logtrans.Calculate(bars.Close);
|
||||
var logSource = Logtrans.Batch(bars.Close);
|
||||
|
||||
var values = logSource.Values.ToArray();
|
||||
var output = new double[count];
|
||||
Exptrans.Calculate(values, output);
|
||||
Exptrans.Batch(values, output);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@@ -94,8 +94,8 @@ public class ExptransValidationTests
|
||||
var bars = gbm.Fetch(50, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var source = bars.Close;
|
||||
|
||||
var logResult = Logtrans.Calculate(source);
|
||||
var expResult = Exptrans.Calculate(logResult);
|
||||
var logResult = Logtrans.Batch(source);
|
||||
var expResult = Exptrans.Batch(logResult);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
|
||||
@@ -106,7 +106,7 @@ public sealed class Exptrans : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source)
|
||||
public static TSeries Batch(TSeries source)
|
||||
{
|
||||
var indicator = new Exptrans();
|
||||
return indicator.Update(source);
|
||||
@@ -115,7 +115,7 @@ public sealed class Exptrans : AbstractBase
|
||||
/// <summary>
|
||||
/// Calculates exponential over a span of values.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
{
|
||||
@@ -152,10 +152,17 @@ public sealed class Exptrans : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Exptrans Indicator) Calculate(TSeries source)
|
||||
{
|
||||
var indicator = new Exptrans();
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_state = new(1.0);
|
||||
_p_state = new(1.0);
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,7 +209,7 @@ public class HighestTests
|
||||
}
|
||||
|
||||
// Batch
|
||||
var batch = Highest.Calculate(source, period);
|
||||
var batch = Highest.Batch(source, period);
|
||||
|
||||
// Compare last values (after warmup)
|
||||
for (int i = period; i < source.Count; i++)
|
||||
@@ -228,12 +228,12 @@ public class HighestTests
|
||||
var source = bars.Close;
|
||||
|
||||
// TSeries batch
|
||||
var batchResult = Highest.Calculate(source, period);
|
||||
var batchResult = Highest.Batch(source, period);
|
||||
|
||||
// Span calculation
|
||||
var values = source.Values.ToArray();
|
||||
var output = new double[count];
|
||||
Highest.Calculate(values, output, period);
|
||||
Highest.Batch(values, output, period);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
@@ -247,21 +247,21 @@ public class HighestTests
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
Span<double> output = stackalloc double[10];
|
||||
Highest.Calculate(ReadOnlySpan<double>.Empty, output, 5);
|
||||
Highest.Batch(ReadOnlySpan<double>.Empty, output, 5);
|
||||
});
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
ReadOnlySpan<double> source = stackalloc double[10];
|
||||
Span<double> output = stackalloc double[5];
|
||||
Highest.Calculate(source, output, 5);
|
||||
Highest.Batch(source, output, 5);
|
||||
});
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
ReadOnlySpan<double> source = stackalloc double[10];
|
||||
Span<double> output = stackalloc double[10];
|
||||
Highest.Calculate(source, output, 0);
|
||||
Highest.Batch(source, output, 0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ public sealed class HighestValidationTests : IDisposable
|
||||
{
|
||||
// Calculate QuanTAlib Highest (Span API)
|
||||
double[] qOutput = new double[sourceData.Length];
|
||||
Highest.Calculate(sourceData.AsSpan(), qOutput.AsSpan(), period);
|
||||
Highest.Batch(sourceData.AsSpan(), qOutput.AsSpan(), period);
|
||||
|
||||
// Calculate TA-Lib MAX
|
||||
var retCode = TALib.Functions.Max<double>(sourceData, 0..^0, talibOutput, out var outRange, period);
|
||||
|
||||
@@ -106,7 +106,7 @@ public sealed class Highest : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source, int period)
|
||||
public static TSeries Batch(TSeries source, int period)
|
||||
{
|
||||
var indicator = new Highest(period);
|
||||
return indicator.Update(source);
|
||||
@@ -115,7 +115,7 @@ public sealed class Highest : AbstractBase
|
||||
/// <summary>
|
||||
/// Calculates rolling maximum over a span of values.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output, int period)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output, int period)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
{
|
||||
@@ -238,6 +238,13 @@ public sealed class Highest : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Highest Indicator) Calculate(TSeries source, int period)
|
||||
{
|
||||
var indicator = new Highest(period);
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_buffer.Clear();
|
||||
@@ -245,4 +252,4 @@ public sealed class Highest : AbstractBase
|
||||
_p_state = default;
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,7 +102,7 @@ public class JerkTests
|
||||
|
||||
// Output must be same length as source
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
Jerk.Calculate(source.AsSpan(), wrongSizeOutput.AsSpan()));
|
||||
Jerk.Batch(source.AsSpan(), wrongSizeOutput.AsSpan()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -115,7 +115,7 @@ public class JerkTests
|
||||
// 1. Batch Mode (static span)
|
||||
var tValues = series.Values.ToArray();
|
||||
var batchOutput = new double[tValues.Length];
|
||||
Jerk.Calculate(tValues, batchOutput);
|
||||
Jerk.Batch(tValues, batchOutput);
|
||||
double expected = batchOutput[^1];
|
||||
|
||||
// 2. Streaming Mode
|
||||
@@ -127,7 +127,7 @@ public class JerkTests
|
||||
double streamingResult = streamingInd.Last.Value;
|
||||
|
||||
// 3. TSeries Batch Mode
|
||||
var batchSeriesResult = Jerk.Calculate(series);
|
||||
var batchSeriesResult = Jerk.Batch(series);
|
||||
double tseriesResult = batchSeriesResult.Last.Value;
|
||||
|
||||
Assert.Equal(expected, streamingResult, precision: 9);
|
||||
@@ -211,7 +211,7 @@ public class JerkTests
|
||||
|
||||
// Batch
|
||||
var batchResults = new double[count];
|
||||
Jerk.Calculate(data, batchResults);
|
||||
Jerk.Batch(data, batchResults);
|
||||
|
||||
// Compare
|
||||
for (int i = 0; i < count; i++)
|
||||
|
||||
@@ -128,7 +128,7 @@ public class JerkValidationTests
|
||||
double[] expected = [0, 0, 0, 6, 6, 6];
|
||||
double[] output = new double[data.Length];
|
||||
|
||||
Jerk.Calculate(data, output);
|
||||
Jerk.Batch(data, output);
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
|
||||
@@ -146,7 +146,7 @@ public sealed class Jerk : AbstractBase
|
||||
var tSpan = CollectionsMarshal.AsSpan(t);
|
||||
var vSpan = CollectionsMarshal.AsSpan(v);
|
||||
|
||||
Calculate(sourceValues, vSpan);
|
||||
Batch(sourceValues, vSpan);
|
||||
sourceTimes.CopyTo(tSpan);
|
||||
|
||||
// Prime state with last three values using cached span
|
||||
@@ -200,7 +200,7 @@ public sealed class Jerk : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source)
|
||||
public static TSeries Batch(TSeries source)
|
||||
{
|
||||
var jerk = new Jerk();
|
||||
return jerk.Update(source);
|
||||
@@ -211,7 +211,7 @@ public sealed class Jerk : AbstractBase
|
||||
/// jerk[i] = source[i] - 3*source[i-1] + 3*source[i-2] - source[i-3]
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output)
|
||||
{
|
||||
if (source.Length != output.Length)
|
||||
{
|
||||
@@ -385,6 +385,13 @@ public sealed class Jerk : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Jerk Indicator) Calculate(TSeries source)
|
||||
{
|
||||
var indicator = new Jerk();
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static double FindFinite(double a, double b, double c, double d)
|
||||
{
|
||||
@@ -410,4 +417,4 @@ public sealed class Jerk : AbstractBase
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,7 +197,7 @@ public class LineartransTests
|
||||
series.Add(new TValue(time.AddSeconds(i), 10.0 * (i + 1)), true);
|
||||
}
|
||||
|
||||
var result = Lineartrans.Calculate(series, slope: 0.5, intercept: 5.0);
|
||||
var result = Lineartrans.Batch(series, slope: 0.5, intercept: 5.0);
|
||||
|
||||
Assert.Equal(3, result.Count);
|
||||
Assert.Equal(10.0, result[0].Value, 1e-10); // 0.5*10+5
|
||||
@@ -211,7 +211,7 @@ public class LineartransTests
|
||||
double[] source = [10.0, 20.0, 30.0, 40.0, 50.0];
|
||||
double[] output = new double[5];
|
||||
|
||||
Lineartrans.Calculate(source, output, slope: 2.0, intercept: -5.0);
|
||||
Lineartrans.Batch(source, output, slope: 2.0, intercept: -5.0);
|
||||
|
||||
Assert.Equal(15.0, output[0], 1e-10); // 2*10-5
|
||||
Assert.Equal(35.0, output[1], 1e-10); // 2*20-5
|
||||
@@ -226,10 +226,10 @@ public class LineartransTests
|
||||
double[] source = [1.0, 2.0, 3.0];
|
||||
double[] output = new double[3];
|
||||
|
||||
Assert.Throws<ArgumentException>(() => Lineartrans.Calculate([], output));
|
||||
Assert.Throws<ArgumentException>(() => Lineartrans.Calculate(source, new double[2]));
|
||||
Assert.Throws<ArgumentException>(() => Lineartrans.Calculate(source, output, slope: double.NaN));
|
||||
Assert.Throws<ArgumentException>(() => Lineartrans.Calculate(source, output, intercept: double.PositiveInfinity));
|
||||
Assert.Throws<ArgumentException>(() => Lineartrans.Batch([], output));
|
||||
Assert.Throws<ArgumentException>(() => Lineartrans.Batch(source, new double[2]));
|
||||
Assert.Throws<ArgumentException>(() => Lineartrans.Batch(source, output, slope: double.NaN));
|
||||
Assert.Throws<ArgumentException>(() => Lineartrans.Batch(source, output, intercept: double.PositiveInfinity));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -255,7 +255,7 @@ public class LineartransTests
|
||||
double intercept = -20.0;
|
||||
|
||||
// Batch
|
||||
var batchResult = Lineartrans.Calculate(series, slope, intercept);
|
||||
var batchResult = Lineartrans.Batch(series, slope, intercept);
|
||||
|
||||
// Stream
|
||||
var streamIndicator = new Lineartrans(slope, intercept);
|
||||
@@ -267,7 +267,7 @@ public class LineartransTests
|
||||
|
||||
// Span
|
||||
var spanOutput = new double[series.Count];
|
||||
Lineartrans.Calculate(series.Values, spanOutput, slope, intercept);
|
||||
Lineartrans.Batch(series.Values, spanOutput, slope, intercept);
|
||||
|
||||
// Compare last 50 values
|
||||
for (int i = 50; i < series.Count; i++)
|
||||
|
||||
@@ -19,7 +19,7 @@ public class LineartransValidationTests
|
||||
double slope = 2.5;
|
||||
double intercept = -15.0;
|
||||
|
||||
var result = Lineartrans.Calculate(series, slope, intercept);
|
||||
var result = Lineartrans.Batch(series, slope, intercept);
|
||||
|
||||
for (int i = 0; i < series.Count; i++)
|
||||
{
|
||||
@@ -55,7 +55,7 @@ public class LineartransValidationTests
|
||||
double slope = -1.5;
|
||||
double intercept = 50.0;
|
||||
|
||||
Lineartrans.Calculate(source, output, slope, intercept);
|
||||
Lineartrans.Batch(source, output, slope, intercept);
|
||||
|
||||
for (int i = 0; i < source.Length; i++)
|
||||
{
|
||||
@@ -71,7 +71,7 @@ public class LineartransValidationTests
|
||||
var bars = _gbm.Fetch(50, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var series = bars.Close;
|
||||
|
||||
var result = Lineartrans.Calculate(series, slope: 1.0, intercept: 0.0);
|
||||
var result = Lineartrans.Batch(series, slope: 1.0, intercept: 0.0);
|
||||
|
||||
for (int i = 0; i < series.Count; i++)
|
||||
{
|
||||
@@ -87,7 +87,7 @@ public class LineartransValidationTests
|
||||
var series = bars.Close;
|
||||
double intercept = 42.0;
|
||||
|
||||
var result = Lineartrans.Calculate(series, slope: 0.0, intercept: intercept);
|
||||
var result = Lineartrans.Batch(series, slope: 0.0, intercept: intercept);
|
||||
|
||||
for (int i = 0; i < series.Count; i++)
|
||||
{
|
||||
@@ -106,13 +106,13 @@ public class LineartransValidationTests
|
||||
double c = 3.0, d = -10.0; // Second transform
|
||||
|
||||
// Compose sequentially
|
||||
var step1 = Lineartrans.Calculate(series, a, b);
|
||||
var composed = Lineartrans.Calculate(step1, c, d);
|
||||
var step1 = Lineartrans.Batch(series, a, b);
|
||||
var composed = Lineartrans.Batch(step1, c, d);
|
||||
|
||||
// Direct composed transform: y = c*(a*x + b) + d = (a*c)*x + (b*c + d)
|
||||
double composedSlope = a * c;
|
||||
double composedIntercept = b * c + d;
|
||||
var direct = Lineartrans.Calculate(series, composedSlope, composedIntercept);
|
||||
var direct = Lineartrans.Batch(series, composedSlope, composedIntercept);
|
||||
|
||||
for (int i = 0; i < series.Count; i++)
|
||||
{
|
||||
@@ -129,8 +129,8 @@ public class LineartransValidationTests
|
||||
|
||||
double a = 2.5, b = -15.0;
|
||||
|
||||
var transformed = Lineartrans.Calculate(series, a, b);
|
||||
var recovered = Lineartrans.Calculate(transformed, 1.0 / a, -b / a);
|
||||
var transformed = Lineartrans.Batch(series, a, b);
|
||||
var recovered = Lineartrans.Batch(transformed, 1.0 / a, -b / a);
|
||||
|
||||
for (int i = 0; i < series.Count; i++)
|
||||
{
|
||||
@@ -158,8 +158,8 @@ public class LineartransValidationTests
|
||||
}
|
||||
|
||||
// a * (x + offset) should equal a*x + a*offset
|
||||
var scaledSum = Lineartrans.Calculate(shifted, a, 0.0);
|
||||
var sumOfScaled = Lineartrans.Calculate(series, a, a * offset);
|
||||
var scaledSum = Lineartrans.Batch(shifted, a, 0.0);
|
||||
var sumOfScaled = Lineartrans.Batch(series, a, a * offset);
|
||||
|
||||
for (int i = 0; i < series.Count; i++)
|
||||
{
|
||||
@@ -174,7 +174,7 @@ public class LineartransValidationTests
|
||||
var bars = _gbm.Fetch(50, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var series = bars.Close;
|
||||
|
||||
var negated = Lineartrans.Calculate(series, slope: -1.0, intercept: 0.0);
|
||||
var negated = Lineartrans.Batch(series, slope: -1.0, intercept: 0.0);
|
||||
|
||||
for (int i = 0; i < series.Count; i++)
|
||||
{
|
||||
@@ -188,8 +188,8 @@ public class LineartransValidationTests
|
||||
var bars = _gbm.Fetch(50, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var series = bars.Close;
|
||||
|
||||
var negated = Lineartrans.Calculate(series, slope: -1.0, intercept: 0.0);
|
||||
var recovered = Lineartrans.Calculate(negated, slope: -1.0, intercept: 0.0);
|
||||
var negated = Lineartrans.Batch(series, slope: -1.0, intercept: 0.0);
|
||||
var recovered = Lineartrans.Batch(negated, slope: -1.0, intercept: 0.0);
|
||||
|
||||
for (int i = 0; i < series.Count; i++)
|
||||
{
|
||||
@@ -208,7 +208,7 @@ public class LineartransValidationTests
|
||||
series.Add(new TValue(time.AddSeconds(3), 100.0), true);
|
||||
|
||||
// y = 2x + 3
|
||||
var result = Lineartrans.Calculate(series, slope: 2.0, intercept: 3.0);
|
||||
var result = Lineartrans.Batch(series, slope: 2.0, intercept: 3.0);
|
||||
|
||||
Assert.Equal(3.0, result[0].Value, Tolerance); // 2*0+3
|
||||
Assert.Equal(5.0, result[1].Value, Tolerance); // 2*1+3
|
||||
@@ -229,7 +229,7 @@ public class LineartransValidationTests
|
||||
double slope = 2.5;
|
||||
double intercept = 100.0;
|
||||
|
||||
var result = Lineartrans.Calculate(series, slope, intercept);
|
||||
var result = Lineartrans.Batch(series, slope, intercept);
|
||||
|
||||
// Difference between consecutive values should be scaled by slope
|
||||
double diff_01_input = series[1].Value - series[0].Value; // 20
|
||||
@@ -257,7 +257,7 @@ public class LineartransValidationTests
|
||||
double slope = 1.0 + 1e-10;
|
||||
double intercept = -1e15;
|
||||
|
||||
var result = Lineartrans.Calculate(series, slope, intercept);
|
||||
var result = Lineartrans.Batch(series, slope, intercept);
|
||||
|
||||
// Verify each result matches direct computation
|
||||
for (int i = 0; i < series.Count; i++)
|
||||
|
||||
@@ -124,7 +124,7 @@ public sealed class Lineartrans : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source, double slope = 1.0, double intercept = 0.0)
|
||||
public static TSeries Batch(TSeries source, double slope = 1.0, double intercept = 0.0)
|
||||
{
|
||||
var indicator = new Lineartrans(slope, intercept);
|
||||
return indicator.Update(source);
|
||||
@@ -134,7 +134,7 @@ public sealed class Lineartrans : AbstractBase
|
||||
/// Calculates linear transformation over a span of values using SIMD when available.
|
||||
/// Uses FMA intrinsics for y = slope * x + intercept.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output,
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output,
|
||||
double slope = 1.0, double intercept = 0.0)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
@@ -250,10 +250,17 @@ public sealed class Lineartrans : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Lineartrans Indicator) Calculate(TSeries source, double slope = 1.0, double intercept = 0.0)
|
||||
{
|
||||
var indicator = new Lineartrans(slope, intercept);
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_state = default;
|
||||
_p_state = default;
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -197,7 +197,7 @@ public class LogtransTests
|
||||
}
|
||||
|
||||
// Batch
|
||||
var batch = Logtrans.Calculate(source);
|
||||
var batch = Logtrans.Batch(source);
|
||||
|
||||
// Compare all values
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
@@ -215,12 +215,12 @@ public class LogtransTests
|
||||
var source = bars.Close;
|
||||
|
||||
// TSeries batch
|
||||
var batchResult = Logtrans.Calculate(source);
|
||||
var batchResult = Logtrans.Batch(source);
|
||||
|
||||
// Span calculation
|
||||
var values = source.Values.ToArray();
|
||||
var output = new double[count];
|
||||
Logtrans.Calculate(values, output);
|
||||
Logtrans.Batch(values, output);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
@@ -234,14 +234,14 @@ public class LogtransTests
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
Span<double> output = stackalloc double[10];
|
||||
Logtrans.Calculate(ReadOnlySpan<double>.Empty, output);
|
||||
Logtrans.Batch(ReadOnlySpan<double>.Empty, output);
|
||||
});
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
ReadOnlySpan<double> source = stackalloc double[10];
|
||||
Span<double> output = stackalloc double[5];
|
||||
Logtrans.Calculate(source, output);
|
||||
Logtrans.Batch(source, output);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ public class LogtransValidationTests
|
||||
var bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var source = bars.Close;
|
||||
|
||||
var result = Logtrans.Calculate(source);
|
||||
var result = Logtrans.Batch(source);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
@@ -55,7 +55,7 @@ public class LogtransValidationTests
|
||||
|
||||
var values = source.Values.ToArray();
|
||||
var output = new double[count];
|
||||
Logtrans.Calculate(values, output);
|
||||
Logtrans.Batch(values, output);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@@ -199,7 +199,7 @@ public class LogtransValidationTests
|
||||
var values = new double[] { 2.0, 0.0, 3.0 };
|
||||
var output = new double[3];
|
||||
|
||||
Logtrans.Calculate(values, output);
|
||||
Logtrans.Batch(values, output);
|
||||
|
||||
Assert.Equal(Math.Log(2.0), output[0], Tolerance); // ln(2)
|
||||
Assert.Equal(Math.Log(2.0), output[1], Tolerance); // zero -> uses last valid (ln(2))
|
||||
@@ -213,7 +213,7 @@ public class LogtransValidationTests
|
||||
var values = new double[] { 2.0, -5.0, 3.0 };
|
||||
var output = new double[3];
|
||||
|
||||
Logtrans.Calculate(values, output);
|
||||
Logtrans.Batch(values, output);
|
||||
|
||||
Assert.Equal(Math.Log(2.0), output[0], Tolerance); // ln(2)
|
||||
Assert.Equal(Math.Log(2.0), output[1], Tolerance); // negative -> uses last valid (ln(2))
|
||||
|
||||
@@ -99,7 +99,7 @@ public sealed class Logtrans : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source)
|
||||
public static TSeries Batch(TSeries source)
|
||||
{
|
||||
var indicator = new Logtrans();
|
||||
return indicator.Update(source);
|
||||
@@ -109,7 +109,7 @@ public sealed class Logtrans : AbstractBase
|
||||
/// Calculates natural logarithm over a span of values.
|
||||
/// Note: Math.Log has no SIMD intrinsic; uses scalar path with last-valid substitution.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
{
|
||||
@@ -138,10 +138,17 @@ public sealed class Logtrans : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Logtrans Indicator) Calculate(TSeries source)
|
||||
{
|
||||
var indicator = new Logtrans();
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_state = default;
|
||||
_p_state = default;
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,7 +207,7 @@ public class LowestTests
|
||||
}
|
||||
|
||||
// Batch
|
||||
var batch = Lowest.Calculate(source, period);
|
||||
var batch = Lowest.Batch(source, period);
|
||||
|
||||
// Compare last values (after warmup)
|
||||
for (int i = period; i < source.Count; i++)
|
||||
@@ -226,12 +226,12 @@ public class LowestTests
|
||||
var source = bars.Close;
|
||||
|
||||
// TSeries batch
|
||||
var batchResult = Lowest.Calculate(source, period);
|
||||
var batchResult = Lowest.Batch(source, period);
|
||||
|
||||
// Span calculation
|
||||
var values = source.Values.ToArray();
|
||||
var output = new double[count];
|
||||
Lowest.Calculate(values, output, period);
|
||||
Lowest.Batch(values, output, period);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
@@ -245,21 +245,21 @@ public class LowestTests
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
Span<double> output = stackalloc double[10];
|
||||
Lowest.Calculate(ReadOnlySpan<double>.Empty, output, 5);
|
||||
Lowest.Batch(ReadOnlySpan<double>.Empty, output, 5);
|
||||
});
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
ReadOnlySpan<double> source = stackalloc double[10];
|
||||
Span<double> output = stackalloc double[5];
|
||||
Lowest.Calculate(source, output, 5);
|
||||
Lowest.Batch(source, output, 5);
|
||||
});
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
ReadOnlySpan<double> source = stackalloc double[10];
|
||||
Span<double> output = stackalloc double[10];
|
||||
Lowest.Calculate(source, output, 0);
|
||||
Lowest.Batch(source, output, 0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ public sealed class LowestValidationTests : IDisposable
|
||||
{
|
||||
// Calculate QuanTAlib Lowest (Span API)
|
||||
double[] qOutput = new double[sourceData.Length];
|
||||
Lowest.Calculate(sourceData.AsSpan(), qOutput.AsSpan(), period);
|
||||
Lowest.Batch(sourceData.AsSpan(), qOutput.AsSpan(), period);
|
||||
|
||||
// Calculate TA-Lib MIN
|
||||
var retCode = TALib.Functions.Min<double>(sourceData, 0..^0, talibOutput, out var outRange, period);
|
||||
|
||||
@@ -106,7 +106,7 @@ public sealed class Lowest : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source, int period)
|
||||
public static TSeries Batch(TSeries source, int period)
|
||||
{
|
||||
var indicator = new Lowest(period);
|
||||
return indicator.Update(source);
|
||||
@@ -115,7 +115,7 @@ public sealed class Lowest : AbstractBase
|
||||
/// <summary>
|
||||
/// Calculates rolling minimum over a span of values.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output, int period)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output, int period)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
{
|
||||
@@ -217,6 +217,13 @@ public sealed class Lowest : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Lowest Indicator) Calculate(TSeries source, int period)
|
||||
{
|
||||
var indicator = new Lowest(period);
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_buffer.Clear();
|
||||
@@ -224,4 +231,4 @@ public sealed class Lowest : AbstractBase
|
||||
_p_state = default;
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,7 +215,7 @@ public class MidpointTests
|
||||
}
|
||||
|
||||
// Batch
|
||||
var batch = Midpoint.Calculate(source, period);
|
||||
var batch = Midpoint.Batch(source, period);
|
||||
|
||||
// Compare last values (after warmup)
|
||||
for (int i = period; i < source.Count; i++)
|
||||
@@ -234,12 +234,12 @@ public class MidpointTests
|
||||
var source = bars.Close;
|
||||
|
||||
// TSeries batch
|
||||
var batchResult = Midpoint.Calculate(source, period);
|
||||
var batchResult = Midpoint.Batch(source, period);
|
||||
|
||||
// Span calculation
|
||||
var sourceArray = source.Values.ToArray();
|
||||
var output = new double[count];
|
||||
Midpoint.Calculate(sourceArray.AsSpan(), output.AsSpan(), period);
|
||||
Midpoint.Batch(sourceArray.AsSpan(), output.AsSpan(), period);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
@@ -253,21 +253,21 @@ public class MidpointTests
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
Span<double> output = stackalloc double[10];
|
||||
Midpoint.Calculate(ReadOnlySpan<double>.Empty, output, 5);
|
||||
Midpoint.Batch(ReadOnlySpan<double>.Empty, output, 5);
|
||||
});
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
ReadOnlySpan<double> source = stackalloc double[10];
|
||||
Span<double> output = stackalloc double[5];
|
||||
Midpoint.Calculate(source, output, 5);
|
||||
Midpoint.Batch(source, output, 5);
|
||||
});
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
ReadOnlySpan<double> source = stackalloc double[10];
|
||||
Span<double> output = stackalloc double[10];
|
||||
Midpoint.Calculate(source, output, 0);
|
||||
Midpoint.Batch(source, output, 0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ public sealed class MidpointValidationTests : IDisposable
|
||||
{
|
||||
// Calculate QuanTAlib Midpoint (Span API)
|
||||
double[] qOutput = new double[sourceData.Length];
|
||||
Midpoint.Calculate(sourceData.AsSpan(), qOutput.AsSpan(), period);
|
||||
Midpoint.Batch(sourceData.AsSpan(), qOutput.AsSpan(), period);
|
||||
|
||||
// Calculate TA-Lib MIDPOINT
|
||||
var retCode = TALib.Functions.MidPoint<double>(sourceData, 0..^0, talibOutput, out var outRange, period);
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class Midpoint : AbstractBase
|
||||
private readonly Lowest _lowest;
|
||||
private readonly ITValuePublisher? _source;
|
||||
private readonly TValuePublishedHandler? _handler;
|
||||
private bool _disposed;
|
||||
|
||||
public override bool IsHot => _highest.IsHot && _lowest.IsHot;
|
||||
|
||||
@@ -57,9 +58,13 @@ public sealed class Midpoint : AbstractBase
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _source != null && _handler != null)
|
||||
if (!_disposed)
|
||||
{
|
||||
_source.Pub -= _handler;
|
||||
if (disposing && _source != null && _handler != null)
|
||||
{
|
||||
_source.Pub -= _handler;
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
@@ -106,7 +111,7 @@ public sealed class Midpoint : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source, int period)
|
||||
public static TSeries Batch(TSeries source, int period)
|
||||
{
|
||||
var indicator = new Midpoint(period);
|
||||
return indicator.Update(source);
|
||||
@@ -115,7 +120,7 @@ public sealed class Midpoint : AbstractBase
|
||||
/// <summary>
|
||||
/// Calculates rolling midpoint over a span of values.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output, int period)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output, int period)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
{
|
||||
@@ -150,8 +155,8 @@ public sealed class Midpoint : AbstractBase
|
||||
|
||||
try
|
||||
{
|
||||
Highest.Calculate(source, highBuffer, period);
|
||||
Lowest.Calculate(source, lowBuffer, period);
|
||||
Highest.Batch(source, highBuffer, period);
|
||||
Lowest.Batch(source, lowBuffer, period);
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
@@ -172,10 +177,17 @@ public sealed class Midpoint : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Midpoint Indicator) Calculate(TSeries source, int period)
|
||||
{
|
||||
var indicator = new Midpoint(period);
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_highest.Reset();
|
||||
_lowest.Reset();
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -205,7 +205,7 @@ public class NormalizeTests
|
||||
}
|
||||
|
||||
// Static calculation
|
||||
var staticResult = Normalize.Calculate(tseries, 14);
|
||||
var staticResult = Normalize.Batch(tseries, 14);
|
||||
|
||||
// Streaming calculation
|
||||
var streamNorm = new Normalize(14);
|
||||
@@ -230,7 +230,7 @@ public class NormalizeTests
|
||||
double[] output = new double[values.Length];
|
||||
|
||||
// Span calculation
|
||||
Normalize.Calculate(values, output, 14);
|
||||
Normalize.Batch(values, output, 14);
|
||||
|
||||
// Streaming calculation
|
||||
var norm = new Normalize(14);
|
||||
@@ -247,9 +247,9 @@ public class NormalizeTests
|
||||
double[] source = { 1, 2, 3, 4, 5 };
|
||||
double[] output = new double[5];
|
||||
|
||||
Assert.Throws<ArgumentException>(() => Normalize.Calculate(Array.Empty<double>(), output));
|
||||
Assert.Throws<ArgumentException>(() => Normalize.Calculate(source, new double[3]));
|
||||
Assert.Throws<ArgumentException>(() => Normalize.Calculate(source, output, 0));
|
||||
Assert.Throws<ArgumentException>(() => Normalize.Batch(Array.Empty<double>(), output));
|
||||
Assert.Throws<ArgumentException>(() => Normalize.Batch(source, new double[3]));
|
||||
Assert.Throws<ArgumentException>(() => Normalize.Batch(source, output, 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -203,7 +203,7 @@ public class NormalizeValidationTests
|
||||
|
||||
// Batch
|
||||
double[] batchResults = new double[values.Length];
|
||||
Normalize.Calculate(values, batchResults, 14);
|
||||
Normalize.Batch(values, batchResults, 14);
|
||||
|
||||
// Compare all values
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
@@ -233,12 +233,12 @@ public class NormalizeValidationTests
|
||||
tseries.Add(new TValue(bar.Time, bar.Close), true);
|
||||
}
|
||||
|
||||
var results2 = Normalize.Calculate(tseries, period);
|
||||
var results2 = Normalize.Batch(tseries, period);
|
||||
|
||||
// Mode 3: Static span Calculate
|
||||
double[] values = series.Select(b => b.Close).ToArray();
|
||||
double[] results3 = new double[values.Length];
|
||||
Normalize.Calculate(values, results3, period);
|
||||
Normalize.Batch(values, results3, period);
|
||||
|
||||
// Mode 4: Event-based chaining
|
||||
var source = new TSeries();
|
||||
|
||||
@@ -154,7 +154,7 @@ public sealed class Normalize : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source, int period = 14)
|
||||
public static TSeries Batch(TSeries source, int period = 14)
|
||||
{
|
||||
var indicator = new Normalize(period);
|
||||
return indicator.Update(source);
|
||||
@@ -163,7 +163,7 @@ public sealed class Normalize : AbstractBase
|
||||
/// <summary>
|
||||
/// Calculates Min-Max Normalization over a span of values.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output, int period = 14)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output, int period = 14)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
{
|
||||
@@ -231,6 +231,13 @@ public sealed class Normalize : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Normalize Indicator) Calculate(TSeries source, int period = 14)
|
||||
{
|
||||
var indicator = new Normalize(period);
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_buffer.Clear();
|
||||
@@ -238,4 +245,4 @@ public sealed class Normalize : AbstractBase
|
||||
_p_state = _state;
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,7 +179,7 @@ public class ReluTests
|
||||
var gbm = new GBM(startPrice: 100, mu: 0.05, sigma: 0.2, seed: 42000);
|
||||
var bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
// Use returns (which can be negative) for meaningful ReLU test
|
||||
var source = Change.Calculate(bars.Close);
|
||||
var source = Change.Batch(bars.Close);
|
||||
|
||||
// Streaming
|
||||
var streaming = new Relu();
|
||||
@@ -191,7 +191,7 @@ public class ReluTests
|
||||
}
|
||||
|
||||
// Batch
|
||||
var batch = Relu.Calculate(source);
|
||||
var batch = Relu.Batch(source);
|
||||
|
||||
// Compare all values
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
@@ -206,15 +206,15 @@ public class ReluTests
|
||||
int count = 50;
|
||||
var gbm = new GBM(startPrice: 100, mu: 0.05, sigma: 0.2, seed: 42001);
|
||||
var bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var source = Change.Calculate(bars.Close);
|
||||
var source = Change.Batch(bars.Close);
|
||||
|
||||
// TSeries batch
|
||||
var batchResult = Relu.Calculate(source);
|
||||
var batchResult = Relu.Batch(source);
|
||||
|
||||
// Span calculation
|
||||
var values = source.Values.ToArray();
|
||||
var output = new double[count];
|
||||
Relu.Calculate(values, output);
|
||||
Relu.Batch(values, output);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
@@ -228,14 +228,14 @@ public class ReluTests
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
Span<double> output = stackalloc double[10];
|
||||
Relu.Calculate(ReadOnlySpan<double>.Empty, output);
|
||||
Relu.Batch(ReadOnlySpan<double>.Empty, output);
|
||||
});
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
ReadOnlySpan<double> source = stackalloc double[10];
|
||||
Span<double> output = stackalloc double[5];
|
||||
Relu.Calculate(source, output);
|
||||
Relu.Batch(source, output);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public class ReluValidationTests
|
||||
time = time.AddMinutes(1);
|
||||
}
|
||||
|
||||
var result = Relu.Calculate(source);
|
||||
var result = Relu.Batch(source);
|
||||
|
||||
for (int i = 0; i < testValues.Length; i++)
|
||||
{
|
||||
@@ -54,7 +54,7 @@ public class ReluValidationTests
|
||||
double[] testValues = { -10.0, -5.0, -1.0, -0.5, 0.0, 0.5, 1.0, 5.0, 10.0 };
|
||||
double[] output = new double[testValues.Length];
|
||||
|
||||
Relu.Calculate(testValues, output);
|
||||
Relu.Batch(testValues, output);
|
||||
|
||||
for (int i = 0; i < testValues.Length; i++)
|
||||
{
|
||||
@@ -70,9 +70,9 @@ public class ReluValidationTests
|
||||
int count = 100;
|
||||
var gbm = new GBM(startPrice: 100, mu: 0.0, sigma: 0.5, seed: 43000);
|
||||
var bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var source = Change.Calculate(bars.Close);
|
||||
var source = Change.Batch(bars.Close);
|
||||
|
||||
var result = Relu.Calculate(source);
|
||||
var result = Relu.Batch(source);
|
||||
|
||||
for (int i = 0; i < result.Count; i++)
|
||||
{
|
||||
@@ -87,7 +87,7 @@ public class ReluValidationTests
|
||||
double[] positiveValues = { 0.001, 0.1, 1.0, 10.0, 100.0, 1000.0 };
|
||||
double[] output = new double[positiveValues.Length];
|
||||
|
||||
Relu.Calculate(positiveValues, output);
|
||||
Relu.Batch(positiveValues, output);
|
||||
|
||||
for (int i = 0; i < positiveValues.Length; i++)
|
||||
{
|
||||
@@ -102,7 +102,7 @@ public class ReluValidationTests
|
||||
double[] negativeValues = { -0.001, -0.1, -1.0, -10.0, -100.0, -1000.0 };
|
||||
double[] output = new double[negativeValues.Length];
|
||||
|
||||
Relu.Calculate(negativeValues, output);
|
||||
Relu.Batch(negativeValues, output);
|
||||
|
||||
for (int i = 0; i < negativeValues.Length; i++)
|
||||
{
|
||||
@@ -125,7 +125,7 @@ public class ReluValidationTests
|
||||
int count = 100;
|
||||
var gbm = new GBM(startPrice: 100, mu: 0.05, sigma: 0.3, seed: 43001);
|
||||
var bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var source = Change.Calculate(bars.Close);
|
||||
var source = Change.Batch(bars.Close);
|
||||
|
||||
// Streaming
|
||||
var streaming = new Relu();
|
||||
@@ -137,11 +137,11 @@ public class ReluValidationTests
|
||||
}
|
||||
|
||||
// Batch
|
||||
var batch = Relu.Calculate(source);
|
||||
var batch = Relu.Batch(source);
|
||||
|
||||
// Span
|
||||
var spanOutput = new double[source.Count];
|
||||
Relu.Calculate(source.Values.ToArray(), spanOutput);
|
||||
Relu.Batch(source.Values.ToArray(), spanOutput);
|
||||
|
||||
// All three should match
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
|
||||
@@ -25,6 +25,7 @@ public sealed class Relu : AbstractBase
|
||||
private State _state, _p_state;
|
||||
private readonly ITValuePublisher? _source;
|
||||
private readonly TValuePublishedHandler? _handler;
|
||||
private bool _disposed;
|
||||
|
||||
public override bool IsHot => true; // No warmup needed
|
||||
|
||||
@@ -35,7 +36,7 @@ public sealed class Relu : AbstractBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Initializes a new ReLU indicator chained to a source publisher.
|
||||
/// </summary>
|
||||
/// <param name="source">Source indicator for chaining</param>
|
||||
public Relu(ITValuePublisher source) : this()
|
||||
@@ -47,9 +48,13 @@ public sealed class Relu : AbstractBase
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && _source != null && _handler != null)
|
||||
if (!_disposed)
|
||||
{
|
||||
_source.Pub -= _handler;
|
||||
if (disposing && _source != null && _handler != null)
|
||||
{
|
||||
_source.Pub -= _handler;
|
||||
}
|
||||
_disposed = true;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
@@ -104,7 +109,7 @@ public sealed class Relu : AbstractBase
|
||||
var vSpan = System.Runtime.InteropServices.CollectionsMarshal.AsSpan(v);
|
||||
|
||||
// Use vectorized Calculate for batch processing
|
||||
Calculate(source.Values, vSpan);
|
||||
Batch(source.Values, vSpan);
|
||||
source.Times.CopyTo(tSpan);
|
||||
|
||||
// Restore state from last value
|
||||
@@ -130,7 +135,7 @@ public sealed class Relu : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source)
|
||||
public static TSeries Batch(TSeries source)
|
||||
{
|
||||
var indicator = new Relu();
|
||||
return indicator.Update(source);
|
||||
@@ -139,7 +144,7 @@ public sealed class Relu : AbstractBase
|
||||
/// <summary>
|
||||
/// Calculates ReLU over a span of values with SIMD optimization.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
{
|
||||
@@ -213,10 +218,17 @@ public sealed class Relu : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Relu Indicator) Calculate(TSeries source)
|
||||
{
|
||||
var indicator = new Relu();
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_state = default;
|
||||
_p_state = default;
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,7 +238,7 @@ public class SigmoidTests
|
||||
series.Add(new TValue(DateTime.UtcNow.AddSeconds(i), i - 50), isNew: true);
|
||||
}
|
||||
|
||||
var result = Sigmoid.Calculate(series);
|
||||
var result = Sigmoid.Batch(series);
|
||||
|
||||
Assert.Equal(series.Count, result.Count);
|
||||
}
|
||||
@@ -251,7 +251,7 @@ public class SigmoidTests
|
||||
public void Calculate_Span_EmptySource_ThrowsArgumentException()
|
||||
{
|
||||
double[] output = new double[10];
|
||||
Assert.Throws<ArgumentException>(() => Sigmoid.Calculate(ReadOnlySpan<double>.Empty, output.AsSpan()));
|
||||
Assert.Throws<ArgumentException>(() => Sigmoid.Batch(ReadOnlySpan<double>.Empty, output.AsSpan()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -260,7 +260,7 @@ public class SigmoidTests
|
||||
double[] source = [1, 2, 3, 4, 5];
|
||||
double[] output = new double[3];
|
||||
|
||||
Assert.Throws<ArgumentException>(() => Sigmoid.Calculate(source.AsSpan(), output.AsSpan()));
|
||||
Assert.Throws<ArgumentException>(() => Sigmoid.Batch(source.AsSpan(), output.AsSpan()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -269,7 +269,7 @@ public class SigmoidTests
|
||||
double[] source = [1, 2, 3, 4, 5];
|
||||
double[] output = new double[5];
|
||||
|
||||
Assert.Throws<ArgumentException>(() => Sigmoid.Calculate(source.AsSpan(), output.AsSpan(), k: 0));
|
||||
Assert.Throws<ArgumentException>(() => Sigmoid.Batch(source.AsSpan(), output.AsSpan(), k: 0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -283,7 +283,7 @@ public class SigmoidTests
|
||||
}
|
||||
|
||||
double[] spanOutput = new double[source.Length];
|
||||
Sigmoid.Calculate(source.AsSpan(), spanOutput.AsSpan());
|
||||
Sigmoid.Batch(source.AsSpan(), spanOutput.AsSpan());
|
||||
|
||||
var sigmoid = new Sigmoid();
|
||||
double[] streamOutput = new double[source.Length];
|
||||
@@ -304,7 +304,7 @@ public class SigmoidTests
|
||||
double[] source = [1.0, double.NaN, 2.0];
|
||||
double[] output = new double[3];
|
||||
|
||||
Sigmoid.Calculate(source.AsSpan(), output.AsSpan());
|
||||
Sigmoid.Batch(source.AsSpan(), output.AsSpan());
|
||||
|
||||
Assert.True(double.IsFinite(output[0]));
|
||||
Assert.True(double.IsFinite(output[1])); // NaN replaced with last valid
|
||||
|
||||
@@ -228,7 +228,7 @@ public class SigmoidValidationTests
|
||||
|
||||
// Span calculation
|
||||
double[] spanOutput = new double[source.Length];
|
||||
Sigmoid.Calculate(source.AsSpan(), spanOutput.AsSpan(), k, x0);
|
||||
Sigmoid.Batch(source.AsSpan(), spanOutput.AsSpan(), k, x0);
|
||||
|
||||
// Streaming calculation
|
||||
var sigmoid = new Sigmoid(k, x0);
|
||||
|
||||
@@ -136,7 +136,7 @@ public sealed class Sigmoid : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source, double k = 1.0, double x0 = 0.0)
|
||||
public static TSeries Batch(TSeries source, double k = 1.0, double x0 = 0.0)
|
||||
{
|
||||
var indicator = new Sigmoid(k, x0);
|
||||
return indicator.Update(source);
|
||||
@@ -145,7 +145,7 @@ public sealed class Sigmoid : AbstractBase
|
||||
/// <summary>
|
||||
/// Calculates Sigmoid over a span of values.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output, double k = 1.0, double x0 = 0.0)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output, double k = 1.0, double x0 = 0.0)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
{
|
||||
@@ -190,10 +190,17 @@ public sealed class Sigmoid : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Sigmoid Indicator) Calculate(TSeries source, double k = 1.0, double x0 = 0.0)
|
||||
{
|
||||
var indicator = new Sigmoid(k, x0);
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_state = default;
|
||||
_p_state = default;
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,7 @@ public class SlopeTests
|
||||
|
||||
// Output must be same length as source
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
Slope.Calculate(source.AsSpan(), wrongSizeOutput.AsSpan()));
|
||||
Slope.Batch(source.AsSpan(), wrongSizeOutput.AsSpan()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -107,7 +107,7 @@ public class SlopeTests
|
||||
// 1. Batch Mode (static span)
|
||||
var tValues = series.Values.ToArray();
|
||||
var batchOutput = new double[tValues.Length];
|
||||
Slope.Calculate(tValues, batchOutput);
|
||||
Slope.Batch(tValues, batchOutput);
|
||||
double expected = batchOutput[^1];
|
||||
|
||||
// 2. Streaming Mode
|
||||
@@ -119,7 +119,7 @@ public class SlopeTests
|
||||
double streamingResult = streamingInd.Last.Value;
|
||||
|
||||
// 3. TSeries Batch Mode
|
||||
var batchSeriesResult = Slope.Calculate(series);
|
||||
var batchSeriesResult = Slope.Batch(series);
|
||||
double tseriesResult = batchSeriesResult.Last.Value;
|
||||
|
||||
Assert.Equal(expected, streamingResult, precision: 9);
|
||||
@@ -194,7 +194,7 @@ public class SlopeTests
|
||||
|
||||
// Batch
|
||||
var batchResults = new double[count];
|
||||
Slope.Calculate(data, batchResults);
|
||||
Slope.Batch(data, batchResults);
|
||||
|
||||
// Compare
|
||||
for (int i = 0; i < count; i++)
|
||||
|
||||
@@ -104,7 +104,7 @@ public class SlopeValidationTests
|
||||
double[] expected = [0, 2, 2, 2, 2, 2];
|
||||
double[] output = new double[data.Length];
|
||||
|
||||
Slope.Calculate(data, output);
|
||||
Slope.Batch(data, output);
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
|
||||
@@ -114,7 +114,7 @@ public sealed class Slope : AbstractBase
|
||||
var tSpan = CollectionsMarshal.AsSpan(t);
|
||||
var vSpan = CollectionsMarshal.AsSpan(v);
|
||||
|
||||
Calculate(sourceValues, vSpan);
|
||||
Batch(sourceValues, vSpan);
|
||||
sourceTimes.CopyTo(tSpan);
|
||||
|
||||
// Prime state with last value
|
||||
@@ -145,7 +145,7 @@ public sealed class Slope : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source)
|
||||
public static TSeries Batch(TSeries source)
|
||||
{
|
||||
var slope = new Slope();
|
||||
return slope.Update(source);
|
||||
@@ -155,7 +155,7 @@ public sealed class Slope : AbstractBase
|
||||
/// Calculates first derivative (slope) for a span.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output)
|
||||
{
|
||||
if (source.Length != output.Length)
|
||||
{
|
||||
@@ -290,4 +290,11 @@ public sealed class Slope : AbstractBase
|
||||
output[i] = curr - prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Slope Indicator) Calculate(TSeries source)
|
||||
{
|
||||
var indicator = new Slope();
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
}
|
||||
@@ -201,7 +201,7 @@ public class SqrttransTests
|
||||
}
|
||||
|
||||
// Batch
|
||||
var batch = Sqrttrans.Calculate(source);
|
||||
var batch = Sqrttrans.Batch(source);
|
||||
|
||||
// Compare all values
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
@@ -219,12 +219,12 @@ public class SqrttransTests
|
||||
var source = bars.Close;
|
||||
|
||||
// TSeries batch
|
||||
var batchResult = Sqrttrans.Calculate(source);
|
||||
var batchResult = Sqrttrans.Batch(source);
|
||||
|
||||
// Span calculation
|
||||
var values = source.Values.ToArray();
|
||||
var output = new double[count];
|
||||
Sqrttrans.Calculate(values, output);
|
||||
Sqrttrans.Batch(values, output);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
@@ -238,14 +238,14 @@ public class SqrttransTests
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
Span<double> output = stackalloc double[10];
|
||||
Sqrttrans.Calculate(ReadOnlySpan<double>.Empty, output);
|
||||
Sqrttrans.Batch(ReadOnlySpan<double>.Empty, output);
|
||||
});
|
||||
|
||||
Assert.Throws<ArgumentException>(() =>
|
||||
{
|
||||
ReadOnlySpan<double> source = stackalloc double[10];
|
||||
Span<double> output = stackalloc double[5];
|
||||
Sqrttrans.Calculate(source, output);
|
||||
Sqrttrans.Batch(source, output);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public class SqrttransValidationTests
|
||||
var bars = gbm.Fetch(count, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
var source = bars.Close;
|
||||
|
||||
var result = Sqrttrans.Calculate(source);
|
||||
var result = Sqrttrans.Batch(source);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
@@ -54,7 +54,7 @@ public class SqrttransValidationTests
|
||||
|
||||
var values = source.Values.ToArray();
|
||||
var output = new double[count];
|
||||
Sqrttrans.Calculate(values, output);
|
||||
Sqrttrans.Batch(values, output);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@@ -132,7 +132,7 @@ public class SqrttransValidationTests
|
||||
squared.Add(new TValue(tv.Time, tv.Value * tv.Value));
|
||||
}
|
||||
|
||||
var sqrtResult = Sqrttrans.Calculate(squared);
|
||||
var sqrtResult = Sqrttrans.Batch(squared);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
|
||||
@@ -99,7 +99,7 @@ public sealed class Sqrttrans : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source)
|
||||
public static TSeries Batch(TSeries source)
|
||||
{
|
||||
var indicator = new Sqrttrans();
|
||||
return indicator.Update(source);
|
||||
@@ -108,7 +108,7 @@ public sealed class Sqrttrans : AbstractBase
|
||||
/// <summary>
|
||||
/// Calculates square root over a span of values.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
{
|
||||
@@ -137,10 +137,17 @@ public sealed class Sqrttrans : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Sqrttrans Indicator) Calculate(TSeries source)
|
||||
{
|
||||
var indicator = new Sqrttrans();
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_state = default;
|
||||
_p_state = default;
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,7 +258,7 @@ public class StandardizeTests
|
||||
}
|
||||
|
||||
// Static calculation
|
||||
var staticResult = Standardize.Calculate(tseries, 14);
|
||||
var staticResult = Standardize.Batch(tseries, 14);
|
||||
|
||||
// Streaming calculation
|
||||
var streamStandardize = new Standardize(14);
|
||||
@@ -283,7 +283,7 @@ public class StandardizeTests
|
||||
double[] output = new double[values.Length];
|
||||
|
||||
// Span calculation
|
||||
Standardize.Calculate(values, output, 14);
|
||||
Standardize.Batch(values, output, 14);
|
||||
|
||||
// Streaming calculation
|
||||
var standardize = new Standardize(14);
|
||||
@@ -300,9 +300,9 @@ public class StandardizeTests
|
||||
double[] source = [1, 2, 3, 4, 5];
|
||||
double[] output = new double[5];
|
||||
|
||||
Assert.Throws<ArgumentException>(() => Standardize.Calculate([], output));
|
||||
Assert.Throws<ArgumentException>(() => Standardize.Calculate(source, new double[3]));
|
||||
Assert.Throws<ArgumentException>(() => Standardize.Calculate(source, output, 1));
|
||||
Assert.Throws<ArgumentException>(() => Standardize.Batch([], output));
|
||||
Assert.Throws<ArgumentException>(() => Standardize.Batch(source, new double[3]));
|
||||
Assert.Throws<ArgumentException>(() => Standardize.Batch(source, output, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -243,7 +243,7 @@ public class StandardizeValidationTests
|
||||
|
||||
// Batch
|
||||
double[] batchResults = new double[values.Length];
|
||||
Standardize.Calculate(values, batchResults, 14);
|
||||
Standardize.Batch(values, batchResults, 14);
|
||||
|
||||
// Compare all values
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
@@ -273,12 +273,12 @@ public class StandardizeValidationTests
|
||||
tseries.Add(new TValue(bar.Time, bar.Close), true);
|
||||
}
|
||||
|
||||
var results2 = Standardize.Calculate(tseries, period);
|
||||
var results2 = Standardize.Batch(tseries, period);
|
||||
|
||||
// Mode 3: Static span Calculate
|
||||
double[] values = series.Select(b => b.Close).ToArray();
|
||||
double[] results3 = new double[values.Length];
|
||||
Standardize.Calculate(values, results3, period);
|
||||
Standardize.Batch(values, results3, period);
|
||||
|
||||
// Mode 4: Event-based chaining
|
||||
var source = new TSeries();
|
||||
|
||||
@@ -175,7 +175,7 @@ public sealed class Standardize : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static TSeries Calculate(TSeries source, int period = 20)
|
||||
public static TSeries Batch(TSeries source, int period = 20)
|
||||
{
|
||||
var indicator = new Standardize(period);
|
||||
return indicator.Update(source);
|
||||
@@ -184,7 +184,7 @@ public sealed class Standardize : AbstractBase
|
||||
/// <summary>
|
||||
/// Calculates Z-score normalization over a span of values.
|
||||
/// </summary>
|
||||
public static void Calculate(ReadOnlySpan<double> source, Span<double> output, int period = 20)
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output, int period = 20)
|
||||
{
|
||||
if (source.Length == 0)
|
||||
{
|
||||
@@ -264,6 +264,13 @@ public sealed class Standardize : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
public static (TSeries Results, Standardize Indicator) Calculate(TSeries source, int period = 20)
|
||||
{
|
||||
var indicator = new Standardize(period);
|
||||
TSeries results = indicator.Update(source);
|
||||
return (results, indicator);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_buffer.Clear();
|
||||
@@ -271,4 +278,4 @@ public sealed class Standardize : AbstractBase
|
||||
_p_state = _state;
|
||||
Last = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user