Does anyone want to work on reproducing Vladimir 's amazing In-Out ROC v1.9 results? He mentioned that the extra returns were inspired by Quantopian's pipeline, so I added Leandro Maia 's stock filtering code which allows for easy factor picking.
Unfortunately I haven't been able to get even close to the original v1.3 results yet. Thinking that perhaps this is the wrong direction and the direction would be some sort of different momentum play.
Any thoughts?
Peter Guenther
Radu Spineanu, I just remembered your thread here: Yesterday, I have posted an implementation in the In & Out thread which might be of interest. I also attach it here for reference. It comes close to the 40,000% displayed in the picture that Vovik had posted in the thread. A few days/weeks back the implemented algo actually was at 50,000%+ total return which was then diminished by the recent market drawdown particularly pertaining to high-flying tech stocks. So, this might be the implementation you are after. Of course, an issue is that the algo is based on a fixed selection of stocks and hence non-negligible lookback bias (i.e. a selection of stocks that we know performed well in the past). A dynamic selection is likely to be preferable.
Radu Spineanu
Thanks Peter Guenther
On a previous thread I thought I read that DistilledBear did a great job with the current pullback vs the standard InOut. Was planning on testing it soon, is that still the case?
We are living in weird times with what's happening right now.
Peter Guenther
That's right, Radu Spineanu, and is still the case, although it really depends not only on the in & out type you use but also (and critically) on the stock selection that you combine the in & out with. The winning combination currently seems to be the [QualUp] + [DistilledBear] combo. See attached regarding the returns since the beginning of the year. We also have a related discussion in our Amazing returns = superior stock selection strategy + superior in & out strategy thread.
However, tech might recover at some point and then possibly quickly, so that we'll have to see what will happen in the next few weeks. The QualUp stock selection also seems to have benefitted from Reddit meme stocks and it's not fully clear whether this can be replicated in the future (plus, we also have to acknowledge the massive drawdown because of these stocks).
Radu Spineanu
Awesome! Really appreciate this! Can't wait to play with this over the weekend.
Radu Spineanu
Peter Guenther have you tried paper trading this last version? Seems to get stuck for some reason.
Peter Guenther
Radu Spineanu, I recall that there was an issue regarding the warmup (350 days) and that it consumes more memory than available. You could reduce the number of warmup days or remove/comment out the corresponding line completely. Not sure whether this might solve the issue (?). Did it give you an error message or did the algo just not perform any trades?
Radu Spineanu
Peter Guenther I keep on adding debug logs, right now it's printing this after two days:
2021-04-05 14:00:01 :Starting rebalance_when_out_of_the_market.2021-04-05 14:00:01 :Be in.2021-04-05 14:00:01 :Calling rebalance.2021-04-05 14:00:01 :['Starting rebalance.', '250']2021-04-06 14:00:01 :Starting rebalance_when_out_of_the_market.2021-04-06 14:00:01 :Be in.Radu Spineanu
It seems to be entering this branch:
if not self.CurrentSlice.ContainsKey(symbol) or self.CurrentSlice[symbol] is None: self.Log([ "Second loop 1.", str(symbol) ]); continue
I'll research what CurrentSlice does.
Derek Melchin
Hi Peter & Radu,
The call to `SetWarmUp` is not necessary since all the indicators are manually warmed up. In addition, we can replace the position sizing logic in the algorithm by using the `SetHoldings` and `Liquidate` methods. See the attached backtest for reference.
When paper trading this algorithm, trading may not start immediately because we have to wait for the `rebalance_when_out_of_the_market` Scheduled Event to be called before the first order is placed.
Best,
Derek Melchin
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.
.ekz.
Great work, all.
I'm curious: for these strategies that were sparked from Quantopian days: has anyone tried backtesting option trades of these securities, rather than the securities themselves?
Peter Guenther
Great algo update, thanks for sharing, Derek Melchin!
Very timely question, .ekz.. I am currently trying to get my head around options and hopefully there is something to share at some point. It can take a bit of time, though . . .
.ekz.
Peter Guenther: I implemented an options version, attached below. I'd recommend some refactoring before considering it ready for live trading. It can also probably be optimized for performance.
New Behaviour:
Instead of stock, buy call options that are X% above current price and expire in Y days (it picks the options contract that matches X and Y the closest). I've abstracted the logic out so there's been minimal change to the main code, and externalized X & Y as parameters. You can see my code diffs at a quick glance here (visual generated from diffchecker), and here are the external parameters:
For each opened order, I have added a message to the order memo, with the strike price and current price. For each liquidated order, I add a message for the proft / loss incurred. In either case, you can see these in the 'Tag' column of the orders tab in your backtest results (see example for liquidated orders in this scr shot).
Suggestions:
Given that it's trading a universe, strike selection shouldnt really be done via '% above price', as this will have different implications depending on the asset's trading price. This test just selects the at-the-money strike, by setting this to 0%. You could also explore opening a vertical spread instead of a single call option, and allocating only a portion of capital as tradable funds (rather than ALL of it).
Note:
There were some tickers for which the options contracts arent being retrieved, but i havent had time to troubleshoot. You can have a look at the debug console to see which. It depends on your testing period. For this year, i'm seeing the issue with BEEM and BTB
.ekz.
Another thought... When it comes to shares, buying one share of a symbol is the same as buying another share.
However, with options, we have more specificity --we can choose contracts based on conviction, much the same way we assign higher weights in our portfolio based on our conviction (of higher return).
For example, if we've determined a particular symbol should have higher weight in our long portfolio (presumably because we expect a stronger move), we might pick a call contract that is farther out of the money (OTM). Since OTM calls have higher rate of return than ATM or ITM calls, we stand to be well rewarded (assuming you don't go too far OTM). You could decide which OTMs to pick based on ATR, perhaps.
Just a thought. Would love to hear from others.
Derek Melchin
Hi .ekz.,
Great addition to the algorithm! We can improve its efficiency by only subscribing to the option contract that we trade instead of subscribing to the entire option chain. To accomplish this, we can first remove the OnData method. Next, we replace the call to QueueOptionHoldings with a new method, TradeOption.
def TradeOption(self, holdingSymbol, holdingWeight): # Search OptionChainProvider for option to select callStrike = self.GetTargetStrikeByPctDist( holdingSymbol,self.distFromPrice ) putStrike = self.GetTargetStrikeByPctDist( holdingSymbol,(-1* self.distFromPrice)) expiryDate = self.GetTargetExpiryByDTE( self.daysTillExp ) contract = self.SelectContract(holdingSymbol, callStrike, expiryDate, OptionRight.Call) if contract is None: return option_contract = self.algo.AddOptionContract(contract, Resolution.Minute) # Purchase self.algo.SetHoldings(option_contract.Symbol, holdingWeight)
Lastly, we extend the LiquidateOptionsOfType method to ensure we remove our option contract subscription.
def LiquidateOptionsOfType(self, symbolArg, optionRightArg = OptionRight.Call, orderMsgArg="Liquidated"): for symbolKey in self.algo.Securities.Keys: # ... self.algo.RemoveSecurity(symbolKey)
See the attached backtest for reference.
Best,
Derek Melchin
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.
.ekz.
That's great Derek Melchin I was hoping for some performance tips. Thanks.
I added that options order 'queueing' logic to an old algo to troubleshoot an empty option chain. I wasnt sure if it was necessary but the code stuck around.
Question: if I wanted to use greeks (like Delta) to select strikes, would i have had to pre-subscribe to the feed, like I am doing? Or would your way work just as well?
Spacetime
receiving error message: ArgumentException : The underlying equity asset (TLT) is set to Adjusted, please change this to DataNormalizationMode.Raw with the SetDataNormalization() method
can be solved by adding below in initialization.
self.Securities["TLT"].SetDataNormalizationMode(DataNormalizationMode.Raw)
.ekz.
Strange. I dont think we are seeing that error, spacetime
As you can see from the backtest, it ran just fine. Perhaps you are using an older LEAN build.
Spacetime
if you run the backtesting for a longer duration, then that error is seen.
.ekz.
Ah, great catch. Thanks.
I'm mobile only at the moment and can't make any changes. Feel free to attach an updated backtest with the fix.
Peter Guenther
Kudos to your options algo, .ekz.! This looks very elaborate (= lots of work) and interesting, thanks a lot for sharing it with us. I am looking forward to playing around with it in the next few days.
Radu Spineanu
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!