我想计算mean absolute deviation,目前正在使用link here发布的Stack Overflow(Alex)中的以下类:
public class MovingAverageCalculator
{
private readonly int _period;
private readonly double[] _window;
private int _numAdded;
private double _varianceSum;
public MovingAverageCalculator(int period)
{
_period = period;
_window = new double[period];
}
public double Average { get; private set; }
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 ? _varianceSum / (n - 1) : 0.0;
}
}
public bool HasFullPeriod
{
get { return _numAdded >= _period; }
}
public IEnumerable<double> Observations
{
get { return _window.Take(N); }
}
public int N
{
get { return Math.Min(_numAdded, _period); }
}
public void AddObservation(double observation)
{
// Window is treated as a circular buffer.
var ndx = _numAdded % _period;
var old = _window[ndx]; // get value to remove from window
_window[ndx] = observation; // add new observation in its place.
_numAdded++;
// Update average and standard deviation using deltas
var old_avg = Average;
if (_numAdded <= _period)
{
var delta = observation - old_avg;
Average += delta / _numAdded;
_varianceSum += (delta * (observation - Average));
}
else // use delta vs removed observation.
{
var delta = observation - old;
Average += delta / _period;
_varianceSum += (delta * ((observation - Average) + (old - old_avg)));
}
}
}
创建该类的人以某种方式做了怪异的事,我不理解计算结果,因为他使用了不同的公式。例如,人们通常像this一样计算方差。
有人可以解释一下该类别中的平均绝对偏差吗?
公式:
这个准确一些,但还不够。有什么想法吗?
输出(应该是):
CCI = -29.189669
CCI = -57.578105
CCI = 1.537557
CCI = 46.973803
CCI = 68.662979
CCI = 78.647204
CCI = 52.798310
CCI = 84.266845
CCI = 104.694912
CCI = 99.048428
CCI = 58.068118
CCI = 57.575758
CCI = 68.387309
CCI = 127.625967
CCI = 128.826508
CCI = 124.751608
CCI = 112.929293
CCI = 165.170449
CCI = 141.586505
CCI = 114.463325
CCI = 155.766418
输出(它是什么):
CCI = -26.630104
CCI = -53.295597
CCI = 1.476909
CCI = 44.829571
CCI = 67.857143
CCI = 80.059829
CCI = 55.447471
CCI = 90.681818
CCI = 116.030534
CCI = 106.314948
CCI = 61.242833
CCI = 61.664226
CCI = 74.962064
CCI = 150.864780
CCI = 163.034547
CCI = 162.636347
CCI = 153.194865
CCI = 197.583882
CCI = 159.622130
CCI = 122.744143
CCI = 163.325826
另一个CCI的输出(应该是):
Typical Price: 0.010153 | SMA: 0.009989 | Mean Deviation: 0.000139
Typical Price: 0.010100 | SMA: 0.009988 | Mean Deviation: 0.000142
Typical Price: 0.010180 | SMA: 0.009991 | Mean Deviation: 0.000150
Typical Price: 0.010230 | SMA: 0.009990 | Mean Deviation: 0.000153
Typical Price: 0.010233 | SMA: 0.010000 | Mean Deviation: 0.000157
Typical Price: 0.010147 | SMA: 0.010008 | Mean Deviation: 0.000159
Typical Price: 0.010160 | SMA: 0.010027 | Mean Deviation: 0.000154
Typical Price: 0.010200 | SMA: 0.010044 | Mean Deviation: 0.000152
Typical Price: 0.010380 | SMA: 0.010077 | Mean Deviation: 0.000158
Typical Price: 0.010413 | SMA: 0.010107 | Mean Deviation: 0.000159
Typical Price: 0.010447 | SMA: 0.010138 | Mean Deviation: 0.000165
Typical Price: 0.010450 | SMA: 0.010171 | Mean Deviation: 0.000165
Typical Price: 0.010657 | SMA: 0.010199 | Mean Deviation: 0.000185
Typical Price: 0.010647 | SMA: 0.010224 | Mean Deviation: 0.000199
Typical Price: 0.010623 | SMA: 0.010252 | Mean Deviation: 0.000216
Typical Price: 0.010880 | SMA: 0.010308 | Mean Deviation: 0.000245
Typical Price: 0.010863 | SMA: 0.010354 | Mean Deviation: 0.000263
Typical Price: 0.010853 | SMA: 0.010397 | Mean Deviation: 0.000285
Typical Price: 0.010967 | SMA: 0.010442 | Mean Deviation: 0.000307
Typical Price: 0.011480 | SMA: 0.010517 | Mean Deviation: 0.000356
Typical Price: 0.011750 | SMA: 0.010600 | Mean Deviation: 0.000408
Typical Price: 0.011653 | SMA: 0.010674 | Mean Deviation: 0.000448
来自CommodityChannelIndex.cs的输出(它是什么):
Typical Price: 0.010153 | SMA: 0.009989 | Mean Deviation: 0.000137
Typical Price: 0.010100 | SMA: 0.009988 | Mean Deviation: 0.000135
Typical Price: 0.010180 | SMA: 0.009991 | Mean Deviation: 0.000139
Typical Price: 0.010230 | SMA: 0.009990 | Mean Deviation: 0.000138
Typical Price: 0.010233 | SMA: 0.010000 | Mean Deviation: 0.000146
Typical Price: 0.010147 | SMA: 0.010008 | Mean Deviation: 0.000151
Typical Price: 0.010160 | SMA: 0.010027 | Mean Deviation: 0.000144
Typical Price: 0.010200 | SMA: 0.010044 | Mean Deviation: 0.000139
Typical Price: 0.010380 | SMA: 0.010077 | Mean Deviation: 0.000134
Typical Price: 0.010413 | SMA: 0.010107 | Mean Deviation: 0.000125
Typical Price: 0.010447 | SMA: 0.010138 | Mean Deviation: 0.000127
Typical Price: 0.010450 | SMA: 0.010171 | Mean Deviation: 0.000122
Typical Price: 0.010657 | SMA: 0.010199 | Mean Deviation: 0.000154
Typical Price: 0.010647 | SMA: 0.010224 | Mean Deviation: 0.000177
Typical Price: 0.010623 | SMA: 0.010252 | Mean Deviation: 0.000202
Typical Price: 0.010880 | SMA: 0.010308 | Mean Deviation: 0.000234
Typical Price: 0.010863 | SMA: 0.010354 | Mean Deviation: 0.000244
Typical Price: 0.010853 | SMA: 0.010397 | Mean Deviation: 0.000255
Typical Price: 0.010967 | SMA: 0.010442 | Mean Deviation: 0.000273
Typical Price: 0.011480 | SMA: 0.010517 | Mean Deviation: 0.000329
Typical Price: 0.011750 | SMA: 0.010600 | Mean Deviation: 0.000389
Typical Price: 0.011653 | SMA: 0.010674 | Mean Deviation: 0.000423
有效的示例代码:
public decimal[] Calculate(IReadOnlyList<(decimal High, decimal Low, decimal Close)> candles, int period)
{
var ccis = new decimal[candles.Count];
SMA sma = new SMA(period);
var smas = sma.Calculate(candles.Select(e => e.Close).ToArray());
for (int i = 0; i < candles.Count; i++)
{
var typicalPrice = (candles[i].High + candles[i].Low + candles[i].Close) / 3m;
decimal total = 0m;
for (int j = i; j >= Math.Max(i - period + 1, 0); j--)
{
total += Math.Abs(smas[j] - candles[j].Close);
Console.WriteLine("Sum = " + total.ToString("f6"));
}
decimal meanDeviation = total / period;
decimal cci = meanDeviation != 0 ? (typicalPrice - smas[i]) / meanDeviation / 0.015m : 0;
//Console.WriteLine($"Typical Price: {typicalPrice.ToString("f6")} | SMA: {smas[i].ToString("f6")} | Mean Deviation: {meanDeviation.ToString("f6")}");
ccis[i] = cci;
}
return ccis;
}
我要修复的实际(损坏)代码:
public class MovingAverageCalculator
{
private readonly int _period;
private readonly double[] _window;
private int _numAdded;
private double _varianceSum;
public MovingAverageCalculator(int period)
{
_period = period;
_window = new double[period];
}
public double Average { get; private set; }
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 ? _varianceSum / (n - 1) : 0.0;
}
}
public double MeanAbsoluteDeviation
{
get
{
//return _window.Average(e => Math.Abs(e - Average));
// https://stackoverflow.com/questions/5336457/how-to-calculate-a-standard-deviation-array
var n = N;
var sumOfDifferences = _window.Sum(e => Math.Abs(e - Average));
return n > 1 ? sumOfDifferences / (n - 1) : 0.0;
}
}
public bool HasFullPeriod
{
get { return _numAdded >= _period; }
}
public IEnumerable<double> Observations
{
get { return _window.Take(N); }
}
public int N
{
get { return Math.Min(_numAdded, _period); }
}
public void AddObservation(double observation)
{
// Window is treated as a circular buffer.
var ndx = _numAdded % _period;
var old = _window[ndx]; // get value to remove from window
_window[ndx] = observation; // add new observation in its place.
_numAdded++;
// Update average and standard deviation using deltas
var oldAvg = Average;
if (_numAdded <= _period)
{
var delta = observation - oldAvg;
Average += delta / _numAdded;
_varianceSum += (delta * (observation - Average));
}
else // use delta vs removed observation.
{
var delta = observation - old;
Average += delta / _period;
_varianceSum += (delta * ((observation - Average) + (old - oldAvg)));
}
}
public void Reset()
{
_numAdded = 0;
_varianceSum = 0;
}
}
public class CommodityChannelIndex : Indicator<(decimal High, decimal Low, decimal Close), decimal>
{
private readonly int _period;
private readonly MovingAverageCalculator _movingAvg;
public CommodityChannelIndex(int period)
{
_period = period;
_movingAvg = new MovingAverageCalculator(_period);
}
public override decimal ComputeNextValue((decimal High, decimal Low, decimal Close) input)
{
decimal typicalPrice = (input.High + input.Low + input.Close) / 3m;
_movingAvg.AddObservation((double)input.Close);
if (_movingAvg.HasFullPeriod)
{
var average = (decimal)_movingAvg.Average;
var meanDeviation = (decimal)_movingAvg.MeanAbsoluteDeviation;
return meanDeviation != 0m ? (typicalPrice - average) / meanDeviation / 0.015m : 0m;
}
return 0;
}
public override void Reset()
{
throw new System.NotImplementedException();
}
}
// USAGE
CommodityChannelIndex rsi = new CommodityChannelIndex(20);
for (int i = 0; i < candles.Count - 1; i++)
{
var result = rsi.ComputeNextValue((candles[i].High, candles[i].Low, candles[i].Close));
Console.WriteLine($"CCI = {result.ToString("f6")}");
}
平均绝对偏差之和被破坏。问题是如何解决?
在Alireza纠正之后。仍然不准确。
Correct (how it should be):
CCI = -11.554556
CCI = 21.045918
CCI = 38.828097
CCI = 22.566381
CCI = 59.149184
CCI = 77.075455
CCI = 38.104311
CCI = 13.746847
CCI = -41.996578
CCI = -89.997229
CCI = -77.630112
CCI = 18.273976
CCI = 9.525936
CCI = -11.306480
CCI = 74.880871
CCI = 186.070619
CCI = 19.839042
CCI = -159.106198
Incorrect (n - 1) - before Alireza's answer:
CCI = -29.587542
CCI = 45.010768
CCI = 69.666667
CCI = 34.518799
CCI = 75.449922
CCI = 89.486260
CCI = 43.181818
CCI = 15.962060
CCI = -47.174211
CCI = -99.664083
CCI = -80.542391
CCI = 17.952962
CCI = 8.888889
CCI = -10.138104
CCI = 66.560510
CCI = 169.550087
CCI = 18.679280
CCI = -154.360812
Incorrect (n) - after Alireza's answer
CCI = -31.144781
CCI = 47.379756
CCI = 73.333333
CCI = 36.335578
CCI = 79.420970
CCI = 94.196064
CCI = 45.454545
CCI = 16.802168
CCI = -49.657064
CCI = -104.909561
CCI = -84.781464
CCI = 18.897855
CCI = 9.356725
CCI = -10.671689
CCI = 70.063694
CCI = 178.473776
CCI = 19.662400
CCI = -162.485066
答案 0 :(得分:1)
您为什么不滚动自己的处理数据的统计信息类?这是一个开始:
class Program
{
static void Main(string[] args)
{
double[] observations = new double[]
{
61.27657038 ,
6.738725617 ,
4.888532706 ,
68.5439831 ,
7.979694724 ,
46.29444503 ,
55.91040488 ,
2.120589448 ,
18.75847801 ,
1.340159128 ,
1.188675161 ,
0.444025252 ,
0.126010202 ,
55.90778938 ,
55.76919429 ,
4.976797265 ,
56.27591183 ,
34.25639959 ,
1.045892651 ,
15.92770207 ,
};
// take the last 10 data for statistics
var data = observations.Reverse().Take(10).ToArray();
var stats = new Statistics(data);
Debug.WriteLine($"Count ={stats.Count}");
Debug.WriteLine($"Min ={stats.MinValue}");
Debug.WriteLine($"Max ={stats.MaxValue}");
Debug.WriteLine($"Median ={stats.MedianValue}");
Debug.WriteLine($"Mean ={stats.MeanValue}");
Debug.WriteLine($"Var ={stats.Variance}");
Debug.WriteLine($"Mad ={stats.MeanAbsoluteDeviation}");
Debug.WriteLine($"SDev ={stats.StandardDeviation}");
}
}
public class Statistics
{
public Statistics(params double[] data)
{
this.Count = data.Length;
// first pass to get mean;
double sum = 0, min = 0, max = 0;
for (int i = 0; i < data.Length; i++)
{
double x = data[i];
if (i==0) // use first data for min/max
{
min = x;
max = x;
}
else
{
min = Math.Min(min, x);
max = Math.Max(max, x);
}
sum += x;
}
this.MinValue = min;
this.MaxValue = max;
this.MeanValue = sum/Count;
// second pass for variance
double var = 0, dev = 0, dx;
for (int i = 0; i < data.Length; i++)
{
dx = data[i]-MeanValue;
dev += Math.Abs(dx);
var += dx*dx;
}
this.MeanAbsoluteDeviation = dev/Count;
this.Variance = var/Count;
}
public int Count { get; }
public double MaxValue { get; }
public double MinValue { get; }
public double MedianValue => (MinValue+MaxValue)/2;
public double MeanValue { get; }
public double MeanAbsoluteDeviation { get; }
public double Variance { get; }
public double StandardDeviation => Sqrt(Variance);
}
带有示例结果:
Count =10
Min =0.126010202
Max =56.27591183
Median =28.200961016
Mean =22.5918397691
Var =575.363095007382
Mad =22.36838720272
SDev =23.9867274759893
答案 1 :(得分:1)
我认为此更正是您想要的。您应该替换以下不正确的代码:
public double MeanAbsoluteDeviation
{
get
{
//return _window.Average(e => Math.Abs(e - Average));
// https://stackoverflow.com/questions/5336457/how-to-calculate-a-standard-deviation-array
var n = N;
var sumOfDifferences = _window.Sum(e => Math.Abs(e - Average));
return n > 1 ? sumOfDifferences / (n - 1) : 0.0;
}
}
使用正确的一个:
public double MeanAbsoluteDeviation
{
get
{
//return _window.Average(e => Math.Abs(e - Average));
// https://stackoverflow.com/questions/5336457/how-to-calculate-a-standard-deviation-array
var n = N;
var sumOfDifferences = _window.Sum(e => Math.Abs(e - Average));
return n > 1 ? sumOfDifferences / n : 0.0;
}
}
编辑
还请注意,您对MeanAbsoluteDeviation的计算是错误的!您正在考虑所有值的当前平均值,同时应该将每个值与其平均值进行比较。
这是完整的解决方案:
public class Candle
{
public double average { get; set; } = 0;
public double close { get; set; } = 0;
}
public class MovingAverageCalculator
{
private readonly int _period;
private readonly Candle[] _window;
private int _numAdded;
private double _varianceSum;
public MovingAverageCalculator(int period)
{
_period = period;
_window = new Candle[period];
for (int i = 0; i < period; i++)
_window[i] = new Candle();
}
public double Average { get; private set; }
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 ? _varianceSum / (n - 1) : 0.0;
}
}
public double MeanAbsoluteDeviation
{
get
{
//return _window.Average(e => Math.Abs(e - Average));
// https://stackoverflow.com/questions/5336457/how-to-calculate-a-standard-deviation-array
var n = N;
var sumOfDifferences = _window.Sum(e => Math.Abs(e.close - e.average));
return n > 1 ? sumOfDifferences / n : 0.0;
}
}
public bool HasFullPeriod
{
get { return _numAdded > _period; }
}
public IEnumerable<double> Observations
{
get { return _window.Take(N).Select(a=>a.close); }
}
public int N
{
get { return Math.Min(_numAdded, _period); }
}
public void AddObservation(double observation)
{
// Window is treated as a circular buffer.
var ndx = _numAdded % _period;
var old = _window[ndx].close; // get value to remove from window
_window[ndx] = new Candle() { close=observation,average=0 }; // add new observation in its place.
_numAdded++;
// Update average and standard deviation using deltas
var oldAvg = Average;
if (_numAdded <= _period)
{
var delta = observation - oldAvg;
Average += delta / _numAdded;
_window[ndx].average = Average;
_varianceSum += (delta * (observation - Average));
}
else // use delta vs removed observation.
{
var delta = observation - old;
Average += delta / _period;
_window[ndx].average = Average;
_varianceSum += (delta * ((observation - Average) + (old - oldAvg)));
}
}
public void Reset()
{
_numAdded = 0;
_varianceSum = 0;
}
}