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.
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
- 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
- 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)
- 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?
- If it is broken, does that mean each algorithm to use RSI must implement it, like this one?
- 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?
|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|