In my algorithm I ran into to the problem that all my MarketOnOpenOrders are filled one day later as they should be. For simplicity reasons I recreated the problem in a far simplified algorithm. I am aware that the effects of this simplified algorithm could be achieved easier in many places, however I wanted to stay as close as possible to my original algorithm (e.g. keep a coarse and fine universe selection). Nevertheless I would like to ask that answers concentrate on the problem with the belated fill of the MarketOnOpenOrder.
The simplified algorithm is:
# region imports
from AlgorithmImports import *
# endregion
import datetime as dt
class Test(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2023, 11, 7)
self.SetEndDate(2023, 11, 11)
self.SetCash(100000)
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.AddEquity('SPY', Resolution.Daily)
self.Schedule.On(self.DateRules.EveryDay('SPY'), self.TimeRules.AfterMarketOpen('SPY', -10), self.__BeforeOpen)
self.RemoveSecurity('SPY')
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.__SelectCoarse, self.__SelectFine)
self.count = 0
def OnEndOfAlgorithm(self):
self.AddEquity('MSFT', Resolution.Daily)
BarList = self.History[TradeBar](self.Symbol('MSFT'), dt.datetime(2023,11,7), self.Time, Resolution.Daily)
for bar in BarList:
self.Debug('{:s}: Open = {:.4f}'.format(bar.Time.strftime('%m-%d-%Y %H:%M'), bar.Open))
def __BeforeOpen(self):
for sym in self.ActiveSecurities.Keys:
if self.count == 0:
self. count += 1
self.Debug('{:s}: MarketOnOpenOrder for 100 shares of {:s}'.format(self.Time.strftime('%m-%d-%Y %H:%M'), sym.Value))
ticket = self.MarketOnOpenOrder(sym, 100)
def OnOrderEvent(self, orderEvent: OrderEvent):
self.Debug('{:s} OnOrdrEvent: Symbol={:s}, filled={:.2f} for ${:.4f} per share'.format(self.Time.strftime('%m-%d-%Y %H:%M'), orderEvent.Symbol.Value, orderEvent.FillQuantity, orderEvent.FillPrice))
def __SelectCoarse(self, coarse: List[CoarseFundamental]) -> List[Symbol]:
if self.count == 0:
C = [c.Symbol for c in coarse if c.Symbol.Value == 'MSFT']
else:
C = []
return C
def __SelectFine(self, fine: List[FineFundamental]) -> List[Symbol]:
List = [f.Symbol for f in fine]
return List
The debug output is:
11-07-2023 09:20: MarketOnOpenOrder for 100 shares of MSFT
11-07-2023 09:20 OnOrdrEvent: Symbol=MSFT, filled=0.00 for $0.0000 per share
11-09-2023 00:00 OnOrdrEvent: Symbol=MSFT, filled=100.00 for $361.2668 per share
11-07-2023 00:00: Open = 358.5722
11-08-2023 00:00: Open = 361.2668
11-09-2023 00:00: Open = 361.4165
11-10-2023 00:00: Open = 360.7578
Lets go through the timeline of this algorithm to see where the error occurs:
- on 11/7 at 00:00 a universe of ['MSFT'] is defined
- on 11/7 at 9:20 a Market on open order is issued
- on 11/9 at at 00:00 the order is filled with the open price from 8/11
My question is:
Shouldn't the order be filled with the open price of 11/7 since it was issued before the open on 11/7? I understand that due to the daily resolution, it would be reported as filled on 11/8 at 00:00 when the full candle for 11/7 is available. But instead it is filled with the open price of 11/8 and reported as filled on 11/9 at 00:00.
Thank you for any kind of help, because that really confuses me.
Thanks,
Markus
Mia Alissi
Hello Markus,
The behavior you're observing is due to the way QuantConnect's LEAN engine handles data and order fills. When you're using daily resolution data, your algorithm receives the data bar at the start of the next day (at midnight). This is because the bar represents the entire trading day and is only "complete" at the end of the day.
When you place a MarketOnOpen order, it gets filled with the opening price of the next trading day. This is because the order is placed after the market has opened for the current day (even if it's just a few minutes after the open), and the LEAN engine treats it as an order for the next trading day.
In your case, the MarketOnOpen order is placed on 11/7 at 9:20, which is after the market open. Therefore, it gets filled on the next trading day (11/8) with the opening price of that day. However, because you're using daily resolution data, this fill is reported at the start of the next day (11/9 at 00:00), when the data bar for 11/8 becomes available.
If you want your MarketOnOpen orders to be filled with the opening price of the current trading day, you need to place them before the market opens. You can do this by scheduling your orders to be placed a few minutes before the market open.
Here's an example of how you can do this in Python:
This will schedule your
__BeforeOpen
method to run 10 minutes before the market opens, allowing you to place your MarketOnOpen orders for the current trading day.I hope this helps clarify the behavior you're observing. Let me know if you have any other questions!
Sources:
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.
Melanie Schiefele
Hi Mia,
Thank you for your answer. I can not quite follow your response. The order was sent at 9:20 i.e. 10 minutes before market open. This is why I don't understand it was not filled at 9:30 on market open.
Thanks,
Markus
Mia Alissi
Apologies for the confusion, Markus. You're correct that the order was placed before the market open. However, the issue might be related to the data resolution and the way the LEAN engine handles MarketOnOpen orders.
In the LEAN engine, the MarketOnOpen orders are filled with the opening price of the next bar. When you're using daily resolution data, the next bar is the next trading day. This is why your order placed on 11/7 at 9:20 is filled with the opening price of 11/8.
However, the fill should be reported at the start of the next day (11/8 at 00:00), not on 11/9 at 00:00. The delay in reporting the fill might be due to the way the LEAN engine handles order events. It's possible that the order event for the fill is not processed until the start of the next day after the fill.
If you want your MarketOnOpen orders to be filled with the opening price of the same day, you might need to use a higher resolution data (like minute or second resolution). This way, the next bar after your order is placed would be the same trading day, not the next trading day.
Here's an example of how you can do this in Python:
This will add SPY to your universe with minute resolution data, allowing your MarketOnOpen orders to be filled with the opening price of the same trading day.
I hope this helps clarify the issue. Let me know if you have any other questions!
Sources:
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.
Melanie Schiefele
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!