Я хочу вычислить среднее абсолютное отклонение , и в настоящее время я использую следующий класс из Переполнения стека ( ссылка здесь ), опубликованный 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")}");
}
Сумма для среднего абсолютного отклонения нарушена. Вопрос в том, как это исправить?
Редактировать:
После исправления Алирезы. Все еще неточно.
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
Репо проекта:
https://github.com/Warrolen/test-project