Time Modeling
Time Zones
Exchange Time Zone
Exchanges are located in different areas, so they can have different time zones. To get the time zone of the exchange that a Security
trades on, use its Exchange.Hours.TimeZone
exchange.hours.time_zone
property.
// Get the time zone of the exchange for a specific asset. var timeZone = Securities[_symbol].Exchange.Hours.TimeZone;
# Get the time zone of the exchange for a specific asset. time_zone = self.securities[self._symbol].exchange.hours.time_zone
Algorithm Time Zone
LEAN supports international trading across multiple time zones and markets, so it needs a reference time zone for the algorithm to set the Time
time
. The default time zone is Eastern Time (ET), which is UTC-4 in summer and UTC-5 in winter. To set a different time zone, call the SetTimeZone
set_time_zone
method. This method accepts either a string following the IANA Time Zone database convention or a NodaTime.DateTimeZone object. If you pass a string, the method converts it to a NodaTime.DateTimeZone
object. The TimeZones
class provides the following helper attributes to create NodaTime.DateTimeZone
objects:
SetTimeZone("Europe/London"); SetTimeZone(NodaTime.DateTimeZone.Utc); SetTimeZone(TimeZones.Chicago);
self.set_time_zone("Europe/London") self.set_time_zone(TimeZones.CHICAGO)
To get the time zone of your algorithm, use the TimeZone
time_zone
property.
# The algorithm timezone property can assist with multi-asset trading. time_zone = self.time_zone
// The algorithm timezone property can assist with multi-asset trading. var timeZone = TimeZone;
To get the algorithm time in Coordinated Universal Time (UTC), use the UtcTime
utc_time
property.
# Access the current UTC time to coordinate multi-timezone events or improve logging. utc_time = self.utc_time
// Access the current UTC time to coordinate multi-timezone events or improve logging. var utcTime = UtcTime;
The Time
time
and UtcTime
utc_time
objects have no time zone. LEAN maintains their state to be consistent.
Data Time Zone
Datasets can have different time zones because the time zone is up to the data provider, where they are located, and where they collect the data. LEAN tracks the time zone of each dataset so that you receive the correct data at the right point in time in your algorithm. If you have multiple datasets in your algorithm from different time zones, LEAN synchronizes them to your algorithm time. Furthermore, if you set up time period consolidators, LEAN consolidates the data based on the data time zone.
To get the time zone of a dataset, view the listing page in the Dataset Market or call the GetDataTimeZone
method.
# Get the timezone of an asset. time_zone = self.market_hours_database.get_data_time_zone(Market.USA, self._symbol, SecurityType.EQUITY)
// Get the timezone of an asset. var timeZone = MarketHoursDatabase.GetDataTimeZone(Market.USA, _symbol, SecurityType.Equity);
Examples
The following examples demonstrate some common practices for time zone modeling.
Example 1: Futures Time Zone
The following algorithm changes its time zone to be the same as the EMini SP500 Futures exchange, i.e., Chicago time zone. It is comparable in validating data across different sources and has a more convenient time notification without further conversion.
public class TimeZoneModelingAlgorithm : QCAlgorithm { private Future _future; private OrderTicket _ticket; public override void Initialize() { SetStartDate(2021, 1, 1); SetEndDate(2021, 3, 1); // Request ES future data for trading. _future = AddFuture("ES", Resolution.Minute, extendedMarketHours: true, dataNormalizationMode: DataNormalizationMode.BackwardsRatio, dataMappingMode: DataMappingMode.OpenInterest, contractDepthOffset: 0); // Set the time zone to be the same as the Future (Chicago). // It will make the time in the backtest more comparable and easily analyzed with any other data sources. // Performance of the backtest will only be altered by this change if the trading logic depends on the Time property. SetTimeZone(_future.Exchange.TimeZone); } public override void OnData(Slice slice) { if (!Portfolio.Invested && _ticket == null) { _ticket = LimitOrder(_future.Mapped, 1, Securities[_future.Mapped].Price * 0.995m); } // Cancel unfilled orders if they are not filled within 2 minutes to avoid stale fills. // Note that the Time property in the order ticket is in the UTC timezone. if (_ticket.Status != OrderStatus.Filled && _ticket.Time.AddMinutes(2) < UtcTime) { // You can change to a different time zone and compare the log differences. _ticket.Cancel($"{Time} :: utc: {UtcTime} :: Order canceled due to placed over 2 minutes"); _ticket = null; } } }
class TimeZoneModelingAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2021, 1, 1) self.set_end_date(2021, 3, 1) # Request ES future data for trading. self._future = self.add_future("ES", Resolution.Minute, extended_market_hours=True, data_normalization_mode=DataNormalizationMode.BACKWARDS_RATIO, data_mapping_mode=DataMappingMode.OPEN_INTEREST, contract_depth_offset=0) # Set the time zone to be the same as the Future (Chicago). # It will make the time in the backtest more comparable and easily analyzed with any other data sources. # Performance of the backtest will only be altered by this change if the trading logic depends on the Time property. self.set_time_zone(self._future.exchange.time_zone) self.ticket = None def on_data(self, slice: Slice) -> None: if not self.portfolio.invested and not self.ticket: self.ticket = self.limit_order(self._future.mapped, 1, self.securities[self._future.mapped].price * 0.995) # Cancel unfilled orders if they are not filled within 2 minutes to avoid stale fills. # Note that the Time property in the order ticket is in UTC timezone. if self.ticket.status != OrderStatus.Filled and self.ticket.time + timedelta(minutes=2) < self.utc_time: # You can change to a different time zone and compare the log differences. self.ticket.cancel(f"{self.time} :: utc: {self.utc_time} :: Order canceled due to placed over 2 minutes") self.ticket = None