Zipline Strategy Code

The strategy code is provided in winners.py.

Install strategy file

To "install" the strategy, execute the following cell to move the strategy file to the /codeload/zipline directory, where Zipline looks:

The ! sytax below lets us execute terminal commands from inside the notebook.

In [1]:
# make directory if doesn't exist
!mkdir -p /codeload/zipline

!mv winners.py /codeload/zipline/

Strategy overview

We define our pipeline in a helper function called make_pipeline, using code copied from an earlier notebook:

def make_pipeline():
    """
    Create a pipeline that filters by dollar volume and 
    calculates 1-year return.
    """
    pipeline = Pipeline(
        columns={
            "1y_returns": Returns(window_length=252),
        },
        screen=AverageDollarVolume(window_length=30) > 10e6
    )
    return pipeline

In the initialize function (required in all Zipline strategies), we attach the pipeline to the algorithm, and we schedule a custom function called rebalance that will run every market day 30 minutes before the close:

def initialize(context):
    """
    Called once at the start of a backtest, and once per day at
    the start of live trading.
    """
    # Attach the pipeline to the algo
    algo.attach_pipeline(make_pipeline(), 'pipeline')

    # Rebalance every day, 30 minutes before market close.
    algo.schedule_function(
        rebalance,
        algo.date_rules.every_day(),
        algo.time_rules.market_close(minutes=30),
    )

In before_trading_start, another built-in function which Zipline calls once per day before the market opens, we gather the pipeline output for that day and select our winners (copying code from an earlier notebook):

def before_trading_start(context, data):
    """
    Called every day before market open.
    """
    factors = algo.pipeline_output('pipeline')

    # Get the top and bottom 3 stocks by 1-year return
    returns = factors["1y_returns"].sort_values(ascending=False)
    context.winners = returns.index[:3]

Finally, in the custom rebalance function which we scheduled to run before the close, we calculate the intraday returns (again copying code from an earlier notebook) and add logic for the entering and exiting of positions:

def rebalance(context, data):    
    # calculate intraday returns for our winners
    current_prices = data.current(context.winners, "price")
    prior_closes = data.history(context.winners, "close", 2, "1d").iloc[0]
    intraday_returns = (current_prices - prior_closes) / prior_closes

    positions = context.portfolio.positions

    # Exit positions we no longer want to hold
    for asset, position in positions.items():
        ...

Next Up

Part 6: Zipline Backtest