normalization of methods

This commit is contained in:
Miha Kralj
2026-02-10 21:33:16 -08:00
parent 915d7a007b
commit 6d6259a47d
527 changed files with 10525 additions and 2123 deletions
+16 -16
View File
@@ -13,26 +13,26 @@ Statistical tools applied to price and returns. These indicators quantify relati
| [COINTEGRATION](cointegration/Cointegration.md) | Cointegration | Tests if series share long-term equilibrium. Pairs trading foundation. |
| [CORRELATION](correlation/Correlation.md) | Correlation | Linear relationship between two variables. Range: -1 to +1. |
| [COVARIANCE](covariance/Covariance.md) | Covariance | Joint variability of two random variables. Building block for β. |
| [ENTROPY](entropy/Entropy.md) | Shannon Entropy | Measures uncertainty/randomness. Higher entropy = less predictable. |
| [GEOMEAN](geomean/Geomean.md) | Geometric Mean | nth root of product. Use for growth rates and ratios. |
| [GRANGER](granger/Granger.md) | Granger Causality | Tests if one series helps predict another. Not true causality. |
| [HARMEAN](harmean/Harmean.md) | Harmonic Mean | Reciprocal of arithmetic mean of reciprocals. For rates/ratios. |
| [HURST](hurst/Hurst.md) | Hurst Exponent | Long-term memory. H>0.5: trending. H<0.5: mean-reverting. |
| [IQR](iqr/Iqr.md) | Interquartile Range | P75 - P25. Robust dispersion measure. |
| [JB](jb/Jb.md) | Jarque-Bera Test | Normality test using skewness and kurtosis. |
| [KENDALL](kendall/Kendall.md) | Kendall Rank Correlation | Ordinal association. Robust to outliers. |
| [KURTOSIS](kurtosis/Kurtosis.md) | Kurtosis | Tail heaviness. High kurtosis = fat tails = more extreme events. |
| ENTROPY | Shannon Entropy | Measures uncertainty/randomness. Higher entropy = less predictable. |
| GEOMEAN | Geometric Mean | nth root of product. Use for growth rates and ratios. |
| GRANGER | Granger Causality | Tests if one series helps predict another. Not true causality. |
| HARMEAN | Harmonic Mean | Reciprocal of arithmetic mean of reciprocals. For rates/ratios. |
| HURST | Hurst Exponent | Long-term memory. H>0.5: trending. H<0.5: mean-reverting. |
| IQR | Interquartile Range | P75 - P25. Robust dispersion measure. |
| JB | Jarque-Bera Test | Normality test using skewness and kurtosis. |
| KENDALL | Kendall Rank Correlation | Ordinal association. Robust to outliers. |
| KURTOSIS | Kurtosis | Tail heaviness. High kurtosis = fat tails = more extreme events. |
| [LINREG](linreg/LinReg.md) | Linear Regression | Least squares fit. Outputs slope, intercept, R². |
| [MEDIAN](median/Median.md) | Median | Middle value in sorted window. Robust to outliers. |
| [MODE](mode/Mode.md) | Mode | Most frequent value. Use for categorical or discrete data. |
| MODE | Mode | Most frequent value. Use for categorical or discrete data. |
| [PACF](pacf/Pacf.md) | Partial Autocorrelation Function | Direct correlation at lag k after removing intermediate effects. For AR model identification. |
| [PERCENTILE](percentile/Percentile.md) | Percentile | Value below which given percentage of observations fall. |
| [QUANTILE](quantile/Quantile.md) | Quantile | Divides distribution into equal probability intervals. |
| PERCENTILE | Percentile | Value below which given percentage of observations fall. |
| QUANTILE | Quantile | Divides distribution into equal probability intervals. |
| [SKEW](skew/Skew.md) | Skewness | Distribution asymmetry. Positive: right tail. Negative: left tail. |
| [SPEARMAN](spearman/Spearman.md) | Spearman Rank Correlation | Pearson on ranks. Measures monotonic relationship. |
| SPEARMAN | Spearman Rank Correlation | Pearson on ranks. Measures monotonic relationship. |
| [STDDEV](stddev/StdDev.md) | Standard Deviation | Square root of variance. Same units as data. |
| [SUM](sum/Sum.md) | Rolling Sum | Kahan-Babuška summation. Numerically stable. |
| [THEIL](theil/Theil.md) | Theil Index | Inequality measure. Decomposable into within/between group. |
| THEIL | Theil Index | Inequality measure. Decomposable into within/between group. |
| [VARIANCE](variance/Variance.md) | Variance | Average squared deviation from mean. Units are squared. |
| [ZSCORE](zscore/Zscore.md) | Z-Score | Standard deviations from mean. Normalizes different scales. |
| [ZTEST](ztest/Ztest.md) | Z-Test | Hypothesis test comparing sample mean to population mean. |
| ZSCORE | Z-Score | Standard deviations from mean. Normalizes different scales. |
| ZTEST | Z-Test | Hypothesis test comparing sample mean to population mean. |
+1 -1
View File
@@ -416,7 +416,7 @@ public class AcfTests
var batchResult = batchIndicator.Update(tSeries);
// Mode 3: Static Calculate
var staticResult = Acf.Calculate(tSeries, period, lag);
var staticResult = Acf.Batch(tSeries, period, lag);
// Mode 4: Span-based Batch
double[] sourceArray = new double[dataLen];
+2 -2
View File
@@ -159,7 +159,7 @@ public class AcfValidationTests
tSeries.Add(new TValue(bar.Time, bar.Close));
}
var batch = Acf.Calculate(tSeries, period, lag);
var batch = Acf.Batch(tSeries, period, lag);
// Compare last values
Assert.Equal(batch[^1].Value, streaming.Last.Value, Tolerance);
@@ -182,7 +182,7 @@ public class AcfValidationTests
tSeries.Add(new TValue(bar.Time, bar.Close));
}
var tSeriesResult = Acf.Calculate(tSeries, period, lag);
var tSeriesResult = Acf.Batch(tSeries, period, lag);
// Span approach
double[] source = new double[dataLen];
+8 -1
View File
@@ -296,7 +296,7 @@ public sealed class Acf : AbstractBase
/// <summary>
/// Calculates ACF for a time series.
/// </summary>
public static TSeries Calculate(TSeries source, int period, int lag = 1)
public static TSeries Batch(TSeries source, int period, int lag = 1)
{
var acf = new Acf(period, lag);
return acf.Update(source);
@@ -332,6 +332,13 @@ public sealed class Acf : AbstractBase
CalculateScalarCore(source, output, period, lag);
}
public static (TSeries Results, Acf Indicator) Calculate(TSeries source, int period, int lag = 1)
{
var indicator = new Acf(period, lag);
TSeries results = indicator.Update(source);
return (results, indicator);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CalculateScalarCore(ReadOnlySpan<double> source, Span<double> output, int period, int lag)
{
@@ -401,7 +401,7 @@ public class CointegrationTests
seriesB.Add(barB.Time, barB.Close);
}
var result = Cointegration.Calculate(seriesA, seriesB, DefaultPeriod);
var result = Cointegration.Batch(seriesA, seriesB, DefaultPeriod);
Assert.Equal(seriesA.Count, result.Count);
}
@@ -423,7 +423,7 @@ public class CointegrationTests
}
// Batch calculation
var batchResult = Cointegration.Calculate(seriesA, seriesB, DefaultPeriod);
var batchResult = Cointegration.Batch(seriesA, seriesB, DefaultPeriod);
// Streaming calculation
var streamingIndicator = new Cointegration(DefaultPeriod);
@@ -464,7 +464,7 @@ public class CointegrationTests
seriesB.Add(bar.Time, bar.Close);
}
var ex = Assert.Throws<ArgumentException>(() => Cointegration.Calculate(seriesA, seriesB, DefaultPeriod));
var ex = Assert.Throws<ArgumentException>(() => Cointegration.Batch(seriesA, seriesB, DefaultPeriod));
Assert.Equal("seriesB", ex.ParamName);
}
@@ -485,7 +485,7 @@ public class CointegrationTests
}
// Span calculation
Cointegration.Calculate(seriesA, seriesB, output, DefaultPeriod);
Cointegration.Batch(seriesA, seriesB, output, DefaultPeriod);
// Streaming calculation
var streamingIndicator = new Cointegration(DefaultPeriod);
@@ -515,7 +515,7 @@ public class CointegrationTests
var seriesB = new double[30];
var output = new double[50];
var ex = Assert.Throws<ArgumentException>(() => Cointegration.Calculate(seriesA, seriesB, output, DefaultPeriod));
var ex = Assert.Throws<ArgumentException>(() => Cointegration.Batch(seriesA, seriesB, output, DefaultPeriod));
Assert.Equal("seriesB", ex.ParamName);
}
@@ -526,7 +526,7 @@ public class CointegrationTests
var seriesB = new double[50];
var output = new double[30];
var ex = Assert.Throws<ArgumentException>(() => Cointegration.Calculate(seriesA, seriesB, output, DefaultPeriod));
var ex = Assert.Throws<ArgumentException>(() => Cointegration.Batch(seriesA, seriesB, output, DefaultPeriod));
Assert.Equal("output", ex.ParamName);
}
@@ -537,7 +537,7 @@ public class CointegrationTests
var seriesB = new double[50];
var output = new double[50];
var ex = Assert.Throws<ArgumentException>(() => Cointegration.Calculate(seriesA, seriesB, output, 1));
var ex = Assert.Throws<ArgumentException>(() => Cointegration.Batch(seriesA, seriesB, output, 1));
Assert.Equal("period", ex.ParamName);
}
@@ -125,7 +125,7 @@ public class CointegrationValidationTests
}
// Batch calculation
var batchResult = Cointegration.Calculate(seriesA, seriesB, 20);
var batchResult = Cointegration.Batch(seriesA, seriesB, 20);
// Streaming calculation
var streamingIndicator = new Cointegration(20);
@@ -160,7 +160,7 @@ public class CointegrationValidationTests
}
// Span calculation
Cointegration.Calculate(seriesA, seriesB, output, 20);
Cointegration.Batch(seriesA, seriesB, output, 20);
// Streaming calculation
var streamingIndicator = new Cointegration(20);
+12 -4
View File
@@ -127,7 +127,7 @@ public sealed class Cointegration : AbstractBase
/// <remarks>Not supported for bi-input indicator. Use Calculate(seriesA, seriesB, period) instead.</remarks>
public override TSeries Update(TSeries source)
{
throw new NotSupportedException("Cointegration requires two inputs. Use Calculate(seriesA, seriesB, period).");
throw new NotSupportedException("Cointegration requires two inputs. Use Batch(seriesA, seriesB, period).");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -472,7 +472,7 @@ public sealed class Cointegration : AbstractBase
/// <summary>
/// Calculates cointegration for two time series.
/// </summary>
public static TSeries Calculate(TSeries seriesA, TSeries seriesB, int period = 20)
public static TSeries Batch(TSeries seriesA, TSeries seriesB, int period = 20)
{
if (seriesA.Count != seriesB.Count)
{
@@ -499,7 +499,7 @@ public sealed class Cointegration : AbstractBase
/// <summary>
/// Static batch calculation for span-based processing.
/// </summary>
public static void Calculate(
public static void Batch(
ReadOnlySpan<double> seriesA,
ReadOnlySpan<double> seriesB,
Span<double> output,
@@ -528,4 +528,12 @@ public sealed class Cointegration : AbstractBase
output[i] = result.Value;
}
}
}
public static (TSeries Results, Cointegration Indicator) Calculate(TSeries seriesA, TSeries seriesB, int period = 20)
{
var indicator = new Cointegration(period);
TSeries results = Batch(seriesA, seriesB, period);
return (results, indicator);
}
}
@@ -251,7 +251,7 @@ public class CorrelationTests
seriesY.Add(new TValue(DateTime.UtcNow.AddMinutes(i), 200.0 + (i * 2)));
}
var result = Correlation.Calculate(seriesX, seriesY, 5);
var result = Correlation.Batch(seriesX, seriesY, 5);
Assert.Equal(20, result.Count);
}
@@ -271,7 +271,7 @@ public class CorrelationTests
seriesY.Add(new TValue(DateTime.UtcNow.AddMinutes(i), 200.0 + i));
}
Assert.Throws<ArgumentException>(() => Correlation.Calculate(seriesX, seriesY, 5));
Assert.Throws<ArgumentException>(() => Correlation.Batch(seriesX, seriesY, 5));
}
[Fact]
@@ -287,7 +287,7 @@ public class CorrelationTests
seriesY[i] = 200.0 + (i * 2);
}
Correlation.Calculate(seriesX, seriesY, output, 5);
Correlation.Batch(seriesX, seriesY, output, 5);
// First value should be NaN (not enough data)
Assert.True(double.IsNaN(output[0]));
@@ -303,7 +303,7 @@ public class CorrelationTests
double[] seriesY = new double[15];
double[] output = new double[10];
Assert.Throws<ArgumentException>(() => Correlation.Calculate(seriesX, seriesY, output, 5));
Assert.Throws<ArgumentException>(() => Correlation.Batch(seriesX, seriesY, output, 5));
}
[Fact]
@@ -313,7 +313,7 @@ public class CorrelationTests
double[] seriesY = new double[20];
double[] output = new double[10];
Assert.Throws<ArgumentException>(() => Correlation.Calculate(seriesX, seriesY, output, 5));
Assert.Throws<ArgumentException>(() => Correlation.Batch(seriesX, seriesY, output, 5));
}
[Fact]
@@ -323,7 +323,7 @@ public class CorrelationTests
double[] seriesY = new double[20];
double[] output = new double[20];
Assert.Throws<ArgumentException>(() => Correlation.Calculate(seriesX, seriesY, output, 1));
Assert.Throws<ArgumentException>(() => Correlation.Batch(seriesX, seriesY, output, 1));
}
[Fact]
@@ -374,7 +374,7 @@ public class CorrelationTests
// Batch calculation
double[] batchResults = new double[length];
Correlation.Calculate(seriesX, seriesY, batchResults, period);
Correlation.Batch(seriesX, seriesY, batchResults, period);
// Compare last 50 values (after warmup)
for (int i = length - 50; i < length; i++)
@@ -190,7 +190,7 @@ public class CorrelationValidationTests
}
// Batch calculation
var batchResult = Correlation.Calculate(seriesX, seriesY, 20);
var batchResult = Correlation.Batch(seriesX, seriesY, 20);
// Streaming calculation
var streamingIndicator = new Correlation(20);
@@ -227,7 +227,7 @@ public class CorrelationValidationTests
}
// Span calculation
Correlation.Calculate(seriesX, seriesY, output, 20);
Correlation.Batch(seriesX, seriesY, output, 20);
// Streaming calculation
var streamingIndicator = new Correlation(20);
+12 -4
View File
@@ -113,7 +113,7 @@ public sealed class Correlation : AbstractBase
/// <remarks>Not supported for bi-input indicator. Use Calculate(seriesX, seriesY, period) instead.</remarks>
public override TSeries Update(TSeries source)
{
throw new NotSupportedException("Correlation requires two inputs. Use Calculate(seriesX, seriesY, period).");
throw new NotSupportedException("Correlation requires two inputs. Use Batch(seriesX, seriesY, period).");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -286,7 +286,7 @@ public sealed class Correlation : AbstractBase
/// <summary>
/// Calculates correlation for two time series.
/// </summary>
public static TSeries Calculate(TSeries seriesX, TSeries seriesY, int period = 20)
public static TSeries Batch(TSeries seriesX, TSeries seriesY, int period = 20)
{
if (seriesX.Count != seriesY.Count)
{
@@ -313,7 +313,7 @@ public sealed class Correlation : AbstractBase
/// <summary>
/// Static batch calculation for span-based processing.
/// </summary>
public static void Calculate(
public static void Batch(
ReadOnlySpan<double> seriesX,
ReadOnlySpan<double> seriesY,
Span<double> output,
@@ -342,4 +342,12 @@ public sealed class Correlation : AbstractBase
output[i] = result.Value;
}
}
}
public static (TSeries Results, Correlation Indicator) Calculate(TSeries seriesX, TSeries seriesY, int period = 20)
{
var indicator = new Correlation(period);
TSeries results = Batch(seriesX, seriesY, period);
return (results, indicator);
}
}
@@ -26,7 +26,7 @@ public class CovarianceSimdTests
// Act
// This will use SIMD if available and length >= 256
var simdResult = Covariance.Calculate(sourceX, sourceY, period);
var simdResult = Covariance.Batch(sourceX, sourceY, period);
// Calculate expected using scalar loop (simulating by using small chunks or manual calc,
// but easier to just use the streaming update which is scalar)
@@ -67,7 +67,7 @@ public class CovarianceSimdTests
// The implementation checks for ContainsNonFinite() before using SIMD.
// If NaN is present, it should fall back to Scalar.
// We want to verify that the result is correct regardless of the path taken.
var result = Covariance.Calculate(sourceX, sourceY, period);
var result = Covariance.Batch(sourceX, sourceY, period);
// Assert
// Verify around the NaN values
@@ -119,7 +119,7 @@ public class CovarianceSimdTests
sourceY.Add(dataY);
// Act
var result = Covariance.Calculate(sourceX, sourceY, period);
var result = Covariance.Batch(sourceX, sourceY, period);
// Assert
// For y=2x, Cov(X,Y) = 2*Var(X)
+9 -2
View File
@@ -179,7 +179,7 @@ public sealed class Covariance : AbstractBase
_sumXY = sumXY;
}
public static TSeries Calculate(TSeries sourceX, TSeries sourceY, int period, bool isPopulation = false)
public static TSeries Batch(TSeries sourceX, TSeries sourceY, int period, bool isPopulation = false)
{
if (sourceX.Count != sourceY.Count)
{
@@ -231,6 +231,13 @@ public sealed class Covariance : AbstractBase
CalculateScalarCore(sourceX, sourceY, output, period, isPopulation);
}
public static (TSeries Results, Covariance Indicator) Calculate(TSeries sourceX, TSeries sourceY, int period, bool isPopulation = false)
{
var indicator = new Covariance(period, isPopulation);
TSeries results = Batch(sourceX, sourceY, period, isPopulation);
return (results, indicator);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CalculateScalarCore(ReadOnlySpan<double> sourceX, ReadOnlySpan<double> sourceY, Span<double> output, int period, bool isPopulation)
{
@@ -512,4 +519,4 @@ public sealed class Covariance : AbstractBase
Unsafe.Add(ref outRef, i) = numerator * invDenom;
}
}
}
}
+4 -4
View File
@@ -120,11 +120,11 @@ public class LinRegTests
// Period must be > 0
Assert.Throws<ArgumentException>(() =>
LinReg.Calculate(source.AsSpan(), output.AsSpan(), 0));
LinReg.Batch(source.AsSpan(), output.AsSpan(), 0));
// Output must be same length as source
Assert.Throws<ArgumentException>(() =>
LinReg.Calculate(source.AsSpan(), wrongSizeOutput.AsSpan(), 3));
LinReg.Batch(source.AsSpan(), wrongSizeOutput.AsSpan(), 3));
}
[Fact]
@@ -145,7 +145,7 @@ public class LinRegTests
var tseriesResult = LinReg.Batch(series, period);
double[] output = new double[100];
LinReg.Calculate(source.AsSpan(), output.AsSpan(), period);
LinReg.Batch(source.AsSpan(), output.AsSpan(), period);
for (int i = 0; i < 100; i++)
{
@@ -213,7 +213,7 @@ public class LinRegTests
var tValues = series.Values.ToArray();
var spanInput = new ReadOnlySpan<double>(tValues);
var spanOutput = new double[tValues.Length];
LinReg.Calculate(spanInput, spanOutput, period);
LinReg.Batch(spanInput, spanOutput, period);
double spanResult = spanOutput[^1];
// 3. Streaming Mode
+10 -3
View File
@@ -279,7 +279,7 @@ public sealed class LinReg : AbstractBase
var vSpan = CollectionsMarshal.AsSpan(v);
double initialLastValid = _state.LastValidValue;
Calculate(source.Values, vSpan, _period, _offset, initialLastValid);
Batch(source.Values, vSpan, _period, _offset, initialLastValid);
source.Times.CopyTo(tSpan);
// Restore state
@@ -334,7 +334,7 @@ public sealed class LinReg : AbstractBase
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Calculate(ReadOnlySpan<double> source, Span<double> output, int period, int offset = 0, double initialLastValid = 0)
public static void Batch(ReadOnlySpan<double> source, Span<double> output, int period, int offset = 0, double initialLastValid = 0)
{
if (source.Length != output.Length)
{
@@ -458,6 +458,13 @@ public sealed class LinReg : AbstractBase
}
}
public static (TSeries Results, LinReg Indicator) Calculate(TSeries source, int period, int offset = 0)
{
var indicator = new LinReg(period, offset);
TSeries results = indicator.Update(source);
return (results, indicator);
}
public override void Reset()
{
_buffer.Clear();
@@ -469,4 +476,4 @@ public sealed class LinReg : AbstractBase
Intercept = 0;
RSquared = 0;
}
}
}
+18 -14
View File
@@ -21,14 +21,14 @@ namespace QuanTAlib;
/// This is significantly faster than O(N log N) full sort for each update.
/// </remarks>
[SkipLocalsInit]
public sealed class Median : AbstractBase, IDisposable
public sealed class Median : AbstractBase
{
private readonly int _period;
private readonly RingBuffer _buffer;
private readonly double[] _sortedBuffer;
private readonly double[] _p_sortedBuffer;
private readonly TValuePublishedHandler _handler;
private ITValuePublisher? _source;
private readonly ITValuePublisher? _source;
private bool _disposed;
/// <summary>
@@ -312,6 +312,13 @@ public sealed class Median : AbstractBase, IDisposable
}
}
public static (TSeries Results, Median Indicator) Calculate(TSeries source, int period)
{
var indicator = new Median(period);
TSeries results = indicator.Update(source);
return (results, indicator);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int BinarySearchSpan(Span<double> span, int length, double value)
{
@@ -352,19 +359,16 @@ public sealed class Median : AbstractBase, IDisposable
/// <summary>
/// Disposes the indicator and unsubscribes from the source.
/// </summary>
public new void Dispose()
protected override void Dispose(bool disposing)
{
if (_disposed)
if (!_disposed)
{
return;
if (disposing && _source != null)
{
_source.Pub -= _handler;
}
_disposed = true;
}
if (_source != null)
{
_source.Pub -= _handler;
_source = null;
}
_disposed = true;
base.Dispose(disposing);
}
}
}
+1 -1
View File
@@ -414,7 +414,7 @@ public class PacfTests
var batchResult = batchIndicator.Update(tSeries);
// Mode 3: Static Calculate
var staticResult = Pacf.Calculate(tSeries, period, lag);
var staticResult = Pacf.Batch(tSeries, period, lag);
// Mode 4: Span-based Batch
double[] sourceArray = new double[dataLen];
+2 -2
View File
@@ -201,7 +201,7 @@ public class PacfValidationTests
}
// Batch
var batchResult = Pacf.Calculate(tSeries, period, lag);
var batchResult = Pacf.Batch(tSeries, period, lag);
// Compare last values
Assert.Equal(batchResult[^1].Value, streaming.Last.Value, Epsilon);
@@ -228,7 +228,7 @@ public class PacfValidationTests
{
tSeries.Add(new TValue(bar.Time, bar.Close));
}
var tSeriesResult = Pacf.Calculate(tSeries, period, lag);
var tSeriesResult = Pacf.Batch(tSeries, period, lag);
// Compare last 50 values
for (int i = source.Length - 50; i < source.Length; i++)
+8 -1
View File
@@ -303,7 +303,7 @@ public sealed class Pacf : AbstractBase
/// <summary>
/// Calculates PACF for a time series.
/// </summary>
public static TSeries Calculate(TSeries source, int period, int lag = 1)
public static TSeries Batch(TSeries source, int period, int lag = 1)
{
var pacf = new Pacf(period, lag);
return pacf.Update(source);
@@ -339,6 +339,13 @@ public sealed class Pacf : AbstractBase
CalculateScalarCore(source, output, period, lag);
}
public static (TSeries Results, Pacf Indicator) Calculate(TSeries source, int period, int lag = 1)
{
var indicator = new Pacf(period, lag);
TSeries results = indicator.Update(source);
return (results, indicator);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CalculateScalarCore(ReadOnlySpan<double> source, Span<double> output, int period, int lag)
{
+4 -4
View File
@@ -131,7 +131,7 @@ public class SkewTests
var series = new TSeries(times, values);
// 1. Batch Mode (static method)
var batchSeries = Skew.Calculate(series, period);
var batchSeries = Skew.Batch(series, period);
double expected = batchSeries.Last.Value;
// 2. Span Mode (static method with spans)
@@ -192,7 +192,7 @@ public class SkewTests
var series = new TSeries(times, values);
var tseriesResult = Skew.Calculate(series, 10);
var tseriesResult = Skew.Batch(series, 10);
Skew.Batch(source.AsSpan(), output.AsSpan(), 10);
for (int i = 0; i < count; i++)
@@ -313,7 +313,7 @@ public class SkewTests
// Batch
var series = new TSeries(new System.Collections.Generic.List<long>(new long[data.Length]), new System.Collections.Generic.List<double>(data));
var batchResult = Skew.Calculate(series, period);
var batchResult = Skew.Batch(series, period);
for (int i = 0; i < data.Length; i++)
{
@@ -391,7 +391,7 @@ public class SkewTests
var series = new TSeries(new System.Collections.Generic.List<long>(new long[count]), new System.Collections.Generic.List<double>(data));
// Batch calculation
var batchResult = Skew.Calculate(series, 10);
var batchResult = Skew.Batch(series, 10);
// Verify last value against streaming
var skew = new Skew(10);
+9 -2
View File
@@ -222,7 +222,7 @@ public sealed class Skew : AbstractBase
}
}
public static TSeries Calculate(TSeries source, int period, bool isPopulation = false)
public static TSeries Batch(TSeries source, int period, bool isPopulation = false)
{
var skew = new Skew(period, isPopulation);
return skew.Update(source);
@@ -260,6 +260,13 @@ public sealed class Skew : AbstractBase
CalculateScalarCore(source, output, period, isPopulation);
}
public static (TSeries Results, Skew Indicator) Calculate(TSeries source, int period, bool isPopulation = false)
{
var indicator = new Skew(period, isPopulation);
TSeries results = indicator.Update(source);
return (results, indicator);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CalculateScalarCore(ReadOnlySpan<double> source, Span<double> output, int period, bool isPopulation)
{
@@ -547,4 +554,4 @@ public sealed class Skew : AbstractBase
Unsafe.Add(ref outRef, i) = CalculateSkewFromSums(sum, sumSq, sumCu, n, isPopulation);
}
}
}
}
+1 -1
View File
@@ -135,7 +135,7 @@ public class StdDevTests
double streamingResult = streamingInd.Last.Value;
// 3. TSeries Batch Mode
var batchSeriesResult = StdDev.Calculate(series, period);
var batchSeriesResult = StdDev.Batch(series, period);
double tseriesResult = batchSeriesResult.Last.Value;
Assert.Equal(expected, streamingResult, precision: 6);
+9 -2
View File
@@ -108,7 +108,7 @@ public sealed class StdDev : AbstractBase
}
}
public static TSeries Calculate(TSeries source, int period, bool isPopulation = false)
public static TSeries Batch(TSeries source, int period, bool isPopulation = false)
{
var stdDev = new StdDev(period, isPopulation);
return stdDev.Update(source);
@@ -127,6 +127,13 @@ public sealed class StdDev : AbstractBase
SqrtSpan(output);
}
public static (TSeries Results, StdDev Indicator) Calculate(TSeries source, int period, bool isPopulation = false)
{
var indicator = new StdDev(period, isPopulation);
TSeries results = indicator.Update(source);
return (results, indicator);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SqrtSpan(Span<double> data)
{
@@ -192,4 +199,4 @@ public sealed class StdDev : AbstractBase
data[i] = (val > 0) ? Math.Sqrt(val) : 0.0;
}
}
}
}
+5 -5
View File
@@ -104,7 +104,7 @@ public class VarianceTests
var series = new TSeries(times, values);
// 1. Batch Mode (static method)
var batchSeries = Variance.Calculate(series, period);
var batchSeries = Variance.Batch(series, period);
double expected = batchSeries.Last.Value;
// 2. Span Mode (static method with spans)
@@ -165,7 +165,7 @@ public class VarianceTests
var series = new TSeries(times, values);
var tseriesResult = Variance.Calculate(series, 10);
var tseriesResult = Variance.Batch(series, 10);
Variance.Batch(source.AsSpan(), output.AsSpan(), 10);
for (int i = 0; i < count; i++)
@@ -359,7 +359,7 @@ public class VarianceTests
var series = new TSeries(new System.Collections.Generic.List<long>(new long[count]), new System.Collections.Generic.List<double>(data));
// Batch calculation
var batchResult = Variance.Calculate(series, 10);
var batchResult = Variance.Batch(series, 10);
Assert.True(double.IsFinite(batchResult.Last.Value));
Assert.True(batchResult.Last.Value >= 0);
@@ -471,7 +471,7 @@ public class VarianceTests
source.Add(DateTime.UtcNow.Ticks + 1, 20);
source.Add(DateTime.UtcNow.Ticks + 2, 30);
var result = Variance.Calculate(source, 3); // Sample variance by default
var result = Variance.Batch(source, 3); // Sample variance by default
Assert.Equal(3, result.Count);
Assert.Equal(100.0, result.Last.Value, precision: 6); // Sample variance: 200/2 = 100
@@ -485,7 +485,7 @@ public class VarianceTests
source.Add(DateTime.UtcNow.Ticks + 1, 20);
source.Add(DateTime.UtcNow.Ticks + 2, 30);
var result = Variance.Calculate(source, 3, isPopulation: true);
var result = Variance.Batch(source, 3, isPopulation: true);
Assert.Equal(3, result.Count);
Assert.Equal(66.666666, result.Last.Value, precision: 5); // Population variance: 200/3 ≈ 66.67
+9 -2
View File
@@ -168,7 +168,7 @@ public sealed class Variance : AbstractBase
}
}
public static TSeries Calculate(TSeries source, int period, bool isPopulation = false)
public static TSeries Batch(TSeries source, int period, bool isPopulation = false)
{
var variance = new Variance(period, isPopulation);
return variance.Update(source);
@@ -229,6 +229,13 @@ public sealed class Variance : AbstractBase
CalculateScalarCore(source, output, period, isPopulation);
}
public static (TSeries Results, Variance Indicator) Calculate(TSeries source, int period, bool isPopulation = false)
{
var indicator = new Variance(period, isPopulation);
TSeries results = indicator.Update(source);
return (results, indicator);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CalculateScalarCore(ReadOnlySpan<double> source, Span<double> output, int period, bool isPopulation)
{
@@ -694,4 +701,4 @@ public sealed class Variance : AbstractBase
Unsafe.Add(ref outRef, i) = numerator * invDenom;
}
}
}
}