/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using NodaTime; using System.Linq; using QuantConnect.Util; using System.Collections.Generic; namespace QuantConnect.Securities { /// /// Base exchange class providing information and helper tools for reading the current exchange situation /// public class SecurityExchange { private LocalTimeKeeper _timeProvider; /// /// Gets the for this exchange /// public SecurityExchangeHours Hours { get; private set; } /// /// Gets the time zone for this exchange /// public DateTimeZone TimeZone => Hours.TimeZone; /// /// Number of trading days per year for this security. By default the market is open 365 days per year. /// /// Used for performance statistics to calculate sharpe ratio accurately public virtual int TradingDaysPerYear => 365; /// /// Time from the most recent data /// public DateTime LocalTime => _timeProvider.LocalTime; /// /// Boolean property for quickly testing if the exchange is open. /// public bool ExchangeOpen => Hours.IsOpen(LocalTime, false); /// /// Boolean property for quickly testing if the exchange is 10 minutes away from closing. /// public bool ClosingSoon => IsClosingSoon(minutesToClose:10); /// /// Initializes a new instance of the class using the specified /// exchange hours to determine open/close times /// /// Contains the weekly exchange schedule plus holidays public SecurityExchange(SecurityExchangeHours exchangeHours) { Hours = exchangeHours; } /// /// Set the current datetime in terms of the exchange's local time zone /// /// Most recent data tick public void SetLocalDateTimeFrontierProvider(LocalTimeKeeper timeProvider) { _timeProvider = timeProvider; } /// /// Check if the *date* is open. /// /// This is useful for first checking the date list, and then the market hours to save CPU cycles /// Date to check /// True to consider days with extended market hours only as open /// Return true if the exchange is open for this date public bool DateIsOpen(DateTime dateToCheck, bool extendedMarketHours = false) { return Hours.IsDateOpen(dateToCheck, extendedMarketHours); } /// /// Check if this DateTime is open. /// /// DateTime to check /// Boolean true if the market is open public bool DateTimeIsOpen(DateTime dateTime) { return Hours.IsOpen(dateTime, false); } /// /// Determines if the exchange was open at any time between start and stop /// public bool IsOpenDuringBar(DateTime barStartTime, DateTime barEndTime, bool isExtendedMarketHours) { return Hours.IsOpen(barStartTime, barEndTime, isExtendedMarketHours); } /// /// Determines if the exchange is going to close in the next provided minutes /// /// Minutes to close to check /// Returns true if the exchange is going to close in the next provided minutes public bool IsClosingSoon(int minutesToClose) { return !Hours.IsOpen(LocalTime.AddMinutes(minutesToClose), false); } /// /// Sets the regular market hours for the specified days If no days are specified then /// all days will be updated. /// /// Specifies each segment of the market hours, such as premarket/market/postmark /// The days of the week to set these times for public void SetMarketHours(IEnumerable marketHoursSegments, params DayOfWeek[] days) { if (days.IsNullOrEmpty()) days = Enum.GetValues(typeof(DayOfWeek)).OfType().ToArray(); var marketHours = Hours.MarketHours.ToDictionary(); marketHoursSegments = marketHoursSegments as IList ?? marketHoursSegments.ToList(); foreach (var day in days) { marketHours[day] = new LocalMarketHours(day, marketHoursSegments); } // create a new exchange hours instance for the new hours Hours = new SecurityExchangeHours(Hours.TimeZone, Hours.Holidays, marketHours, Hours.EarlyCloses, Hours.LateOpens); } } }