Notebook
In [15]:
from quantopian.pipeline import CustomFactor
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
import numpy as np
from scipy import stats

class MomentumScore(CustomFactor):
    """
    Computes Annualized Exponential Regression Slope * R2

    Pre-declares close as default inputs and `window_length` as
    125.
    """

    inputs = [USEquityPricing.close]
    window_length = 125

    def compute(self, today, assets, out, ts):
        # Make a list of consecutive numbers
        x=np.arange(ts.shape[0])
        # Get logs
        log_ts=np.log(ts)
        # Calculate regression values
        statistics=np.polyfit(x,log_ts,1,full=True)
        slope=statistics[0][0,:]
        r_value=statistics[1]
        # Annualize percent
        annualized_slope=(np.power(np.exp(slope),252)-1)*100
        # Adjust for fitness and return score
        out[:] = np.multiply(annualized_slope,np.power(r_value,2))

momentum_score = MomentumScore()
In [16]:
# Pipeline imports
from quantopian.pipeline import Pipeline
from quantopian.pipeline.filters import Q3000US


from scipy import stats
import numpy as np

# Pipeline definition
def  make_pipeline():

    base_universe = Q3000US()

    score = MomentumScore()

    # Create filter for top 350 and bottom 350
    # assets based on their sentiment scores
    top_scores = (
        score.top(300)
    )

    return Pipeline(
        columns={
            'score': score,
        },
        # Set screen as the intersection between our filter
        # and trading universe
        screen=(
            base_universe
            & top_scores
        )
    )
In [36]:
# Import run_pipeline method
from quantopian.research import run_pipeline

# Specify a time range to evaluate
period_start = '2003-01-01'
period_end = '2020-01-01'

# Execute pipeline over evaluation period
pipeline_output = run_pipeline(
    make_pipeline(),
    start_date=period_start,
    end_date=period_end
)

Pipeline Execution Time: 8 Minutes, 17.81 Seconds
In [37]:
pipeline_output
Out[37]:
score
2003-01-02 00:00:00+00:00 Equity(115 [ADCT]) 1.953473e+03
Equity(1209 [CA]) 1.206031e+03
Equity(1237 [NXTL]) 7.752644e+03
Equity(1343 [CCK]) 2.400315e+03
Equity(1826 [CPWR]) 1.218228e+03
Equity(2000 [CVC]) 1.207128e+04
Equity(3241 [GLW]) 3.457485e+04
Equity(3801 [IDCC]) 1.870531e+03
Equity(3871 [IMCL]) 2.216821e+03
Equity(4303 [KRON]) 1.013503e+03
Equity(4794 [MENT]) 1.690610e+03
Equity(6769 [SEE]) 1.862453e+04
Equity(6785 [SEPR]) 5.131898e+03
Equity(7157 [STK]) 2.669166e+03
Equity(7468 [TLAB]) 1.310070e+03
Equity(8106 [TTEK]) 1.454890e+03
Equity(8132 [WDC]) 2.125283e+03
Equity(8459 [CREE]) 1.452996e+03
Equity(9490 [UCOMA]) 1.710389e+03
Equity(10442 [MACR]) 1.357700e+03
Equity(11191 [RATL]) 3.828194e+03
Equity(11371 [PVN]) 1.150987e+03
Equity(11718 [ADTN]) 1.193928e+03
Equity(13226 [LGTO]) 5.700377e+03
Equity(13306 [SUNE]) 1.583528e+04
Equity(13506 [CKFR]) 2.139075e+03
Equity(13905 [NTAP]) 1.112808e+03
Equity(13940 [SNDK]) 1.542733e+03
Equity(14014 [CTXS]) 2.654185e+03
Equity(14848 [AABA]) 1.967079e+03
... ... ...
2020-01-02 00:00:00+00:00 Equity(51199 [KRYS]) 4.903572e+02
Equity(51231 [ROKU]) 3.508368e+02
Equity(51233 [DCPH]) 3.708478e+03
Equity(51271 [MAXR]) 2.133343e+03
Equity(51580 [NMRK]) 2.105884e+02
Equity(51649 [ADT]) 1.013249e+03
Equity(51693 [GTES]) 2.317922e+02
Equity(51753 [CDLX]) 8.193154e+02
Equity(51957 [LASR]) 2.108429e+02
Equity(51987 [AMRX]) 9.266134e+02
Equity(52115 [EIDX]) 7.068193e+02
Equity(52117 [FTSV]) 6.490770e+05
Equity(52143 [EVER]) 4.093615e+03
Equity(52209 [ALLK]) 3.953411e+04
Equity(52213 [CNST]) 2.714245e+06
Equity(52223 [REPL]) 2.410371e+02
Equity(52404 [PRNB]) 5.341201e+02
Equity(52454 [ARVN]) 6.459218e+03
Equity(52490 [KOD]) 4.582142e+05
Equity(52697 [THOR]) 3.026370e+05
Equity(52831 [NFE]) 2.276169e+02
Equity(52983 [DSSI]) 2.252626e+02
Equity(53016 [DTIL]) 2.434555e+02
Equity(53047 [NGM]) 3.044340e+02
Equity(53083 [TPTX]) 4.987801e+02
Equity(53144 [CRTX]) 7.300473e+02
Equity(53145 [NXTC]) 3.193465e+04
Equity(53274 [PRVL]) 3.547513e+02
Equity(53303 [BBIO]) 1.234437e+03
Equity(53314 [KRTX]) 1.599021e+06

319637 rows × 1 columns

In [38]:
# Import prices function
from quantopian.research import prices

# Get list of unique assets from the pipeline output
asset_list = pipeline_output.index.levels[1].unique()

# Query pricing data for all assets present during
# evaluation period
asset_prices = prices(
    asset_list,
    start=period_start,
    end=period_end
)
In [39]:
# Import Alphalens
import alphalens as al

# Get asset forward returns and quantile classification
# based on sentiment scores
factor_data = al.utils.get_clean_factor_and_forward_returns(
    factor=pipeline_output['score'],
    prices=asset_prices,
    max_loss=1
)

# Display first 5 rows
factor_data.head(5)
Dropped 1.4% entries from factor data: 1.4% in forward returns computation and 0.0% in binning phase (set max_loss=0 to see potentially suppressed Exceptions).
max_loss is 100.0%, not exceeded: OK!
Out[39]:
1D 5D 10D factor factor_quantile
date asset
2003-01-02 00:00:00+00:00 Equity(115 [ADCT]) 0.147186 0.108225 0.281385 1953.473281 3
Equity(1209 [CA]) 0.000000 0.086721 0.079581 1206.030991 1
Equity(1237 [NXTL]) 0.018444 0.121893 0.121091 7752.644437 5
Equity(1343 [CCK]) -0.021656 0.000000 -0.014013 2400.314735 3
Equity(1826 [CPWR]) 0.008401 -0.065578 -0.084714 1218.228239 1
In [40]:
import pandas as pd
# Calculate factor-weighted long-short portfolio returns
ls_factor_returns = al.performance.factor_returns(factor_data)

# Plot cumulative returns for 5 day holding period
al.plotting.plot_cumulative_returns(ls_factor_returns['1D'], '1D', freq=pd.tseries.offsets.BDay());
al.plotting.plot_cumulative_returns(ls_factor_returns['5D'], '5D', freq=pd.tseries.offsets.BDay());
al.plotting.plot_cumulative_returns(ls_factor_returns['10D'], '10D', freq=pd.tseries.offsets.BDay());