patternpythonMinor
Calculating Exponential Moving Average in Python
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
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
emaonly needs to run once.
- will fail with large enough value of
windowdue to overflowing Python's call stack.
- Please document at least the parameters of each function, eg. that
windowis the length of the window, and thatpositioncounts backwards from the end ofdata. (In fact things would be clearer ifpositionwere a normal forward index intodata)
- Raise an exception when you find a parameter has an invalid value. Returning
Noneinstead will only cause a more confusing exception later. In fact, if I tryIndicators().ema(close_prices, 600)I get infinite recursion becausesmareturnsNone, which makesemacallsmaover and over again.
- The previous point also reveals that
if len(data)
- The + 1
indata[-window2 + 1:-window + 1]don't seem correct to me. I suppose you wantdata[-window2:-window]
- The statement return previous_ema
is in an odd place because at that point you have calculated a newcurrent_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_emaCode 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_emaContext
StackExchange Code Review Q#70510, answer score: 6
Revisions (0)
No revisions yet.