Now that we've covered the basic components of the Pipeline API, let's construct a pipeline that we might want to use in an algorithm.
To do so, we will create a filter to narrow down the full universe of US stocks to a subset of tradable securities, defined as those securities that meet all of the following criteria:
usstock_SecurityType2
field will automatically exclude preferred stocks, ETFs, ADRs, and LPs, as the latter all have different values for usstock_SecurityType2
.Former Quantopian users may notice that this universe is modeled on Quantopian's most popular universe, QTradableStocksUS
, described in this archived Quantopian forum post. To reduce data dependencies, we have omitted one rule, namely that market cap must be over \$500M. See the note further down if you have a Sharadar fundamentals subscription and would like to add this market cap filter.
Let's create a filter for each criterion and combine them together to create a TradableStocksUS
filter.
from zipline.pipeline import EquityPricing, master
from zipline.pipeline.factors import AverageDollarVolume, Latest
Now we can define our filters. As discussed in the lesson on masking, we use masks in the later steps of our asset funnel to reduce computational load.
def TradableStocksUS():
# Equities listed as common stock (not preferred stock, ETF, ADR, LP, etc)
common_stock = master.SecuritiesMaster.usstock_SecurityType2.latest.eq('Common Stock')
# Filter for primary share equities; primary shares can be identified by a
# null usstock_PrimaryShareSid field (i.e. no pointer to a primary share)
is_primary_share = master.SecuritiesMaster.usstock_PrimaryShareSid.latest.isnull()
# combine the security type filters to begin forming our universe
tradable_stocks = common_stock & is_primary_share
# also require high dollar volume
tradable_stocks = AverageDollarVolume(window_length=200, mask=tradable_stocks) >= 2.5e6
# also require price > $5. Note that we use Latest(...) instead of EquityPricing.close.latest
# so that we can pass a mask
tradable_stocks = Latest(EquityPricing.close, mask=tradable_stocks) > 5
# also require no missing data for 200 days
tradable_stocks = EquityPricing.close.all_present(200, mask=tradable_stocks)
has_volume = EquityPricing.volume.latest > 0
tradable_stocks = has_volume.all(200, mask=tradable_stocks)
return tradable_stocks
Note that when defining our filters, we used several methods that we haven't yet seen including isnull
, all
, and all_present
. Documentation on these methods is available in the Pipeline API Reference or by clicking on the method name in JupyterLab and pressing Control.
If you have a Sharadar fundamentals subscription and would like to add a market cap filter to your universe to fully re-create the QTradableStocksUS
universe, you can do so by adding the following line to the above function:
# also require market cap over $500M
tradable_stocks = Latest([sharadar.Fundamentals.slice(dimension='ARQ', period_offset=0).MARKETCAP], mask=tradable_stocks) >= 500e6
Our universe may be useful to us in numerous notebooks and Zipline algorithms, so a practical next step is to transfer the pipeline code to a .py
file to facilitate code reuse. We have done so in tradable_stocks.py. The universe can now be imported in any notebook or Zipline algorithm as follows:
from codeload.pipeline_tutorial.tradable_stocks import TradableStocksUS
universe = TradableStocksUS()
We'll import and use this universe in the next lesson.
Next Lesson: Using Pipeline with Alphalens