Writing Algorithms
Scheduled Events
Create Scheduled Events
To create a Scheduled Event, call the Schedule.On
schedule.on
method. The method expects a DateRules
object, a TimeRules
object, and a function to execute. The following examples demonstrate some common Scheduled Events.
Schedule Events Before Market Open
You may want to train a model or fetch historical data before the market opens. The following example demonstrates how to set a Scheduled Event for 10 minutes before the market opens.
public override void Initialize() { // Call the BeforeMarketOpen method 10 minutes before open every day SPY is trading. var symbol = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA); Schedule.On( DateRules.EveryDay(symbol), TimeRules.BeforeMarketOpen(symbol, 10), BeforeMarketOpen ); }
def initialize(self): # Call the _before_market_open method 10 minutes before open every day SPY is trading. symbol = Symbol.create('SPY', SecurityType.EQUITY, Market.USA) self.schedule.on( self.date_rules.every_day(symbol), self.time_rules.before_market_open(symbol, 10), self._before_market_open )
Schedule Events on the Last Trading Day of the Week
You may want to rebalance your portfolio on the last trading day of each week and factor in market holidays. The following example demonstrates how to set a Scheduled Event for the last trading day of each week 30 minutes before the market closes.
public override void Initialize() { // Call the Rebalance method 30 minutes before the end of the SPY trading week. var symbol = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA); Schedule.On( DateRules.WeekEnd(symbol), TimeRules.BeforeMarketClose(symbol, 30), Rebalance ); }
def initialize(self): # Call the _rebalance method 30 minutes before the end of the SPY trading week. symbol = Symbol.create('SPY', SecurityType.EQUITY, Market.USA) self.schedule.on( self.date_rules.week_end(symbol), self.time_rules.before_market_close(symbol, 30), self._rebalance )
Schedule Events on Regular Intervals Throughout the Trading Day
You may want to perform some action on a regular interval through each trading day. The following example demonstrates how to set a Scheduled Event for every 30 minutes through the trading day for SPY.
public override void Initialize() { // Every day SPY is trading, call the 'SomeAction' method every 30 minutes. var symbol = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA); Schedule.On( DateRules.EveryDay(symbol), TimeRules.Every(TimeSpan.FromMinutes(30)), SomeAction ); }
def initialize(self): # Every day SPY is trading, call the '_some_action' method every 30 minutes. symbol = Symbol.create('SPY', SecurityType.EQUITY, Market.USA) self.schedule.on( self.date_rules.every_day(symbol), self.time_rules.every(timedelta(minutes=30)), self._some_action )
Date Rules
The following table describes the supported DateRules
:
Member | Description |
---|---|
self.date_rules.set_default_time_zone(time_zone: DateTimeZone)
DateRules.SetDefaultTimeZone(DateTimeZone timeZone); | Sets the time zone for the DateRules object used in all methods in this table. The default time zone is the algorithm time zone. |
self.date_rules.on(year: int, month: int, day: int)
DateRules.On(int year, int month, int day) | Trigger an event on a specific date. |
self.date_rules.every_day()
DateRules.EveryDay() | Trigger an event every day. |
self.date_rules.every_day(symbol: Symbol, extended_market_hours: bool = False)
DateRules.EveryDay(Symbol symbol, bool extendedMarketHours = false) | Trigger an event every day a specific symbol is trading. |
self.date_rules.every(days: List[DayOfWeek])
DateRules.Every(params DayOfWeek[] days) | Trigger an event on specific days throughout the week. To view the DayOfWeek enum members, see DayOfWeek Enum in the .NET documentation. |
self.date_rules.month_start(days_offset: int = 0)
DateRules.MonthStart(int daysOffset = 0) | Trigger an event on the first day of each month plus an offset. |
self.date_rules.month_start(symbol: Symbol, daysOffset: int = 0)
DateRules.MonthStart(Symbol symbol, int daysOffset = 0) | Trigger an event on the first tradable date of each month for a specific symbol plus an offset. |
self.date_rules.month_end(days_offset: int = 0)
DateRules.MonthEnd(int daysOffset = 0) | Trigger an event on the last day of each month minus an offset. |
self.date_rules.month_end(symbol: Symbol, daysOffset: int = 0)
DateRules.MonthEnd(Symbol symbol, int daysOffset = 0) | Trigger an event on the last tradable date of each month for a specific symbol minus an offset. |
self.date_rules.week_start(days_offset: int = 0)
DateRules.WeekStart(int daysOffset = 0) | Trigger an event on the first day of each week plus an offset. |
self.date_rules.week_start(symbol: Symbol, days_offset: int = 0)
DateRules.WeekStart(Symbol symbol, int daysOffset = 0) | Trigger an event on the first tradable date of each week for a specific symbol plus an offset. |
self.date_rules.week_end(days_offset: int = 0)
DateRules.WeekEnd(int daysOffset = 0) | Trigger an event on the last day of each week minus an offset. |
self.date_rules.week_end(symbol: Symbol, days_offset: int = 0)
DateRules.WeekEnd(Symbol symbol, int daysOffset = 0) | Trigger an event on the last tradable date of each week for a specific symbol minus an offset. |
self.date_rules.year_start(days_offset: int = 0)
DateRules.YearStart(int daysOffset = 0) | Trigger an event on the first day of each year plus an offset. |
self.date_rules.year_start(symbol: Symbol, days_offset: int = 0)
DateRules.YearStart(Symbol symbol, int daysOffset = 0) | Trigger an event on the first tradable date of each year for a specific symbol plus an offset. |
self.date_rules.year_end(days_offset: int = 0)
DateRules.YearEnd(int daysOffset = 0) | Trigger an event on the last day of each year minus an offset. |
self.date_rules.year_end(symbol: Symbol, days_offset: int = 0)
DateRules.YearEnd(Symbol symbol, int daysOffset = 0) | Trigger an event on the last tradable date of each year for a specific symbol minus an offset. |
self.date_rules.today DateRules.Today | Trigger an event once today. |
self.date_rules.tomorrow DateRules.Tomorrow | Trigger an event once tomorrow. |
To define custom date rules, create a FuncDateRule
object.
The FuncDateRule
constructor expects a name
argument of type string
str
and a getDatesFunction
get_dates_function
argument of type Func<DateTime, DateTime, IEnumerable<DateTime>>
Callable[[datetime, datetime], List[datetime]]
.
The getDatesFunction
get_dates_function
function receives the start and end dates of the algorithm and returns a list of dates for the date rule.
In live trading, the end date is 12/31/2025.
The following example demonstrates how to define a date rule that represents the 10th day of each month:
// Create a date rule that specifies the 10th day of each month. var dateRule = new FuncDateRule( name: "10th_day_of_the_month", getDatesFunction: (start, end) => Enumerable.Range(start.Year, end.Year - start.Year + 1) .SelectMany(year => Enumerable.Range(1, 12).Select(month => new DateTime(year, month, 10))) );
# Create a date rule that specifies the 10th day of each month. date_rule = FuncDateRule( name="10th_day_of_the_month", get_dates_function=lambda start, end: [ datetime(year, month, 10) for year in range(start.year, end.year) for month in range(1,12) ] )
Time Rules
The following table describes the supported TimeRules
:
Member | Description |
---|---|
self.time_rules.set_default_time_zone(time_zone: DateTimeZone)
TimeRules.SetDefaultTimeZone(DateTimeZone timeZone) | Sets the time zone for the TimeRules object used in all methods in this table, except when a different time zone is given. The default time zone is the algorithm time zone. |
self.time_rules.before_market_open(symbol: Symbol, minutes_before_open: float = 0, extended_market_open: bool = False)
TimeRules.BeforeMarketOpen(Symbol symbol, double minutesBeforeOpen = 0, bool extendedMarketOpen = false) | Trigger an event a few minutes before market open for a specific symbol (default is 0). This rule doesn't work for Crypto securities or custom data. |
self.time_rules.after_market_open(symbol: Symbol, minutes_after_open: float = 0, extended_market_open: bool = False)
TimeRules.AfterMarketOpen(Symbol symbol, double minutesAfterOpen = 0, bool extendedMarketOpen = false) | Trigger an event a few minutes after market open for a specific symbol (default is 0). This rule doesn't work for Crypto securities or custom data. |
self.time_rules.before_market_close(symbol: Symbol, minutes_before_close: float = 0, extended_market_open: bool = False)
TimeRules.BeforeMarketClose(Symbol symbol, double minutesBeforeClose = 0, bool extendedMarketOpen = false) | Trigger an event a few minutes before market close for a specific symbol (default is 0). This rule doesn't work for Crypto securities or custom data. |
self.time_rules.after_market_close(symbol: Symbol, minutes_after_close: float = 0, extended_market_open: bool = False)
TimeRules.AfterMarketClose(Symbol symbol, double minutesAfterClose = 0, bool extendedMarketOpen = false) | Trigger an event a few minutes after market close for a specific symbol (default is 0). This rule doesn't work for Crypto securities or custom data. |
self.time_rules.every(interval: timedelta)
TimeRules.Every(TimeSpan interval) | Trigger an event every period interval starting at midnight. |
self.time_rules.now TimeRules.Now | Trigger an event at the current time of day. |
self.time_rules.midnight TimeRules.Midnight | Trigger an event at midnight. |
self.time_rules.noon TimeRules.Noon | Trigger an event at noon. |
self.time_rules.at(hour: int, minute: int, second: int = 0)
TimeRules.At(int hour, int minute, int second = 0) | Trigger an event at a specific time of day (e.g. 13:10). |
self.time_rules.at(hour: int, minute: int, second: int, time_zone: DateTimeZone)
TimeRules.At(int hour, int minute, int second, DateTimeZone timeZone) | Trigger an event at a specific time of day in the given time zone (e.g. 13:10 UTC). |
To define custom time rules, create a FuncTimeRule
object.
The FuncTimeRule
constructor expects a name
argument of type string
str
and a createUtcEventTimesFunction
create_utc_event_times_function
argument of type Func<IEnumerable<DateTime>, IEnumerable<DateTime>>
Callable[[List[datetime]], List[datetime]]
.
The function receives the list of dates from the date rule and then returns a list of DateTime
datetime
that define the time rule.
var timeRule = new FuncTimeRule( name: "CustomTimeRule", createUtcEventTimesFunction: dates => dates.Select(d => d.AddHours(10)));
time_rule = FuncTimeRule( name="CustomTimeRule", create_utc_event_times_function=lambda dates: [d + timedelta(hours=10) for d in dates] )
Remove Scheduled Events
If you no longer need a Scheduled Event in your algorithm, remove it so your algorithm doesn't execute unnecessary functions. To remove a Scheduled Event, save a reference to the Scheduled Event when you create it and then call the Remove
remove
method to remove it.
private ScheduledEvent _scheduledEvent; public override void Initialize() { // Remove a scheduled event by keeping a copy of the object on creation. var symbol = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA); _scheduledEvent = Schedule.On( DateRules.EveryDay(symbol), TimeRules.AfterMarketOpen(symbol, 10), TenMinutesAfterOpen ) }; // Remove the scheduled event using the object reference in any method Schedule.Remove(_scheduledEvent);
def initialize(self): # Remove a scheduled event by keeping a copy of the object on creation. symbol = Symbol.create('SPY', SecurityType.EQUITY, Market.USA) self.scheduled_event = self.schedule.on( self.date_rules.every_day(symbol), self.time_rules.after_market_open(symbol, 10), self._ten_minutes_after_open) # Remove the scheduled event using the object reference in any method self.schedule.remove(self.scheduled_event)
Common Errors
Common errors with Scheduled Events include stale fills and execution timeouts.
Stale Fills
A common error is to subscribe to daily resolution data and set a Scheduled Event intraday to place trades. If you trade intraday with daily data, you get stale fills.
Another common error is to set a Scheduled Event to trade immediately after the market open on illiquid securities. Illiquid securities can have no trades for the first few minutes after the market open. If you trade during this time, you get stale fills.
Execution Timeouts
If your Scheduled Event takes longer than 10 minutes to execute, your algorithm will timeout. To increase the amount of time that your Scheduled Event can run, replace your Scheduled Event with a training session.
Invoking the Callback Method
Make sure to not accidentally invote the event handler method by adding trailing braces ()
.
Use self._event_handler_func
MyCallbackFunction
, not self._event_handler_func()
MyCallbackFunction()
.
Execution Sequence
The algorithm manager calls events in the following order:
- Scheduled Events
- Consolidation event handlers
OnData
on_data
event handler
This event flow is important to note. For instance, if your consolidation handlers or OnData
on_data
event handler appends data to a RollingWindow
and you use that RollingWindow
in your Scheduled Event, when the Scheduled Event executes, the RollingWindow
won't contain the most recent data.
Live Trading Considerations
In live trading, Scheduled Events execute in a parallel thread based on a real-time clock. If you set a Scheduled Event to fire at 10:00 AM, it executes at exactly 10:00 AM. In backtesting, Scheduled Events are part of the main algorithm manager loop, so they may not execute exactly when you set them. For example, if your algorithm subscribes to minute resolution US Equity data with regular trading hours and you set a Scheduled Event to occur at 2:00 AM, your Scheduled Event will execute at 9:31 AM when the next bar is fed into your algorithm.
The difference between live trading and backtesting is important to note because it can affect your algorithm's behavior. There are two common scenarios to consider.
Execution Timing and Backtest Timeouts
Take the following scenario:
- You set Scheduled Events for 2:00 AM, 3:00 AM, and 4:00 AM each day.
- Each Scheduled Event takes eight minutes to execute.
- Your algorithm only subscribes to US Equity securities without extended market hours (9:30 AM - 4:00 PM).
In this scenario, the Scheduled Events each fire at the correct time and execute without error in live trading. In backtesting, all of the Scheduled Events execute at 9:31 AM when your algorithm receives the first bar of the trading day. Since all the Scheduled Events take eight minutes to execute, the algorithm tries to execute all the Scheduled Events but reaches the 10-minute timeout and the backtest stops execution.
Live Data Delays
In backtests, your algorithm receives data at perfect timing. If you request minute resolution data, your algorithm receives the bars at the top of each minute. In live trading, bars have a slight delay, so you may receive them milliseconds after the top of each minute. Take the following scenario:
- You subscribe to minute resolution data
- You set a Scheduled Event for 10:00 AM
- The Scheduled Event checks the current asset price
In live trading, the Scheduled Event executes at exactly 10:00 AM but your algorithm may receive the 9:59-10:00 AM bar at 10:00:00.01 AM. Therefore, when you check the price in the Scheduled Event, the price from the 9:58-9:59 AM bar is the latest price. In backtesting, the Scheduled Event gets the price from the 9:59-10:00 AM bar since your algorithm receives the bar at perfect timing.
Examples
public override void Initialize() { var symbol = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA); // Schedule an event to fire at a specific date/time using inline callback function. Schedule.On(DateRules.On(2013, 10, 7), TimeRules.At(13, 0), () => Log($"SpecificTime: Fired at : {Time}")); // Schedule an event to fire every trading day for a security // The time rule here tells it to fire at 13:00:00 UTC Schedule.On(DateRules.EveryDay(symbol), TimeRules.At(13, 0, 0, TimeZones.Utc), () => Log($"EveryDay.SPY SpecificTime: Fired at: {Time}")); // Schedule an event to fire every trading day for a security // The time rule here tells it to fire 10 minutes before SPY's market open Schedule.On(DateRules.EveryDay(symbol), TimeRules.BeforeMarketOpen(symbol, 10), () => Log($"EveryDay.SPY 10 min before open: Fired at: {Time}")); // Schedule an event to fire every trading day for a security // The time rule here tells it to fire 10 minutes after SPY's market open Schedule.On(DateRules.EveryDay(symbol), TimeRules.AfterMarketOpen(symbol, 10), () => Log($"EveryDay.SPY 10 min after open: Fired at: {Time}")); // Schedule an event to fire every trading day for a security // The time rule here tells it to fire 10 minutes before SPY's market close Schedule.On(DateRules.EveryDay(symbol), TimeRules.BeforeMarketClose(symbol, 10), () => Log($"EveryDay.SPY 10 min before close: Fired at: {Time}")); // Schedule an event to fire every trading day for a security // The time rule here tells it to fire 10 minutes after SPY's market close Schedule.On(DateRules.EveryDay(symbol), TimeRules.AfterMarketClose(symbol, 10), () => Log($"EveryDay.SPY 10 min after close: Fired at: {Time}")); // Schedule an event to fire on certain days of the week Schedule.On(DateRules.Every(DayOfWeek.Monday, DayOfWeek.Friday), TimeRules.At(12, 0), () => Log($"Mon/Fri at 12pm: Fired at: {Time}")); // Schedule an event to fire once today at when this method is called (now) Schedule.On(DateRules.Today, TimeRules.Now, () => Log($"Now: Fired at: {Time}")); // Schedule an event to fire once tomorrow at midnight Schedule.On(DateRules.Tomorrow, TimeRules.Midnight, () => Log($"Tomorrow at midnight: Fired at: {Time}")); // Schedule an event to fire once today at noon Schedule.On(DateRules.Today, TimeRules.Noon, () => Log($"Today at noon: Fired at: {Time}")); // The scheduling methods return the ScheduledEvent object which can be used // for other things here I set the event up to check the portfolio value every // 10 minutes, and liquidate if we have too many losses Schedule.On(DateRules.EveryDay(), TimeRules.Every(TimeSpan.FromMinutes(10)), LiquidateUnrealizedLosses); // Schedule an event to fire at the beginning of the month, the symbol is optional. // If specified, it will fire the first trading day for that symbol of the month. // Otherwise, it will fire on the first day of the month. Schedule.On(DateRules.MonthStart(symbol), TimeRules.AfterMarketOpen(symbol), RebalancingCode); // Schedule an event to fire at the end of the month, the symbol is optional. // If specified, it will fire the last trading day for that symbol of the month. // Otherwise, it will fire on the last day of the month. Schedule.On(DateRules.MonthEnd(symbol), TimeRules.BeforeMarketClose(symbol), RebalancingCode); // Schedule an event to fire at the beginning of the week, the symbol is optional. // If specified, it will fire the first trading day for that symbol of the week. // Otherwise, it will fire on the first day of the week. Schedule.On(DateRules.WeekStart(symbol), TimeRules.AfterMarketOpen(symbol, 5), RebalancingCode); // Schedule an event to fire at the end of the week, the symbol is optional. // If specified, it will fire the last trading day for that symbol of the week. // Otherwise, it will fire on the first day of the week. Schedule.On(DateRules.WeekEnd(symbol), TimeRules.BeforeMarketClose(symbol, 5), RebalancingCode); } // The following methods are not defined in Initialize: private void LiquidateUnrealizedLosses() { // if we have over 1000 dollars in unrealized losses, liquidate if (Portfolio.TotalUnrealizedProfit < -1000) { Log($"Liquidated due to unrealized losses at: {Time}"); Liquidate(); } } private void RebalancingCode() { // Good spot for rebalancing code? }
def initialize(self): symbol = Symbol.create('SPY', SecurityType.EQUITY, Market.USA) # Schedule an event to fire at a specific date/time using inline callback function. self.schedule.on(self.date_rules.on(2013, 10, 7), self.time_rules.at(13, 0), lambda: self.log(f"SpecificTime: Fired at : {self.time}")) # Schedule an event to fire every trading day for a security at 13:00:00 UTC. self.schedule.on(self.date_rules.every_day(symbol), self.time_rules.at(13, 0, 0, TimeZones.UTC), lambda: self.log(f"EveryDay.SPY SpecificTime: Fired at: {self.time}")) # Schedule an event to fire every trading day for a security - 10 minutes before SPY's market open. self.schedule.on(self.date_rules.every_day(symbol), self.time_rules.before_market_open(symbol, 10), lambda: self.log(f"EveryDay.SPY 10 min before open: Fired at: {self.time}")) # Schedule an event to fire every trading day for a security - 10 minutes after SPY's market open. self.schedule.on(self.date_rules.every_day(symbol), self.time_rules.after_market_open(symbol, 10), lambda: self.log(f"EveryDay.SPY 10 min after open: Fired at: {self.time}")) # Schedule an event to fire every trading day for a security - 10 minutes before SPY's market close. self.schedule.on(self.date_rules.every_day(symbol), self.time_rules.before_market_close(symbol, 10), lambda: self.log(f"EveryDay.SPY 10 min before close: Fired at: {self.time}")) # Schedule an event to fire every trading day for a security - 10 minutes after SPY's market close. self.schedule.on(self.date_rules.every_day(symbol), self.time_rules.after_market_close(symbol, 10), lambda: self.log(f"EveryDay.SPY 10 min after close: Fired at: {self.time}")) # Schedule an event to fire on certain days of the week self.schedule.on(self.date_rules.every(DayOfWeek.MONDAY, DayOfWeek.FRIDAY), self.time_rules.at(12, 0), lambda: self.log(f"Mon/Fri at 12pm: Fired at: {self.time}")) # Schedule an event to fire once today at when this method is called (now) self.schedule.on(self.date_rules.today, self.time_rules.now, lambda: self.log(f"Now: Fired at: {self.time}")) # Schedule an event to fire once tomorrow at midnight self.schedule.on(self.date_rules.tomorrow, self.time_rules.midnight, lambda: self.log(f"Tomorrow at midnight: Fired at: {self.time}")) # Schedule an event to fire once today at noon self.schedule.on(self.date_rules.today, self.time_rules.noon, lambda: self.log(f"Today at noon: Fired at: {self.time}")) # Scan a method every ten minutes, every day. self.schedule.on(self.date_rules.every_day(), self.time_rules.every(timedelta(minutes=10)), self._liquidate_unrealized_losses) # Schedule an event to fire at the beginning of the month. # The symbol is optional but if specified, it will fire the first trading day # for that symbol of the month. Otherwise, it will fire on the first day of the month. self.schedule.on(self.date_rules.month_start(symbol), self.time_rules.after_market_open(symbol), self._rebalancing_code) # Schedule an event to fire at the end of the month, the symbol is optional. # If specified, it will fire the last trading day for that symbol of the month. # Otherwise, it will fire on the last day of the month. self.schedule.on(self.date_rules.month_end(symbol), self.time_rules.before_market_close(symbol), self._rebalancing_code) # Schedule an event to fire at the beginning of the week, the symbol is optional. # If specified, it will fire the first trading day for that symbol of the week. # Otherwise, it will fire on the first day of the week. self.schedule.on(self.date_rules.week_start(symbol), self.time_rules.after_market_open(symbol, 5), self._rebalancing_code) # Schedule an event to fire at the end of the week, the symbol is optional. # If specified, it will fire the last trading day for that symbol of the week. # Otherwise, it will fire on the last day of the week. self.schedule.on(self.date_rules.week_end(symbol), self.time_rules.before_market_close(symbol, 5), self._rebalancing_code) # The following methods from examples above should be defined in the algorithm body. def _liquidate_unrealized_losses(self) -> None: ''' if we have over 1000 dollars in unrealized losses, liquidate''' if self.portfolio.total_unrealized_profit < -1000: self.log(f"Liquidated due to unrealized losses at: {self.time}") self.liquidate() def _rebalancing_code(self) -> None: ''' Good spot for rebalancing code?''' pass