Код: Выделить всё
public class ExponentialMovingAverage {
public Int32 Period { get; set; }
public ExponentialMovingAverage(Int32 period = 20) {
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(period);
Period = period;
}
public override IEnumerable Compute(IEnumerable inputs) {
ArgumentNullException.ThrowIfNull(inputs);
inputs = inputs.OrderBy(x => x.Stamp);
Decimal? previous = null;
Decimal factor = (Decimal)(2d / (Period + 1));
Decimal? sum = 0;
Int32 notNulls = 0;
for (Int32 index = 0; index < inputs.Count(); index++) {
(DateTimeOffset stamp, Decimal? value) = inputs.ElementAt(index);
if (value == null) {
notNulls++;
yield return (stamp, null);
continue;
}
if (index < notNulls + Period - 1) {
sum += value;
yield return (stamp, null);
continue;
}
if (index == notNulls + Period - 1) {
sum += value;
Decimal? sma = sum / Period;
previous = sma;
yield return (stamp, sma);
continue;
}
Decimal? ema = previous + (factor * (value - previous));
previous = ema;
yield return (stamp, ema);
}
}
}
Код: Выделить всё
[Fact]
public void Test_AllNonNullInputs() {
var ema = new ExponentialMovingAverage(3);
var inputs = new List {
(new DateTimeOffset(2024, 1, 1, 0, 0, 0, TimeSpan.Zero), 10),
(new DateTimeOffset(2024, 1, 2, 0, 0, 0, TimeSpan.Zero), 15),
(new DateTimeOffset(2024, 1, 3, 0, 0, 0, TimeSpan.Zero), 20),
(new DateTimeOffset(2024, 1, 4, 0, 0, 0, TimeSpan.Zero), 25),
(new DateTimeOffset(2024, 1, 5, 0, 0, 0, TimeSpan.Zero), 30),
(new DateTimeOffset(2024, 1, 6, 0, 0, 0, TimeSpan.Zero), 35)
};
var output = ema.Compute(inputs).ToList();
Assert.Equal(6, output.Count);
Assert.Null(output[0].ExponentialMovingAverage);
Assert.Null(output[1].ExponentialMovingAverage);
Assert.Equal(15m, output[2].ExponentialMovingAverage);
Assert.Equal(20m, output[3].ExponentialMovingAverage);
Assert.Equal(25m, output[4].ExponentialMovingAverage);
Assert.Equal(30m, output[5].ExponentialMovingAverage);
}
[Fact]
public void Test_FirstTwoInputsAreNull() {
var ema = new ExponentialMovingAverage(3);
var inputs = new List {
(new DateTimeOffset(2024, 1, 1, 0, 0, 0, TimeSpan.Zero), null),
(new DateTimeOffset(2024, 1, 2, 0, 0, 0, TimeSpan.Zero), null),
(new DateTimeOffset(2024, 1, 3, 0, 0, 0, TimeSpan.Zero), 20),
(new DateTimeOffset(2024, 1, 4, 0, 0, 0, TimeSpan.Zero), 25),
(new DateTimeOffset(2024, 1, 5, 0, 0, 0, TimeSpan.Zero), 30),
(new DateTimeOffset(2024, 1, 6, 0, 0, 0, TimeSpan.Zero), 35)
};
var output = ema.Compute(inputs).ToList();
Assert.Equal(6, output.Count);
Assert.Null(output[0].ExponentialMovingAverage);
Assert.Null(output[1].ExponentialMovingAverage);
Assert.Null(output[2].ExponentialMovingAverage);
Assert.Null(output[3].ExponentialMovingAverage);
Assert.Equal(25m, output[4].ExponentialMovingAverage);
Assert.Equal(30m, output[5].ExponentialMovingAverage);
}
Код: Выделить всё
var ema1 = new ExponentialMovingAverage(3);
var outputs1 = ema1.Compute(inputs);
var ema2 = new ExponentialMovingAverage(3);
var outputs2 = ema2.Compute(ema1);
Как я могу улучшить код, в том числе его производительность?
Подробнее здесь: https://stackoverflow.com/questions/784 ... st-foreach