This thread is meant to continue the development of the In & Out strategy started on Quantopian. The first challenge for us will probalbly be to translate our ideas to QC code.
I'll start by attaching the version Bob Bob kindly translated on Vladimir's request.
Vladimir:
About your key error, did you also initialize UUP like this?
self.UUP = self.AddEquity('UUP', res).Symbol
Vladimir
Peter Guenther,
Every strategy goes in and out, but this strategy goes in and out according to the waiting day rule.
Asking "Was everything as intended?" I mean, the strategy must wait at least 15 days after the exit signal before entering.
if self.dcount >= self.outday + adjwaitdays:
self.be_in = True
But instead it made 10 trades in November.
Vladimir
Peter Guenther,
Here are some "Rules of the algo" from your post on Quantopian forum
Are they still active in current version of the algorithm?
Goldie Yalamanchi
Vladimir,
I will wait for Peter Guenther to answer. But from my debugging the "adjwaitdays" isn't always 15 days. I have seen it be 20 days or 24 days, etc.
If we wanted to always be 15 days... then this below calculation isn't needed...
self.WDadjvar = int( max(0.50 * self.WDadjvar, self.INI_WAIT_DAYS * max(1, np.where((returns_sample[self.GOLD].iloc[-1]>0) & (returns_sample[self.SLVA].iloc[-1]<0) & (returns_sample[self.SLVA].iloc[-2]>0), self.INI_WAIT_DAYS, 1), np.where((returns_sample[self.UTIL].iloc[-1]>0) & (returns_sample[self.INDU].iloc[-1]<0) & (returns_sample[self.INDU].iloc[-2]>0), self.INI_WAIT_DAYS, 1), np.where((returns_sample[self.SHCU].iloc[-1]>0) & (returns_sample[self.RICU].iloc[-1]<0) & (returns_sample[self.RICU].iloc[-2]>0), self.INI_WAIT_DAYS, 1) )) ) adjwaitdays = min(60, self.WDadjvar)
Instead I guess we would just hard code self.WDadjvar = 15, no? The above self.WDadjvar is based on how long the decay 50% value of the indicators is.
Jack Pizza
Just had the algo fail with an error, probably trying to enter a position:
Runtime Error: LiveTradingRealTimeHandler.Run(): There was an error in a scheduled event EveryDay: QQQ: 120 min after MarketOpen. The error was KeyError : 'close' Stack Trace: System.Exception: LiveTradingRealTimeHandler.Run(): There was an error in a scheduled event EveryDay: QQQ: 120 min after MarketOpen. The error was KeyError : 'close'
T Smith
Hi folks... moved over from quantopian.
Here is my input to this algo;
- IN-OUT signal unchanged
- IN and OUT assets determined by momentum (IN: QQQ/IWF, OUT: TLT/IEF)
Nathan Swenson
Wow T.Smith! Those are some awesome results and you did that with non-leveraged instruments. Very Nice!
Nathan Swenson
T.Smith, if you check the logs, there are some invalid orders due to lack of margin. I see the order quantity is just slightly too high and the order gets rejected.
Goldie Yalamanchi
Yes I noticed the same thing... I think QQQ needs to be sold first before IWF (Russell) is bought.
2020-09-11 11:31:00 TLT Sell Market Fill: $164.259732735 USD -1048 Filled
2020-09-11 11:31:00 QQQ Buy Market Fill: $273.40 USD 632 Filled
2020-09-25 11:31:00 IWF Buy Market 810 Invalid
2020-10-02 11:31:00 IWF Buy Market 809 Invalid
2020-11-06 11:30:00 QQQ Sell Market Fill: $291.99 USD -632 Filled
That small detail aside, it seems like an interesting iteration that still continues to use the SHY signal but has properly entered the market again in late half 2020 without issues. Something the last iteration of the algo has suffered from.
Goldie Yalamanchi
I may stand corrected, after applying the fix to sell QQQ before IWF buy... the algo proceeds along. But doesn't make a trade after 10/6 again. Just stuck in bonds (IEF). Take a look below, maybe I made a mistake... but here is my backtest....
Jack Pizza
Goldie Yalamanchi are you saying there is an issue with the algo? I don't understand, or you want it to be more active in trades? I would prefer it to be in bonds, if you've noticed QQQ hasn't done much and looks like it's getting ready to roll over.
Nathan Swenson
Yes, I agree. Prefer bonds right now, although entry was too early with 10/6. The maximum out time is 60 days if I'm reading code correctly, which would be 3 months.
Goldie Yalamanchi
So you can review the discussion around SHY. But it fires the signal over and over again due to SHY moving %1 or so. Bond yields are near 0%. TLT and IEF do well when the fed rate is low. But they can't go lower than 0% can they? Hence I believe the SHY signal to be a FED created signal. I guess they can go to negative % which has happened in some countries.
Here is a log of the signals.... if any are true it exits the IN state and switches to bonds. In 2020 this happens....
2020-10-06 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-10-07 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-10-08 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-10-09 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-10-12 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-10-20 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-10-21 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-10-22 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-10-23 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-10-26 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-11-03 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-11-04 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-11-06 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-11-10 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-11-11 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-11-12 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-11-13 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-11-19 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
2020-12-02 11:30:00 : symbol XLI False DBB False IGE False SHY True UUP False G_S False U_I False C_A False
We have in other variations of this algo, removed SHY as a signal. Again it is debateable because since Nov QQQ has had a nice move but the algo sat on the sidelines. I have removed SHY from the algo and it performs very nicely still. Here is your algo minus the SHY signal....
Jack Pizza
Goldie Yalamanchi the removal of SHY seems to have icreased DD a lot, think the original was around 16-18%, now you're closer to 23%
Jack Pizza
This is an original version the one i've been running live, but for some reason today it failed with the above error message i posted before.
Goldie Yalamanchi
No doubt, the SHY signal WAS very valuable in the past from 2008 or even 1999+ to prevent drawdowns. The only question is will it continue to be. Again defer to the conversation on the FED and rates, etc. Your opinion may vary. Obviously you may wish to keep the signal. Yes I think the above code before we added that fix... was just trying to buy IWM before it sold QQQ, so that is resolved now right? This below code I put in one of the fixes to address that.
These changes below they were to ensure that sells happen before buys. And in the case of where QQQ was switched to IWF... the code in the trade() handles to liquidate first.
def rebalance_when_out_of_the_market(self): # Swap to 'out' assets if applicable if not self.be_in: # Only trade when changing from in to out self.trade({**dict.fromkeys(self.HLD_IN, 0), **self.HLD_OUT}) def rebalance_when_in_the_market(self): # Swap to 'in' assets if applicable if self.be_in: # Only trade when changing from out to in self.trade({**self.HLD_IN, **dict.fromkeys(self.HLD_OUT, 0)}) self.Log(f"TotalPortfolioValue: {self.Portfolio.TotalPortfolioValue}, TotalMarginUsed: {self.Portfolio.TotalMarginUsed}, MarginRemaining: {self.Portfolio.MarginRemaining}, Cash: {self.Portfolio.Cash}") for key in sorted(self.Portfolio.keys()): if self.Portfolio[key].Quantity > 0.0: self.Log(f"Symbol/Qty: {key} / {self.Portfolio[key].Quantity}, Avg: {self.Portfolio[key].AveragePrice}, Curr: { self.Portfolio[key].Price}, Profit($): {self.Portfolio[key].UnrealizedProfit}") def trade(self, weight_by_sec): if self.Portfolio.Invested: for symbol in self.Portfolio.Keys: if symbol not in weight_by_sec: self.Liquidate(symbol) buys = [] for sec, weight in weight_by_sec.items(): # Check that we have data in the algorithm to process a trade if not self.CurrentSlice.ContainsKey(sec) or self.CurrentSlice[sec] is None: continue cond1 = weight == 0 and self.Portfolio[sec].IsLong cond2 = weight > 0 and not self.Portfolio[sec].Invested if cond1 or cond2: quantity = self.CalculateOrderQuantity(sec, weight) if quantity > 0: buys.append((sec, quantity)) elif quantity < 0: self.Order(sec, quantity) for sec, quantity in buys: self.Order(sec, quantity)
T Smith
Goldie Yalamanchi cheers for the trade logic!...
Regarding the want to drop SHY as an indicator. I like the fundamental idea behind having short term bonds as an indicator and believe wishing to remove it would be a poor decision. Doesn't it defeats the point of having a deterministic strategy if we edit it based upon present unclosed trades?
Goldie Yalamanchi
You maybe right T Smith but we have thought that rates are too low and SHY is triggering over and over again. Also going forward if rates are like 0% how can TLT really make a move up? Bond funds borrow from treasury at 10 or 20 year yields and lend out at higher % to make money right? So if they are at near zero which is a move that happened from 1990 all the way to 2020 to get to 0%, how can the bond yield be used as an indicator.
Very welcome to keep SHY as an indicator. I was just discussing the merits of removing it. It will be interesting to see how the market moves forward. Either the rates go the less than 0% which has happened in Germany and pretty much sovereign funds of all developed countries. Maybe finally they will go back up and there will be rates to cut? There simply isn't enough tax revenue to do that at the moment. Idk, next market crash maybe bonds and stocks will both crash.
Jack Pizza
Goldie Yalamanchi not sure I posted the algo above that is the code I have supposedly if i remember correctly fixed any order logic, but you can confirm.
I totally agree with you there will come a time when both bonds / stocks will crash, it's just we don't know when or where. That is why I brought up the idea of implementing a tail risk strategy like Taleb.
Peter Guenther
Quickly sharing some sensitivity results: Bootstrapping
For the past couple of weeks, I was playing around with the idea of using bootstrapping to test the In & Out algo’s sensitivity to possible futures that do not play out exactly (sometimes not even remotely) like the past, a concern that I reckon is present for any trading strategy that we create. Thus, the test may have some applicability beyond our In & Out discussion here. Specifically, bootstrapping can indicate how much an algo’s total return depends on the chronology and idiosyncratic events of the past, i.e. the realization that we use in our backtests. Happy to discuss the test and how it may be expanded; any questions/comments fire away, as usual.
Bootstrapping results for the In & Out
The following chart shows the distribution of the In & Out algo’s total excess returns for 5,000 fundamentally different stock price data scenarios that each span about 13 years (i.e., equivalent length as the time period that we use in our backtests from 1 Jan 2008 to today). The algo holdings are: In = SPY and Out = TLT/IEF. The displayed total excess return (x-axis) is the algo’s total return minus the SPY total returns. An excess return of zero (i.e. the zero vertical line in the chart below) means that the algo performs at par with the market (SPY).
On average, the algo yields a positive excess return (~450%) across the 5,000 different data scenarios. This looks promising since the data scenarios can be extremely different from the past (see the technical discussion below). In data scenarios that are unfavorable for the algo, the algo underperforms the market, which happens in about 10% of the data scenarios. This finding may help to measure risk regarding using the algo for investing. At the bottom 10% percentile, the underperformance is about 30% below the market over 13 years or about 2% below the market per annum.
Technical explanations and discussion
The algo is the In & Out percentile version including the signals PRDC, METL, NRES, DEBT, USDX, the pair comparisons GOLD vs SLVA, UTIL vs INDU, SHCU vs RICU, and the flexible waitdays approach. We bootstrap via drawing random monthly segments, with replacement, from the original timeseries of returns (1 Jan 2008 – 30 Nov 2020; all relevant assets i.e. SPY, signals, pair elements). Using monthly (e.g., vs daily) segments may preserve some of that evolving character of stock prices which are not completely random from one day to the next. Drawing one bootstrap sample gives us one randomly collated new returns series spanning about 13 years (i.e., a possible future). The returns series is then converted to a price series so that the algo can make its decisions as usual. Theoretically, this series could consist of about 155 repetitions of Jan 2008 or any other month; very unlikely, but not impossible. Yet, almost always it is a random mix of months such as Nov 2012 being followed by Mar 2008, being followed by Jun 2020, and so on. When an algo’s performance strongly depends on the past chronology of events, its returns will break down as we break the chronology via random sampling. When an algo’s performance strongly depends on a few favorable (for the algo) idiosyncratic events and patterns in the timeseries, random sampling will tend to make the algo’s performance break down in many of the bootstrap samples, showing up in the distribution chart via many below zero results. For each bootstrap sample, the algo’s decisions are simulated exactly how we would perform them if the bootstrap sample was the actual (a possible future?) price series.
Vladimir
Despite the fact that I don't completely agree with the latest development of "IN OUT"
it was nice to play with "Dual Momentum IN OUT".
Thanks to T Smith.
Enjoy.
Tentor Testivis
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!