【问题标题】:Calculate Exponential Moving Average on a Queue in C#在 C# 中计算队列的指数移动平均线
【发布时间】:2011-12-09 18:28:02
【问题描述】:

我有一个简单的类来计算我添加到它的值的移动平均值。我是这样使用的:

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 属性,但我不确定如何完成计算。

【问题讨论】:

    标签: c# average


    【解决方案1】:

    使用 LINQ 怎么样:

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

    我要指出,对于实时财务数据,这是高度低效的。更好的方法是缓存以前的 EMA 值,并使用上述(恒定时间)重复公式在新报价上更新它。

    【讨论】:

    • alpha 未定义。你为此做了什么?
    • @Levitikon:见Exponential_moving_average。 “系数 α 代表权重降低的程度,是一个介于 0 和 1 之间的恒定平滑因子。更高的 α 会更快地折扣较旧的观测值。”
    【解决方案2】:

    指数移动平均线不需要排队,因为您只需要跟踪前一个 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;
        }
    }
    

    【讨论】:

    • 您不会将_lookback 字段用于任何用途。只在 ctor 中使用就足够了。
    【解决方案3】:

    这是@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;
    }
    

    【讨论】:

      【解决方案4】:

      我认为@Ani 的回答需要稍作调整。 初始值将设置为“alpha * nextQuote”,而不仅仅是“nextQuote”。 最简单的解决方法是设置初始种子值匹配第一条记录,然后第一次迭代变为 alpha * S1 + (1 - alpha) * S1:

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

      【讨论】:

        猜你喜欢
        • 2010-10-04
        • 2021-04-09
        • 1970-01-01
        • 2012-01-21
        • 2023-01-30
        • 2012-06-14
        • 1970-01-01
        • 2023-04-07
        相关资源
        最近更新 更多