refactoring

This commit is contained in:
Miha Kralj
2025-12-16 21:16:50 -08:00
parent a67ad65fa5
commit d277e08056
137 changed files with 5074 additions and 3178 deletions
+1 -1
View File
@@ -116,7 +116,7 @@ public class DemaIndicatorTests
{
var indicator = new DemaIndicator();
indicator.Initialize();
// We can't easily mock PaintChartEventArgs fully, but we can verify the method exists and is callable
// if we could mock the args. Since we can't, we skip the actual call but verify the method is overridden.
var method = indicator.GetType().GetMethod("OnPaintChart");
+3 -3
View File
@@ -46,7 +46,7 @@ public class DemaTests
}
// Act
var demaSeries = Dema.Calculate(source, period);
var demaSeries = Dema.Batch(source, period);
var demaObj = new Dema(period);
// Assert
@@ -123,7 +123,7 @@ public class DemaTests
}
// Act
var demaSeries = Dema.Calculate(source, alpha);
var demaSeries = Dema.Batch(source, alpha);
var demaObj = new Dema(alpha);
// Assert
@@ -271,7 +271,7 @@ public class DemaTests
var series = bars.Close;
// 1. Batch Mode
var batchSeries = Dema.Calculate(series, period);
var batchSeries = Dema.Batch(series, period);
double expected = batchSeries.Last.Value;
// 2. Span Mode
+20 -14
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 : ITValuePublisher
public sealed class Dema : AbstractBase
{
private record struct EmaState(double Ema, double E, bool IsHot, bool IsCompensated)
{
@@ -31,19 +31,16 @@ public sealed class Dema : ITValuePublisher
private readonly double _alpha;
private readonly double _decay;
private EmaState _state1 = EmaState.New();
private EmaState _state2 = EmaState.New();
private EmaState _p_state1 = EmaState.New();
private EmaState _p_state2 = EmaState.New();
private double _lastValidValue;
private double _p_lastValidValue;
public string Name { get; }
public TValue Last { get; private set; }
public bool IsHot => _state2.IsHot;
public event Action<TValue>? Pub;
public override bool IsHot => _state2.IsHot;
public Dema(int period)
{
@@ -52,6 +49,7 @@ public sealed class Dema : ITValuePublisher
_alpha = 2.0 / (period + 1);
_decay = 1.0 - _alpha;
Name = $"Dema({period})";
WarmupPeriod = period;
}
public Dema(ITValuePublisher source, int period) : this(period)
@@ -69,7 +67,7 @@ public sealed class Dema : ITValuePublisher
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TValue Update(TValue input, bool isNew = true)
public override TValue Update(TValue input, bool isNew = true)
{
if (isNew)
{
@@ -98,11 +96,11 @@ public sealed class Dema : ITValuePublisher
double result = 2 * e1 - e2;
Last = new TValue(input.Time, result);
Pub?.Invoke(Last);
PubEvent(Last);
return Last;
}
public TSeries Update(TSeries source)
public override TSeries Update(TSeries source)
{
if (source.Count == 0) return [];
@@ -117,7 +115,7 @@ public sealed class Dema : ITValuePublisher
source.Times.CopyTo(tSpan);
var sourceValues = source.Values;
// Use current state
EmaState s1 = _state1;
EmaState s2 = _state2;
@@ -151,6 +149,14 @@ public sealed class Dema : ITValuePublisher
return new TSeries(t, v);
}
public override void Prime(ReadOnlySpan<double> source)
{
foreach (var value in source)
{
Update(new TValue(DateTime.MinValue, value));
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double Compute(double input, double alpha, double decay, ref EmaState state)
{
@@ -182,13 +188,13 @@ public sealed class Dema : ITValuePublisher
return result;
}
public static TSeries Calculate(TSeries source, int period)
public static TSeries Batch(TSeries source, int period)
{
var dema = new Dema(period);
return dema.Update(source);
}
public static TSeries Calculate(TSeries source, double alpha)
public static TSeries Batch(TSeries source, double alpha)
{
var dema = new Dema(alpha);
return dema.Update(source);
@@ -280,7 +286,7 @@ public sealed class Dema : ITValuePublisher
}
}
public void Reset()
public override void Reset()
{
_state1 = EmaState.New();
_state2 = EmaState.New();
+3 -3
View File
@@ -62,12 +62,12 @@ Console.WriteLine($"Current DEMA: {result.Value}");
// Batch calculation (TSeries API)
TSeries source = ...;
TSeries results = Dema.Calculate(source, 14);
TSeries results = Dema.Batch(source, 14);
// High-performance Span API (zero allocation)
double[] prices = new double[10000];
double[] output = new double[10000];
Dema.Calculate(prices.AsSpan(), output.AsSpan(), period: 14);
Dema.Batch(prices.AsSpan(), output.AsSpan(), period: 14);
```
### Zero-Allocation Span API
@@ -80,7 +80,7 @@ double[] source = new double[200000];
double[] demaOutput = new double[200000];
// Zero heap allocation during calculation
Dema.Calculate(source.AsSpan(), demaOutput.AsSpan(), period: 50);
Dema.Batch(source.AsSpan(), demaOutput.AsSpan(), period: 50);
```
### Eventing and Reactive Support