Disclaimer: I know that everything that is posted in the community is free to clone, which I don't have a problem with, but if you do make any improvements to the algorthm, it would be much appreciated if you post your finding back here.
Hello all,
I have created this strategy that seems to work very well, but I found a flaw while testing it, and I was hoping I could get an explanation. First, let me give you a rundown of what this algorithm does.
I can not exaggerate enough on how simple this also is. First things first, here are the indicators that I use (all of these indicators are on hourly bars):
1. Exponential Moving Average 5 and 2 on XIV. These indicators will be referred to as EMA5 and EMA2.
2. Exponential Moving Average 50 and 25 on SPY. These indicators will be referred to as EMA 50 and EMA 25.
3. Simple Moving Average 200 and 100 on SPY. These indicators will be referred to as SMA 200 and SMA 100.
Now here's the strategy. I'm going to split it up into market trends:
Bull market:
If SMA200 is less than SMA 100 -this indicates that the market is bull- and EMA5 is less than EMA2, buy XIV because the XIV is going up in a bull market. If EMA5 goes above EMA2, sell all positions.
Bear Market with short-term bull:
If SMA200 is greater than SMA100, EMA50 is less than EMA25, and EMA5 is less than EMA2, buy XIV because the market is bear long term, but EMA50 and EMA25 indicate that there is a short-term bull trend. If, however, EMA5 is greater than EMA2 the algo will sell all XIV shares and move half of its cash into UVXY because the market is in a short-term bull market, but it's still bear long-term according to the SMA200 and SMA100 indicators.
Full Bear Market:
If SMA200 is greater than SMA100, EMA50 is greater than EMA25, and EMA5 is less than EMA2, buy XIV. If EMA5 is greater than EMA2, the algo will use all of its cash on UVXY because the market is going down in both the short-term and the long-term.
That's the strategy, but I have a problem. I have a schedule that runs every 5 minutes. In my early testing, I used this schedule to try stop losses. However, I found that it was not needed and put a "pass" statement at the beginning of the function so that it wouldn't run. When I run the code, I get the backtest as seen below which isn't bad. Here's the problem, though. When I take out the schedule that isn't supposed to be running in the first place, I get slightly worse results as seen in the backtest in the post below this one. Why is this happening?
Thanks in advance,
Malachi
Malachi Bazar
Here's the other backtest without the schedule:
Warren Harding
You've got to love these XIV/UVXY algos. I don't think it's entirely false hope Malachi. Liquidity is excellent and there actually seems to be some money to be made here. You should use XIV as a benchmark to ensure you are soundly beating it. You seem to be.
Malachi Bazar
Hello Warren,
Thanks for the feedback. Speaking of setting the benchmark to XIV, I did that in the code, but it never shows up in the back test. Also, any ideas on why there would be a difference between the two back tests?
Thanks,
Malachi
Tyler Durden
Nice Algo. Do you need 200 days of warmup? if not, i'd use this:
self.SetWarmUp(200) # 200 bars. You're using hours,
Warren Harding
Unfortunately, I don't have an answer to either of your questions.
Malachi Bazar
@Tyler Durden, thanks for the feedback! I guess I didn't need 200 days of data. As you can tell, the code is kinda a mess and in that, may be the source of my problems.
Tyler Durden
Malachi Bazar, there's a bit of false hope here with liquidity. Expect slippage of up to $0.10 per order if you're using interactive brokers.
You'll get better profitability results if you can refine your indicators to use minute data rather than hour.
Trap for new players, don't mix different resolutions like Resolution.Minute and Resolution.Hour with self.AddEquity because the back-tester will try to fill using the hourly price, peeking into the future, even though you trigger a buy or sell order at the minute resolution.
To demonstrate what I mean, I've optimized your strategy by mixing Hour and Minute equity resolutions for UVXY and XIV. Backtesting results are awesome but it won't work when trading a real account.
Tyler Durden
Here's what the strategy looks like when not mixing Resolution.Hour and Resolution.Minute with self.AddEquity but just using Resolution.Minute for both UVXY and XIV.
This is how live trading the same strategy will actually look.
If you can find a suitable combination of EMA or SMA indicators that work at the Resolution.Minute level for both instruments, you could have a winning system.
Jared Broad
Thanks not quite correct Tyler; its performing different trades because of the different indicator values from running on different bars; the minute vs hourly fills won't change the equity curve.
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.
Tyler Durden
Hey Jared, I think we're saying the same thing. If not, please help me understand what I'm missing.
If we're back test this code, will the fill price for UVXY be self.Time or the price from Resolution.Hour?
<snip init code> self.vxx = self.AddEquity("UVXY", Resolution.Hour).Symbol self.xiv = self.AddEquity("XIV", Resolution.Minute).Symbol def OnData(self, slice): self.SetHoldings("UVXY", 0.2) self.SetHoldings("XIV", 0.2)
Put another way, if self.Time is 15:56 will the UVXY fill price be the 15:00 price or the 15:56 price?
Here's a captured log. As expected, it shows the UVXY price changing each hour (Resolution.Hour). What's not expected is for self.SetHoldings to travel back in time and fill using a price that's 56 miutes old.
2018-01-10 15:48:00 : Time: 2018-01-10 15:48:00 UVXY hourly: 8.83000000000 XIV minute: 143.73000000000 2018-01-10 15:49:00 : Time: 2018-01-10 15:49:00 UVXY hourly: 8.83000000000 XIV minute: 143.79000000000 2018-01-10 15:50:00 : Time: 2018-01-10 15:50:00 UVXY hourly: 8.83000000000 XIV minute: 143.87000000000 2018-01-10 15:51:00 : Time: 2018-01-10 15:51:00 UVXY hourly: 8.83000000000 XIV minute: 144.03000000000 2018-01-10 15:52:00 : Time: 2018-01-10 15:52:00 UVXY hourly: 8.83000000000 XIV minute: 144.03000000000 2018-01-10 15:53:00 : Time: 2018-01-10 15:53:00 UVXY hourly: 8.83000000000 XIV minute: 144.00000000000 2018-01-10 15:54:00 : Time: 2018-01-10 15:54:00 UVXY hourly: 8.83000000000 XIV minute: 144.07000000000 2018-01-10 15:55:00 : Time: 2018-01-10 15:55:00 UVXY hourly: 8.83000000000 XIV minute: 144.18000000000 2018-01-10 15:56:00 : Time: 2018-01-10 15:56:00 UVXY hourly: 8.83000000000 XIV minute: 144.12000000000 2018-01-10 15:56:00 : 2018-01-10 15:56:00: 0: Time: 1/10/2018 8:56:00 PM OrderID: 38 Symbol: XIV Status: Submitted 2018-01-10 15:56:00 : 2018-01-10 15:56:00: 0: Time: 1/10/2018 8:56:00 PM OrderID: 38 Symbol: XIV Status: Filled Quantity: 690 FillPrice: 144.12 USD OrderFee: 3.45 USD 2018-01-10 15:56:00 : 2018-01-10 15:56:00: 0: Time: 1/10/2018 8:56:00 PM OrderID: 39 Symbol: UVXY Status: Submitted 2018-01-10 15:56:00 : 2018-01-10 15:56:00: 0: Time: 1/10/2018 8:56:00 PM OrderID: 39 Symbol: UVXY Status: Filled Quantity: -11269 FillPrice: 8.83 USD OrderFee: 56.345 USD 2018-01-10 15:57:00 : Time: 2018-01-10 15:57:00 UVXY hourly: 8.83000000000 XIV minute: 144.08000000000 2018-01-10 15:58:00 : Time: 2018-01-10 15:58:00 UVXY hourly: 8.83000000000 XIV minute: 144.12500000000 2018-01-10 15:59:00 : Time: 2018-01-10 15:59:00 UVXY hourly: 8.83000000000 XIV minute: 144.10000000000 2018-01-10 16:00:00 : Time: 2018-01-10 16:00:00 UVXY hourly: 8.78000000000 XIV minute: 144.19000000000 2018-01-11 09:31:00 : Time: 2018-01-11 09:31:00 UVXY hourly: 8.78000000000 XIV minute: 145.52000000000 2018-01-11 09:32:00 : Time: 2018-01-11 09:32:00 UVXY hourly: 8.78000000000 XIV minute: 145.42000000000 2018-01-11 09:33:00 : Time: 2018-01-11 09:33:00 UVXY hourly: 8.78000000000 XIV minute: 145.48000000000 2018-01-11 09:34:00 : Time: 2018-01-11 09:34:00 UVXY hourly: 8.78000000000 XIV minute: 145.50000000000
In my view, SetHoldings should always fill at the price closest to self.Time, regardless of the bar resolution.
If the Resolutions for all instruments are the same then it's not going to be an issue but if we mix different bar resolutions then I'd still expect self.SetHoldings to mimick live bahavior and fill at the price closest to self.Time.
Let me explain. If we go live, it's unlikely that SetHoldings will fill at a price that's 56 minutes, old unless the market doesn't move, so what bar time/price is used for the fill when the algo is live? Is it the live price closest to self.Time? If yes, shouldn't the same behavior apply when back testing?
Jared Broad
10am instead of 931am. Theres no travelling back in time :D
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.
Tyler Durden
Back to the future? :-) Ok. Thanks for clarifying. Lot's of things to consider when back-testing v.s. live. Behaviors can be different.
There's no way live trading can know the 10am closing price at 931am so I'll keep that in mind when mixing different minute/hour/day bars
I'm LOVING ths platform!
Malachi Bazar
Tyler, thanks for the tips and feed back! Just to be clear, are you saying that I'm using hourly and minute data? If so, I'm using only hourly because it's able to filter out the volitility better than using minute bars. I was under the impression that if I use hour bars, it will update the indicators as well as the prices of the equities every hour. So, the algorithm should only be able to trade every hour because it's only able to get the latest data every hour. I don't want to use mix minute data and hour data. That would create uneeded bias because some indicators and equities would't update values simultaneously. If I am wrong please advise, because I'm still a noob.
Jared, I posted on Slack yesterday that setting benchmarks in Python didn't seem to be working. This algorithm tries to change the benchmark to XIV, but as you can see in the benchmark, it is still set to the SPY.
Thanks again,
Malachi
Tyler Durden
Hey Malachi,
Your algo uses hourly bars but I optimized it (badly) thinking that i could mix hour and minute bars. The backtester gave me impressive results however they're misleading. My bad trying to mix hourly and minute bars.
Can you see my discussion above with Jared about it? I go into quite a bit of depth and show some raw timestamp data.
Thanks
Jared Broad
"There's no way live trading can know the 10am closing price at 931am so I'll keep that in mind when mixing different minute/hour/day bars" -- You don't need to keep it in mind -- the backtester automatically feeds you data at the right time. This prevents "look ahead bias".
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.
Malachi Bazar
Jared,
are you saying that Tyler's first backtest is more or less legitament. He mixed minute and hour bars on the indicators, so I think that would send false signals and bad buy/sell orders because if an event is triggered on a minute indicator and trys to buy/sell a stock with hourly bars, the backtest engine would buy/sell old data. This old data may be very different from current data that set off the indicator's event. Sorry if I'm misunderstanding, but it seems that it is not a good idea to mix minute and hour indicators. It seems that the indicators bars should be set to whatever the longest bar is for the equities. Please correct me if I'm wrong.
Tyler,
I just got your other messages. I had to clear my browser cache.
Thanks,
Malachi
Jared Broad
Ah sorry I misunderstood -- in this case if the assets are highly correlated you'll get inadvertant look ahead bias as your minute data will "look into the future" for the hour bar which hasn't arrived yet. I think you can look at the Time property on the bars themselves (slice.Bars["AAPL"].Time) to see when they were emitted and only trade where there's new hourly data.
Interesting case; we could probably put a note/warning onto the order tag to let people know it was an old-close price used for the fill.
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.
Malachi Bazar
Jared,
Thanks for the confirmation! A warning would probably be good for new developers.
Thanks,
Malachi
Malachi Bazar
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!