[英]Calculate Exponential Moving Average on a Queue in C#
我有一个简单的类来计算我添加到它的值的移动平均值。 我像这样使用它:
MovingAverage ma = new MovingAverage();
ma.push(value1);
ma.push(value2);
...
Console.Writeline(average.Average);
//the class
public class MovingAverage
{
public int Period = 5;
private Queue<double> Quotes = new Queue<double>();
public void Push(double quote)
{
if (Quotes.Count == Period)
Quotes.Dequeue();
Quotes.Enqueue(quote);
}
public void Clear()
{
Quotes.Clear();
}
public double Average { get { if (Quotes.Count == 0) return 0; return Quotes.Average(); } }
public double ExponentialMovingAverage
{
get
{
???
}
}
}
我想扩展这个类以返回 ExponentialMovingAverage。 您将如何编写返回报价中排队项目的指数平均值?
我意识到您需要在类中添加一个 Alpha 属性,但我不确定如何完成计算的数学运算。
使用 LINQ 怎么样:
return Quotes.DefaultIfEmpty()
.Aggregate((ema, nextQuote) => alpha * nextQuote + (1 - alpha) * ema);
我要指出的是,对于实时财务数据,这是非常低效的。 更好的方法是缓存之前的 EMA 值并使用上述(恒定时间)重复公式在新报价上更新它。
不需要指数移动平均线的队列,因为您只需要跟踪之前的 EMA。
public class ExponentialMovingAverageIndicator
{
private bool _isInitialized;
private readonly int _lookback;
private readonly double _weightingMultiplier;
private double _previousAverage;
public double Average { get; private set; }
public double Slope { get; private set; }
public ExponentialMovingAverageIndicator(int lookback)
{
_lookback = lookback;
_weightingMultiplier = 2.0/(lookback + 1);
}
public void AddDataPoint(double dataPoint)
{
if (!_isInitialized)
{
Average = dataPoint;
Slope = 0;
_previousAverage = Average;
_isInitialized = true;
return;
}
Average = ((dataPoint - _previousAverage)*_weightingMultiplier) + _previousAverage;
Slope = Average - _previousAverage;
//update previous average
_previousAverage = Average;
}
}
这是@MattWolf 答案的最小版本,其 API 略有不同,并使用 C# 7。
public sealed class FloatExponentialMovingAverageCalculator
{
private readonly float _alpha;
private float _lastAverage = float.NaN;
public FloatExponentialMovingAverageCalculator(int lookBack) => _alpha = 2f / (lookBack + 1);
public float NextValue(float value) => _lastAverage = float.IsNaN(_lastAverage)
? value
: (value - _lastAverage)*_alpha + _lastAverage;
}
我认为@Ani 的回答需要进行一些小调整。 初始值将设置为“alpha * nextQuote”,而不仅仅是“nextQuote”。 最简单的解决方法是设置初始种子值以匹配第一条记录,然后第一次迭代变为 alpha * S1 + (1 - alpha) * S1:
return Quotes
.DefaultIfEmpty()
.Aggregate(Quotes.FirstOrDefault() ?? 0.0,
(ema, nextQuote) => alpha * nextQuote + (1 - alpha) * ema);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.