2011-12-09 16 views
8

Ho una classe semplice per calcolare la media mobile dei valori che aggiungo ad essa. Io lo uso come questo:Calcola media mobile esponenziale su una coda in 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 
     { 
      ??? 
     } 
    } 
} 

vorrei estendere questa classe per restituire anche l'ExponentialMovingAverage. Come scriveresti restituire la media esponenziale degli elementi in coda in virgolette?

Mi rendo conto che sarà necessario aggiungere una proprietà Alpha alla classe, ma non sono sicuro di come completare la matematica per il calcolo.

risposta

14

ne dite con LINQ:

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

vorrei sottolineare che per i dati finanziari in tempo reale, questo è altamente inefficiente. Un modo molto migliore sarebbe quello di memorizzare nella cache il valore EMA precedente e aggiornarlo su una nuova citazione con la formula di ricorrenza (a tempo costante) sopra riportata.

+0

alpha non è definito. Cosa hai impostato per questo? – Levitikon

+1

@Levitikon: vedere [Exponential_moving_average] (https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average). "Il coefficiente α rappresenta il grado di diminuzione della ponderazione, un fattore di livellamento costante compreso tra 0 e 1. A α più elevato sconta più velocemente le osservazioni più vecchie." – Ani

2

Non c'è bisogno di una coda per una media mobile esponenziale perché è sufficiente tenere traccia del precedente 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; 
    } 
} 
+0

Non si usa il campo '_lookback' per nulla. Basterebbe usarlo solo nel ctor. –

3

Ecco una versione minimale di @ risposta di MattWolf con un API leggermente diversa, e l'utilizzo di 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; 
} 
Problemi correlati