Рассчитать экспоненциальное скользящее среднее в очереди в C # - PullRequest
8 голосов
/ 09 декабря 2011

У меня есть простой класс для вычисления скользящего среднего значения, которое я добавляю к нему. Я использую это так:

MovingAverage ma = new MovingAverage();
ma.push(value1);
ma.push(value2);
... 
Console.Writeline(average.Average);

//the class
public class MovingAverage
{
    public int Period = 5;
    private Queue<double> Quotes = new Queue<double>();

    public void Push(double quote)
    {
        if (Quotes.Count == Period)
            Quotes.Dequeue();
        Quotes.Enqueue(quote);

    }
    public void Clear()
    {
        Quotes.Clear();
    }
    public double Average { get { if (Quotes.Count == 0) return 0; return Quotes.Average(); } }
    public double ExponentialMovingAverage
    {
        get
        {
            ???
        }
    }
}

Я хотел бы расширить этот класс, чтобы он также возвращал ExponentialMovingAverage. Как бы вы написали, чтобы вернуть экспоненциальное среднее из элементов в очереди в кавычках?

Я понимаю, что вам нужно будет добавить свойство Alpha к классу, но я не уверен, как завершить вычисления для вычисления.

Ответы [ 3 ]

14 голосов
/ 09 декабря 2011

Как насчет LINQ:

return Quotes.DefaultIfEmpty()
             .Aggregate((ema, nextQuote) => alpha * nextQuote + (1 - alpha) * ema);

Я хотел бы отметить, что для финансовых данных в режиме реального времени это очень неэффективно.Гораздо лучшим способом было бы кешировать предыдущее значение EMA и обновить его в новой цитате с приведенной выше формулой повторения (с постоянным временем).

4 голосов
/ 28 октября 2016

Не требуется очередь для экспоненциального скользящего среднего, потому что вам нужно только отслеживать предыдущую EMA.

public class ExponentialMovingAverageIndicator
{
    private bool _isInitialized;
    private readonly int _lookback;
    private readonly double _weightingMultiplier;
    private double _previousAverage;

    public double Average { get; private set; }
    public double Slope { get; private set; }

    public ExponentialMovingAverageIndicator(int lookback)
    {
        _lookback = lookback;
        _weightingMultiplier = 2.0/(lookback + 1);
    }

    public void AddDataPoint(double dataPoint)
    {
        if (!_isInitialized)
        {
            Average = dataPoint;
            Slope = 0;
            _previousAverage = Average;
            _isInitialized = true;
            return;
        }

        Average = ((dataPoint - _previousAverage)*_weightingMultiplier) + _previousAverage;
        Slope = Average - _previousAverage;

        //update previous average
        _previousAverage = Average;
    }
}
3 голосов
/ 19 мая 2017

Вот минимальная версия ответа @ MattWolf с немного другим API и использованием C # 7.

public sealed class FloatExponentialMovingAverageCalculator
{
    private readonly float _alpha;
    private float _lastAverage = float.NaN;

    public FloatExponentialMovingAverageCalculator(int lookBack) => _alpha = 2f / (lookBack + 1);

    public float NextValue(float value) => _lastAverage = float.IsNaN(_lastAverage)
        ? value
        : (value - _lastAverage)*_alpha + _lastAverage;
}
...