I'm trying to build a variation of the opening range break but seems as though my orders are not working. Would anyone know why? I'm fairly new to coding so might be missing something somewhere.
# First 30 minutes Highest High and Lowest Low
# -------------------------
STOCK = "SPY"; PERIOD = 30;
# -------------------------
class OpeningRangeBreakout(QCAlgorithm):
# Order ticket for our stop order, Datetime when stop order was last hit
stopMarketTicket = None
stopMarketOrderFillTime = datetime.min
highestSPYPrice = 0
def Initialize(self):
self.SetStartDate(2021, 9, 1)
self.SetEndDate(2021, 9, 10)
self.SetCash(100000)
self.stock = self.AddEquity(STOCK, Resolution.Minute).Symbol
self.max = self.MAX(self.stock, PERIOD, Resolution.Minute, Field.High)
self.min = self.MIN(self.stock, PERIOD, Resolution.Minute, Field.Low)
self.SetWarmUp(PERIOD, Resolution.Minute)
def OnData(self, data):
# # 1. Plot the current SPY price to "Data Chart" on series "Asset Price"
# self.Plot("Data Chart", "Asset Price", self.Securities["SPY"].Close)
if self.IsWarmingUp:
return
if not (self.max.IsReady or self.mi.IsReady):
return
if self.Time.hour < 10 or self.Time.hour > 10 or self.Time.minute != 31:
return
first_30_min_HH = self.max.Current.Value
first_30_min_LL = self.min.Current.Value
self.Log(f"First 30 min Highest High: {first_30_min_HH}")
self.Log(f"First 30 min Lowest Low: {first_30_min_LL}")
self.Plot("Data Chart", 'first_30_min_HH', first_30_min_HH)
self.Plot("Data Chart", 'first_30_min_LL', first_30_min_LL)
if not self.Portfolio.Invested:
if data["SPY"].Close > first_30_min_HH:
self.MarketOrder("SPY", 500)
self.stopMarketTicket = self.StopMarketOrder("SPY", -500, 0.99 * self.Securities["SPY"].High)
elif data["SPY"].Close < first_30_min_LL:
self.MarketOrder("SPY", -500)
self.stopMarketTicket = self.StopMarketOrder("SPY", +500, 1.01 * self.Securities["SPY"].Low)
else:
#2. Plot the moving stop price on "Data Chart" with "Stop Price" series name
self.Plot("Data Chart", "Stop Price", self.highestSPYPrice * 0.9)
if self.Securities["SPY"].High > self.highestSPYPrice:
#2. Save the new high to highestSPYPrice; then update the stop price to 90% of highestSPYPrice
self.highestSPYPrice = self.Securities["SPY"].High
updateFields = UpdateOrderFields()
updateFields.StopPrice = self.highestSPYPrice * 0.99
self.stopMarketTicket.Update(updateFields)
#3. Print the new stop price with Debug()
self.Debug("SPY: " + str(self.highestSPYPrice) + " Stop: " + str(updateFields.StopPrice))
def OnOrderEvent(self, orderEvent):
if orderEvent.Status != OrderStatus.Filled:
return
if self.stopMarketTicket is not None and self.stopMarketTicket.OrderId == orderEvent.OrderId:
self.stopMarketOrderFillTime = self.Time
Victoria Butler
Hi Ivan, I fixed your problem, and found another one in the process.
So, the first one was somewhat silly, and actually took me forever to find. You were placing market orders for 500 shares of SPY, when your cash was only set to 100000, so there was insufficient buying power.
Â
Second. The way the maximum/minimum indicators work is that they will continue updating with new data, so despite setting it to 30, if you want 9:30-10:00's max value, at 10:05 for example, you would have 9:35 - 10:05's value. I created a method that will save the value of the indicator to a variable at 10:AM which resets each night, which you can then reference in OnData for your trade logic.Â
Â
For my own ease, when debugging I messed with a few of your variables such as resolution, period, etc, and just added them into initialize, but you can switch that back if you want.
Victoria Butler
Whoops, the backtest did not attach. I also found an issue with your trailing stop loss where you were trying to reference tickets that did not exist. I created Tickets for both your short and long positions. Also, you still use -(quantity)n not ‘+’ when exiting short positions(I know that's a little confusing) This is all I have time for now. really, but I hope this helps. Also, keep in mind that you have no mechanism for taking profits, apart from the liberal trailing stop which updates every minute. Without the trailing stop, you algo makes numerous orders, so take a look at that when you are playing around.Â
Victoria Butler
Fixed a couple values
Vladimir
Victoria Butler
Thanks for sharing your version of "Opening Range Breakout".
Its metric great in sample backtest (2021,9,1 : 2021,10,10) with only one trade being executed.
It behaves as expected, switching between long and short as we extend the backtest to 2022.5.5 with 40 completed trades.
For some unknown reason it change behavior when we start  backtest earlier from 2020, 5, 1.
With only 13 trades being executed in short period of time (2020-05-01 : 2020-05-18) Â and the rest time being in long position.
Don’t you think that this strategy should choose a position on daily basis?
Â
Mcdawgzy
Thanks Victoria for your help - the QC system seems to be down right now so I can't check whether the outputs match what I'm expecting but I will do once I get a chance, but greatly appreciate your help.
Vladmir - the system doesn't necessarily enter a position every single day. It is dependent on price breaking the opening range to enter a trade. If that range isn't broken, there should be no trade on that particular day,
Victoria Butler
Vladimir
I am much more inclined toward intraday positions, so yes, I would have it take a daily position. This is much closer to what I would prefer, though, I do think much of its success is attributed to the market, not the algo specifically, as is seen on a three-year backtest.
Vladimir
Ivanc,
-→ If that range isn't broken, there should be no trade on that particular day.
There are only 5% such days (508-265-217)/508.
But Victoria Butler got my message right..
def OnEndOfDay(self):
    self.spy30High = 0
    self.spy30Low = 0
Total Trades 1150 (2019, 5, 5 : 2022, 5, 5)
Mcdawgzy
Hi both,
I still don't think the trailing stop is working as I originally intended. In theory, if on a particular day a stock is making lower lows, shouldn't the stop be updated multiple times per day? (and vice versa for higher highs?)Â
I'm only seeing it update once when an opening order has been filled, but no subsequent updates afterwards. For example see attached backtest - I am seeing 29th April order get entered at 10:19am. The stop also gets updated at 10:19am. Then there are no subsequent updates to the stop until the stop order is cancelled as the position is liquidated 5 mins before close.Â
How would I change the code for that?
Thanks
Mcdawgzy
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!