volume indicators

This commit is contained in:
Miha Kralj
2026-01-30 12:47:25 -08:00
parent 76d2b50cbb
commit 7b3a6520d2
99 changed files with 9539 additions and 283 deletions
+34 -5
View File
@@ -24,7 +24,7 @@ public enum MaenvType
/// Lower = Middle - (Middle × percentage / 100)
/// </summary>
[SkipLocalsInit]
public sealed class Maenv : ITValuePublisher
public sealed class Maenv : ITValuePublisher, IDisposable
{
private readonly int _period;
private readonly double _percentage;
@@ -60,6 +60,10 @@ public sealed class Maenv : ITValuePublisher
private readonly TValuePublishedHandler _valueHandler;
// Subscription tracking for IDisposable
private TSeries? _source;
private bool _disposed;
public string Name { get; }
public int WarmupPeriod { get; }
public TValue Last { get; private set; }
@@ -108,10 +112,30 @@ public sealed class Maenv : ITValuePublisher
public Maenv(TSeries source, int period = 20, double percentage = 1.0, MaenvType maType = MaenvType.EMA) : this(period, percentage, maType)
{
_source = source;
Prime(source);
source.Pub += _valueHandler;
}
/// <summary>
/// Releases the event subscription to the source publisher.
/// </summary>
public void Dispose()
{
if (_disposed)
{
return;
}
if (_source != null)
{
_source.Pub -= _valueHandler;
_source = null;
}
_disposed = true;
}
private void HandleValue(object? sender, in TValueEventArgs e) => Update(e.Value, e.IsNew);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -249,15 +273,20 @@ public sealed class Maenv : ITValuePublisher
var vUpperSpan = CollectionsMarshal.AsSpan(vUpper);
var vLowerSpan = CollectionsMarshal.AsSpan(vLower);
Batch(source.Values, vMiddleSpan, vUpperSpan, vLowerSpan, _period, _percentage, _maType);
// Process through streaming path to compute results and prime state in one pass
Reset();
for (int i = 0; i < len; i++)
{
Update(source[i], isNew: true);
vMiddleSpan[i] = Last.Value;
vUpperSpan[i] = Upper.Value;
vLowerSpan[i] = Lower.Value;
}
source.Times.CopyTo(tSpan);
tSpan.CopyTo(CollectionsMarshal.AsSpan(tUpper));
tSpan.CopyTo(CollectionsMarshal.AsSpan(tLower));
// Prime internal state for continued streaming
Prime(source);
var lastTime = new DateTime(source.Times[^1], DateTimeKind.Utc);
Last = new TValue(lastTime, vMiddleSpan[^1]);
Upper = new TValue(lastTime, vUpperSpan[^1]);