Notebook

You want to run a lot of backtests. I get it.

We get it. We're working hard so you can eventually start doing that, so in the meanwhile, here's something that might quench your thirst. It's the basic framework for how to run, test, and optimize an algorithm over N number of parameters.

Trust me, it's super simple and easy to follow and will make your life a whole lot easier.

Look at this scenario:

Let's say I want an algorithm that only longs AAPL and SPY but I don't know how much to hold in each security. I could try hitting 'build algorithm' 50 times in the IDE but that's tedious and my macbook can't open that many tabs. So what do I do?

The answer is easy: Create that same algorithm in Zipline and spin up 50 algorithm runs. Each run will have different parameters and because I can get the results of each run through Zipline, I can see exactly which parameter led to the best returns or Sharpe ratio.

If you haven't guessed, I'm going to show you how to do exactly that.

Step One: The Setup

In [40]:
"""
This cell is going to create the basic framework of the algorithm
"""

import zipline
import pytz
from datetime import datetime
import matplotlib.pyplot as pyplot
from collections import defaultdict

from zipline import TradingAlgorithm
from zipline.api import order_target, record, symbol, history, add_history
import numpy as np

#: NOTICE HOW THIS IS OUTSIDE INITIALIZE, BECAUSE IT IS, WE CAN REDFINE IT EVERYTIME WE REDINE INITIALIZE
aapl_weights = .50
spy_weights = .50

def initialize(context):
    context.aapl = 24
    context.spy = 8554
    context.aapl_weights = aapl_weights
    context.spy_weights = spy_weights
    context.first_time = True
    
def handle_data(context, data):
    #: Only order on the first bar
    if context.first_time:
        order_target_percent(context.aapl, context.aapl_weights)
        order_target_percent(context.spy, context.spy_weights)
        context.first_time = False
In [41]:
"""
This cell is going to load in the data, run the algorithm, and print out the Sharpe Ratio
"""

data = get_pricing(
    ['AAPL', 'SPY'],
    start_date='2014-01-01',
    end_date = '2015-02-15',
    frequency='daily'
)

algo_obj = TradingAlgorithm(
    initialize=initialize, 
    handle_data=handle_data
)

#: See this perf_manual object? I'm going to use that to get ending portfolio value
perf_manual = algo_obj.run(data.transpose(2,1,0))

#: Get the sharpe ratio
sharpe = (perf_manual.returns.mean()*252)/(perf_manual.returns.std() * np.sqrt(252))
print "The Sharpe ratio is %0.6f" % sharpe
[2015-04-22 19:36:13.253553] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 19:36:13.254157] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 19:36:13.254574] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
The Sharpe ratio is 2.005427

Okay, look at the process above. What I'm going to do is take this same exact process and rerun it 25 times with different weights for AAPL and SPY. For the sake of this example, I'm going to generate weights that sum to > (1) and show you a really cool heatmap to go along with it.

In [65]:
aapl_weights = [weight for weight in np.arange(0, 1, .2)]
spy_weights = [weight for weight in np.arange(0, 1, .2)]

#: Create a dictionary to hold all the results of our algorithm run
all_sharpes = defaultdict(dict)

for aapl_weight in aapl_weights:
    for spy_weight in spy_weights:
        
        #: Redfine initialize with new weights
        def initialize(context):
            context.aapl = 24
            context.spy = 8554
            context.aapl_weights = aapl_weight
            context.spy_weights = spy_weight
            context.first_time = True

        algo_obj = TradingAlgorithm(
            initialize=initialize, 
            handle_data=handle_data
        )
        perf_manual = algo_obj.run(data.transpose(2,1,0))
        sharpe = (perf_manual.returns.mean()*252)/(perf_manual.returns.std() * np.sqrt(252))
        
        #: Add the result to our dict
        all_sharpes[aapl_weight][spy_weight] = sharpe

all_sharpes = pd.DataFrame(all_sharpes)
all_sharpes.index.name = "SPY Weight"
all_sharpes.columns.name = "AAPL Weight"
[2015-04-22 20:32:44.405010] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:32:44.405629] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:32:44.406044] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:32:47.244669] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:32:47.245282] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:32:47.245719] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:32:50.143468] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:32:50.144069] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:32:50.144500] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:32:52.991096] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:32:52.991695] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:32:52.992116] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:32:55.894009] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:32:55.894607] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:32:55.895025] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:32:58.752676] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:32:58.753286] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:32:58.753720] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:01.662805] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:01.663413] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:01.663828] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:04.569230] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:04.569870] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:04.570287] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:07.419620] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:07.420227] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:07.420642] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:10.311976] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:10.312586] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:10.313012] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:13.156879] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:13.157500] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:13.157920] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:16.055305] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:16.055908] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:16.056323] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:18.905650] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:18.906274] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:18.906695] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:21.803305] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:21.803908] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:21.804325] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:24.653356] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:24.653971] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:24.654396] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:27.555332] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:27.555933] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:27.556357] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:30.417713] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:30.418323] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:30.418741] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:33.313264] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:33.313883] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:33.314308] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:36.163478] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:36.164078] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:36.164494] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:39.058356] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:39.058954] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:39.059369] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:41.901990] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:41.902592] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:41.903020] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:44.807386] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:44.807985] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:44.808407] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:47.652465] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:47.653059] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:47.653495] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:50.557814] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:50.558416] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:50.558830] INFO: Performance: last close: 2015-02-13 21:00:00+00:00
[2015-04-22 20:33:53.459274] INFO: Performance: Simulated 282 trading days out of 282.
[2015-04-22 20:33:53.459875] INFO: Performance: first open: 2014-01-02 14:31:00+00:00
[2015-04-22 20:33:53.460295] INFO: Performance: last close: 2015-02-13 21:00:00+00:00

Step Three: Plot our results

In [63]:
import matplotlib.pyplot as pyplot

def heat_map(df):
    """
    This creates our heatmap using our sharpe ratio dataframe
    """
    fig = pyplot.figure()
    ax = fig.add_subplot(111)
    axim = ax.imshow(df.values,cmap = pyplot.get_cmap('RdYlGn'), interpolation = 'nearest')
    ax.set_xlabel(df.columns.name)
    ax.set_xticks(np.arange(len(df.columns)))
    ax.set_xticklabels(list(df.columns))
    ax.set_ylabel(df.index.name)
    ax.set_yticks(np.arange(len(df.index)))
    ax.set_yticklabels(list(df.index))
    ax.set_title("Sharpe Ratios")
    pyplot.colorbar(axim)
    
#: Plot our heatmap
heat_map(all_sharpes)

print all_sharpes
AAPL Weight       0.0       0.2       0.4       0.6       0.8
SPY Weight                                                   
0.0               NaN  2.044952  2.052969  2.057890  2.060229
0.2          1.062258  1.984622  2.047838  2.063273  2.068378
0.4          1.072133  1.853648  1.999961  2.043871  2.060710
0.6          1.081684  1.739242  1.937322  2.010452  2.042240
0.8          1.091011  1.650665  1.873353  1.970127  2.016760

The best Sharpe ratio seems to come from an AAPL weight of 0.8 and a SPY weight of 0.2.

Step Four: Use your own algorithm

Rinse, repeat. Plug and chug with your own algorithms. Just make sure to replace the initialize, handle_data, and get_pricing methods with your own data.