Lean  $LEAN_TAG$
TradingCalendar.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using System.Collections.Generic;
18 using System.Linq;
20 using QLNet;
21 
22 namespace QuantConnect
23 {
24  /// <summary>
25  /// Class represents trading calendar, populated with variety of events relevant to currently trading instruments
26  /// </summary>
27  public class TradingCalendar
28  {
29  private readonly MarketHoursDatabase _marketHoursDatabase;
30  private readonly SecurityManager _securityManager;
31 
32  /// <summary>
33  /// Initialize a new <see cref="TradingCalendar"/> instance.
34  /// </summary>
35  /// <param name="securityManager">SecurityManager for this calendar</param>
36  /// <param name="marketHoursDatabase">MarketHoursDatabase for this calendar</param>
37  public TradingCalendar(SecurityManager securityManager, MarketHoursDatabase marketHoursDatabase)
38  {
39  _securityManager = securityManager;
40  _marketHoursDatabase = marketHoursDatabase;
41  }
42  /// <summary>
43  /// Method returns <see cref="TradingDay"/> that contains trading events associated with today's date
44  /// </summary>
45  /// <returns>Populated instance of <see cref="TradingDay"/></returns>
47  {
48  var today = _securityManager.UtcTime.Date;
49 
50  return GetTradingDay(today);
51  }
52 
53  /// <summary>
54  /// Method returns <see cref="TradingDay"/> that contains trading events associated with the given date
55  /// </summary>
56  /// <returns>Populated instance of <see cref="TradingDay"/></returns>
57  public TradingDay GetTradingDay(DateTime day)
58  {
59  return GetTradingDays(day, day).First();
60  }
61 
62  /// <summary>
63  /// Method returns <see cref="TradingDay"/> that contains trading events associated with the range of dates
64  /// </summary>
65  /// <param name="start">Start date of the range (inclusive)</param>
66  /// <param name="end">End date of the range (inclusive)</param>
67  /// <returns>>Populated list of <see cref="TradingDay"/></returns>
68  public IEnumerable<TradingDay> GetTradingDays(DateTime start, DateTime end)
69  {
70  return PopulateTradingDays(start, end);
71  }
72 
73  /// <summary>
74  /// Method returns <see cref="TradingDay"/> of the specified type (<see cref="TradingDayType"/>) that contains trading events associated with the range of dates
75  /// </summary>
76  /// <param name="type">Type of the events</param>
77  /// <param name="start">Start date of the range (inclusive)</param>
78  /// <param name="end">End date of the range (inclusive)</param>
79  /// <returns>>Populated list of <see cref="TradingDay"/></returns>
80  public IEnumerable<TradingDay> GetDaysByType(TradingDayType type, DateTime start, DateTime end)
81  {
82  Func<TradingDay, bool> typeFilter = day =>
83  {
84  switch (type)
85  {
86  case TradingDayType.BusinessDay:
87  return day.BusinessDay;
88  case TradingDayType.PublicHoliday:
89  return day.PublicHoliday;
90  case TradingDayType.Weekend:
91  return day.Weekend;
92  case TradingDayType.OptionExpiration:
93  return day.OptionExpirations.Any();
94  case TradingDayType.FutureExpiration:
95  return day.FutureExpirations.Any();
96  case TradingDayType.FutureRoll:
97  return day.FutureRolls.Any();
98  case TradingDayType.SymbolDelisting:
99  return day.SymbolDelistings.Any();
100  case TradingDayType.EquityDividends:
101  return day.EquityDividends.Any();
102  };
103  return false;
104  };
105  return GetTradingDays(start, end).Where(typeFilter);
106  }
107 
108 
109  private IEnumerable<TradingDay> PopulateTradingDays(DateTime start, DateTime end)
110  {
111  var symbols = _securityManager.Keys;
112 
113  var holidays = new HashSet<DateTime>();
114  foreach (var symbol in symbols)
115  {
116  var entry = _marketHoursDatabase.GetEntry(symbol.ID.Market, symbol, symbol.ID.SecurityType);
117 
118  foreach (var holiday in entry.ExchangeHours.Holidays)
119  {
120  holidays.Add(holiday.Date);
121  }
122  }
123 
124  var qlCalendar = new UnitedStates();
125  var options = symbols.Where(x => x.ID.SecurityType.IsOption()).ToList();
126  var futures = symbols.Where(x => x.ID.SecurityType == SecurityType.Future).ToList();
127 
128  var totalDays = (int)(end.Date.AddDays(1.0) - start.Date).TotalDays;
129  if (totalDays < 0)
130  {
131  throw new ArgumentException($"TradingCalendar.PopulateTradingDays(): {Messages.TradingCalendar.InvalidTotalDays(totalDays)}");
132  }
133 
134  foreach (var dayIdx in Enumerable.Range(0, totalDays))
135  {
136  var currentDate = start.Date.AddDays(dayIdx);
137 
138  var publicHoliday = holidays.Contains(currentDate) || !qlCalendar.isBusinessDay(currentDate);
139  var weekend = currentDate.DayOfWeek == DayOfWeek.Sunday ||
140  currentDate.DayOfWeek == DayOfWeek.Saturday;
141  var businessDay = !publicHoliday && !weekend;
142 
143  yield return
144  new TradingDay
145  {
146  Date = currentDate,
147  PublicHoliday = publicHoliday,
148  Weekend = weekend,
149  BusinessDay = businessDay,
150  OptionExpirations = options.Where(x => x.ID.Date.Date == currentDate),
151  FutureExpirations = futures.Where(x => x.ID.Date.Date == currentDate)
152  };
153  }
154  }
155  }
156 }