mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-26 06:18:05 +00:00
v0.8.7: Replace periodic ResyncInterval with Kahan compensated summation
Comprehensive refactor across all indicators replacing the periodic ResyncInterval-based drift correction (every 1000 ticks recalculate from scratch) with Kahan compensated summation for running sums. Key changes: - Remove ResyncInterval constants and TickCount fields from all State records - Add Kahan compensation fields (SumComp, SumSqComp, etc.) to State records - Replace naive sum += val - removed with Kahan delta pattern - Remove Resync()/RecalculateSum() methods that did O(N) recalculation - Update batch/SIMD paths to use Kahan compensation instead of resync loops - IIR filters (EMA, REMA, RGMA) simplified: inherently self-correcting - Version bump to 0.8.7 - Build system: README version stamping via Directory.Build.props - Minor doc/test tolerance adjustments for new numerical characteristics Affected modules: channels, core, cycles, dynamics, errors, momentum, oscillators, statistics, trends_FIR, trends_IIR, volatility, volume
This commit is contained in:
+15
-31
@@ -31,17 +31,15 @@ public sealed class Vhf : AbstractBase
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
private record struct State(
|
||||
double DiffSum,
|
||||
double DiffSumComp,
|
||||
double PrevClose,
|
||||
double LastValidValue,
|
||||
int TickCount,
|
||||
bool HasPrevClose
|
||||
);
|
||||
|
||||
private State _s;
|
||||
private State _ps;
|
||||
|
||||
private const int ResyncInterval = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Creates VHF with specified lookback period.
|
||||
/// </summary>
|
||||
@@ -58,7 +56,7 @@ public sealed class Vhf : AbstractBase
|
||||
_diffBuffer = new RingBuffer(period); // period absolute differences
|
||||
Name = $"Vhf({period})";
|
||||
WarmupPeriod = period + 1;
|
||||
_s = new State(0, 0, 0, 0, false);
|
||||
_s = default;
|
||||
_ps = _s;
|
||||
}
|
||||
|
||||
@@ -116,11 +114,14 @@ public sealed class Vhf : AbstractBase
|
||||
absDiff = Math.Abs(val - s.PrevClose);
|
||||
}
|
||||
|
||||
// Update diff buffer running sum
|
||||
// Update diff buffer running sum — Kahan compensated
|
||||
if (s.HasPrevClose)
|
||||
{
|
||||
double diffRemoved = _diffBuffer.Count == _diffBuffer.Capacity ? _diffBuffer.Oldest : 0.0;
|
||||
s.DiffSum = s.DiffSum - diffRemoved + absDiff;
|
||||
double delta = absDiff - diffRemoved - s.DiffSumComp;
|
||||
double newSum = s.DiffSum + delta;
|
||||
s.DiffSumComp = (newSum - s.DiffSum) - delta;
|
||||
s.DiffSum = newSum;
|
||||
_diffBuffer.Add(absDiff);
|
||||
}
|
||||
|
||||
@@ -129,14 +130,6 @@ public sealed class Vhf : AbstractBase
|
||||
|
||||
s.PrevClose = val;
|
||||
s.HasPrevClose = true;
|
||||
|
||||
// Resync to prevent floating-point drift
|
||||
s.TickCount++;
|
||||
if (_diffBuffer.IsFull && s.TickCount >= ResyncInterval)
|
||||
{
|
||||
s.TickCount = 0;
|
||||
s.DiffSum = _diffBuffer.RecalculateSum();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -151,6 +144,7 @@ public sealed class Vhf : AbstractBase
|
||||
double newAbsDiff = Math.Abs(val - prevCloseForDiff);
|
||||
_diffBuffer.UpdateNewest(newAbsDiff);
|
||||
s.DiffSum = _diffBuffer.Sum;
|
||||
s.DiffSumComp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,6 +321,7 @@ public sealed class Vhf : AbstractBase
|
||||
try
|
||||
{
|
||||
double diffSum = 0;
|
||||
double diffSumComp = 0;
|
||||
double lastValid = 0;
|
||||
double prevClose = 0;
|
||||
bool hasPrevClose = false;
|
||||
@@ -334,7 +329,6 @@ public sealed class Vhf : AbstractBase
|
||||
int closeFilled = 0;
|
||||
int diffIdx = 0;
|
||||
int diffFilled = 0;
|
||||
int tickCount = 0;
|
||||
|
||||
// Find first valid value to seed lastValid
|
||||
for (int k = 0; k < len; k++)
|
||||
@@ -363,12 +357,14 @@ public sealed class Vhf : AbstractBase
|
||||
{
|
||||
double absDiff = Math.Abs(val - prevClose);
|
||||
|
||||
// Update diff buffer
|
||||
if (diffFilled >= period)
|
||||
// Kahan-compensated update for diff buffer
|
||||
{
|
||||
diffSum -= diffBuf[diffIdx];
|
||||
double deltaD = absDiff - (diffFilled >= period ? diffBuf[diffIdx] : 0);
|
||||
double yD = deltaD - diffSumComp;
|
||||
double tD = diffSum + yD;
|
||||
diffSumComp = (tD - diffSum) - yD;
|
||||
diffSum = tD;
|
||||
}
|
||||
diffSum += absDiff;
|
||||
diffBuf[diffIdx] = absDiff;
|
||||
if (diffFilled < period)
|
||||
{
|
||||
@@ -396,18 +392,6 @@ public sealed class Vhf : AbstractBase
|
||||
prevClose = val;
|
||||
hasPrevClose = true;
|
||||
|
||||
// Resync diff sum
|
||||
tickCount++;
|
||||
if (diffFilled >= period && tickCount >= ResyncInterval)
|
||||
{
|
||||
tickCount = 0;
|
||||
double recalc = 0;
|
||||
for (int k = 0; k < period; k++)
|
||||
{
|
||||
recalc += diffBuf[k];
|
||||
}
|
||||
diffSum = recalc;
|
||||
}
|
||||
|
||||
// Calculate VHF
|
||||
if (closeFilled >= closeBufSize && diffFilled >= period)
|
||||
|
||||
Reference in New Issue
Block a user