Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to calculate simple moving average faster in C#?

Tags:

What is the fastest library/algorithm for calculating simple moving average? I wrote my own, but it takes too long on 330 000 items decimal dataset.

  • period / time(ms)
  • 20 / 300;
  • 60 / 1500;
  • 120 / 3500.

Here is the code of my method:

public decimal MA_Simple(int period, int ii) {
    if (period != 0 && ii > period) {
        //stp.Start();
        decimal summ = 0;
        for (int i = ii; i > ii - period; i--) {
            summ = summ + Data.Close[i];
        }
        summ = summ / period;
        //stp.Stop();
        //if (ii == 1500) System.Windows.Forms.MessageBox.Show((stp.ElapsedTicks * 1000.0) / Stopwatch.Frequency + " ms");
        return summ;
    } else return -1;
}

The Data.Close[] is a fixed size(1 000 000) decimal array.

like image 650
zozed Avatar asked Oct 14 '12 17:10

zozed


People also ask

How do you calculate simple moving average?

A simple moving average (SMA) is an arithmetic moving average calculated by adding recent prices and then dividing that figure by the number of time periods in the calculation average.

How do you calculate a 5 point simple moving average?

A simple moving average is formed by computing the average price of a security over a specific number of periods. Most moving averages are based on closing prices; for example, a 5-day simple moving average is the five-day sum of closing prices divided by five.

How do you calculate 20-day moving average?

For a 20-day moving average, the multiplier would be [2/(20+1)]= 0.0952. The smoothing factor is combined with the previous EMA to arrive at the current value. The EMA thus gives a higher weighting to recent prices, while the SMA assigns an equal weighting to all values.


2 Answers

    public class MovingAverage  
    {
        private Queue<Decimal> samples = new Queue<Decimal>();
        private int windowSize = 16;
        private Decimal sampleAccumulator;
        public Decimal Average { get; private set; }

        /// <summary>
        /// Computes a new windowed average each time a new sample arrives
        /// </summary>
        /// <param name="newSample"></param>
        public void ComputeAverage(Decimal newSample)
        {
            sampleAccumulator += newSample;
            samples.Enqueue(newSample);

            if (samples.Count > windowSize)
            {
                sampleAccumulator -= samples.Dequeue();
            }

            Average = sampleAccumulator / samples.Count;
        }
    }
like image 73
J.L. Haynes Avatar answered Sep 18 '22 14:09

J.L. Haynes


Your main problem is that you throw away too much information for each iteration. If you want to run this fast, you need to keep a buffer of the same size as the frame length.

This code will run moving averages for your whole dataset:

(Not real C# but you should get the idea)

decimal buffer[] = new decimal[period];
decimal output[] = new decimal[data.Length];
current_index = 0;
for (int i=0; i<data.Length; i++)
    {
        buffer[current_index] = data[i]/period;
        decimal ma = 0.0;
        for (int j=0;j<period;j++)
            {
                ma += buffer[j];
            }
        output[i] = ma;
        current_index = (current_index + 1) % period;
    }
return output;

Please note that it may be tempting to keep a running cumsum instead of keeping the whole buffer and calculating the value for each iteration, but this does not work for very long data lengths as your cumulative sum will grow so big that adding small additional values will result in rounding errors.

like image 35
Storstamp Avatar answered Sep 20 '22 14:09

Storstamp