在C ++中实现指数移动平均线

时间:2016-05-18 13:12:00

标签: c++ math

我正在开发一个小型交易机器人作为练习。他日复一日地接受股票价格(表示为迭代)。

这是我的Trade课程的样子:

class   Trade
{
private:
  int                   capital_;
  int                   days_; // Total number of days of available stock prices                                       
  int                   daysInTrading_; // Increments as days go by.                                                   
  std::list<int>        stockPrices_; // Contains stock prices day after day.                                          
  int                   currentStock_; // Current stock we are dealing with.                                           
  int                   lastStock_; // Last stock dealt with                                                           
  int                   trend_; // Either {-1; 0; 1} depending on the trend.                                           
  int                   numOfStocks_; // Number of stocks in our possession
  int                   EMA_; // Exponential Moving Average                                                            
  int                   lastEMA_; // Last EMA                                                                          

public:
    // functions
};

从我最近的两个属性中可以看出,我希望将指数移动平均线作为趋势跟踪算法的一部分来实现。

但我认为我不太明白如何实施它;这是我的calcEMA函数,它只计算EMA

int     Trade::calcEMA()
{
  return ((this->currentStock_ - this->lastEMA_
           * (2/(this->daysInTrading_ + 1)))
          + this->lastEMA_);
}

但是当我的股票价值(在文件中传递)是这样的时候:

1000, 1100, 1200, 1300, 1400, 1500, 1400, 1300, 1200, 1100, 1000

为了确保我的EMA有意义,而且......它没有!

我在哪里操作错了?

另外,如果我第一次拨打lastEMA,我应该给calcEMA一个什么价值?

3 个答案:

答案 0 :(得分:1)

正如您所注意到的那样,操作是错误的。

免责声明 我从wikipedia获得了此算法,因此可能不准确。 Here(第3页)可能更好,但我无法判断,我从未使用过这些算法,因此不知道我在说什么:)

  

c(EMA) = y(EMA) + a * (c(price) - y(EMA))

     
      
  • c(EMA)是当前的EMA
  •   
  • y(EMA)是以前的EMA
  •   
  • a是介于0和1之间的“随机”值
  •   
  • c(price)是当前价格
  •   

但你做了几乎相同的事情:

  

c(EMA) = (c(price) - y(EMA) * b) + y(EMA)

我不知道你为什么做2 / daysInTrading_ + 1,但这并不总是0到1之间的值(实际上,它甚至可能大部分时间都是0,因为这些都是整数)。 / p>

您将括号放在错误的位置(b之后,而不是y(EMA)之后)。

所以操作现在看起来像这样:

<强> lastEMA_ + 0.5 * (currentStock_ - lastEMA_)

对于第一个lastEMA_,根据Wikipedia

  

S 1 未定义。 S 1 可以通过多种不同的方式初始化,最常见的是通过设置S 11 [列表中的第一个元素],尽管其他技术存在,例如将S 1 设置为前4或5个观测值的平均值。

     

S 1 初始化对合成移动平均线影响的重要性取决于α;较小的α值使得S 1 的选择比较大的α值相对更重要,因为较高的α会使较早的观察值更快地折现。

答案 1 :(得分:1)

我相信你在calcEMA函数中遗漏了一个括号。它有助于将表达式分解为具有临时变量的较小表达式,以保存中间结果。

int Trade::calcEMA()
{       
   auto mult = 2/(timePeriod_ + 1);
   auto rslt = (currentStock_ - lastEMA_) * mult + lastEMA_;      
   return rslt;
}

另外,正如PaulMcKenzie在评论中指出的那样,你正在使用整数进行浮点数学运算。您应该考虑使用浮点数或双精度数来避免截断。

像您这样的EMA定义了一段时间,上面称为timePeriod_。虽然daysInTrading_小于或等于timePeriod_,但lastEMA_应该设置为正常平均值。一旦daysInTrading_大于timePeriod_,您就可以开始调用calcEMA函数并正确初始化lastEMA_。请记住在每次调用calcEMA后更新lastEMA_。这是一个可能的实现:

#include <vector>
#include <list>
#include <iostream>

// calculate a moving average
double calcMA(double previousAverage, unsigned int previousNumDays, double newStock)
{
   auto rslt = previousNumDays * previousAverage + newStock;
   return rslt / (previousNumDays + 1.0);
}

// calculate an exponential moving average
double calcEMA(double previousAverage, int timePeriod, double newStock)
{
   auto mult = 2.0 / (timePeriod + 1.0);
   auto rslt = (newStock - previousAverage) * mult + previousAverage;
   return rslt;
}

class Trade
{
   unsigned int timePeriod_ = 5;
   double lastMA_ = 0.0;
   std::list<double> stockPrices_;

public:

   void addStock(double newStock)
   {
      stockPrices_.push_back(newStock);
      auto num_days = stockPrices_.size(); 

      if (num_days <= timePeriod_)
         lastMA_ = calcMA(lastMA_, num_days - 1, newStock);
      else
         lastMA_ = calcEMA(lastMA_, num_days - 1, newStock);
   }

   double getAverage() const { return lastMA_; }
};

int main()
{
   std::vector<double> stocks =
     {1000, 1100, 1200, 1300, 1400, 1500, 1400, 1300, 1200, 1100, 1000};

   Trade trade;
   for (auto stock : stocks)
      trade.addStock(stock);

   std::cout << "Average: " << trade.getAverage() << std::endl;

   return 0;
}

答案 2 :(得分:1)

通常有两种可接受的EMA形式。

传统:

m = 2/(1+n)                               // where n >= 1
EMA = m * currentPrice + (1-m) * previousEMA

rf the Wilder:

m = 1/n                                   // where n >= 1
EMA Wilder = m * currentPrice + (1-m) * previousEMA