mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-17 18:18:04 +00:00
feat(statistics): add Variance indicator with O(1) calculation and usage example
This commit is contained in:
@@ -28,7 +28,7 @@ public sealed class Bilateral : AbstractBase
|
||||
private readonly RingBuffer _buffer;
|
||||
private readonly double[] _spatialWeights;
|
||||
|
||||
private record struct State(double SumSq, double LastInput, double LastValidValue);
|
||||
private record struct State(double SumSq, double LastValidValue);
|
||||
private State _state;
|
||||
private State _p_state;
|
||||
|
||||
@@ -104,11 +104,12 @@ public sealed class Bilateral : AbstractBase
|
||||
{
|
||||
_state.SumSq -= (removed * removed);
|
||||
}
|
||||
_state.LastInput = val;
|
||||
}
|
||||
|
||||
double result = CalculateBilateral();
|
||||
Last = new TValue(DateTime.MinValue, result);
|
||||
// Use DateTime.UtcNow as Prime(ReadOnlySpan<double>) does not provide timestamps.
|
||||
// This represents an initial/primed reading rather than a real source timestamp.
|
||||
Last = new TValue(DateTime.UtcNow, result);
|
||||
_p_state = _state;
|
||||
}
|
||||
|
||||
@@ -151,7 +152,6 @@ public sealed class Bilateral : AbstractBase
|
||||
{
|
||||
_state.SumSq -= (removed * removed);
|
||||
}
|
||||
_state.LastInput = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+19
-3
@@ -87,7 +87,10 @@ public sealed class Blma : AbstractBase
|
||||
else
|
||||
{
|
||||
// Full period, use pre-calculated weights
|
||||
result = CalculateWeightedSum(_buffer, _weights) / _weightSum;
|
||||
// Fallback for cases where weights sum to zero (e.g. N=2)
|
||||
result = Math.Abs(_weightSum) < double.Epsilon
|
||||
? _buffer.Average()
|
||||
: CalculateWeightedSum(_buffer, _weights) / _weightSum;
|
||||
}
|
||||
|
||||
var tValue = new TValue(input.Time, result);
|
||||
@@ -223,8 +226,21 @@ public sealed class Blma : AbstractBase
|
||||
else
|
||||
{
|
||||
// Full period
|
||||
double sum = source.Slice(i - period + 1, period).DotProduct(weights);
|
||||
destination[i] = sum / weightSum;
|
||||
if (Math.Abs(weightSum) < double.Epsilon)
|
||||
{
|
||||
// Fallback for zero sum weights (e.g. N=2)
|
||||
double sum = 0;
|
||||
for (int j = 0; j < period; j++)
|
||||
{
|
||||
sum += source[i - period + 1 + j];
|
||||
}
|
||||
destination[i] = sum / period;
|
||||
}
|
||||
else
|
||||
{
|
||||
double sum = source.Slice(i - period + 1, period).DotProduct(weights);
|
||||
destination[i] = sum / weightSum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +86,6 @@ public sealed class Butter : AbstractBase
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override TValue Update(TValue input, bool isNew = true)
|
||||
{
|
||||
if (double.IsNaN(input.Value) || double.IsInfinity(input.Value))
|
||||
{
|
||||
return Last;
|
||||
}
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
_p_state = _state;
|
||||
@@ -100,6 +95,11 @@ public sealed class Butter : AbstractBase
|
||||
_state = _p_state;
|
||||
}
|
||||
|
||||
if (double.IsNaN(input.Value) || double.IsInfinity(input.Value))
|
||||
{
|
||||
return Last;
|
||||
}
|
||||
|
||||
double x = input.Value;
|
||||
double y = _state.Count < 2
|
||||
? x
|
||||
@@ -181,6 +181,11 @@ public sealed class Butter : AbstractBase
|
||||
for (int i = 0; i < source.Length; i++)
|
||||
{
|
||||
double x = source[i];
|
||||
if (double.IsNaN(x) || double.IsInfinity(x))
|
||||
{
|
||||
destination[i] = i > 0 ? destination[i - 1] : 0;
|
||||
continue;
|
||||
}
|
||||
double y = i < 2
|
||||
? x
|
||||
: (b0 * x + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2) * invA0;
|
||||
|
||||
@@ -240,7 +240,11 @@ public sealed class Ema : AbstractBase
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static double Compute(double input, double alpha, double decay, ref State state)
|
||||
{
|
||||
state.Ema += alpha * (input - state.Ema);
|
||||
// state.Ema += alpha * (input - state.Ema)
|
||||
// state.Ema = state.Ema + alpha * input - alpha * state.Ema
|
||||
// state.Ema = state.Ema * (1 - alpha) + alpha * input
|
||||
// state.Ema = state.Ema * decay + alpha * input
|
||||
state.Ema = Math.FusedMultiplyAdd(state.Ema, decay, alpha * input);
|
||||
|
||||
double result;
|
||||
if (!state.IsCompensated)
|
||||
@@ -285,7 +289,8 @@ public sealed class Ema : AbstractBase
|
||||
else
|
||||
val = lastValidValue;
|
||||
|
||||
state.Ema += alpha * (val - state.Ema);
|
||||
|
||||
state.Ema = Math.FusedMultiplyAdd(state.Ema, decay, alpha * val);
|
||||
state.E *= decay;
|
||||
|
||||
if (!state.IsHot && state.E <= COVERAGE_THRESHOLD)
|
||||
@@ -305,7 +310,8 @@ public sealed class Ema : AbstractBase
|
||||
else
|
||||
val = lastValidValue;
|
||||
|
||||
state.Ema += alpha * (val - state.Ema);
|
||||
// state.Ema += alpha * (val - state.Ema); // skipcq: S125
|
||||
state.Ema = Math.FusedMultiplyAdd(state.Ema, decay, alpha * val);
|
||||
output[i] = state.Ema;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +164,8 @@ public sealed class Kama : AbstractBase
|
||||
// Cap ER at 1.0 just in case floating point errors push it slightly over
|
||||
if (er > 1.0) er = 1.0;
|
||||
|
||||
double sc = er * (_fastAlpha - _slowAlpha) + _slowAlpha;
|
||||
// double sc = er * (_fastAlpha - _slowAlpha) + _slowAlpha; // skipcq: S125
|
||||
double sc = Math.FusedMultiplyAdd(er, _fastAlpha - _slowAlpha, _slowAlpha);
|
||||
sc *= sc;
|
||||
|
||||
double prevKama = _p_state.Kama;
|
||||
@@ -173,7 +174,8 @@ public sealed class Kama : AbstractBase
|
||||
prevKama = _state.Kama;
|
||||
}
|
||||
|
||||
_state.Kama = prevKama + sc * (val - prevKama);
|
||||
// _state.Kama = prevKama + sc * (val - prevKama); // skipcq: S125
|
||||
_state.Kama = Math.FusedMultiplyAdd(sc, val - prevKama, prevKama);
|
||||
}
|
||||
|
||||
Last = new TValue(input.Time, _state.Kama);
|
||||
@@ -314,10 +316,12 @@ public sealed class Kama : AbstractBase
|
||||
double er = (volatilitySum > 1e-10) ? change / volatilitySum : 0.0;
|
||||
if (er > 1.0) er = 1.0;
|
||||
|
||||
double sc = er * (fastAlpha - slowAlpha) + slowAlpha;
|
||||
// double sc = er * (fastAlpha - slowAlpha) + slowAlpha; // skipcq: S125
|
||||
double sc = Math.FusedMultiplyAdd(er, fastAlpha - slowAlpha, slowAlpha);
|
||||
sc *= sc;
|
||||
|
||||
kama += sc * (val - kama);
|
||||
// kama += sc * (val - kama); // skipcq: S125
|
||||
kama = Math.FusedMultiplyAdd(sc, val - kama, kama);
|
||||
output[i] = kama;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
description: Configuration for AI behavior when interacting with Codacy's MCP Server
|
||||
applyTo: '**'
|
||||
description: Configuration for AI behavior when interacting with Codacy's MCP Server
|
||||
applyTo: '**'
|
||||
---
|
||||
---
|
||||
# Codacy Rules
|
||||
|
||||
+14
-14
@@ -97,7 +97,7 @@ public sealed class Lsma : AbstractBase
|
||||
|
||||
// O(1) update for sum_xy
|
||||
// sum_xy_new = sum_xy_old + sum_y_prev - n * oldest
|
||||
_state.SumXY = _state.SumXY + prev_sum_y - _period * oldest;
|
||||
_state.SumXY = Math.FusedMultiplyAdd(-_period, oldest, _state.SumXY + prev_sum_y);
|
||||
|
||||
// O(1) update for sum_y
|
||||
_state.SumY = _state.SumY - oldest + val;
|
||||
@@ -119,7 +119,7 @@ public sealed class Lsma : AbstractBase
|
||||
// index j in buffer corresponds to x = count - 1 - j
|
||||
// sum_xy = sum(x * y)
|
||||
int x = span.Length - 1 - i;
|
||||
_state.SumXY += x * span[i];
|
||||
_state.SumXY = Math.FusedMultiplyAdd(x, span[i], _state.SumXY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ public sealed class Lsma : AbstractBase
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
int x = span.Length - 1 - i;
|
||||
_state.SumXY += x * span[i];
|
||||
_state.SumXY = Math.FusedMultiplyAdd(x, span[i], _state.SumXY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,11 +197,11 @@ public sealed class Lsma : AbstractBase
|
||||
}
|
||||
else
|
||||
{
|
||||
double m = (n * _state.SumXY - sx * _state.SumY) / denom;
|
||||
double b = (_state.SumY - m * sx) / n;
|
||||
double m = Math.FusedMultiplyAdd(n, _state.SumXY, -sx * _state.SumY) / denom;
|
||||
double b = Math.FusedMultiplyAdd(-m, sx, _state.SumY) / n;
|
||||
|
||||
// LSMA = b - m * offset
|
||||
result = b - m * _offset;
|
||||
result = Math.FusedMultiplyAdd(-m, _offset, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ public sealed class Lsma : AbstractBase
|
||||
{
|
||||
// buffer[j] is at index j
|
||||
// x = count - 1 - j
|
||||
sum_xy += (count - 1 - j) * buffer[j];
|
||||
sum_xy = Math.FusedMultiplyAdd(count - 1 - j, buffer[j], sum_xy);
|
||||
}
|
||||
|
||||
if (count <= 1)
|
||||
@@ -355,9 +355,9 @@ public sealed class Lsma : AbstractBase
|
||||
}
|
||||
else
|
||||
{
|
||||
double m = (n * sum_xy - sx * sum_y) / denom;
|
||||
double b = (sum_y - m * sx) / n;
|
||||
output[i] = b - m * offset;
|
||||
double m = Math.FusedMultiplyAdd(n, sum_xy, -sx * sum_y) / denom;
|
||||
double b = Math.FusedMultiplyAdd(-m, sx, sum_y) / n;
|
||||
output[i] = Math.FusedMultiplyAdd(-m, offset, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ public sealed class Lsma : AbstractBase
|
||||
double prev_sum_y = sum_y;
|
||||
|
||||
// sum_xy_new = sum_xy_old + sum_y_prev - n * oldest
|
||||
sum_xy = sum_xy + prev_sum_y - period * oldest;
|
||||
sum_xy = Math.FusedMultiplyAdd(-period, oldest, sum_xy + prev_sum_y);
|
||||
|
||||
sum_y = sum_y - oldest + val;
|
||||
buffer[bufferIndex] = val;
|
||||
@@ -382,9 +382,9 @@ public sealed class Lsma : AbstractBase
|
||||
if (bufferIndex >= period)
|
||||
bufferIndex = 0;
|
||||
|
||||
double m = (period * sum_xy - full_sum_x * sum_y) / full_denom;
|
||||
double b = (sum_y - m * full_sum_x) / period;
|
||||
output[i] = b - m * offset;
|
||||
double m = Math.FusedMultiplyAdd(period, sum_xy, -full_sum_x * sum_y) / full_denom;
|
||||
double b = Math.FusedMultiplyAdd(-m, full_sum_x, sum_y) / period;
|
||||
output[i] = Math.FusedMultiplyAdd(-m, offset, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-14
@@ -80,15 +80,15 @@ public sealed class Pwma : AbstractBase
|
||||
double oldest = _buffer.Oldest;
|
||||
|
||||
_state.Sum = _state.Sum - oldest + val;
|
||||
_state.WSum = _state.WSum - oldSum + (_period * val);
|
||||
_state.PSum = _state.PSum - 2 * oldWSum + oldSum + ((double)_period * _period * val);
|
||||
_state.WSum = Math.FusedMultiplyAdd(_period, val, _state.WSum - oldSum);
|
||||
_state.PSum = Math.FusedMultiplyAdd((double)_period * _period, val, _state.PSum - 2 * oldWSum + oldSum);
|
||||
}
|
||||
else
|
||||
{
|
||||
int count = _buffer.Count + 1;
|
||||
_state.Sum += val;
|
||||
_state.WSum += count * val;
|
||||
_state.PSum += (double)count * count * val;
|
||||
_state.WSum = Math.FusedMultiplyAdd(count, val, _state.WSum);
|
||||
_state.PSum = Math.FusedMultiplyAdd((double)count * count, val, _state.PSum);
|
||||
}
|
||||
|
||||
_buffer.Add(val);
|
||||
@@ -104,8 +104,8 @@ public sealed class Pwma : AbstractBase
|
||||
foreach (double item in _buffer)
|
||||
{
|
||||
recalcSum += item;
|
||||
recalcWsum += i * item;
|
||||
recalcPsum += (double)i * i * item;
|
||||
recalcWsum = Math.FusedMultiplyAdd(i, item, recalcWsum);
|
||||
recalcPsum = Math.FusedMultiplyAdd((double)i * i, item, recalcPsum);
|
||||
i++;
|
||||
}
|
||||
_state.Sum = recalcSum;
|
||||
@@ -143,8 +143,8 @@ public sealed class Pwma : AbstractBase
|
||||
double diff = val - _state.LastInput;
|
||||
|
||||
_state.Sum += diff;
|
||||
_state.WSum += n * diff;
|
||||
_state.PSum += (double)n * n * diff;
|
||||
_state.WSum = Math.FusedMultiplyAdd(n, diff, _state.WSum);
|
||||
_state.PSum = Math.FusedMultiplyAdd((double)n * n, diff, _state.PSum);
|
||||
|
||||
_buffer.UpdateNewest(val);
|
||||
}
|
||||
@@ -264,8 +264,8 @@ public sealed class Pwma : AbstractBase
|
||||
val = lastValid;
|
||||
|
||||
sum += val;
|
||||
wsum += (i + 1) * val;
|
||||
psum += (double)(i + 1) * (i + 1) * val;
|
||||
wsum = Math.FusedMultiplyAdd(i + 1, val, wsum);
|
||||
psum = Math.FusedMultiplyAdd((double)(i + 1) * (i + 1), val, psum);
|
||||
buffer[i] = val;
|
||||
|
||||
double currentDivisor = (double)(i + 1) * (i + 2) * (2 * (i + 1) + 1) / 6.0;
|
||||
@@ -286,8 +286,8 @@ public sealed class Pwma : AbstractBase
|
||||
double oldest = buffer[bufferIdx];
|
||||
|
||||
sum = sum - oldest + val;
|
||||
wsum = wsum - oldSum + (period * val);
|
||||
psum = psum - 2 * oldWSum + oldSum + ((double)period * period * val);
|
||||
wsum = Math.FusedMultiplyAdd(period, val, wsum - oldSum);
|
||||
psum = Math.FusedMultiplyAdd((double)period * period, val, psum - 2 * oldWSum + oldSum);
|
||||
|
||||
buffer[bufferIdx] = val;
|
||||
bufferIdx++;
|
||||
@@ -309,8 +309,8 @@ public sealed class Pwma : AbstractBase
|
||||
|
||||
double v = buffer[idx];
|
||||
recalcSum += v;
|
||||
recalcWsum += (k + 1) * v;
|
||||
recalcPsum += (double)(k + 1) * (k + 1) * v;
|
||||
recalcWsum = Math.FusedMultiplyAdd(k + 1, v, recalcWsum);
|
||||
recalcPsum = Math.FusedMultiplyAdd((double)(k + 1) * (k + 1), v, recalcPsum);
|
||||
}
|
||||
sum = recalcSum;
|
||||
wsum = recalcWsum;
|
||||
|
||||
Reference in New Issue
Block a user