Notebook

Clenow Momentum Alphalens

In [27]:
from quantopian.pipeline import Pipeline
from quantopian.research import run_pipeline
from quantopian.pipeline.filters import QTradableStocksUS, Q500US
from quantopian.pipeline.data import factset, USEquityPricing, Fundamentals
from quantopian.pipeline.classifiers.fundamentals import Sector
from quantopian.pipeline.factors import Returns, SimpleMovingAverage, CustomFactor, RSI

from alphalens.performance import mean_information_coefficient
from alphalens.utils import get_clean_factor_and_forward_returns
from alphalens.tears import create_information_tear_sheet, create_returns_tear_sheet

from scipy.stats.mstats import winsorize
from sklearn import preprocessing
import numpy as np

from scipy import stats
In [28]:
def _slope(ts):
    # calculates expected yearly returns, i.e. 0.30 is 30%.
    x = np.arange(len(ts))  
    log_ts = np.log(ts)  
    slope, intercept, r_value, p_value, std_err = stats.linregress(x, log_ts)  
    annualized_slope = (np.power(np.exp(slope), 250) - 1) 
    return annualized_slope * (r_value ** 2)  
In [47]:
class ClenowMomentum(CustomFactor):
    inputs = [USEquityPricing.close]
    window_length = 90
    window_safe = True
    def compute(self, today, assets, out, close):
        res = []
        for i in range(close.shape[1]):
            res.append(_slope(close[:, i]))
        out[:] = res
In [52]:
def make_pipeline():
    return Pipeline(
        columns = {'clenow_momentum': ClenowMomentum(mask=QTradableStocksUS())},
        screen = QTradableStocksUS()
    )
In [53]:
factor_data = run_pipeline(make_pipeline(), '2014-9-1', '2018-9-1')
In [54]:
pricing_data = get_pricing(factor_data.index.levels[1], '2014-9-1', '2018-4-12', fields='open_price')
In [55]:
factor_data.head()
Out[55]:
clenow_momentum
2014-09-02 00:00:00+00:00 Equity(2 [ARNC]) 1.073375
Equity(24 [AAPL]) 0.666485
Equity(31 [ABAX]) 0.346337
Equity(41 [ARCB]) -0.078149
Equity(52 [ABM]) -0.063804

Determine The Decay Rate Of Your Alpha Factor.

In [62]:
longest_look_forward_period = 90 # week = 5, month = 21, quarter = 63, year = 252
range_step = 5

merged_data = get_clean_factor_and_forward_returns(
    factor = factor_data['clenow_momentum'],
    prices = pricing_data,
    periods = range(1, longest_look_forward_period, range_step)
)
    
mean_information_coefficient(merged_data).plot(title="IC Decay")
Dropped 19.6% entries from factor data: 19.6% 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!
Out[62]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f9b0b784050>

Create Tear Sheets

In [63]:
merged_data = get_clean_factor_and_forward_returns(
    factor = factor_data['clenow_momentum'],
    prices = pricing_data,
    binning_by_group = False,
    periods = ([20, 30, 40, 60, 80, 90])
)

create_information_tear_sheet(merged_data)
create_returns_tear_sheet(merged_data)
Dropped 20.0% entries from factor data: 20.0% 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!
Information Analysis
20D 30D 40D 60D 80D 90D
IC Mean 0.014 0.016 0.021 0.031 0.035 0.035
IC Std. 0.146 0.135 0.130 0.129 0.125 0.119
Risk-Adjusted IC 0.096 0.122 0.164 0.241 0.277 0.292
t-stat(IC) 2.763 3.488 4.699 6.889 7.937 8.359
p-value(IC) 0.006 0.001 0.000 0.000 0.000 0.000
IC Skew -0.136 -0.035 -0.081 -0.192 -0.089 0.006
IC Kurtosis -0.258 -0.165 0.204 -0.353 -0.549 -0.637
<matplotlib.figure.Figure at 0x7f9b1d411e50>