How to code your own stock backtester [PART 1: Getting Data]

Lucas Moyer
3 min readNov 11, 2023

--

This article is one in a series of coding your own backtester. Here is the intro for some background.

To code a MACD (Moving Average, Convergence/Divergence) backtesting strategy, we need to take the price data over a time period and simulate buying and selling of stocks and the management of your portfolio value.

This means, we need the Open and Closing prices of a stock for each day in our time range.

One option we have for getting this data is through a python package called pandas-datareader

!pip install pandas_datareader

from pandas_datareader import data as pdr

Another feature of this code is that we will be saving whatever data we grab so we don’t have to constanlty redownload the stock data or possibly be limited by api request limits from pandas_datareader

The way we will store the data is in a python dictionary with the key being the stock ticker and the value being the pandas dataframe

savedData = {
'AAPL': <pandas>
'MSFT': <pandas>
'T': <pandas>
}

This is a basic use of pandas_datareader


from pandas_datareader import data as pdr
savedData = {}
import yfinance as yfin # this is a support package for pandas_datareader to work
yfin.pdr_override()


def getStocksData(ticker, start='2023-01-01', end='2023-09-01', save_new=False, saveToCSV=True):
stock_data = pdr.get_data_yahoo(ticker, start=start,end=end)
savedData[ticker] = stock_data # saved the stock data to our python dictionary
return stock_data

data = getStocksData('T')

The data comes back as:

Now we have a function that takes a stock ticker and a range of dates and returns the stock information!

If we want a more sophisticated way to save our stock information so we can access, we can save the python dictionary to a .pkl file(pronounced “pickle”). That way, if we restart our python environment, we wouldn’t have to redownload the data.

from pandas_datareader import data as pdr
import yfinance as yfin
yfin.pdr_override()

def getStocksData(ticker, start='1/1/2023', end='9/1/2023', save_new=False, saveToCSV=True):
path=r"/Users/lucasmoyer/development/two-dolla/stocks.pkl"
savedData = {}
with open(path, 'rb') as handle:
savedData = pickle.load(handle)

if (save_new or ticker not in savedData):
stock_data = pdr.get_data_yahoo(ticker, start=start,end=end)
savedData[ticker] = stock_data # saved the stock data to our python dictionary
with open(path, 'wb') as handle:
pickle.dump(savedData, handle,
protocol=pickle.HIGHEST_PROTOCOL)
else:
return savedData[ticker]
return stock_data

data = getStocksData('T', start='2023-01-01', end='2023-09-01', save_new=False)

One more way to do it is to use the requests_cache python package like so:

from pandas_datareader import data as pdr
import yfinance as yfin
yfin.pdr_override()
from pandas_datareader.yahoo.headers import DEFAULT_HEADERS
import datetime
import requests_cache

expire_after = datetime.timedelta(days=3)
session = requests_cache.CachedSession(cache_name='cache', backend='sqlite', expire_after=expire_after)
session.headers = DEFAULT_HEADERS

def getStocksData(ticker, start='2023-01-01', end='2023-09-01', save_new=False, saveToCSV=True):
stock_data = pdr.get_data_yahoo(ticker, start=start,end=end,session=session)
savedData[ticker] = stock_data # saved the stock data to our python dictionary
return stock_data

data = getStocksData('T')

Well there you have it! Now you can get the stock data, and save it for FREE!
What can you do now? You could try to sell this data as a service for other stock traders, or we can manipulate this data into a trading indicator for us to make stock trades with.

In part 2, we will transform this stock data into a MACD indicator.

Stay tuned!

Happy Halloween!

--

--

Lucas Moyer

I strive to wake up everyday and pursue what I find most interesting. Writer for The Startup. Owner of The Koi Life medium.com/lucas-moyer