2011-12-09 38 views
8

Tôi có một lớp đơn giản để tính giá trị trung bình di chuyển của các giá trị mà tôi thêm vào. Tôi sử dụng nó như sau:Tính trung bình di chuyển theo hàm mũ trên một hàng đợi trong C#

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 
     { 
      ??? 
     } 
    } 
} 

Tôi muốn mở rộng lớp này cũng trả lại ExponentialMovingAverage. Làm thế nào bạn có thể viết trả về giá trị trung bình theo hàm mũ của các mục được xếp hàng trong báo giá?

Tôi nhận ra rằng bạn sẽ cần thêm thuộc tính Alpha vào lớp nhưng tôi không chắc chắn cách hoàn thành phép tính cho phép tính.

Trả lời

14

Làm thế nào về với LINQ:

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

tôi sẽ chỉ ra rằng đối với dữ liệu tài chính theo thời gian thực, đây là cao không hiệu quả. Một cách tốt hơn là nhớ cache giá trị EMA trước đó và cập nhật nó trên một báo giá mới với công thức lặp lại (hằng số) ở trên.

+0

alpha là undefined. Bạn đã làm gì cho điều đó? – Levitikon

+1

@Levitikon: Xem [Exponential_moving_average] (https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average). "Hệ số α đại diện cho mức độ giảm trọng số, một yếu tố làm trơn không đổi giữa 0 và 1. Một α cao hơn giảm giá các quan sát cũ hơn nhanh hơn." – Ani

2

Không cần hàng đợi cho Số trung bình di chuyển theo hàm mũ vì bạn chỉ cần theo dõi EMA trước đó.

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; 
    } 
} 
+0

Bạn không sử dụng trường '_lookback' cho bất kỳ thứ gì. Nó đủ để sử dụng nó chỉ trong ctor. –

3

Dưới đây là một phiên bản tối thiểu của @ câu trả lời MattWolf với một API hơi khác nhau, và sử dụng 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; 
} 
Các vấn đề liên quan