如何在C#中更快地计算简单移动平均线?

如何在C#中更快地计算简单移动平均线?,c#,algorithm,financial,moving-average,C#,Algorithm,Financial,Moving Average,计算简单移动平均线的最快库/算法是什么?我自己写的,但在330 000项十进制数据集上花费的时间太长了 时段/时间(毫秒) 20/300 60/1500 120/3500 以下是我的方法代码: public decimal MA_Simple(int period, int ii) { if (period != 0 && ii > period) { //stp.Start(); decimal summ = 0;

计算简单移动平均线的最快库/算法是什么?我自己写的,但在330 000项十进制数据集上花费的时间太长了

  • 时段/时间(毫秒)
  • 20/300
  • 60/1500
  • 120/3500
以下是我的方法代码:

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

数据.Close[]
是一个固定大小(1000 000)的十进制数组。

如果数据是静态的,您可以对数组进行预处理,以快速进行移动平均查询:

decimal[] GetCSum(decimal[] data) {
    decimal csum[] = new decimal[data.Length];
    decimal cursum = 0;
    for(int i=0; i<data.Length; i++) {
        cursum += data[i];
        csum[i] = cursum;
    }
    return csum;
}
decimal[]GetCSum(decimal[]data){
十进制csum[]=新的十进制[data.Length];
十进制游标=0;

对于(inti=0;i,您的主要问题是每次迭代都会浪费太多的信息。 如果你想跑得这么快,你需要保持一个与帧长相同大小的缓冲区

此代码将为整个数据集运行移动平均值:

(不是真正的C#但你应该明白)

decimal buffer[]=新的十进制[句点];
十进制输出[]=新的十进制[data.Length];
当前_指数=0;

对于(int i=0;i这是我在应用程序中使用的MA

double[] MovingAverage(int period, double[] source)
{
    var ma = new double[source.Length];

    double sum = 0;
    for (int bar = 0; bar < period; bar++)
        sum += source[bar];

    ma[period - 1] = sum/period;

    for (int bar = period; bar < source.Length; bar++)
        ma[bar] = ma[bar - 1] + source[bar]/period
                              - source[bar - period]/period;

    return ma;
}
double[]移动平均值(整数周期,double[]源)
{
var ma=新的双精度[源.长度];
双和=0;
用于(int bar=0;bar

一旦对整个数据系列进行了计算,您就可以立即获取特定值。

以下是我如何尝试的。但警告我是一个完全的业余爱好者,因此这可能是完全错误的

List<decimal> MovingAverage(int period, decimal[] Data)
{
     decimal[] interval = new decimal[period];
     List<decimal> MAs = new List<decimal>();

     for (int i=0, i < Data.length, i++)
     {
          interval[i % period] = Data[i];
          if (i > period - 1)
          {
               MAs.Add(interval.Average());
          }
     }
     return MAs;
}
列表移动平均值(整数周期,十进制[]数据)
{
十进制[]间隔=新的十进制[期间];
List MAs=新列表();
对于(int i=0,i周期-1)
{
MAs.Add(interval.Average());
}
}
返回MAs;
}
应返回包含数据移动平均值的小数列表。

当前(接受的)解决方案包含一个内部循环。删除此项也会更有效。您可以在此处看到如何实现此目的:

//
///基于浮点数学的快速低CPU使用率移动平均
///注意:此算法通过每1000个值重新求和缓冲区来补偿浮点错误
/// 
公共类FastMovingAverageDouble
{
/// 
///根据您认为合适的情况进行调整,以适应场景
/// 
const int maximumWindowsSize=100;
/// 
///根据您的需要进行调整
/// 
const int recreacteeveryxvalue=1000;
/// 
///初始化指定窗口大小的移动平均值
/// 
///移动平均窗口的大小介于2和MaximumWindowSize之间
///注意:这个值不应该太大,同时也要注意溢出和浮点错误的可能性,因为这个类在内部保持窗口中的值的总和
公共FastMovingAverageDouble(int\u WindowsSize)
{
如果(_WindowSize<2)
{
_WindowSize=2;
}
否则如果(_WindowSize>MaximumWindowSize)
{
_窗口大小=最大窗口大小;
}
m_WindowSize=_WindowSize;
}
私有对象SyncRoot=新对象();
专用队列缓冲区=新队列();
私有int m_窗口大小;
私人双移动平均值=0d;
专用双动sum=0d;
私人布尔缓冲区满;
专用整数计数器=0;
/// 
///计算移动平均线
/// 
公共双动平均
{
得到
{
锁定(同步根)
{
返回移动平均值;
}
}
}
/// 
///初始化期间构造函数设置的移动平均值窗口的大小
/// 
公共int窗口大小
{
得到
{
返回m_WindowSize;
}
}
/// 
///向序列添加新值并重新计算移动平均seee
/// 
///新增价值
公共void AddValue(int NewValue)
{
锁定(同步根)
{
Buffer.Enqueue(NewValue);
MovingSum+=新值;
如果(!BufferFull)
{
int BufferSize=Buffer.Count;
BufferFull=BufferSize==WindowsSize;
m_MovingAverage=MovingSum/缓冲区大小;
}
其他的
{
计数器+=1;
如果(计数器>重新计算值)
{
MovingSum=0;
foreach(缓冲区中的双缓冲值)
{
MovingSum+=缓冲值;
}
计数器=0;
}
MovingSum-=Buffer.Dequeue();
m_MovingAverage=MovingSum/WindowsSize;
}
}
}
}
现在,库中有一个名为的类可以为您执行此操作。如果您只想在最后的“X”项上执行此操作,请改用

两者都将计算运行平均值、方差和标准偏差,只需一次通过,不存储额外的数据副本。

公共类移动平均值
    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;
        }
    }
{ 私有队列样本=新队列(); 私有int windowSize=16; 专用十进制采样累加器; 公共十进制平均值{get;private set;} /// ///每次新样本到达时计算新的窗口平均值 /// /// 公共无效计算平均值(十进制新闻示例) { 样本累加器+=新样本; 样本。排队(新闻样本); 如果(samples.Count>windowSize) { sampleAccumulator-=samples.Dequeue();
double *values = new double[10]; // the input
double *averages = new double[10]; // the output
values[0] = 55;
values[1] = 113;
values[2] = 92.6;
...
values[9] = 23;
moving_average(values, averages, 10, 5); // 5-day moving average
double[] MovingAverage(int period, double[] source)
{
    var ma = new double[source.Length];

    double sum = 0;
    for (int bar = 0; bar < period; bar++)
        sum += source[bar];

    ma[period - 1] = sum/period;

    for (int bar = period; bar < source.Length; bar++)
        ma[bar] = ma[bar - 1] + source[bar]/period
                              - source[bar - period]/period;

    return ma;
}
List<decimal> MovingAverage(int period, decimal[] Data)
{
     decimal[] interval = new decimal[period];
     List<decimal> MAs = new List<decimal>();

     for (int i=0, i < Data.length, i++)
     {
          interval[i % period] = Data[i];
          if (i > period - 1)
          {
               MAs.Add(interval.Average());
          }
     }
     return MAs;
}
/// <summary>
/// Fast low CPU usage moving average based on floating point math
/// Note: This algorithm algorithm compensates for floating point error by re-summing the buffer for every 1000 values
/// </summary>
public class FastMovingAverageDouble
{
    /// <summary>
    /// Adjust this as you see fit to suit the scenario
    /// </summary>
    const int MaximumWindowSize = 100;

    /// <summary>
    /// Adjust this as you see fit
    /// </summary>
    const int RecalculateEveryXValues = 1000;

    /// <summary>
    /// Initializes moving average for specified window size
    /// </summary>
    /// <param name="_WindowSize">Size of moving average window between 2 and MaximumWindowSize 
    /// Note: this value should not be too large and also bear in mind the possibility of overflow and floating point error as this class internally keeps a sum of the values within the window</param>
    public FastMovingAverageDouble(int _WindowSize)
    {
        if (_WindowSize < 2)
        {
            _WindowSize = 2;
        }
        else if (_WindowSize > MaximumWindowSize)
        {
            _WindowSize = MaximumWindowSize;
        }
        m_WindowSize = _WindowSize;
    }
    private object SyncRoot = new object();
    private Queue<double> Buffer = new Queue<double>();
    private int m_WindowSize;
    private double m_MovingAverage = 0d;
    private double MovingSum = 0d;
    private bool BufferFull;
    private int Counter = 0;

    /// <summary>
    /// Calculated moving average
    /// </summary>
    public double MovingAverage
    {
        get
        {
            lock (SyncRoot)
            {
                return m_MovingAverage;
            }
        }
    }

    /// <summary>
    /// Size of moving average window set by constructor during intialization
    /// </summary>
    public int WindowSize
    {
        get
        {
            return m_WindowSize;
        }
    }

    /// <summary>
    /// Add new value to sequence and recalculate moving average seee <see cref="MovingAverage"/>
    /// </summary>
    /// <param name="NewValue">New value to be added</param>
    public void AddValue(int NewValue)
    {
        lock (SyncRoot)
        {
            Buffer.Enqueue(NewValue);
            MovingSum += NewValue;
            if (!BufferFull)
            {
                int BufferSize = Buffer.Count;
                BufferFull = BufferSize == WindowSize;
                m_MovingAverage = MovingSum / BufferSize;
            }
            else
            {
                Counter += 1;
                if (Counter > RecalculateEveryXValues)
                {
                    MovingSum = 0;
                    foreach (double BufferValue in Buffer)
                    {
                        MovingSum += BufferValue;
                    }
                    Counter = 0;
                }
                MovingSum -= Buffer.Dequeue();
                m_MovingAverage = MovingSum / WindowSize;
            }
        }
    }
}
    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;
        }
    }
using System.Collections.Generic;
using System.Linq;

public class MovingAverage
{
    private readonly Queue<decimal> _queue;
    private readonly int _period;

    public MovingAverage(int period)
    {
        _period = period;
        _queue = new Queue<decimal>(period);
    }

    public decimal Compute(decimal x)
    {
        if (_queue.Count >= _period)
        {
            _queue.Dequeue();
        }

        _queue.Enqueue(x);

        return _queue.Average();
    }
}
MovingAverage ma = new MovingAverage(3);

foreach(var val in new decimal[] { 1,2,3,4,5,6,7,8,9 })
{
   Console.WriteLine(ma.Compute(val));
}
  // n is the window for your Simple Moving Average
  public List<double> GetMovingAverages(List<Price> prices, int n)
  {
    var movingAverages = new double[prices.Count];
    var runningTotal = 0.0d;       

    for (int i = 0; i < prices.Count; ++i)
    {
      runningTotal += prices[i].Value;
      if( i - n >= 0) {
        var lost = prices[i - n].Value;
        runningTotal -= lost;
        movingAverages[i] = runningTotal / n;
      }
    }
    return movingAverages.ToList();
  }
public class Sample
{
    private decimal sum = 0;
    private uint count = 0;

    public void Add(decimal value)
    {
        sum += value;
        count++;
    }

    public decimal AverageMove => count > 0 ? sum / count : 0;
}
public class ThreadSafeSample
{
private decimal sum = 0;
private uint count = 0;

private static object locker = new object();
public void Add(decimal value)
{
    lock (locker)
    {
        sum += value;
        count++;
    }
}

public decimal AverageMove => count > 0 ? sum / count : 0;
int period = 20;
for(int k=0;data.Count()-period;k++){
   decimal summe = data.Skip(k).Take(period).Sum();
   summe /= (decimal)period;
}