Here are the results after I fixed the issue I mentioned. I changed the screen to do multiple sorts and cull the worst stocks, instead of just having static limits. I used some standard valuation ratios: EV/EBITDA, P/CF, P/E, P/FCF (P/B and P/S did not test well). This way we'll get the cheapest stocks but still have enough stocks to buy if valuations are higher than the limits. The performance improved a lot (and are frankly unbelievable), and returns are actually positive since 2014, matching the market's performance.
Some surprising things I found:
- Removing the momentum component improved the returns, even risk adjusted (by setting num_stock = num_screener_end).
- Removing the profitability filters improved returns (ROE and ROIC). I also tried to sort/cull by them, didn't help.
I still need to get the logging of leverage to work. For some reason it complains when I try to use record_leverage: "OrderSecurityOutsideUniverse: 0036 You have placed an order with an unexpected security: Security(2114 [DCO]). Please declare all securities in the initialize function by calling sid(123) for each security that will be used later in your algorithm."
I'm not sure if the strategy is using leverage or not. It's not supposed to but I suspect it might be, if it tries to close out a position but is not able to, while still opening new positions.
Also need to figure out how to use limit orders. I'm thinking some of these stocks are pretty illiquid and market orders would be risky.
And I want to try adding some logic to reduce drawdowns, maybe using a stoploss or shorting the index like Josh showed.