QuantRocket logo
Disclaimer


Zipline Intro › Part 5: Zipline Code


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 (note that we factor out our 252-day momentum window into a module-level attribute, MOMENTUM_WINDOW, which will facilitate running a parameter scan later):

MOMENTUM_WINDOW = 252

def make_pipeline():
    """
    Create a pipeline that filters by dollar volume and 
    calculates return.
    """
    pipeline = Pipeline(
        columns={
            "returns": Returns(window_length=MOMENTUM_WINDOW),
        },
        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: algo.Context):
    """
    Called once at the start of a backtest, and once per day in 
    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: algo.Context, data: algo.BarData):
    """
    Called every day before market open.
    """
    factors = algo.pipeline_output('pipeline')

    # Get the top 3 stocks by return
    returns = factors["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: algo.Context, data: algo.BarData):    
    # 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