Inspired by T Smith idea to implement Gary's Antonacci's dual momentum approach to ETF
selection in "IN OUT" strategy.
-The execution code has been completely changed to keep levarage under control and avoid
insufficient buying power warnings.
-To calculate returns I used widely used in industry momentum with excluding period.
-Modified components that are more in line with the strategy.
-The IN OUT part of the strategy has not changed except for some cosmetics
to make it more readable for myself.
"DUAL MOMENTUM IN OUT" nearly doubled "IN OUT" Net Profit while maintaining risk metrics at the same level.
Compounding Annual Return
30.164%
Sharpe Ratio
1.667
PSR
97.773%
Beta
0.057
Drawdown
19.300%
Annual Standard Deviation
0.154
Here is my second version of "DUAL MOMENTUM-IN OUT".
Leandro Maia
Vladimir,
sorry for the confusing. I actually had tried different solutions but then got confused about what really solved the issue. Now I confirmed that it was:
self.Securities["QQQ"].MarginModel = PatternDayTradingMarginModel()
According to the documentation it gives 4x leverage for day trading but also 2x leverage for overnight positions.
Attached is your code with it implemented.
I think you don't need SetWarmup for this one.
Vladimir
Leandro Maya,
Thanks for your recommendation.
"Insufficient buying power" warnings have disappeared.
But account leverage behaves differently from Quantopian.
May be my formula
account_leverage = self.Portfolio.TotalHoldingsValue / self.Portfolio.TotalPortfolioValue
is wrong?
Or is it not being managed properly by the Lean Engine?
Is there any settings for margin monthly payment?
Leandro Maia
Vladimir,
this leverage oscillations have being annoying me too, but I don't know what is the cause. In this particular case, the way I found to control it was by doing a daily rebalance and calculating the average just after the rebalance. It ended up with 400x more trades, but at least the performance improved.
Regarding margin fees, I read in other posts that is not yet available but in the to do list.
For live trading we are recomended to let some cash in the account. That can be done manually or by using:
security = self.AddEquity("SPY", Resolution.Daily) security.MarginModel = BuyingPowerModel(requiredFreeBuyingPowerPercent = 0.05)Vladimir
Leandro Maya,
Believe me or not but we came to my original version.
def trade(self): for sec, weight in self.wt.items(): if weight == 0 and self.Portfolio[sec].IsLong: self.Liquidate(sec) else: self.SetHoldings(sec, weight)
Those 3 lines was added by Thomas Chang in Oct 2020 and was working fine there.
Thanks for help
Leandro Maia
Vladimir,
what intrigues me is why Thomas Chang lines work with leverage below 1 and don't work with leverages above. I think LEAN probably changes the way it calculate stuff when margin is used...
Flame
I think the easiest solution is to use QC's built in SetHoldings function with a list of PortfolioTarget. This will carry out the trades by releasing margin before the purchases
orders = [] for sec, weight in self.wt.items(): orders.append( PortfolioTarget(sec, weight) ) self.SetHoldings(orders)
Chak
Hey Flame,
In theory, using PortfolioTarget is the easiest, but because the weight for each holding is static, what actually happens is that it makes far more trades daily to meet the weight value - so more trades means more cost. Leandro's and Vlad's idea is closer to the solution when using a margin account.
Kido Nam
Hi Vladimir!
Thanks a lot for sharing this amazing strategy!
I found data with one-day resoultion is consolidated into one-day timeframe agian.
I'd like to know why this process is necessary.
Thanks!
Radu Spineanu
Apologies for just jumping on this thread after being away for a while.
After reading three four differents posts + comments what I'm understanding is that IN-OUT is very good now and you guys are working to figure out how to increase leverage while looking for other signals to exit, right?
Vladimir mentions: "This algorithm unlike those from Peter Gunther has three pairs as a source, two parameters and
concensus of all three for exit signal." Have been trying to identify these but at least the last version from Peter has three consensus pairs as well. I did notice that you are picking the bonds/stocks with highest ttm returns.
Mark hatlan
Hi everyone. I liked this algo so I plugged in some 3x ETFs and removed all margin. I'm not a fan of maxing out margin since House Calls in real life are a pain, and are best avoided.
But then I noticed a lot of order rejections due to buying power. Eventually the orders get filled. But in order to fix that I ended up changing the end just to SetHoldings for either TQQQ or TMF, and skipped the "trade" section. This got rid of the order rejections, but returns dropped significantly.
Was there another reason for the previous higher returns?
Chak
Cash accounts requires a few days for the profit from sales to settle before purchasing.
Mark hatlan
OMG I can't believe I didn't notice that, thanks Chak.
Will Berger
Hey Guys,
I made a small tweak that has noticable impact. I switched the trade-in from Friday to Monday and for my period of 2017-2021 the PSR went up by 4% and the return by 10% cagr by 1.2%.
Also special thank you to Vladmir for sharing his changes and Rahul Chowdry for explaining whats really going on here. Really cool.
For those running this in Paper Trading or Live, I also added some code to email us every day what is happening on Trade In, Trade Out Days, what the signals are indicating for the day.
Will
Vladimir
Will Berger,
Here is the backtest of the latest version 2.5 for the same period you
backtested the modified version 2.2.
Will Berger
Thank you! Will check it out.
Will Berger
Hi Vladimir,
I got a chance to look at your changes. I am trying to understand this line of code here
vola = self.history[[self.MKT]].pct_change().std() * np.sqrt(252)
While I understand and see what it is doing, I don't understand why this is telling us the market is volatile.
Could you shed some light on it? Any help much appreciated.
Chak
Hi Will, when you calculate the standard deviation of the price changes of the market, any large value relative to the X number of days it's calculated from implies market volatility or a market drop.
Let's say you take the last 126 trading days of the market trending one way. In this case, the standard deviation remains small. Suddenly, you get a market drop where SPY whipsaws back and forth. In this case, the constant price change increases the standard deviation.
The number 252 is arbitrary and only denotes the last trading year. I hope this helped.
Vladimir
Will Berger
> Could you shed some light on it? Any help much appreciated.
This may help.
The original "In & Out" strategy, published on the Quantopian forum thread
"New Strategy - In & Out" Oct 4, 2020, had only 4 sources SPY, XLI, DBB, SHY.
There were 6 constant parameters: waitdays = 15, period = 58 and thresholds for each source.
Some participants was asked where these magic numbers came from because the results changed
significantly due to a slight change in parameters.
Tentor Testivis, the great "In & Out" contributor, on October 12, 2020, proposed the idea of
making them adaptive to volatility.
The idea:
Using SPY's volatility to replace the magic numbers
vola = hist[SPY].iloc[-126:].pct_change().std() * np.sqrt(252)
waitdays = int(vola * 100 / 3)
per = int((1 - vola) * 50)
Implementing the idea as is dose not give grate results so in my
"Price relative ratios (intersection) with wait days" Oct 16, 2020
I modified Tentor Testivis idea to what I have been using since then.
vola = self.history[[self.MKT]].pct_change().std() * np.sqrt(252)
wait_days = int(vola * BASE_RET)
period = int((1.0 - vola) * BASE_RET)
You are welcome to modify these empirical formulas.
Will Berger
Thank you for that explanation!
Mark hatlan
Vladimir, why use FDN? FDN and QQQ are very similar in historical price behavior. Also FDN doesn't have any leverage products tracking in like QQQ does. What is the rationale for that?
Vladimir
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!