Back to Community
Pipeline: Long/Short Cross-Sectional Template

This is an updated, Pipeline version of David Edward’s Long/Short Cross-Sectional Momentum strategy. If you aren't familiar with long/short strategies, I would highly recommend going over the full lecture before exploring this algorithm:The basics of the strategy are as follows:

It looks at an N day window of M day returns on a basket of large cap
stocks, then the cross-sectional average for each day is subtracted
out. It then uses the average of the result as a ranking for the
universe, long the top and short the bottom in equal amounts.

Since this algorithm now uses pipeline, it's able to screen a much larger universe of securities on a daily basis. By doing so, I saw performance improvements compared to the original that only used the top 500 securities by market cap.

Here are the full list of changes:

  • This algorithm uses Pipeline to calculate the cross-sectional average looking at the top 1,000 market cap securities
  • Capital base is 1,000,000 versus 100,000
  • There is a minimum liquidity floor of ADV > 10,000,000 for the past 30 trading days
  • Trading frequency is set to bi-monthly
  • Stocks with earnings announcements are excluded from the trading universe using EventVestor’s Earnings Calendar data feed to reduce volatility.
  • Stocks with news sentiments that contradict the main Returns factor are excluded from the universe using Accern's Alphaone data feed.
  • The drawdown and volatility was low enough that I felt comfortable increasing the leverage to 2.0

Like David mentions in the original post, this algorithm can serve as a pretty good template to begin layering on-top of. I expect to be posting a few variations (and encourage you to do the same) so follow this thread for more!

The sample earnings calendar data feed is available from 01 Jan 2007 - 24 Mar 2014.

The sample news sentiment feed is available from 26 Aug 2012 - 30 Mar 2014.

Clone Algorithm
230
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 56fd807115439d0e08051531
There was a runtime error.
Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

16 responses

Very nice! And well commented for a newb like me so I can see what how you worked with the Pipeline.

I'm working on hot rodding this algo with a piece from Ernie Chan's second book.

Is the cross-sectional demeaning across all stocks or filtered stocks?

Shiv,

The returns are calculated cross-sectionally on all stocks not just the filtered ones.

I've attached the pipeline plot that might make things clearer.

Seong

Loading notebook preview...
Notebook previews are currently unavailable.

Thanks Seong.

But don't you think it's important to demean cross-sectionally within filtered stocks. I know this is just a descriptive strategy but do you know of a way where the calculation can be done only on filtered stocks. Is there a way to implement a masking feature (in compute()) for a custom factor like "rank() or top()"?

Thanks
Shiv

Shiv,

I think you bring up a great point and Scott talks a bit about that in his replies to this thread: https://www.quantopian.com/posts/filter-is-no-longer-created-from-factor-comparison

To all,

I've added an extra dimension to this algorithm. Now before entering any long/short position, I do a bit of due diligence to insure that a major event or news article hasn't overshadowed the Returns factor. In this case, Accern's news sentiment is used as risk avoidance factor.

Clone Algorithm
203
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 56fc353586ed940dfdc9ac3e
There was a runtime error.

Pretty cool algo Seong!!
Going through your code I noticed that the returns calculation has an error that's in the original as well. The good news is that both the correct and incorrect versions are monotonic in that they will produce the same results when used as a ranking system. The difference is that the correct version produces fewer NaN/inf values so fewer stocks get dropped from the resulting array.

The error is that the log returns should be: R = log(P2 / P1), or log(P2) - log(P1)
Here the returns are calculated as, R = log(P2) / log(P1)

This backtest has the correct returns calculation. The results are similar, but there seems to be a bit more noise.

Just for fun, here's the factor I came up with for this using just numpy functions.

class CrossSectionalReturns(CustomFactor):  
    inputs = [USEquityPricing.close,]  
    window_length = 300  
    lookback_window = 50  
    log_returns = True  
    def compute(self, today, assets, out, close_price):  
        n = self.lookback_window  
        if self.log_returns:  
            returns = np.log(close_price[n:] / close_price[:-n])  
            # Or  
            # log_px = np.log(close_price)  
            # returns = log_px[n:] - log_px[:-n]  
        else:  
            returns = close_price[n:] / close_price[:-n] - 1  
        means = np.nanmean(returns, axis=1)  
        demeaned_returns = (returns.T - means).T  
        out[:] = np.nanmean(demeaned_returns, axis=0)  
Clone Algorithm
24
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 56fc74922520c40e02e8df75
There was a runtime error.

Thanks David, I updated the main algo with your corrections as well as changing our article sentiment lookback to include the impact score.

The returns seem to have improved from the changes.

Clone Algorithm
230
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 56fd807115439d0e08051531
There was a runtime error.

@Seong - I couldn't seem to get this algo to work. Are you sure it is running well?

Daniel,

Interesting, I'd like to help you figure this out as we've tested the algorithm multiple times and it runs well. Do you mind being specific what the problem is?

Seong

@Seong - I got the program to finally work...must have been an internet connection issue on my end. Still think there is an issue with liquidity on some of the trades, but I wonder why the algo tanks around 2014?

Daniel,

Great question. I don't fully know why either, perhaps there was a change in the markets or some shift in momentum.

Maybe exploring that question through our backtest tearsheet (https://www.quantopian.com/posts/new-feature-comprehensive-backtest-analysis) may help explain.

Seong

i cloned it and tried to build it over the same time-period that has the free data (08/26/12-08/21/14) but it gives this error below .. Is the free data not available any more? How do i fix this so it backtests?

30 Error Runtime exception: NoDataAvailable: Backtest began on 2012-08-26 and ended on 2014-08-21, but some of the requested datasets do not have data for this time. The datasets are: accern.alphaone_free: start=2012-08-26, end=2014-08-21. Your backtest must begin on or after: 2012-08-26 and end on or before: 2014-08-21.

Kiran,

I'm sorry that the error message was confusing. You'll need to adjust the start and end dates to give it a 1 day time buffer, for example, try 2012-08-27 and 2014-08-20.

Hi Seong,

I'm looking for some help adapting this for Quantopian2 and using it as a template.

Specifically I'm looking for how to remove update_universe (deprecated). The migration guide doesn't offer any steps.

update_universe(context.longs.index | context.shorts.index)

Does this filtering logic need to be moved to make_pipline()?

Evan in the context of this algo you can just remove that line all together.

Moreover that line isn't actually doing any filtering, while the pipe | character usually means OR in the case of these pandas indexes it actually means union.

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Thanks James, I figured it out . It was something obvious I missed. The ordering logic was looking in data.stocks which is obviously empty when update_universe is removed. Working as expected now.