futures_pair_trading.py
algo¶This notebook shows how to run a futures backtest in Zipline using the QuantRocket client then analyze the backtests results inside the notebook using pyfolio.
The algo is a pairs trading algo using crude oil and gasoline futures. It is adapted from the Quantopian futures tutorial.
First, let's collect historical data for the backtest. (Typically you might use the command line to perform these steps, but they can also be performed using the Python client, and we show them here to make the notebook more self-contained.)
The first step is to fetch the listings for CL and RB. This retrieves all the individual contracts from IB for the underlying symbols.
from quantrocket.master import collect_listings
collect_listings(exchanges="NYMEX", sec_types=["FUT"], symbols=["CL", "RB"])
Monitor flightlog for the listings to be fetched, then make a universe:
from quantrocket.master import download_master_file, create_universe
import io
# Download the listings we just fetched
f = io.StringIO()
download_master_file(f, exchanges=["NYMEX"], sec_types=["FUT"], symbols=["CL", "RB"])
# then create a universe
create_universe("cl-rb", infilepath_or_buffer=f)
Now create a history database and fetch the data:
from quantrocket.history import create_db, collect_history
create_db("cl-rb-1d", universes=["cl-rb"], bar_size="1 day")
collect_history("cl-rb-1d")
Monitor flightlog for the historical data to be fetched, then move on to the next step, ingesting the data into Zipline.
Next we ingest our history database into Zipline. The historical data for each individual contract is ingested, then Zipline will represent the contracts as continuous futures contracts at the time we run our backtest.
from quantrocket.zipline import ingest_bundle
ingest_bundle(history_db="cl-rb-1d", calendar="us_futures")
QuantRocket looks for Zipline strategies inside the "zipline" directory, so execute the following cell to "install" the strategy by moving the file to that location:
The
!
sytax below lets us execute terminal commands from inside the notebook.
# make directory if doesn't exist
!mkdir -p /codeload/zipline
!mv futures_pairs_trading.py /codeload/zipline/
Next, to run the backtest, we run the futures_pairs_trading.py
algo file.
QuantRocket returns the Zipline backtest results as a CSV. We write this CSV to a file.
(Note that the backtest runs remotely on the zipline service, not inside the jupyter service, i.e. not in the notebook environment itself. QuantRocket's jupyter service doesn't support running Zipline backtests via the %%zipline
extension.)
from quantrocket.zipline import run_algorithm
run_algorithm("futures_pairs_trading.py",
bundle="cl-rb-1d",
start="2015-02-04",
end="2017-06-30",
filepath_or_buffer="futures_pair_trading_results.csv")
We can easily get a pyfolio tear sheet:
import pyfolio as pf
pf.from_zipline_csv("futures_pair_trading_results.csv")
The CSV result file returned by run_algorithm
contains several DataFrames stacked into one: the Zipline performance results, plus the extracted returns, transactions, positions, and benchmark returns from those results. If you want to explore the Zipline backtest results directly, you can use the ZiplineBacktestResult
utility class to parse the CSV and look at the perf
DataFrame:
from quantrocket.zipline import ZiplineBacktestResult
zipline_results = ZiplineBacktestResult.from_csv("futures_pair_trading_results.csv")
print(zipline_results.perf.head())