Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Third-Party Challenge algo attempt

Here's my initial attempt at an algo for:

https://www.quantopian.com/posts/$10k-third-party-challenge-design-a-factor-for-a-large-us-corporate-pension

Comments/questions/improvements welcome.

6 responses

Here's the evaluation notebook. Uniqueness score = 92.83%. Turnover exceeds the 20% upper limit.

@Grant, nice first cut. Try not to limit trading to 500 stocks and trade the entire QTU. See if volatility and turnover is tempered.

Hi @Grant,

Thanks for sharing. Interesting approach! To forecast stock returns by splitting alpha and market returns taking into account how the stock is correlated to the S&P.
There is a thing that is confusing me though. Why you iterate over the sectors to compute alpha and then sum axis=1?

    for s in sectors:  
        alpha = SimpleMovingAverage(inputs=[returns],window_length=WINDOW_LENGTH_REGRESS,mask=QTU&Sector().eq(s))-beta*SimpleMovingAverage(inputs=[returns[sid(8554)]],window_length=WINDOW_LENGTH_REGRESS)  
        returns_forecast = beta*return_SPY + alpha  
        pipeline_columns['sector_'+str(s)] = (returns_forecast-returns_average).zscore()  

And then:

def rebalance(context, data):  
    alpha = pipeline_output('factor_pipeline').sum(axis=1).dropna()  

I would have expected this to behave similar to:

QTU = QTradableStocksUS()  
 sectors = [101,102,103,104,205,206,207,308,309,310,311]  
 returns = Returns(window_length=2, mask=QTU|StaticAssets(symbols('SPY')))  
 beta = SimpleBeta(target=sid(8554),regression_length=WINDOW_LENGTH_REGRESS,allowed_missing_percentage=1.0)  
 return_SPY = SimpleMovingAverage(inputs=[returns[sid(8554)]],window_length=20)  
 returns_average = SimpleMovingAverage(inputs=[returns],window_length=20)  
 pipeline_columns = {}  
 alpha = SimpleMovingAverage(inputs=[returns],window_length=WINDOW_LENGTH_REGRESS,mask=QTU)- beta*SimpleMovingAverage(inputs=[returns[sid(8554)]],window_length=WINDOW_LENGTH_REGRESS)  
 returns_forecast = beta*return_SPY + alpha  
 pipeline_columns['forecast'] = (returns_forecast-returns_average).zscore()  
 pipe = Pipeline(columns = pipeline_columns, screen = QTU)  
 return pipe  

*The code, just removes the iteration and the sector comparison from yours.
But the numbers are quite different. So why iterate over the sectors? How does the mask affect to the SMA for computing the alpha?

Thanks in advance.

Hi Marc -

Glad that you played around with the algo! I think the difference is that summing factor z-scores by sector is different than ignoring sectors and z-scoring the factor across the entire QTU. If one has 9 thingys, and scores them 1-9, this is quite different from breaking the thingys into 3 groups, and scoring within each group. Then one has three things of score 1, three of score 2, and three of score 3.

Hi Grant,

Thanks for clarifying. Understood the concept but was not getting a part of the code so moved it to a Notebook to play with it. Sharing it in case someone wants to mess with it!

Here is algo modified using the entire universe, the turnover is ~30%, still above the contest criteria.