The 2 tools for professional backtesting: Step-by-step Zipline for beginners
The 2 tools for professional backtesting: Step-by-step Zipline for beginners
Backtesting is the only way to really test algorithmic trading strategies.
Doing it right will give you the best chance of making money.
Doing it wrong will guarantee a $0 account balance.
It's not your fault: most backtesting frameworks lack features that reflect reality.
Things like commission, slippage, and special order types are all things algorithmic traders need to worry about.
If the framework you use doesn’t have these things, then you have two options:
❌ Waste time rebuilding your strategies in a “production” framework
❌ Lose money when your strategy starts trading live
Neither sounds great.
So what can you do about it?
Today, you use professional backtesting tools Zipline and PyFolio.
Zipline is an algorithmic trading simulator. It was built and maintained by Quantopian before being acquired by Robinhood in 2020. It's is a professional backtesting framework which means you can use it for both research and live trading.
No more rebuilding your strategy.
Some of what Zipline offers:
✅ Ease of Use: Zipline gets out of your way so that you can focus on strategy development
✅ Realistic: Zipline includes life-like slippage and commission models, order types, and order delays.
✅ Batteries Included: Common statistics like moving average and linear regression are easy to use inside your strategy
✅ PyData Integration: Historical data and output of performance statistics use pandas DataFrames to integrate into other tools
✅ Statistics and Machine Learning Libraries: You can use libraries like scikit-learn to develop state-of-the-art trading systems
✅ Suite of performance and analysis tools: Zipline works well with performance analysis tools like PyFolio, Alphalens, Empyrical
Imports and setup
Start with the imports.
You’ll use pandas_datareader to get data to compare your strategy with the S&P 500, matplotlib for charting, and PyFolio for performance analysis.
1import pandas as pd
2import pandas_datareader.data as web
3
4import matplotlib.pyplot as plt
5
6from zipline import run_algorithm
7from zipline.api import order_target, record, symbol
8from zipline.finance import commission, slippage
9
10import pyfolio as pf
11
12import warnings
13warnings.filterwarnings('ignore')
Since you’re building the backtest in Jupyter Notebook, you need to load the Zipline “magics.” Running this lets you run the Zipline command line right in your Notebook.
1%load_ext zipline
Ingesting free price data
Zipline creates data “bundles” for backtesting. You can build custom bundles to ingest any data you want.
Today, you’ll use the pre-built Quandl bundle to ingest price data between 2000 and 2018 for free.
1! zipline ingest -b quandl
You will see Zipline working its magic to download the data and package it into highly efficient data stores.
Building the algorithm
Every Zipline strategy must have an initialize function. This is run at the beginning of the strategy.
Here, you set a counter to track the days, the symbol to trade, and set the commission and slippage models.
1def initialize(context):
2 context.i = 0
3 context.asset = symbol("AAPL")
4
5 context.set_commission(commission.PerShare(cost=0.01))
6 context.set_slippage(slippage.FixedSlippage(spread=0.01))
Every Zipline strategy must also have a handle_data function.
This function is run at every “bar.” Depending on your data, it might run every minute or day. handle_data is where your strategy logic lives.
In today’s example, you will build a simple dual-moving average cross-over strategy.
1def handle_data(context, data):
2 # Skip first 50 days to get full windows
3 context.i += 1
4 if context.i < 50:
5 return
6
7 # Compute averages
8 # data.history() has to be called with the same params
9 # from above and returns a pandas dataframe.
10 short_mavg = data.history(
11 context.asset,
12 "price",
13 bar_count=14,
14 frequency="1d"
15 ).mean()
16
17 long_mavg = data.history(
18 context.asset,
19 "price",
20 bar_count=50,
21 frequency="1d"
22 ).mean()
23
24 # Trading logic
25 if short_mavg > long_mavg:
26 # order_target orders as many shares as needed to
27 # achieve the desired number of shares.
28 order_target(context.asset, 100)
29 elif short_mavg < long_mavg:
30 order_target(context.asset, 0)
Use the counter to make sure there is enough data to compute the moving averages. If not, skip processing for the day.
If there is enough data, get 14 and 50 days' worth of prices and calculate the moving average.
Then, execute the trading logic.
When the 14-day moving average crosses over a 50-day moving average, the strategy buys 100 shares. When the 14-day moving average crosses under the 50-moving average, it sells them.
Run the backtest
The first step is to define the start and end dates.
1start = pd.Timestamp('2000')
2end = pd.Timestamp('2018')
Then, get data to compare your strategy with the S&P 500.
1sp500 = web.DataReader('SP500', 'fred', start, end).SP500
2benchmark_returns = sp500.pct_change()
Finally, run the backtest.
1perf = run_algorithm(
2 start=start,
3 end=end,
4 initialize=initialize,
5 handle_data=handle_data,
6 analyze=analyze,
7 capital_base=100000,
8 benchmark_returns=benchmark_returns,
9 bundle="quandl",
10 data_frequency="daily",
11)
Take a minute to explore the data in the perf DataFrame. There are 40 columns of rolling analytics! That’s the power of Zipline.
Analyze performance
Now that the backtest is finished, use PyFolio to get a breakdown of the results.
1returns, positions, transactions = \
2 pf.utils.extract_rets_pos_txn_from_zipline(perf)
3
4pf.create_full_tear_sheet(
5 returns,
6 positions=positions,
7 transactions=transactions,
8 live_start_date="2016-01-01",
9 round_trips=True,
10)
This creates a full tear sheet based on your backtest results. There’s a ton of information here, but here are the highlights:
Performance analysis
Cumulative returns
Rolling volatility, Sharpe ratio, and drawdowns
Now you’re comfortable setting up the Zipline backtesting framework. By doing so, you can use the most powerful toolset for algorithmic trading.