Intraday Trading Rules

Our trading strategy will buy recent winners as computed by our end-of-day pipeline. But we will try to improve the strategy performance by adding an intraday twist: we will only buy if the security is down for the day. In other words, we will enter positions on a counter-move.

Testing the performance of intraday trading rules generally requires running a full backtest. However, to facilitate writing the code, you can access intraday data in a notebook using the same API that is available in a Zipline strategy. This allows you to get your code semantics right before transitioning to a backtest.

Introducing the Data Object

In a Zipline strategy, two parameters are passed to user-defined functions: the context parameter, where users can store custom variables about the algorithm's state, and the data parameter, which is used to access intraday (and optionally end-of-day) price data:

def handle_data(context, data):
   ...

The data parameter passed to Zipline functions is always tied to the current simulation minute. That is, if it is currently 2020-07-01 at 3:30 PM within the backtest simulation, the data object allows you to query prices as of that minute and looking backward from that minute.

You can access the data object in notebooks by specifying a particular "as-of" minute you want to use:

In [1]:
from zipline.research import get_data
data = get_data("2020-07-01 15:30:00") # no bundle specified, so the default bundle will be used

Load assets

The data object's methods take one or more Zipline assets (zipline.assets.Asset) as their first argument. There are two ways to get assets in a notebook.

The first option is to run a pipeline and get the assets from the factor data. For example, using our previous pipeline, we could have accessed assets like this:

factors = run_pipeline(pipeline, start_date="2017-01-01", end_date="2019-01-01")
assets = factors.xs("2017-01-03").index

The second option, which we will demonstrate here, is to use the sid function to load asset objects by sid. First, look up the sids in the master database:

In [2]:
from quantrocket.master import get_securities
securities = get_securities(symbols=['AAPL','JNJ'], fields=['Symbol', 'Exchange'])
securities
Out[2]:
SymbolExchange
Sid
FIBBG000B9XRY4AAPLXNAS
FIBBG000BMHYD1JNJXNYS

Then load the asset objects:

In [3]:
from zipline.research import sid

aapl = sid("FIBBG000B9XRY4") # no bundle specified, so the default bundle will be used
jnj = sid("FIBBG000BMHYD1")

Now we can use the data object to calculate the intraday return as of the simulation minute we chose:

In [4]:
current_prices = data.current([aapl, jnj], "price")
prior_closes = data.history([aapl, jnj], "close", 2, "1d").iloc[0]
intraday_returns = (current_prices - prior_closes) / prior_closes
intraday_returns
Out[4]:
Equity(FIBBG000B9XRY4 [AAPL])   -0.000713
Equity(FIBBG000BMHYD1 [JNJ])     0.001387
dtype: float64

We will later transfer this snippet of code to our Zipline .py file, where it will be used to determine whether to enter.