Back to Community
Quantopian Lecture Series: Mean Reversion on Futures

Mean reversion is an oft-covered topic in algorithmic trading and quantitative finance in general. Here we look at some examples of how mean reversion can apply in futures trading. Due to specific structures in contracts and between multiple futures, there are a lot of interesting ways to construct trades that bet on various different quantities or properties. We examine potentially mean-reverting spreads between multiple futures as well as mean-reverting relationships between futures and equities.

All of our lectures can be found here:
quantopian.com/lectures

Loading notebook preview...
Notebook previews are currently unavailable.
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.

15 responses

This is a pairs trading algo on a few futures contracts.

Clone Algorithm
156
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: 5902ae1ec1835d6579d49d34
There was a runtime error.

Welcome, Futures Workshop Attendees!

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.

This is amazing work chaps. A whole world of trading opportunities!

Thanks, Dan!

I modified the template algorithm to trade only on the crush spread.

Clone Algorithm
117
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: 5903a81188e8ed61cd5e66d9
There was a runtime error.

In your code, you check to see if both assets are still cointegrated, which you then log, but yet it isn't a constraint in your call to order_optimal_portfolio. How does your algorithm know to not place a trade when both assets are not cointegrated anymore?

    pvalue = coint(soy_price, (soy_meal_price + soy_oil_price))[1]  
    if pvalue > 0.10:  
        log.info(  
            'No longer cointegrated, no new positions.'  
        )  
    order_optimal_portfolio(  
        opt.TargetPortfolioWeights(context.current_weights),  
        constraints=[  
            opt.MaxGrossLeverage(1.0),  
        ],  
        universe=context.current_weights.keys(),  
    )  

Good catch! I adapted this from the template I wrote earlier and forgot to replace the continue with something relevant. A good substitute would be a return statement after logging.

Thank you for pointing that out.

how do we know our portfolio won't go to margin? the equity curve is only close-to-close. am i right?

Currently, margin is not modeled on Quantopian. To control the spending of your algorithm, you should look at limiting the total target weight of any new portfolio, or better yet, consider the CVaR of your target portfolio. With futures, the term 'margin' is used for the cash that you have to put up when opening positions. In case you haven't seen it, margin is covered in more detail in the Introduction to Futures lecture.

Hi,
I have done some test and the output of coint is not the p-value of adf of the residuals of the regression. So i get that some pairs are cointegrated even if coint gives an output higher that 0.05. I checked the code of coint and is not just using adf p-value but also doing something else. Is coint result reliable?

It is definitely reliable! The adfuller and coint functions (from statsmodels) are performing tests on two different things. Augmented Dickey-Fuller tests the unit roots of the observed variables, while the coint function is going to test the residuals from an estimated cointegrating relationship. Oftentimes, the results of the tests will coincide (and in those cases where they don't, it is definitely hard to make a decision), but the two tests have different critical values associated with them so they won't always have the same result.

These are the exercises for this lecture.

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

Hi Max,

spreads = y_returns - (regression.slope * x_returns)

Shouldn't this be:

spreads = y_returns - (regression.slope * x_returns + regression.intercept)

Also, why is this called "spread"? The name sounds terribly misleading to me, when I hear spread I immediately think about the difference between prices, especially because in that other futures pair trading notebook you have a "currently_long_the_spread" variable which does actually refer to the difference in prices. Instead, that quantity represents the difference between return realised and return predicted by the linear regression. It would better be named maybe fit_error or something like that.

I'm trying to trade Y - \beta * X, as that's the linear combination between the two series. That's the spread the I expect to be stationary, centered around alpha + noise.

I am using "spread" to be consistent across templates, though I recognize that here it is definitely a little confusing. I will take that into account when I finish fixing the algo.

Thanks for coming back Max. Right, I think I understand what's going on. Computing

spreads = y_returns - (regression.slope * x_returns + regression.intercept)

instead of

spreads = y_returns - (regression.slope * x_returns)

just centers the "spread" around zero. But the actual signal is the zscore which is invariant under addition of an overall constant, so the two definitions of "spread" should lead to the same algorithm behaviour.