Intro
Superior algo returns can be thought of as being the result of two components: a great strategy regarding ‘what stocks to buy’ (the stock selection component, SEL) and a ‘clever timing’ (the in & out component, I/O) regarding when we are ‘in’ the market and hold the stocks versus when we are ‘out’ of the market and hold alternative assets such as bonds. We often focus on optimizing SEL and tend to neglect I/O; thus, for an important discussion of recent I/O tactics, see here.
Focus of this thread: Optimal SEL + I/O combinations
It is worthwhile to separately optimize SEL and I/O. However, the ultimate total return will also be determined by a certain synergy or dissonance between the two components. So, it seems that we won’t get around the arduous task of individually testing (all possible) combinations to identify optimal SEL + I/O pairs, which is the eventual focus of this thread. I reckon a preparatory step can be to dig up all the hidden SEL and I/O treasures from this forum and beyond to see what inputs are available for the combinations.
Ultimate objective
Let's get rich together, why not?
Chak
Raymond, to give a different response: When the in-out strategy decides it's better to exit the market it doesn't mean that the best solution is to short the market. When you short the market, it's because you're confident that it will drop a large amount very quickly, with or without influence by ETFs that represents as proxies for economic indicators.
Aalap Sharma
Is there a diff betwwen calculating signal between
https://www.quantconnect.com/forum/discussion/9632/amazing-returns-superior-stock-selection-strategy-superior-in-amp-out-strategy/p1/comment-26829and the recent Guy's version.
I see the former has not switched to stocks yet.
Aalap Sharma
nvmd. Figured the wait days are different. :(
Peter Guenther
3 x leveraged SEL[“QQQ”] + I/O[“In & Out”] with disambiguated DEBT signal
The latest from the In & Out thread, yet, with in holdings TQQQ and out holdings TMF and TYD.
As usual, we should not bet the farm on it (<10-15% ?) since the future is likely to look different from the past ;) However, if it'll work to some extent it may create a decent boost in the portfolio.
Rulak
Peter Guenther i changed paramater on v5 for wait days 5, which seems to generate 78,000% but drawdown did go up.
Peter Guenther
Rojan Ulak: Oh wow, thanks for sharing! Indeed, there seems to be an advantage in being out of the market for shorter periods by default. The return flips ("# Determine waitdays empirically ...") seem to be quite effective in pulling up the waitdays exactly where they are required to be longer. Interesting! I think that Guy Fleury has shown elsewhere that reducing the default to only one waitday (self.INI_WAIT_DAYS = 1) produces the largest returns in the backtest (yet, for a different stock selection strategy but this finding might still also apply here; to be tested).
Aalap Sharma
I may be a total noob on this but shouldnt wait days be some fuction of volatility or something ?
Peter Guenther
Aalap Sharma: A bit different in this algo, see the lines where it says "# Determine waitdays empirically via safe haven excess returns, 50% decay". The wait days go up when the safe haven asset's return is positive (e.g., gold has a positive return) and the alternative asset goes from a positive to a negative return (e.g., silver's return flips).
Just one additional observation regarding Guy Fleury 's test: the post indicates a certain level of surprise that returns go up when changing the initial wait days from 0 to 1 (self.INI_WAIT_DAYS). It's a different algo but it includes the In & Out. When you change self.INI_WAIT_DAYS to 0 in the In & Out, it basically means that the algo is zero days out, i.e. you basically largely deactivate the In & Out logic.
Aalap Sharma
Thanks for the pointer!
Sudip sil
I am new to this platform. I have done some backtest and found that rebalance_when_out_of_the_market takes bit time to complete in compare of rebalance_when_in_the_market. As a result of that if out to in is trade required on friday, it does not happen on the same day, it takes a week to complete. So I am executing rebalance_when_in_the_market 5 minutes after the rebalance_when_out_of_the_market.
I am getting 24,513% which is slightly better than version 5.
Rulak
Peter is there a reason you didn't add some type of stop trail loss to this strategy? Especially when playing with TQQQ drawdown goes very high in some of the backtesting.
Peter Guenther
sudip sil: Thanks for sharing these results! I was wondering, are the performance difference really due to unfilled orders? Or are they because of a better/lucky timing in terms of when to sell off the out holdings and buy the in holdings (i.e. a slightly better price 5 minutes later). Did you have a chance to check the order book and found evidence for unfilled orders to rule out the alternative explanation (lucky timing)? Good luck with your further tests and keep us posted!
Peter Guenther
Rojan Ulak: I would say it's definitely worthwhile to give this thought a go. Just musing about some challenges here: It will require a smart decision rule regarding whether and when we get back into the market after what kind of drawdown. Imagine the TQQQ pulls back 25% and we go out then and do not enter before the next algo cycle. What if the TQQQ quickly recovers the drawdown and we are standing on the side lines? We could say that we try to exit earlier, say at -10% and re-enter at -15%. But what if the TQQQ only falls by 14% and then quickly recovers? I reckon introducing a stop loss requires an entirely new layer of decision making/rules. Definitely worth a shot.
Sudip sil
Peter Guenther Following is the result where my changes is not there. As per this 2020-04-02 out entry was done and 2020-05-01 Out was exited and In was done.
I have done some log.Please check followings. Algo sent a swap signal 2020-04-24, which is 1 week earlier. rebalance_when_in_the_market and rebalance_when_out_of_the_market were executed at the same time on friday, 2020-04-24. rebalance_when_in_the_market completed it's execution before rebalance_when_out_of_the_market. Since rebalance_when_out_of_the_market do not do Out to In swap, existing trades were not exited and new orders were not placed. It waited for a week to do the swaping.
Attaching the existing code with log(without my change).
Peter Guenther
sudip sil: Nice investigative work there! The order overview, the logs, you got it all there, well done. Adding 5 minutes to the in rebalancing scheduling looks like a very good idea. Thanks for spotting this issue and recommending the change!
Rulak
Attemtp with Stop trail loss, keep getting warning with message
Backtest Handled Error: Order Error: id: 39, Insufficient buying power to complete order (Value:-149500.3), Reason: Id: 39, Initial Margin:
but with 15% stop tailing loss on all invested postion, the algo does not seem to do very well relative to without stop trail loss
Mateusz Pulka
Rojan Ulak
Did your algorithm cancel the opened stop-loss order (I did not check the code)? Cause this message about "Insufficient buying power" is about when you have a situation like this
1) Open trade buy QQQ and set stop loss
2) Aglo send out a signal so you close QQQ and buy the bond, however here at this moment you stop-loss order is still open.
3) In case when the price of QQQ reach the price of your stop order you will open short order on QQQ and your portfolio contains both positon QQQ short and bond long.
Peter Guenther
Track: unleveraged strategies
Something I wanted to share with those who are after unleveraged strategies: A prior QC thread which was pretty popular developed the 'Momentum Strategy with Market Cap and EV/EBITDA'. The strategy was introduced by Jing Wu on 6 Feb 2018 (also see Vladimir’s and Goldie Yalamanchi’s discussion in the Quality Companies in an Uptrend thread). It comes down to combining a fundamentals factor (earnings) and momentum. As a short-hand, let’s refer to the selected firms as the ‘earnings rockets’.
SEL[Earnings Rockets] + I/O[In & Out, latest]
The stock selection part has a coarse filter (lines 125-134) to ensure that a firm’s (1) fundamentals data are available, (2) the stock price is not too small (>$5), and (3) it is among the 200 firms with the largest dollar volume (think: size and stock liquidity).
Then comes an additional filter (lines 137-156) that selects the top 200 firms with the best EV/EBITDA ratios.
Then comes a final filter (line 239-256) that calculates the selected firms’ stock returns over 70 days. The top 10 firms are selected (line 230). The strategy invests into these firms with an equal weight (line 235).
The selection (all three filters) is refreshed on a monthly basis.
The In & Out component is the latest version from the In & Out thread: In_out_flex_v5_disambiguate_v2
Total return: 4,101%
Sharpe: 1.69, Max drawdown: 18.70%, Comp. annual rate: 33.33%
PS: Due to the algo’s demands, the backtest takes quite a bit of time to complete. To gain a bit of efficiency, I was trying to save the self.History() call in the UniverseFundamentalsFilter by adding the stocks to the consolidator. However, I always ended up getting errors that stock symbols are missing and I assume that this is because the consolidator fires before the universe filters and adding symbols at the stage of the universe filters is too late and then the stocks’ prices are missing. Just speculating here.
Leandro Maia
Peter,
thanks for sharing this latest algo. If you look further in Jing Wu's original thread you'll find an update where she removed the history call.
"We explore a new method to approximate the market capitalization. The formula is
market cap = Shares Outstanding * Price = Shares Outstanding * (Earnings Per Share * PE ratio)
In terms of fundamental variables in LEAN,
Instead of requesting the history close to calculate the Market cap, this method uses the fundamental data directly and could save the memory."
x.EarningReports.BasicAverageShares.ThreeMonths * (x.EarningReports.BasicEPS.TwelveMonths*x.ValuationRatios.PERatio) > 2e9
What I don't understand is why she didn't simply used:
(x.EarningReports.BasicAverageShares.ThreeMonths) * x.Price > 2e9
Peter Guenther
Leandro Maia: Great call! The last line of code that you have shared is more direct and avoids the History() call in the Fundamentals Filter. Good stuff! I have attached the updated algo. The results are very similar to the first version which is good.
Total return: 4,017%
Sharpe: 1.68, Max drawdown: 18.70%, Comp. annual rate: 33.13%
There are only two direct History() calls left in the calc_return function (lines 239-40) that we may not be able to replace since the filtered stocks are unsubscribed (or subscribed too late) in the consolidator (?).
Peter Guenther
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 QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect 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. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!