HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Calculating Exponential Moving Average in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
exponentialaveragecalculatingmovingpython

Problem

I'm in the process of creating a forex trading algorithm and wanted to try my shot at calculating EMA (Exponential Moving Averages). My results appear to be correct (compared to the calculations I did by hand) so I believe the following method works, but just wanted to get an extra set of eyes to makes sure i'm not missing anything.

Note that this just returns the EMA for the latest price, it doesn't return an array of EMA's as that isn't what I need for my application.

I am using this link as a reference: Exponential Moving Average

```
class Indicators:

def sma(self, data, window):
"""
Calculates Simple Moving Average
http://fxtrade.oanda.com/learn/forex-indicators/simple-moving-average
"""
if len(data) 0:
return self.ema(data, window, position - 1, current_ema)
return previous_ema

# Sample close prices for GBP_USD currency pair on the 2 hour timeframe
close_prices = [1.682555, 1.682545, 1.682535, 1.682655, 1.682455, 1.682685, 1.68205, 1.683245, 1.68405, 1.68401, 1.68506, 1.685825, 1.685955, 1.686595, 1.686325, 1.686375, 1.68701, 1.684995, 1.687245, 1.686135, 1.686205, 1.68724, 1.68753, 1.687775, 1.688245, 1.687745, 1.68699, 1.687285, 1.686325, 1.686295, 1.683945, 1.683035, 1.68401, 1.68327, 1.685185, 1.684755, 1.685265, 1.685325, 1.68625, 1.685645, 1.684355, 1.68387, 1.68413, 1.68416, 1.683425, 1.68481, 1.683245, 1.683645, 1.68325, 1.682745, 1.680385, 1.680655, 1.680875, 1.679995, 1.680445, 1.68064, 1.67937, 1.677735, 1.67769, 1.67777, 1.677525, 1.677435, 1.67766, 1.677835, 1.678005, 1.67823, 1.67902, 1.678605, 1.678425, 1.67876, 1.678555, 1.678505, 1.679085, 1.678755, 1.678125, 1.677495, 1.67677, 1.676205, 1.67716, 1.67741, 1.677135, 1.679295, 1.68054, 1.68143, 1.68115, 1.68111, 1.68055, 1.680495, 1.680565, 1.681375, 1.68244, 1.673395, 1.670885, 1.67156, 1.669525, 1.66906, 1.66903, 1.668935, 1.668805, 1.667895, 1.667905, 1.668485, 1.666345, 1.66832, 1.668005, 1.668615, 1.669305, 1.668

Solution


  • Recursion is a good tool for the right job, but here it is used to accomplish simple looping. As such the code...



  • is more difficult to read and reason about.



  • is slower because much of the code in ema only needs to run once.



  • will fail with large enough value of window due to overflowing Python's call stack.



  • Please document at least the parameters of each function, eg. that window is the length of the window, and that position counts backwards from the end of data. (In fact things would be clearer if position were a normal forward index into data)



  • Raise an exception when you find a parameter has an invalid value. Returning None instead will only cause a more confusing exception later. In fact, if I try Indicators().ema(close_prices, 600) I get infinite recursion because sma returns None, which makes ema call sma over and over again.



  • The previous point also reveals that if len(data)



  • The + 1 in data[-window2 + 1:-window + 1] don't seem correct to me. I suppose you want data[-window2:-window]



  • The statement return previous_ema is in an odd place because at that point you have calculated a new current_ema. This is the base case of the recursion, and it is customary to handle the base case first.



My proposal for
ema`:

def ema(self, data, window):
    if len(data) < 2 * window:
        raise ValueError("data is too short")
    c = 2.0 / (window + 1)
    current_ema = self.sma(data[-window*2:-window], window)
    for value in data[-window:]:
        current_ema = (c * value) + ((1 - c) * current_ema)
    return current_ema

Code Snippets

def ema(self, data, window):
    if len(data) < 2 * window:
        raise ValueError("data is too short")
    c = 2.0 / (window + 1)
    current_ema = self.sma(data[-window*2:-window], window)
    for value in data[-window:]:
        current_ema = (c * value) + ((1 - c) * current_ema)
    return current_ema

Context

StackExchange Code Review Q#70510, answer score: 6

Revisions (0)

No revisions yet.