计算移动标准偏差 [英] Calculate a moving Standard Deviation

查看:188
本文介绍了计算移动标准偏差的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现下面的代码片段在这里计算器,但我认为STDEV变成NaN的问题。任何想法如何解决这一问题。



 公共静态无效AddBollingerBands(REF排序列表<日期时间,字典<字符串,双>>数据,INT期间,INT因子)
{
双total_average = 0;
双TOTAL_SQUARES = 0;

的for(int i = 0; I< data.Count();我++)
{
total_average + = data.Values​​ [I] [亲密];
TOTAL_SQUARES + = Math.Pow(data.Values​​ [I] [亲密],2);

如果(I> =时间 - 1)
{
双total_bollinger = 0;
双平均= total_average /期;

双重标准偏差=的Math.sqrt((TOTAL_SQUARES - Math.Pow(total_average,2)/周期)/期);
data.Values​​ [I] [bollinger_average] =平均值;
data.Values​​ [I] [bollinger_top] =平均+因子*标准偏差;
data.Values​​ [I] [bollinger_bottom] = AVERAGE - 因子×标准偏差;

total_average - = data.Values​​ [我 - 周期+ 1] [亲密];
TOTAL_SQUARES - = Math.Pow(data.Values​​ [I - 周期+ 1] [接近],2);
}
}
}


解决方案

一个数值上更稳定的变体做增量/移动平均值和标准偏差计算时是可取的。这样做的一种方法是使用Knuth的算法,如下面的代码块:

 公共类MovingAverageCalculator 
{
公共MovingAverageCalculator(INT期)
{
_period =期;
_window =新的双[周期];
}

公共双平均
{
{返回_average; }
}

公共双重标准差
{
得到
{
变种差异=方差;
如果(方差> = double.Epsilon)
{
VAR SD =的Math.sqrt(方差);
返回double.IsNaN(SD)? 0.0:SD;
}
回报率0.0;
}
}

公共双差异
{
得到
{
变种N = N;
返回N'GT; 1? _variance_sum /(N - 1):0.0;
}
}

公共BOOL HasFullPeriod
{
{返回_num_added> = _period; }
}

公开的IEnumerable<双>观察
{
{返回_window.Take(N); }
}

公众诠释N
{
{返回Math.Min(_num_added,_period); }
}

公共无效AddObservation(双观察)
{
//窗口被视为循环缓冲器。
VAR NDX = _num_added%_period;
VAR老= _window [NDX] //获得价值从窗口
_window [NDX] =观察捞出; //在其位置添加新的观察。
_num_added ++;

//更新平均值和标准偏差使用增量
VAR old_avg = _average;
如果(_num_added< = _period)
{
VAR三角洲=观察 - old_avg;
_average + =增量/ _num_added;
_variance_sum + =(△*(观察 - _average));
}
,否则//使用增量VS去除观察。
{
VAR三角洲=观察 - 老;
_average + =增量/ _period;
_variance_sum + =(△*((观察 - _average)+(旧 - old_avg)));
}
}

私人只读INT _period;
私人只读双[] _window;
私人诠释_num_added;
私人双_average;
私人双_variance_sum;
}



然后,您可以使用它在你的代码示例如下方式:

 公共静态无效AddBollingerBands(REF排序列表<日期时间,字典<字符串,双>>的数据,诠释期间,INT因子)
{
变种moving_avg =新MovingAverageCalculator(期);
的for(int i = 0; I< data.Count();我++)
{
moving_avg.AddObservation(data.Values​​ [I] [接近]);
如果(moving_avg.HasFullPeriod)
{
VAR平均= moving_avg.Average;
变种限制=系数* moving_avg.StandardDeviation;
data.Values​​ [I] [bollinger_average] =平均值;
data.Values​​ [I] [bollinger_top] =平均+限制;
data.Values​​ [I] [bollinger_bottom] =平均 - 限制;
}
}
}


i found the following code snippet here on stackoverflow, but i have the problem that the stdev becomes NaN. Any ideas how to fix this?

public static void AddBollingerBands(ref SortedList<DateTime, Dictionary<string, double>> data, int period, int factor)
{
    double total_average = 0;
    double total_squares = 0;

    for (int i = 0; i < data.Count(); i++)
    {
        total_average += data.Values[i]["close"];
        total_squares += Math.Pow(data.Values[i]["close"], 2);

        if (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);
        }
    }
}

解决方案

A numerically more stable variant is preferable when doing incremental / moving average and standard deviation calculations. One way to do this is using Knuth's algorithm, as shown in the code block below:

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

You could then use it in the following manner in your code example:

public static void AddBollingerBands(ref SortedList<DateTime, Dictionary<string, double>> 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;
        }
    }
}

这篇关于计算移动标准偏差的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆