Back to Community
Cointegration, RSI signals, Long Only

My first algorithm on here seeks to trade based on RSI signals, using a cointegrated pair. I have included a short description, and a number of n00b questions about observed behavior and the platform in general.

Algo Description
Using any two securities, trade according to the following rules.
1. Take only long positions
2. Invest up to 50% of current portfolio value in either security
3. Consider a low RSI to be a proxy for "oversold", and a high RSI for "overbought"
4. Open a position at the maximum allowed size
5. Close the position entirely with each sale
6. Apply this ruleset with every handle_data / bar

Puzzlements
- A pair that should move oppositely (e.g. an ETF and its inverse ETF) loses money heavily and steadily
- A weakly-related pair (KO & PEP) perform better than benchmark most years
- Often, small quantities were bought, which makes sense, as long as its viewed as rebalancing.
- Often, a fraction of total shares in a security held are sold, whereas I would expect all of them to be sold.
This occurs when RSI is low, which leads me to believe that order_target_percent is fixing an over-allocation that occurred via price shifts? Is there a way to prevent this, other than doing the math manually, and wrapping the order_target_percent call in a conditional? The losing strongly-related pair traded was more volatile, and traded much more frequently.

Some log output:

2010-02-08log_order:66INFO      A:18363     Z:8193      $966796.753663      KO      -10 / 20.0  
2010-02-08log_order:66INFO      A:18363     Z:8193      $966796.753663      PEP     4 / 25.0  
2010-03-15log_order:66INFO      A:18353     Z:8197      $1034390.22866      PEP     -8197 / 94.0  
2010-03-16log_order:54INFOorder for PEP was not found  
2010-03-17log_order:54INFOorder for PEP was not found  
2010-03-18log_order:54INFOorder for PEP was not found  
2010-03-19log_order:54INFOorder for PEP was not found  
2010-04-22log_order:66INFO      A:18353     Z:0     $1047435.20753      PEP     8084 / 24.0  
2010-04-23log_order:66INFO      A:18353     Z:8084      $1043154.97842      PEP     -22 / 28.0  
2010-04-26log_order:66INFO      A:18353     Z:8062      $1044305.73342      PEP     -27 / 25.0  
  • Sometimes, the order cannot be found by id

As Expected
- Some verbose logging (now removed) demonstrated that the conditionals were working as expected (e.g., skip every frame wherein a security has an RSI in the 30 - 90 range. Sell the ones above 90, and buy the ones below 30)

Platform Questions
- A version of order methods that returns the order object instead of an id might fix the "missing" orders mystery. Supplying the completed order object to a callback might behave more predictably.
- The ta.RSI wrapper looks handy. Is it definitely broken, as mentioned in this page?
https://www.quantopian.com/posts/why-many-stocks-have-0-rsi-value
- If it is broken, does that mean each algorithm to use RSI must implement it, like this one?
https://www.quantopian.com/posts/rsi-attempt-general-questions-and-feedback
- the first 14 RSI values in RSI(14) turn up as "nan". Is there a way to request that the platform load the data necessary to calculate? I've seen one example using history(), but I want to make sure I'm not manually duplicating code that is part of the platform.
- some pairs blew up on the error thrown with this rule is violated:
set_long_only() # Raise exception on short (negative share) attempt
Is it recommended to wrap orders in try / except, or to prevent the error occurring by doing the math manually, and evaluating the order size before calling order?

Thanks much,
Monte
nFol.io

Clone Algorithm
36
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: 53b208fca6ebce0720a6aeea
There was a runtime error.
5 responses

Hi Monte,
It sounds like some of the small amounts of sales might be due to non-liquidity and your large starting portfolio size. Quantopian has built-in slippage and commission models, and with a portfolio that large, they can have noticeable effects. These models can be turned off easily if needed, however.

The reason the order sometimes cannot be found by ID is because you are ordering to the same target that you currently own, so no order is placed. Most of the time when this happens, you already have zero shares, and you are placing an order target for zero shares, so there is no order.

I also made my own version of your algorithm that does almost the same thing, but with the updated talib module (we are deprecating the one you are currently using in favor of the one in my code). Note that the slippage and commission models are still turned on in my code, see here (and the section just below that) if you want to turn them off: https://www.quantopian.com/help#ide-slippage

Does that help?
Gus

Clone Algorithm
21
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: 53b455acbd0fb50724c19397
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.

Gus,
Thanks for your thoughtful reply and RSI example.

In general, do you find a particular proxy for "overbought / oversold" to be most useful? Since posting, I have been working on similar algos with stddev, vwap, and mavg.
Cheers,
Monte
nFol.io

Monte,
I doubt there's a one size fits all proxy, but I bet layering multiple signals can be a good way to go. Here I added the Williams%R indicator on top of the RSI signal. It's another overbought/oversold indicator, but it doesn't have the internal smoothing like the RSI and can be more erratic. It trades more, and doesn't make as much in the long run, but it did cut volatility and max drawdown in half.

TA-Lib has tons of indicators, I don't even know what most of them do, but I'm sure you can create a pretty good custom signal by composing several together.

David

Clone Algorithm
40
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: 53b5a28b503d3b07175807b7
There was a runtime error.

Monte Hi, where/how do you calculate cointegration? Thanks. -a

I make a video from youtube about cointegration: https://www.youtube.com/watch?v=fNk6qwKHY1c&t=7s