Implementing Exponential Moving Average in C++

自闭症网瘾萝莉.ら 提交于 2020-01-23 12:32:27

问题


I am developing a small trading robot as an exercise. He receives stock prices day after day (represented as iterations).

Here's what my Trade class looks like:

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

As you can see from my last two attributes, I wish to implement an Exponential Moving Average as part of a Trend Following Algorithm.

But I think I didn't quite understand how to implement it; here's my calcEMA function that simply calculates the EMA:

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

But when my stock values (passed in a file) are like such:

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

As to make sure my EMA makes sense, and well... it does not !

Where did I go wrong on the operation?

Aditionally, what value should I give lastEMA if it's the first time I call calcEMA?


回答1:


I believe you are missing a parentheses in you calcEMA function. It helps to break the expression up into smaller expressions with temporary variables to hold intermediate results.

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

Also, as PaulMcKenzie pointed out in the comments, you are using ints to do floating point math. You should consider using floats or doubles to avoid truncation.

An EMA like yours is defined for a time period, called timePeriod_ above. While daysInTrading_ is less or equal to timePeriod_, lastEMA_ should just be set to a normal average. Once daysInTrading_ is greater than your timePeriod_ you can start calling your calcEMA function with lastEMA_ properly initialized. Remember to update lastEMA_ after each call to calcEMA. Here is a possible implementation:

#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:


The operation is wrong, as you noticed.

Disclaimer I got this algorithm from wikipedia, and as such might no be accurate. Here (page 3) might be a better one, but I can't judge, I never used those algorithms and so have no idea what I'm talking about :)

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

  • c(EMA) is current EMA
  • y(EMA) is previous EMA
  • a is some "random" value between 0 and 1
  • c(price) is current price

But you did almost the same thing:

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

I don't know why you did 2 / daysInTrading_ + 1, but this will not always be a value between 0 and 1 (actually, it might even be most of the time 0, because those are all intergers).

You put a parenthesis at the wrong place (after b, and not after y(EMA)).

So the operation will now look like this:

lastEMA_ + 0.5 * (currentStock_ - lastEMA_)


For the first lastEMA_, according to Wikipedia:

S1 is undefined. S1 may be initialized in a number of different ways, most commonly by setting S11 [First element in the list], though other techniques exist, such as setting S1 to an average of the first 4 or 5 observations.

The importance of the S1 initialisations effect on the resultant moving average depends on α; smaller α values make the choice of S1 relatively more important than larger α values, since a higher α discounts older observations faster.




回答3:


There are generally two accepted forms of EMA.

The traditional:

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


来源:https://stackoverflow.com/questions/37300684/implementing-exponential-moving-average-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!