Once you have a pipeline, there are two main things you can do with it:
Analyzing your pipeline output with Alphalens makes sense if your pipeline includes factors that might be predictive of forward returns; it doesn't make sense if you are only using your pipeline for universe selection.
In this notebook, we will create a pipeline with a moving average factor for the TradableStocksUS
universe, then use Alphalens to analyze whether the factor is predictive.
from zipline.pipeline import Pipeline
from zipline.research import run_pipeline
from zipline.pipeline.data import EquityPricing, master
from zipline.pipeline.factors import SimpleMovingAverage
# import our TradableStocksUS function
from codeload.pipeline_tutorial.tradable_stocks import TradableStocksUS
Let's create a factor that measures the percent difference between the 10-day and 30-day moving averages (close price). In other words, we are computing the degree to which the 10-day moving average is above the 30-day moving average.
As an added benefit, we will include each stock's sector in our pipeline output, which will allow use to view some additional Alphalens plots breaking down the factor's performance by sector.
def make_pipeline():
universe = TradableStocksUS()
# 10-day close price average.
mean_10 = SimpleMovingAverage(inputs=[EquityPricing.close], window_length=10, mask=universe)
# 30-day close price average.
mean_30 = SimpleMovingAverage(inputs=[EquityPricing.close], window_length=30, mask=universe)
# Percent difference factor.
percent_difference = (mean_10 - mean_30) / mean_30
return Pipeline(
columns={
'percent_difference': percent_difference,
'sector': master.SecuritiesMaster.usstock_Sector.latest
},
screen=universe
)
Running this pipeline will result in a DataFrame containing 2 columns, percent_difference
, our predictive factor, and sector
.
factors = run_pipeline(make_pipeline(), start_date='2015-01-01', end_date='2016-01-01')
factors.head()
percent_difference | sector | ||
---|---|---|---|
2015-01-02 00:00:00+00:00 | Equity(FIBBG000C2V3D6 [A]) | -0.003377 | Technology |
Equity(FIBBG005P7Q881 [AAL]) | 0.053626 | Industrials | |
Equity(FIBBG003PNL136 [AAMC]) | -0.162339 | Financials | |
Equity(FIBBG000D9V7T4 [AAN]) | 0.043003 | Industrials | |
Equity(FIBBG000D6VW15 [AAOI]) | -0.004641 | Technology |
To see if our factor is predictive of forward returns, we use the factor data to request forward returns for the assets and dates in our pipeline output. In this example we request returns for the next day, next week (5 trading days), and next month (approx. 21 trading days).
from zipline.research import get_forward_returns
# Get forward returns for the next day, next week, and next month
forward_returns = get_forward_returns(factors, periods=[1,5,21])
Then, we format the factor and returns data for use with Alphalens, passing in our sectors as the grouping key (grouping is optional):
import alphalens as al
al_data = al.utils.get_clean_factor(
factors["percent_difference"],
forward_returns,
groupby=factors['sector']
)
Dropped 8.7% entries from factor data: 8.7% in forward returns computation and 0.0% in binning phase (set max_loss=0 to see potentially suppressed Exceptions). max_loss is 35.0%, not exceeded: OK!
Finally, we create the Alphalens tear sheet.
In this example, the "Mean Period Wise Return By Factor Quantile" plot reveals that forward returns increase from quantiles 1 to 4, but then drop off in quantile 5. Intuitively, this tells us that stocks tend to perform better when their 10-day moving average is above their 30-day moving average, up to a point. But if the 10-day moving average gets too far stretched above the 30-day moving average, the forward returns are poor.
from alphalens.tears import create_full_tear_sheet
create_full_tear_sheet(al_data, by_group=True)
Quantiles Statistics
min | max | mean | std | count | count % | |
---|---|---|---|---|---|---|
factor_quantile | ||||||
1 | -0.679635 | 0.000720 | -0.063912 | 0.048896 | 100677 | 20.018731 |
2 | -0.072488 | 0.021709 | -0.017221 | 0.015982 | 100535 | 19.990495 |
3 | -0.051018 | 0.037782 | -0.000005 | 0.014459 | 100537 | 19.990893 |
4 | -0.035756 | 0.058825 | 0.016335 | 0.014920 | 100535 | 19.990495 |
5 | -0.018567 | 1.518380 | 0.057822 | 0.048915 | 100630 | 20.009385 |
Returns Analysis
1D | 5D | 21D | |
---|---|---|---|
Ann. alpha | -0.035 | -0.033 | -0.033 |
beta | -0.145 | -0.189 | -0.305 |
Mean Period Wise Return Top Quantile (bps) | -2.190 | -2.084 | -1.322 |
Mean Period Wise Return Bottom Quantile (bps) | -0.279 | -0.978 | -1.610 |
Mean Period Wise Spread (bps) | -1.911 | -1.041 | 0.369 |
<Figure size 1152x432 with 0 Axes>
Information Analysis
1D | 5D | 21D | |
---|---|---|---|
IC Mean | 0.005 | 0.004 | 0.001 |
IC Std. | 0.129 | 0.129 | 0.125 |
Risk-Adjusted IC | 0.037 | 0.034 | 0.011 |
t-stat(IC) | 0.558 | 0.524 | 0.167 |
p-value(IC) | 0.578 | 0.601 | 0.867 |
IC Skew | -0.023 | -0.123 | 0.442 |
IC Kurtosis | 0.130 | -0.026 | -0.474 |
Turnover Analysis
1D | 5D | 21D | |
---|---|---|---|
Quantile 1 Mean Turnover | 0.064 | 0.283 | 0.721 |
Quantile 2 Mean Turnover | 0.153 | 0.531 | 0.782 |
Quantile 3 Mean Turnover | 0.182 | 0.580 | 0.775 |
Quantile 4 Mean Turnover | 0.159 | 0.543 | 0.773 |
Quantile 5 Mean Turnover | 0.068 | 0.306 | 0.771 |
1D | 5D | 21D | |
---|---|---|---|
Mean Factor Rank Autocorrelation | 0.99 | 0.82 | 0.062 |
For more information on interpreting an Alphalens tear sheet, please see Lecture 38 of the Quant Finance Lecture series in the Code Library.