Hey Everyone,
I’m encountering a timing issue in my algorithm that involves the interaction between custom daily bars being consolidated and the on_data method. I'm subscribing to minute resolution data for a single stock, then consolidating daily bars using the minute bars. It seems that daily bars can be consolidated before the actual trading day ends. In one instance (2023-01-12 16:00:00), my consolidator event handler ran at 16:00 before the last on_data method call of the trading day, and accidentally triggered a trade. This creates an inconsistency in daily open/high/low values and can incorrectly trigger orders at the end of the day in my code.
Sharing a code snippet below to paint the picture. Am I doing something wrong or is this a bug? Any solutions appreciated!
# region imports
from AlgorithmImports import *
# endregion
class SwimmingLightBrownCobra(QCAlgorithm):
def initialize(self):
self.set_start_date(2023, 1, 10)
self.set_end_date(2023, 1, 16)
self.set_cash(100000)
baba = self.add_equity("BABA", Resolution.MINUTE)
baba.set_data_normalization_mode(DataNormalizationMode.SPLIT_ADJUSTED)
self.baba = baba.symbol
# Attributes for setups
self.setup_type = None
self.entry_price = None
self.stop_price = None
self.target_price = None
self.have_setup = 0
self.ready_for_setups = False
self.order_ticket = None
self.target_order_ticket = None
self.stop_order_ticket = None
# Data Subscriptions - Daily, Weekly
self.daily_consolidator = self.consolidate(self.baba, Resolution.DAILY, self.on_daily_consolidated)
self.weekly_consolidator = self.consolidate(self.baba, Calendar.WEEKLY, self.on_weekly_consolidated)
# Warm Up Rolling Windows
historical_trade_bars = self.history[TradeBar](self.baba, 200, Resolution.DAILY)
for trade_bar in historical_trade_bars:
# Warm up consolidators
self.daily_consolidator.update(trade_bar)
self.weekly_consolidator.update(trade_bar)
# Start looking for setups
self.ready_for_setups = True
def on_data(self, data: Slice):
if self.baba in data.bars:
self.log("self.baba in data.bars")
current_bar = data.bars[self.baba]
# Look for trades if not currently in a trade
if not self.portfolio.invested:
# Check if order already placed
if self.order_ticket is None:
# Bullish setup
if self.have_setup > 0:
self.order_ticket = self.stop_market_order(self.baba, 10, self.entry_price)
self.log("Setting up a bullish order")
self.log(f"Entry Price: {self.entry_price}")
self.log(f"Stop Loss Price: {self.stop_price}")
self.log(f"Target Price: {self.target_price}")
# Bearish setup
elif self.have_setup < 0:
self.order_ticket = self.stop_market_order(self.baba, -10, self.entry_price)
self.log("Setting up a bearish order")
self.log(f"Entry Price: {self.entry_price}")
self.log(f"Stop Loss Price: {self.stop_price}")
self.log(f"Target Price: {self.target_price}")
else:
return
else:
self.log(f"No data for {self.time}")
def on_order_event(self, order_event):
if order_event.status == OrderStatus.FILLED:
# Log the order we filled
self.log("Order was filled")
self.log(order_event)
# Entered the trade, setting target and stop
if order_event.order_id == self.order_ticket.order_id:
self.target_order_ticket = self.limit_order(order_event.symbol, -order_event.fill_quantity, self.target_price)
self.stop_order_ticket = self.stop_market_order(order_event.symbol, -order_event.fill_quantity, self.stop_price)
self.log("Setting target and stop loss orders")
# Reached target, exiting trade
elif self.target_order_ticket is not None and order_event.order_id == self.target_order_ticket.order_id:
self.stop_order_ticket.cancel()
self.log("Reached target, exiting trade; target order ticket below")
self.log(self.target_order_ticket)
# Hit our stop, exiting trade
elif self.stop_order_ticket is not None and order_event.order_id == self.stop_order_ticket.order_id:
self.target_order_ticket.cancel()
self.log("Hit our stop, exiting trade; stop order ticket below")
self.log(self.stop_order_ticket)
elif order_event.status == OrderStatus.SUBMITTED:
self.log("Submitted an order")
self.log(order_event)
else:
self.log("Order event status was different than filled or submitted")
self.log(order_event)
self.log(order_event.status)
def on_daily_consolidated(self, bar):
# Manage orders
if self.order_ticket is not None:
# Cancel any outstanding orders
if self.order_ticket.status == OrderStatus.SUBMITTED:
self.log(f"Canceled order: {self.order_ticket}")
self.order_ticket.cancel()
self.order_ticket = None
# Reset for next day if we made a trade
elif self.order_ticket.status == OrderStatus.FILLED and not self.portfolio.invested:
self.order_ticket = None
self.log("the order status for self.order_ticket was filled and the portfolio was not invested")
else:
self.log("Log - self.order_ticket is None")
# Update rolling window
self.window_daily.add(bar)
# Check setups only after warm-up is complete
if self.ready_for_setups:
self.have_setup = self.check_setups("daily")
def on_weekly_consolidated(self, bar):
self.window_weekly.add(bar)
Mia Alissi
Make sure to define
window_daily
,window_weekly
, andcheck_setups
in your class to avoid errors.Sources: Order Tickets - QuantConnect.com, Calendar Consolidators - QuantConnect.com, Multiple Symbol Consolidation Algorithm, Momentum Effect In Commodities Futures, Extended Market Trading Regression Algorithm
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.
Cayhil Grubbs
Attaching a basic backtest and sharing the log it produced below. I've noticed a few things I'd love perspective on.
Is there a fix?
2023-01-10 00:00:00 Counter: 196; Trade Bar Info: BABA: O: 98.48 H: 104.52 L: 96.97 C: 104 V: 50501702
2023-01-10 00:00:00 Bar Time: 2023-01-04 09:30:00
2023-01-10 00:00:00 Bar End Time: 2023-01-04 16:00:00
2023-01-10 00:00:00 Warm Up Bar: BABA: O: 90.8 H: 94.45 L: 90.79 C: 91.97 V: 25092024
2023-01-10 00:00:00 Warm Up Bar Time: 2023-01-03 09:30:00
2023-01-10 00:00:00 Warm Up Bar End Time: 2023-01-03 16:00:00
2023-01-10 00:00:00 Counter: 197; Trade Bar Info: BABA: O: 101.15 H: 105.7 L: 100.65 C: 104.58 V: 29429529
2023-01-10 00:00:00 Bar Time: 2023-01-05 09:30:00
2023-01-10 00:00:00 Bar End Time: 2023-01-05 16:00:00
2023-01-10 00:00:00 Warm Up Bar: BABA: O: 98.48 H: 104.52 L: 96.97 C: 104 V: 50501702
2023-01-10 00:00:00 Warm Up Bar Time: 2023-01-04 09:30:00
2023-01-10 00:00:00 Warm Up Bar End Time: 2023-01-04 16:00:00
2023-01-10 00:00:00 Counter: 198; Trade Bar Info: BABA: O: 104.11 H: 108 L: 102.46 C: 107.4 V: 20096871
2023-01-10 00:00:00 Bar Time: 2023-01-06 09:30:00
2023-01-10 00:00:00 Bar End Time: 2023-01-06 16:00:00
2023-01-10 00:00:00 Warm Up Bar: BABA: O: 101.15 H: 105.7 L: 100.65 C: 104.58 V: 29429529
2023-01-10 00:00:00 Warm Up Bar Time: 2023-01-05 09:30:00
2023-01-10 00:00:00 Warm Up Bar End Time: 2023-01-05 16:00:00
2023-01-10 00:00:00 Counter: 199; Trade Bar Info: BABA: O: 111.99 H: 113.1 L: 108.12 C: 110.83 V: 37222935
2023-01-10 00:00:00 Bar Time: 2023-01-09 09:30:00
2023-01-10 00:00:00 Bar End Time: 2023-01-09 16:00:00
2023-01-10 00:00:00 Warm Up Bar: BABA: O: 104.11 H: 108 L: 102.46 C: 107.4 V: 20096871
2023-01-10 00:00:00 Warm Up Bar Time: 2023-01-06 09:30:00
2023-01-10 00:00:00 Warm Up Bar End Time: 2023-01-06 16:00:00
2023-01-10 09:31:00 Daily bar was just consolidated: BABA: O: 111.99 H: 113.1 L: 108.12 C: 110.83 V: 37222935
2023-01-10 09:31:00 2023-01-10 09:31:00
2023-01-10 09:31:00 It's exactly 9:31am, proof: 2023-01-10 09:31:00
2023-01-10 15:56:00 It's after 3:55pm, here's the exact date/time: 2023-01-10 15:56:00
2023-01-10 15:57:00 It's after 3:55pm, here's the exact date/time: 2023-01-10 15:57:00
2023-01-10 15:58:00 It's after 3:55pm, here's the exact date/time: 2023-01-10 15:58:00
2023-01-10 15:59:00 It's after 3:55pm, here's the exact date/time: 2023-01-10 15:59:00
2023-01-10 16:00:00 Daily bar was just consolidated: BABA: O: 113 H: 115.48 L: 111.21 C: 114.875 V: 31051842
2023-01-10 16:00:00 Market closed
2023-01-11 09:31:00 2023-01-11 09:31:00
2023-01-11 09:31:00 It's exactly 9:31am, proof: 2023-01-11 09:31:00
2023-01-11 15:56:00 It's after 3:55pm, here's the exact date/time: 2023-01-11 15:56:00
2023-01-11 15:57:00 It's after 3:55pm, here's the exact date/time: 2023-01-11 15:57:00
2023-01-11 15:58:00 It's after 3:55pm, here's the exact date/time: 2023-01-11 15:58:00
2023-01-11 15:59:00 It's after 3:55pm, here's the exact date/time: 2023-01-11 15:59:00
2023-01-11 16:00:00 Daily bar was just consolidated: BABA: O: 114.6 H: 115.2 L: 112.31 C: 115.02 V: 21791153
2023-01-11 16:00:00 Market closed
2023-01-12 09:31:00 2023-01-12 09:31:00
2023-01-12 09:31:00 It's exactly 9:31am, proof: 2023-01-12 09:31:00
2023-01-12 15:56:00 It's after 3:55pm, here's the exact date/time: 2023-01-12 15:56:00
2023-01-12 15:57:00 It's after 3:55pm, here's the exact date/time: 2023-01-12 15:57:00
2023-01-12 15:58:00 It's after 3:55pm, here's the exact date/time: 2023-01-12 15:58:00
2023-01-12 15:59:00 It's after 3:55pm, here's the exact date/time: 2023-01-12 15:59:00
2023-01-12 16:00:00 Daily bar was just consolidated: BABA: O: 113.66 H: 113.79 L: 111.46 C: 113.13 V: 15564457
2023-01-12 16:00:00 Market closed
2023-01-13 09:31:00 2023-01-13 09:31:00
2023-01-13 09:31:00 It's exactly 9:31am, proof: 2023-01-13 09:31:00
2023-01-13 15:56:00 It's after 3:55pm, here's the exact date/time: 2023-01-13 15:56:00
2023-01-13 15:57:00 It's after 3:55pm, here's the exact date/time: 2023-01-13 15:57:00
2023-01-13 15:58:00 It's after 3:55pm, here's the exact date/time: 2023-01-13 15:58:00
2023-01-13 15:59:00 It's after 3:55pm, here's the exact date/time: 2023-01-13 15:59:00
2023-01-13 16:00:00 Daily bar was just consolidated: BABA: O: 114.68 H: 117.98 L: 114.09 C: 117.01 V: 23527440
2023-01-13 16:00:00 Market closed
Cayhil Grubbs
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!