In our previous post, we have explained how to compute simple moving averages in Pandas and Python. In this post, we explain how to compute exponential moving averages in Pandas and Python. It should be noted that the exponential moving average is also known as an exponentially weighted moving average in finance, statistics, and signal processing communities. The codes that are explained in this post and in our previous posts can be found on the GitHub page. The video accompanying this post is given below.
In order to motivate the definition of the exponential moving averages, let us first consider an average of time series , defined as follows:
(1)
where is the average and is the averaging window. The previous equation can be written as follows
(2)
From the last equation, we have
(3)
or
(4)
The last equation can be written compactly as follows
(5)
(6)
where . The previous derivation is very instructive since as you will see in the sequel, the equation (6) represents a special form of the exponential moving average. Formally speaking, the exponential moving average of the time series is defined by
(7)
where is a smoothing factor. Now compare (5) and (6) with (7). We can immediately observe that if , then the exponential moving average becomes the classical average.
Now, the main question is how to select the parameter . One approach is to try to fit the parameter from the time series data using optimization methods, for more details, see for example the Wikipedia page.
In the sequel, we are going to use the Pandas ewm() function. From the help page of this function, we see that this function selects the parameter alpha as follows
(8)
where is a user-selected time span or a time window. In the sequel, we present the Python code for computing the exponential moving averages. The codes are very similar to the codes that are thoroughly explained in our previous post on simple moving averages and for brevity, we will only provide a brief explanation.
The following code blocks import the necessary libraries, define the parameters, and download and save the stock time series of Apple (the famous company that produces computers, phones, and other electronic devices).
# -*- coding: utf-8 -*-
"""
Exponential moving average of stock prices
https://en.wikipedia.org/wiki/Exponential_smoothing
Author:
Aleksandar Haber
Date: January 25, 2021
Some parts of this code are inspired by the following sources:
-- https://www.datacamp.com/community/tutorials/pickle-python-tutorial
-- Pandas help: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.ewm.html
-- "Learn Algorithmic Trading: Build and deploy algorithmic trading systems and strategies
using Python and advanced data analysis", by Sebastien Donadio and Sourav Ghosh
"""
# standard imports
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# used to download the stock prices
import pandas_datareader as pdr
time_period =30 # moving averages window
alpha= 2/(time_period+1) # smoothing factor
# some suggestions for choosing the smoothing factor
# https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.ewm.html
# define the dates for downloading the data
startDate= '2016-01-01'
endDate= '2021-01-01'
# Read about Python pickle file format: https://www.datacamp.com/community/tutorials/pickle-python-tutorial
fileName = 'downloadedData.pkl'
stock_symbol='AAPL'
# this piece of code either reads the data from the saved file or if the saved file does not exist
# it downloads the data
try:
data=pd.read_pickle(fileName)
print('Loading the data from the local disk.')
except FileNotFoundError:
print('The data is not found on the local disk.')
print('Downloading the data from Yahoo.')
data = pdr.get_data_yahoo(stock_symbol,start=startDate,end=endDate)
# save the data to file
print('Saving the data to the local disk.')
data.to_pickle(fileName)
The following code lines are used to inspect and plot the data. We are mainly interested in adjusted closing prices that are denoted by the string “Adj Close” (this is the last column of the “data” object).
# inspect the data
data.head()
data['Adj Close'].plot()
The following code lines are used to compute the exponential moving average of the adjusted closing price and to plot the results.
# isolate the closing price
closingPrice = data['Adj Close']
# isolate the values
closingPrice.values
exponential_moving_average=[] # list used to store the computed exponential moving averages
exponential_moving_average_value=0 # used to store the value of the computed exponential moving average
for price in closingPrice:
if (exponential_moving_average_value==0): # initialization
exponential_moving_average_value=price
else:
exponential_moving_average_value=alpha*price+(1-alpha)*exponential_moving_average_value
exponential_moving_average.append(exponential_moving_average_value)
# append the original data frame with the computed exponential moving average
# that is, add a column that will contain the values of the computed exponential moving averages
data=data.assign(Exponential_moving_average=pd.Series(exponential_moving_average,index=data.index))
#plot the results
fig1=plt.figure(figsize=(10,8))
ax1=fig1.add_subplot(111,ylabel='Stock price in dollars')
data['Adj Close'].plot(ax=ax1, color='b', lw=3, legend=True)
data['Exponential_moving_average'].plot(ax=ax1, color='r', lw=3, legend=True )
plt.savefig('exponential_moving_average.png')
plt.show()
The results are shown in Fig. below.
Next, we explain how to easily compute the exponential moving averages using the built-in Pandas function ewm(). We also compare the results with the manually computed exponential moving averages. The code is given below.
# now verify the results by using the Pandas function
# https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.ewm.html
exponential_moving_average_pandas=data['Adj Close'].ewm(span=time_period, adjust=False).mean()
# explanation of the parameters
# span : float, optional - Specify decay in terms of span, α=2/(span+1), for span≥1.
#adjust: bool, default True
# When adjust=False, the exponentially weighted function is calculated recursively:
# y0=x0
# yt=(1−α)yt−1+αxt,
# CONSEQUENTLY, the parameter "adjust" should be set to "False"
#compare the results
fig2=plt.figure(figsize=(10,8))
ax2=fig2.add_subplot(111,ylabel='Moving averages [$]')
data['Exponential_moving_average'].plot(ax=ax2, color='r', lw=10, label='Manually computed', legend = True )
exponential_moving_average_pandas.plot(ax=ax2, color='k', lw=3, label='Pandas ewm() function', legend = True)
plt.savefig('exponential_moving_average_comparison.png')
plt.show()
This code block produces the following figure that compares the Pandas function ewm() with the manual method for computing the exponential moving averages.
Figure 2 shows that the two methods produce the identical results.
This is the end of this lecture. In this lecture we learned how to compute the exponential moving averages of stock prices using two methods.