feat: Introduce ITValuePublisher interface and refactor indicators for event-driven value updates.

This commit is contained in:
Miha Kralj
2025-12-07 14:36:22 -08:00
parent 3b146b68bd
commit 3734a1c5f6
16 changed files with 572 additions and 177 deletions
+13 -6
View File
@@ -22,7 +22,7 @@ namespace QuanTAlib;
/// Becomes true when the second EMA converges (approx. 2x EMA convergence time).
/// </remarks>
[SkipLocalsInit]
public sealed class Dema
public sealed class Dema : ITValuePublisher
{
private struct EmaState
{
@@ -45,8 +45,9 @@ public sealed class Dema
private double _lastValidValue;
public string Name { get; }
public TValue Value { get; private set; }
public TValue Last { get; private set; }
public bool IsHot => _state2.IsHot;
public event Action<TValue>? Pub;
public Dema(int period)
{
@@ -57,6 +58,11 @@ public sealed class Dema
Name = $"Dema({period})";
}
public Dema(ITValuePublisher source, int period) : this(period)
{
source.Pub += (item) => Update(item);
}
public Dema(double alpha)
{
if (alpha <= 0 || alpha > 1) throw new ArgumentException("Alpha must be between 0 and 1", nameof(alpha));
@@ -93,8 +99,9 @@ public sealed class Dema
double e2 = Compute(e1, _alpha, _decay, ref _state2);
double result = 2 * e1 - e2;
Value = new TValue(input.Time, result);
return Value;
Last = new TValue(input.Time, result);
Pub?.Invoke(Last);
return Last;
}
public TSeries Update(TSeries source)
@@ -141,7 +148,7 @@ public sealed class Dema
_p_state2 = s2;
_lastValidValue = lastValid;
Value = new TValue(tSpan[len - 1], vSpan[len - 1]);
Last = new TValue(tSpan[len - 1], vSpan[len - 1]);
return new TSeries(t, v);
}
@@ -281,6 +288,6 @@ public sealed class Dema
_p_state1 = EmaState.New();
_p_state2 = EmaState.New();
_lastValidValue = 0;
Value = default;
Last = default;
}
}