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
+49 -3
View File
@@ -162,7 +162,7 @@ public sealed class Alma : AbstractBase
Last = new TValue(input.Time, result);
if (publish)
{
PubEvent(Last);
PubEvent(Last, isNew);
}
return Last;
}
@@ -202,10 +202,56 @@ public sealed class Alma : AbstractBase
public override void Prime(ReadOnlySpan<double> source, TimeSpan? step = null)
{
foreach (var value in source)
if (source.Length == 0)
{
Update(new TValue(DateTime.MinValue, value));
return;
}
// Reset state
_buffer.Clear();
_state = default;
_p_state = default;
int warmupLength = Math.Min(source.Length, WarmupPeriod);
int startIndex = source.Length - warmupLength;
// Seed LastValidValue from history before warmup window
double lastValid = double.NaN;
for (int i = startIndex - 1; i >= 0; i--)
{
if (double.IsFinite(source[i]))
{
lastValid = source[i];
break;
}
}
// If not found, search in warmup window
if (double.IsNaN(lastValid))
{
for (int i = startIndex; i < source.Length; i++)
{
if (double.IsFinite(source[i]))
{
lastValid = source[i];
break;
}
}
}
// Initialize state with seeded LastValidValue
if (double.IsFinite(lastValid))
{
_state = new State(lastValid, IsInitialized: true);
}
// Feed the warmup data
for (int i = startIndex; i < source.Length; i++)
{
Update(new TValue(DateTime.MinValue, source[i]), isNew: true, publish: false);
}
_p_state = _state;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
+1 -1
View File
@@ -392,7 +392,7 @@ public sealed class Sgma : AbstractBase
}
else
{
val = 0.0;
val = double.NaN;
}
ring[ringIdx] = val;
+20
View File
@@ -31,6 +31,8 @@ public sealed class Sinema : AbstractBase
private readonly double _weightSum;
private readonly RingBuffer _buffer;
private readonly TValuePublishedHandler _handler;
private readonly ITValuePublisher? _source;
private bool _disposed;
[StructLayout(LayoutKind.Auto)]
private record struct State(double LastValidValue);
@@ -67,6 +69,7 @@ public sealed class Sinema : AbstractBase
public Sinema(ITValuePublisher source, int period) : this(period)
{
_source = source;
source.Pub += _handler;
}
@@ -77,6 +80,7 @@ public sealed class Sinema : AbstractBase
{
Last = new TValue(source.LastTime, Last.Value);
}
_source = source;
source.Pub += _handler;
}
@@ -443,4 +447,20 @@ public sealed class Sinema : AbstractBase
_p_state = default;
Last = default;
}
/// <summary>
/// Disposes the indicator and unsubscribes from the source.
/// </summary>
protected override void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing && _source != null)
{
_source.Pub -= _handler;
}
_disposed = true;
}
base.Dispose(disposing);
}
}
+20
View File
@@ -30,6 +30,8 @@ public sealed class Sma : AbstractBase
private readonly int _period;
private readonly RingBuffer _buffer;
private readonly TValuePublishedHandler _handler;
private readonly ITValuePublisher? _source;
private bool _disposed;
[StructLayout(LayoutKind.Auto)]
private record struct State(double Sum, double LastValidValue, int TickCount);
@@ -58,6 +60,7 @@ public sealed class Sma : AbstractBase
public Sma(ITValuePublisher source, int period) : this(period)
{
_source = source;
source.Pub += _handler;
}
@@ -68,6 +71,7 @@ public sealed class Sma : AbstractBase
{
Last = new TValue(source.LastTime, Last.Value);
}
_source = source;
source.Pub += _handler;
}
@@ -652,4 +656,20 @@ public sealed class Sma : AbstractBase
_p_state = default;
Last = default;
}
/// <summary>
/// Disposes the indicator and unsubscribes from the source.
/// </summary>
protected override void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing && _source != null)
{
_source.Pub -= _handler;
}
_disposed = true;
}
base.Dispose(disposing);
}
}