计算移动的标准偏差

我在stackoverflow上找到了以下代码片段,但是我遇到了stdev变成NaN的问题。 任何想法如何解决这一问题?

public static void AddBollingerBands(ref SortedList<DateTime, Dictionary> data, int period, int factor) { double total_average = 0; double total_squares = 0; for (int i = 0; i = period - 1) { double total_bollinger = 0; double average = total_average / period; double stdev = Math.Sqrt((total_squares - Math.Pow(total_average,2)/period) / period); data.Values[i]["bollinger_average"] = average; data.Values[i]["bollinger_top"] = average + factor * stdev; data.Values[i]["bollinger_bottom"] = average - factor * stdev; total_average -= data.Values[i - period + 1]["close"]; total_squares -= Math.Pow(data.Values[i - period + 1]["close"], 2); } } } 

在进行增量/移动平均值和标准偏差计算时,数值更稳定的变量是更可取的。 一种方法是使用Knuth的算法,如下面的代码块所示:

 public class MovingAverageCalculator { public MovingAverageCalculator(int period) { _period = period; _window = new double[period]; } public double Average { get { return _average; } } public double StandardDeviation { get { var variance = Variance; if (variance >= double.Epsilon) { var sd = Math.Sqrt(variance); return double.IsNaN(sd) ? 0.0 : sd; } return 0.0; } } public double Variance { get { var n = N; return n > 1 ? _variance_sum / (n - 1) : 0.0; } } public bool HasFullPeriod { get { return _num_added >= _period; } } public IEnumerable Observations { get { return _window.Take(N); } } public int N { get { return Math.Min(_num_added, _period); } } public void AddObservation(double observation) { // Window is treated as a circular buffer. var ndx = _num_added % _period; var old = _window[ndx]; // get value to remove from window _window[ndx] = observation; // add new observation in its place. _num_added++; // Update average and standard deviation using deltas var old_avg = _average; if (_num_added <= _period) { var delta = observation - old_avg; _average += delta / _num_added; _variance_sum += (delta * (observation - _average)); } else // use delta vs removed observation. { var delta = observation - old; _average += delta / _period; _variance_sum += (delta * ((observation - _average) + (old - old_avg))); } } private readonly int _period; private readonly double[] _window; private int _num_added; private double _average; private double _variance_sum; } 

然后,您可以在代码示例中以下列方式使用它:

 public static void AddBollingerBands(ref SortedList> data, int period, int factor) { var moving_avg = new MovingAverageCalculator(period); for (int i = 0; i < data.Count(); i++) { moving_avg.AddObservation(data.Values[i]["close"]); if (moving_avg.HasFullPeriod) { var average = moving_avg.Average; var limit = factor * moving_avg.StandardDeviation; data.Values[i]["bollinger_average"] = average; data.Values[i]["bollinger_top"] = average + limit; data.Values[i]["bollinger_bottom"] = average - limit; } } } 

要使stdev成为NaN,在这个任务中必须出错:

 double stdev = Math.Sqrt((total_squares - Math.Pow(total_average,2)/period) / period); 

您不能除以零,因此请确保period未设置为该值。 最简单的解决方法是在调用此行之前打印出每个变量,看看是否已有NaN或数学上无法使用