Lean  $LEAN_TAG$
FuturesExpiryFunctions.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;
19 
21 {
22  /// <summary>
23  /// Calculate the date of a futures expiry given an expiry month and year
24  /// </summary>
26  {
27  /// <summary>
28  /// Method to retrieve the Function for a specific future symbol
29  /// </summary>
30  public static Func<DateTime, DateTime> FuturesExpiryFunction(Symbol symbol)
31  {
32  Func<DateTime, DateTime> result;
33  if (FuturesExpiryDictionary.TryGetValue(symbol.Canonical, out result))
34  {
35  return result;
36  }
37 
38  // If the function cannot be found, throw an exception as it hasn't yet been implemented
39  throw new ArgumentException($"Expiry function not implemented for {symbol} in FuturesExpiryFunctions.FuturesExpiryDictionary");
40  }
41 
42  /// <summary>
43  /// The USDA publishes a report containing contract prices for the contract month.
44  /// You can see future publication dates at https://www.ams.usda.gov/rules-regulations/mmr/dmr (Advanced and Class Price Release Dates)
45  /// These dates are erratic and requires maintenance of a separate list instead of using holiday entries in MHDB.
46  /// </summary>
47  /// <remarks>We only report the publication date of the report. In order to get accurate last trade dates, subtract one (plus holidays) from the value's date</remarks>
48  public static Dictionary<DateTime, DateTime> DairyReportDates = new Dictionary<DateTime, DateTime>()
49  {
50  {new DateTime(2012, 3, 1), new DateTime(2012, 4, 2) },
51  {new DateTime(2012, 4, 1), new DateTime(2012, 5, 2) },
52  {new DateTime(2012, 5, 1), new DateTime(2012, 5, 31) },
53  {new DateTime(2012, 6, 1), new DateTime(2012, 7, 5) },
54  {new DateTime(2012, 7, 1), new DateTime(2012, 8, 1) },
55  {new DateTime(2012, 8, 1), new DateTime(2012, 8, 29) },
56  {new DateTime(2012, 9, 1), new DateTime(2012, 10, 3) },
57  {new DateTime(2012, 10, 1), new DateTime(2012, 10, 31) },
58  {new DateTime(2012, 11, 1), new DateTime(2012, 12, 5) },
59  {new DateTime(2012, 12, 1), new DateTime(2013, 1, 3) },
60  {new DateTime(2013, 1, 1), new DateTime(2013, 1, 30) },
61  {new DateTime(2013, 2, 1), new DateTime(2013, 2, 27) },
62  {new DateTime(2013, 3, 1), new DateTime(2013, 4, 3) },
63  {new DateTime(2013, 4, 1), new DateTime(2013, 5, 1) },
64  {new DateTime(2013, 5, 1), new DateTime(2013, 6, 5) },
65  {new DateTime(2013, 6, 1), new DateTime(2013, 7, 3) },
66  {new DateTime(2013, 7, 1), new DateTime(2013, 7, 31) },
67  {new DateTime(2013, 8, 1), new DateTime(2013, 9, 5) },
68  {new DateTime(2013, 9, 1), new DateTime(2013, 10, 18) },
69  {new DateTime(2013, 10, 1), new DateTime(2013, 10, 30) },
70  {new DateTime(2013, 11, 1), new DateTime(2013, 12, 4) },
71  {new DateTime(2013, 12, 1), new DateTime(2014, 1, 2) },
72  {new DateTime(2014, 1, 1), new DateTime(2014, 2, 5) },
73  {new DateTime(2014, 2, 1), new DateTime(2014, 3, 5) },
74  {new DateTime(2014, 3, 1), new DateTime(2014, 4, 2) },
75  {new DateTime(2014, 4, 1), new DateTime(2014, 4, 30) },
76  {new DateTime(2014, 5, 1), new DateTime(2014, 6, 4) },
77  {new DateTime(2014, 6, 1), new DateTime(2014, 7, 2) },
78  {new DateTime(2014, 7, 1), new DateTime(2014, 7, 30) },
79  {new DateTime(2014, 8, 1), new DateTime(2014, 9, 4) },
80  {new DateTime(2014, 9, 1), new DateTime(2014, 10, 1) },
81  {new DateTime(2014, 10, 1), new DateTime(2014, 11, 5) },
82  {new DateTime(2014, 11, 1), new DateTime(2014, 12, 3) },
83  {new DateTime(2014, 12, 1), new DateTime(2014, 12, 31) },
84  {new DateTime(2015, 1, 1), new DateTime(2015, 2, 4) },
85  {new DateTime(2015, 2, 1), new DateTime(2015, 3, 4) },
86  {new DateTime(2015, 3, 1), new DateTime(2015, 4, 1) },
87  {new DateTime(2015, 4, 1), new DateTime(2015, 4, 29) },
88  {new DateTime(2015, 5, 1), new DateTime(2015, 6, 3) },
89  {new DateTime(2015, 6, 1), new DateTime(2015, 7, 1) },
90  {new DateTime(2015, 7, 1), new DateTime(2015, 8, 5) },
91  {new DateTime(2015, 8, 1), new DateTime(2015, 9, 2) },
92  {new DateTime(2015, 9, 1), new DateTime(2015, 9, 30) },
93  {new DateTime(2015, 10, 1), new DateTime(2015, 11, 4) },
94  {new DateTime(2015, 11, 1), new DateTime(2015, 12, 2) },
95  {new DateTime(2015, 12, 1), new DateTime(2015, 12, 30) },
96  {new DateTime(2016, 1, 1), new DateTime(2016, 2, 3) },
97  {new DateTime(2016, 2, 1), new DateTime(2016, 3, 2) },
98  {new DateTime(2016, 3, 1), new DateTime(2016, 3, 30) },
99  {new DateTime(2016, 4, 1), new DateTime(2016, 5, 4) },
100  {new DateTime(2016, 5, 1), new DateTime(2016, 6, 2) },
101  {new DateTime(2016, 6, 1), new DateTime(2016, 6, 29) },
102  {new DateTime(2016, 7, 1), new DateTime(2016, 8, 3) },
103  {new DateTime(2016, 8, 1), new DateTime(2016, 8, 31) },
104  {new DateTime(2016, 9, 1), new DateTime(2016, 10, 5) },
105  {new DateTime(2016, 10, 1), new DateTime(2016, 11, 2) },
106  {new DateTime(2016, 11, 1), new DateTime(2016, 11, 30) },
107  {new DateTime(2016, 12, 1), new DateTime(2017, 1, 5) },
108  {new DateTime(2017, 1, 1), new DateTime(2017, 2, 1) },
109  {new DateTime(2017, 2, 1), new DateTime(2017, 3, 1) },
110  {new DateTime(2017, 3, 1), new DateTime(2017, 4, 5) },
111  {new DateTime(2017, 4, 1), new DateTime(2017, 5, 3) },
112  {new DateTime(2017, 5, 1), new DateTime(2017, 6, 1) },
113  {new DateTime(2017, 6, 1), new DateTime(2017, 6, 28) },
114  {new DateTime(2017, 7, 1), new DateTime(2017, 8, 2) },
115  {new DateTime(2017, 8, 1), new DateTime(2017, 8, 30) },
116  {new DateTime(2017, 9, 1), new DateTime(2017, 10, 4) },
117  {new DateTime(2017, 10, 1), new DateTime(2017, 11, 1) },
118  {new DateTime(2017, 11, 1), new DateTime(2017, 11, 29) },
119  {new DateTime(2017, 12, 1), new DateTime(2018, 1, 4) },
120  {new DateTime(2018, 1, 1), new DateTime(2018, 1, 31) },
121  {new DateTime(2018, 2, 1), new DateTime(2018, 2, 28) },
122  {new DateTime(2018, 3, 1), new DateTime(2018, 4, 4) },
123  {new DateTime(2018, 4, 1), new DateTime(2018, 5, 2) },
124  {new DateTime(2018, 5, 1), new DateTime(2018, 5, 31) },
125  {new DateTime(2018, 6, 1), new DateTime(2018, 7, 5) },
126  {new DateTime(2018, 7, 1), new DateTime(2018, 8, 1) },
127  {new DateTime(2018, 8, 1), new DateTime(2018, 8, 29) },
128  {new DateTime(2018, 9, 1), new DateTime(2018, 10, 3) },
129  {new DateTime(2018, 10, 1), new DateTime(2018, 10, 31) },
130  {new DateTime(2018, 11, 1), new DateTime(2018, 12, 5) },
131  {new DateTime(2018, 12, 1), new DateTime(2019, 1, 3) },
132  {new DateTime(2019, 1, 1), new DateTime(2019, 1, 30) },
133  {new DateTime(2019, 2, 1), new DateTime(2019, 2, 27) },
134  {new DateTime(2019, 3, 1), new DateTime(2019, 4, 3) },
135  {new DateTime(2019, 4, 1), new DateTime(2019, 5, 1) },
136  {new DateTime(2019, 5, 1), new DateTime(2019, 6, 5) },
137  {new DateTime(2019, 6, 1), new DateTime(2019, 7, 3) },
138  {new DateTime(2019, 7, 1), new DateTime(2019, 7, 31) },
139  {new DateTime(2019, 8, 1), new DateTime(2019, 9, 5) },
140  {new DateTime(2019, 9, 1), new DateTime(2019, 10, 2) },
141  {new DateTime(2019, 10, 1), new DateTime(2019, 10, 30) },
142  {new DateTime(2019, 11, 1), new DateTime(2019, 12, 4) },
143  {new DateTime(2019, 12, 1), new DateTime(2020, 1, 2) },
144  {new DateTime(2020, 1, 1), new DateTime(2020, 2, 5) },
145  {new DateTime(2020, 2, 1), new DateTime(2020, 3, 4) },
146  {new DateTime(2020, 3, 1), new DateTime(2020, 4, 1) },
147  {new DateTime(2020, 4, 1), new DateTime(2020, 4, 29) },
148  {new DateTime(2020, 5, 1), new DateTime(2020, 6, 3) },
149  {new DateTime(2020, 6, 1), new DateTime(2020, 7, 1) },
150  {new DateTime(2020, 7, 1), new DateTime(2020, 8, 5) },
151  {new DateTime(2020, 8, 1), new DateTime(2020, 9, 2) },
152  {new DateTime(2020, 9, 1), new DateTime(2020, 9, 30) },
153  {new DateTime(2020, 10, 1), new DateTime(2020, 11, 4) },
154  {new DateTime(2020, 11, 1), new DateTime(2020, 12, 2) },
155  {new DateTime(2020, 12, 1), new DateTime(2020, 12, 30) },
156  {new DateTime(2021, 1, 1), new DateTime(2021, 2, 3) },
157  {new DateTime(2021, 2, 1), new DateTime(2021, 3, 3) },
158  {new DateTime(2021, 3, 1), new DateTime(2021, 3, 31) },
159  {new DateTime(2021, 4, 1), new DateTime(2021, 5, 5) },
160  {new DateTime(2021, 5, 1), new DateTime(2021, 6, 3) },
161  {new DateTime(2021, 6, 1), new DateTime(2021, 6, 30) },
162  {new DateTime(2021, 7, 1), new DateTime(2021, 8, 4) },
163  {new DateTime(2021, 8, 1), new DateTime(2021, 9, 1) },
164  {new DateTime(2021, 9, 1), new DateTime(2021, 9, 29) },
165  {new DateTime(2021, 10, 1), new DateTime(2021, 11, 3) },
166  {new DateTime(2021, 11, 1), new DateTime(2021, 12, 1) },
167  {new DateTime(2021, 12, 1), new DateTime(2022, 1, 5) },
168  {new DateTime(2022, 1, 1), new DateTime(2022, 2, 2) },
169  {new DateTime(2022, 2, 1), new DateTime(2022, 3, 2) },
170  {new DateTime(2022, 3, 1), new DateTime(2022, 3, 30) },
171  {new DateTime(2022, 4, 1), new DateTime(2022, 5, 4) },
172  {new DateTime(2022, 5, 1), new DateTime(2022, 6, 2) },
173  {new DateTime(2022, 6, 1), new DateTime(2022, 6, 29) },
174  {new DateTime(2022, 7, 1), new DateTime(2022, 8, 3) },
175  {new DateTime(2022, 8, 1), new DateTime(2022, 8, 31) },
176  {new DateTime(2022, 9, 1), new DateTime(2022, 10, 5) },
177  {new DateTime(2022, 10, 1), new DateTime(2022, 11, 2) },
178  {new DateTime(2022, 11, 1), new DateTime(2022, 11, 30) },
179  {new DateTime(2022, 12, 1), new DateTime(2023, 1, 5) },
180  };
181 
182  /// <summary>
183  /// Enbridge's Notice of Shipment report dates. Used to calculate the last trade date for CSW
184  /// </summary>
185  /// <remarks>Subtract a day from the value's date in order to get the last trade date</remarks>
186  public static Dictionary<DateTime, DateTime> EnbridgeNoticeOfShipmentDates = new Dictionary<DateTime, DateTime>()
187  {
188  {new DateTime(2019, 6, 1), new DateTime(2019, 5, 17) },
189  {new DateTime(2019, 7, 1), new DateTime(2019, 6, 15) },
190  {new DateTime(2019, 8, 1), new DateTime(2019, 7, 17) },
191  {new DateTime(2019, 9, 1), new DateTime(2019, 8, 16) },
192  {new DateTime(2019, 10, 1), new DateTime(2019, 9, 14) },
193  {new DateTime(2019, 11, 1), new DateTime(2019, 10, 17) },
194  {new DateTime(2019, 12, 1), new DateTime(2019, 11, 15) },
195  {new DateTime(2020, 1, 1), new DateTime(2019, 12, 14) },
196  {new DateTime(2020, 2, 1), new DateTime(2020, 1, 22) },
197  {new DateTime(2020, 3, 1), new DateTime(2020, 2, 21) },
198  {new DateTime(2020, 4, 1), new DateTime(2020, 3, 21) },
199  {new DateTime(2020, 5, 1), new DateTime(2020, 4, 21) },
200  {new DateTime(2020, 6, 1), new DateTime(2020, 5, 21) },
201  {new DateTime(2020, 7, 1), new DateTime(2020, 6, 23) },
202  {new DateTime(2020, 8, 1), new DateTime(2020, 7, 21) },
203  {new DateTime(2020, 9, 1), new DateTime(2020, 8, 21) },
204  {new DateTime(2020, 10, 1), new DateTime(2020, 9, 22) },
205  {new DateTime(2020, 11, 1), new DateTime(2020, 10, 21) },
206  {new DateTime(2020, 12, 1), new DateTime(2020, 11, 21) },
207  {new DateTime(2021, 1, 1), new DateTime(2020, 12, 22) },
208  {new DateTime(2021, 2, 1), new DateTime(2021, 1, 21) },
209  {new DateTime(2021, 3, 1), new DateTime(2021, 2, 23) },
210  {new DateTime(2021, 4, 1), new DateTime(2021, 3, 23) },
211  {new DateTime(2021, 5, 1), new DateTime(2021, 4, 21) },
212  {new DateTime(2021, 6, 1), new DateTime(2021, 5, 21) },
213  {new DateTime(2021, 7, 1), new DateTime(2021, 6, 22) },
214  {new DateTime(2021, 8, 1), new DateTime(2021, 7, 21) },
215  {new DateTime(2021, 9, 1), new DateTime(2021, 8, 21) },
216  {new DateTime(2021, 10, 1), new DateTime(2021, 9, 21) },
217  {new DateTime(2021, 11, 1), new DateTime(2021, 10, 21) },
218  {new DateTime(2021, 12, 1), new DateTime(2021, 11, 23) },
219  {new DateTime(2022, 1, 1), new DateTime(2021, 12, 21) },
220  {new DateTime(2022, 2, 1), new DateTime(2022, 1, 21) },
221  {new DateTime(2022, 3, 1), new DateTime(2022, 2, 23) },
222  {new DateTime(2022, 4, 1), new DateTime(2022, 3, 22) },
223  {new DateTime(2022, 5, 1), new DateTime(2022, 4, 21) },
224  {new DateTime(2022, 6, 1), new DateTime(2022, 5, 21) },
225  {new DateTime(2022, 7, 1), new DateTime(2022, 6, 21) },
226  {new DateTime(2022, 8, 1), new DateTime(2022, 7, 21) },
227  {new DateTime(2022, 9, 1), new DateTime(2022, 8, 23) },
228  {new DateTime(2022, 10, 1), new DateTime(2022, 9, 21) },
229  {new DateTime(2022, 11, 1), new DateTime(2022, 10, 21) },
230  {new DateTime(2022, 12, 1), new DateTime(2022, 11, 22) },
231  };
232 
233  /// <summary>
234  /// Dictionary of the Functions that calculates the expiry for a given year and month.
235  /// It does not matter what the day and time of day are passed into the Functions.
236  /// The Functions is responsible for calculating the day and time of day given a year and month
237  /// </summary>
238  public static readonly Dictionary<Symbol, Func<DateTime, DateTime>> FuturesExpiryDictionary = new Dictionary<Symbol, Func<DateTime, DateTime>>()
239  {
240  // Metals
241  // Gold (GC): http://www.cmegroup.com/trading/metals/precious/gold_contract_specifications.html
242  {Symbol.Create(Futures.Metals.Gold, SecurityType.Future, Market.COMEX), (time =>
243  {
244  // Monthly contracts
245  // Trading terminates on the third last business day of the delivery month.
246  var market = Market.COMEX;
247  var symbol = Futures.Metals.Gold;
248  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
249  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time,3, holidays);
250  })
251  },
252  // Silver (SI): http://www.cmegroup.com/trading/metals/precious/silver_contract_specifications.html
254  {
255  // Monthly contracts
256  // Trading terminates on the third last business day of the delivery month.
257  var market = Market.COMEX;
258  var symbol = Futures.Metals.Silver;
259  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
260  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time,3, holidays);
261  })
262  },
263  // Platinum (PL): http://www.cmegroup.com/trading/metals/precious/platinum_contract_specifications.html
265  {
266  // Monthly contracts
267  // Trading terminates on the third last business day of the delivery month.
268  var market = Market.NYMEX;
269  var symbol = Futures.Metals.Platinum;
270  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
271  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time,3, holidays);
272  })
273  },
274  // Palladium (PA): http://www.cmegroup.com/trading/metals/precious/palladium_contract_specifications.html
276  {
277  // Monthly contracts
278  // Trading terminates on the third last business day of the delivery month.
279  var market = Market.NYMEX;
280  var symbol = Futures.Metals.Palladium;
281  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
282  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time,3, holidays);
283  })
284  },
285  // Aluminum MW U.S. Transaction Premium Platts (25MT) (AUP): https://www.cmegroup.com/trading/metals/base/aluminum-mw-us-transaction-premium-platts-swap-futures_contract_specifications.html
287  {
288  var market = Market.COMEX;
290  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
291  // Monthly contracts
292  // Trading terminates on the last business day of the contract month.
293  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
294 
295  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
296 
297  return lastBusinessDay;
298  })
299  },
300  // Aluminium European Premium Duty-Paid (Metal Bulletin) (EDP): https://www.cmegroup.com/trading/metals/base/aluminium-european-premium-duty-paid-metal-bulletin_contract_specifications.html
302  {
303  var market = Market.COMEX;
305  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
306  // Monthly contracts
307  // Trading terminates on the last business day of the contract month
308  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
309  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
310 
311  return lastBusinessDay;
312  })
313  },
314  // Copper (HG): https://www.cmegroup.com/trading/metals/base/copper_contract_specifications.html
316  {
317  var market = Market.COMEX;
318  var symbol = Futures.Metals.Copper;
319  // Monthly contracts
320  // Trading terminates at 12:00 Noon CT on the third last business day of the contract month.
321  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
322 
323  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays).Add(new TimeSpan(17, 0, 0));
324  })
325  },
326  // U.S. Midwest Domestic Hot-Rolled Coil Steel (CRU) Index (HRC): https://www.cmegroup.com/trading/metals/ferrous/hrc-steel_contract_specifications.html
328  {
329  var market = Market.NYMEX;
331  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
332  // Monthly contracts
333  // Trading terminates on the business day prior to the last Wednesday of the named contract month.
334  var lastWednesday = (from dateRange in Enumerable.Range(1, DateTime.DaysInMonth(time.Year, time.Month))
335  where new DateTime(time.Year, time.Month, dateRange).DayOfWeek == DayOfWeek.Wednesday
336  select new DateTime(time.Year, time.Month, dateRange)).Last();
337 
338  return FuturesExpiryUtilityFunctions.AddBusinessDays(lastWednesday, -1, holidays);
339  })
340  },
341  // Indices
342  // SP500EMini (ES): http://www.cmegroup.com/trading/equity-index/us-index/e-mini-sandp500_contract_specifications.html
344  {
345  // Quarterly contracts (Mar/3, Jun/6 , Sep/9 , Dec/12) listed for 9 consecutive quarters and 3 additional December contract months.
346  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
347  {
348  time = time.AddMonths(1);
349  }
350 
351  // Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
352  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
353  return thirdFriday.Add(new TimeSpan(13,30,0));
354  })
355  },
356  // EuroStoxx50 (FESX): https://www.xetra.com/resource/blob/63488/437afcd347fb020377873dd1ceac10ba/EURO-STOXX-50-Factsheet-data.pdf
358  {
359  // Quarterly contracts (Mar/3, Jun/6 , Sep/9 , Dec/12) listed for 9 consecutive quarters and 3 additional December contract months.
360  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
361  {
362  time = time.AddMonths(1);
363  }
364 
365  // Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
366  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
367  return thirdFriday.Add(new TimeSpan(13,30,0));
368  })
369  },
370  // NASDAQ100EMini (NQ): http://www.cmegroup.com/trading/equity-index/us-index/e-mini-nasdaq-100_contract_specifications.html
372  {
373  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
374  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
375  {
376  time = time.AddMonths(1);
377  }
378 
379  // Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
380  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
381  return thirdFriday.Add(new TimeSpan(13,30,0));
382  })
383  },
384  // Dow30EMini (YM): http://www.cmegroup.com/trading/equity-index/us-index/e-mini-dow_contract_specifications.html
386  {
387  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 consecutive quarters
388  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
389  {
390  time = time.AddMonths(1);
391  }
392 
393  // Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
394  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
395  return thirdFriday.Add(new TimeSpan(13,30,0));
396  })
397  },
398  // Russell2000EMini (RTY): https://www.cmegroup.com/trading/equity-index/us-index/e-mini-russell-2000_contract_specifications.html
400  {
401  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
402  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
403  {
404  time = time.AddMonths(1);
405  }
406 
407  // Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
408  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
409  return thirdFriday.Add(new TimeSpan (13,30,0));
410  })
411  },
412  // Nikkei225Dollar (NKD): https://www.cmegroup.com/trading/equity-index/international-index/nikkei-225-dollar_contract_specifications.html
414  {
415  var market = Market.CME;
416  var symbol = Futures.Indices.Nikkei225Dollar;
417  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
418  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 12 quarters, and 3 additional Dec contract months
419  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
420  {
421  time = time.AddMonths(1);
422  }
423 
424  // Trading terminates at 5:00 p.m. Eastern Time (ET) on Business Day prior to 2nd Friday of the contract month.
425  var secondFriday = FuturesExpiryUtilityFunctions.SecondFriday(time);
426  var priorBusinessDay = secondFriday.AddDays(-1);
427  while (!FuturesExpiryUtilityFunctions.NotHoliday(priorBusinessDay, holidays))
428  {
429  priorBusinessDay = priorBusinessDay.AddDays(-1);
430  }
431  return priorBusinessDay.Add(TimeSpan.FromHours(21));
432  })
433  },
434  // Nikkei225YenCME (NIY): https://www.cmegroup.com/markets/equities/international-indices/nikkei-225-yen.contractSpecs.html
436  {
437  var market = Market.CME;
438  var symbol = Futures.Indices.Nikkei225YenCME;
439  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
440  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 12 quarters, serial contract listed for 3 months, and 3 additional Dec contract months
441  // Trading terminates at 5:00 p.m. Eastern Time (ET) on Business Day prior to 2nd Friday of the contract month.
442  var secondFriday = FuturesExpiryUtilityFunctions.SecondFriday(time);
443  var priorBusinessDay = secondFriday.AddDays(-1);
444  while (!FuturesExpiryUtilityFunctions.NotHoliday(priorBusinessDay, holidays))
445  {
446  priorBusinessDay = priorBusinessDay.AddDays(-1);
447  }
448  return priorBusinessDay.Add(TimeSpan.FromHours(21));
449  })
450  },
451  // Nikkei225YenEMini (ENY): https://www.cmegroup.com/markets/equities/international-indices/emini-nikkei-225-yen.contractSpecs.html
453  {
454  var market = Market.CME;
455  var symbol = Futures.Indices.Nikkei225YenEMini;
456  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
457  // Four months in the March Quarterly Cycle (Mar, Jun, Sep, Dec)
458  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
459  {
460  time = time.AddMonths(1);
461  }
462 
463  // Trading terminates at 5:00 p.m. Eastern Time (ET) on Business Day prior to 2nd Friday of the contract month.
464  var secondFriday = FuturesExpiryUtilityFunctions.SecondFriday(time);
465  var priorBusinessDay = secondFriday.AddDays(-1);
466  while (!FuturesExpiryUtilityFunctions.NotHoliday(priorBusinessDay, holidays))
467  {
468  priorBusinessDay = priorBusinessDay.AddDays(-1);
469  }
470  return priorBusinessDay.Add(TimeSpan.FromHours(21));
471  })
472  },
473  // FTSEChina50EMini (FT5): https://www.cmegroup.com/markets/equities/international-indices/e-mini-ftse-china-50-index.contractSpecs.html
475  {
476  var market = Market.CME;
477  var symbol = Futures.Indices.FTSEChina50EMini;
478  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
479  //Contracts listed for the 2 nearest serial and 4 quarterly months.
480  //Trading terminates on the second to last business day of the contract month at the end of trading on the Hong Kong Exchange Securities Market
481  var secondLastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time,2, holidays);
482 
483  while (!FuturesExpiryUtilityFunctions.NotHoliday(secondLastBusinessDay, holidays))
484  {
485  secondLastBusinessDay = secondLastBusinessDay.AddDays(-1);
486  }
487  return secondLastBusinessDay.Add(TimeSpan.FromHours(6));
488  })
489  },
490  // FTSE100EMini (FT1): https://www.cmegroup.com/markets/equities/international-indices/e-mini-ftse-100-index.contractSpecs.html
492  {
493  var market = Market.CME;
494  var symbol = Futures.Indices.FTSE100EMini;
495  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
496  //Contracts listed for five months in the March Quarterly Cycle (Mar, Jun, Sep, Dec)
497  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
498  {
499  time = time.AddMonths(1);
500  }
501 
502  //Trading terminates on the third Friday of the contract month
503  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
504 
505  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
506  {
507  thirdFriday = thirdFriday.AddDays(-1);
508  }
509  return thirdFriday;
510  })
511  },
512  // SPEurop350ESGEMini (E3G): https://www.cmegroup.com/markets/equities/international-indices/e-mini-sp-europe-350-esg-index.contractSpecs.html
514  {
515  var market = Market.CME;
516  var symbol = Futures.Indices.SPEurop350ESGEMini;
517  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
518  //Contracts listed for 5 months in the March Quarterly Cycle (Mar, Jun, Sep, Dec)
519  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
520  {
521  time = time.AddMonths(1);
522  }
523 
524  //Trading terminates on the 3rd Friday of contract delivery month.
525  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
526 
527  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
528  {
529  thirdFriday = thirdFriday.AddDays(-1);
530  }
531  return thirdFriday;
532  })
533  },
534  // FTSE100USDEMini (FTU): https://www.cmegroup.com/markets/equities/international-indices/e-mini-sp-europe-350-esg-index.contractSpecs.html
536  {
537  var market = Market.CME;
538  var symbol = Futures.Indices.FTSE100USDEMini;
539  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
540  //Contracts listed for five months in the March Quarterly Cycle (Mar, Jun, Sep, Dec)
541  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
542  {
543  time = time.AddMonths(1);
544  }
545 
546  //Trading terminates on the third Friday of the contract month.
547  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
548 
549  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
550  {
551  thirdFriday = thirdFriday.AddDays(-1);
552  }
553  return thirdFriday;
554  })
555  },
556  // TOPIXUSD (TPD): https://www.cmegroup.com/markets/equities/international-indices/usd-denominated-topix-index.contractSpecs.html
558  {
559  var market = Market.CME;
560  var symbol = Futures.Indices.TOPIXUSD;
561  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
562  //Quarterly Contracts listed for (Mar, Jun, Sep, Dec) for 5 months
563  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
564  {
565  time = time.AddMonths(1);
566  }
567 
568  //Trading terminates at 5:00 p.m. ET on the Thursday prior to the second Friday of the contract month.
569  var secondFriday = FuturesExpiryUtilityFunctions.NthFriday(time,2);
570  var thursdaypriorsecondFriday = secondFriday.AddDays(-1);
571 
572  while (!FuturesExpiryUtilityFunctions.NotHoliday(thursdaypriorsecondFriday, holidays))
573  {
574  thursdaypriorsecondFriday = thursdaypriorsecondFriday.AddDays(-1);
575  }
576  return thursdaypriorsecondFriday.Add(TimeSpan.FromHours(21));
577  })
578  },
579  // TOPIXYEN (TPY): https://www.cmegroup.com/markets/equities/international-indices/usd-denominated-topix-index.contractSpecs.html
581  {
582  var market = Market.CME;
583  var symbol = Futures.Indices.TOPIXYEN;
584  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
585  //Quarterly Contracts listed for (Mar, Jun, Sep, Dec) for 5 months
586  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
587  {
588  time = time.AddMonths(1);
589  }
590 
591  //Trading terminates at 5:00 p.m. ET on the Thursday prior to the second Friday of the contract month.
592  var secondFriday = FuturesExpiryUtilityFunctions.NthFriday(time,2);
593  var thursdaypriorsecondFriday = secondFriday.AddDays(-1);
594 
595  while (!FuturesExpiryUtilityFunctions.NotHoliday(thursdaypriorsecondFriday, holidays))
596  {
597  thursdaypriorsecondFriday = thursdaypriorsecondFriday.AddDays(-1);
598  }
599  return thursdaypriorsecondFriday.Add(TimeSpan.FromHours(21));
600  })
601  },
602  // DowJonesRealEstate (RX): https://www.cmegroup.com/markets/equities/dow-jones/dow-jones-rei.contractSpecs.html
604  {
605  var market = Market.CME;
606  var symbol = Futures.Indices.DowJonesRealEstate;
607  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
608  //Quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 consecutive quarters
609  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
610  {
611  time = time.AddMonths(1);
612  }
613  //Trading can occur up to 9:30 a.m. ET on the 3rd Friday of the contract month
614  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
615 
616  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
617  {
618  thirdFriday = thirdFriday.AddDays(-1);
619  }
620  return thirdFriday.Add(new TimeSpan(13, 30, 0));
621  })
622  },
623  // SP500EMiniESG (ESG): https://www.cmegroup.com/markets/equities/sp/e-mini-sandp-500-esg-index.contractSpecs.html
625  {
626  var market = Market.CME;
627  var symbol = Futures.Indices.SP500EMiniESG;
628  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
629  //Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
630  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
631  {
632  time = time.AddMonths(1);
633  }
634  //Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
635  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
636 
637  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
638  {
639  thirdFriday = thirdFriday.AddDays(-1);
640  }
641  return thirdFriday.Add(new TimeSpan(13, 30, 0));
642  })
643  },
644  // Russell1000EMini (RS1): https://www.cmegroup.com/markets/equities/russell/e-mini-russell-1000-index.contractSpecs.html
646  {
647  var market = Market.CME;
648  var symbol = Futures.Indices.Russell1000EMini;
649  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
650  //Quarterly contracts (Mar, Jun, Sep, Dec) lisrted for 5 consecutive quarters
651  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
652  {
653  time = time.AddMonths(1);
654  }
655  //Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
656  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
657 
658  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
659  {
660  thirdFriday = thirdFriday.AddDays(-1);
661  }
662  return thirdFriday.Add(new TimeSpan(13, 30, 0));
663  })
664  },
665  // SP500AnnualDividendIndex (SDA): https://www.cmegroup.com/markets/equities/sp/sp-500-annual-dividend-index.contractSpecs.html
667  {
668  var market = Market.CME;
670  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
671  //Annual contracts (December) listed for 11 consecutive years
672  while (!FutureExpirationCycles.December.Contains(time.Month))
673  {
674  time = time.AddMonths(1);
675  }
676  //Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
677  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
678 
679  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
680  {
681  thirdFriday = thirdFriday.AddDays(-1);
682  }
683  return thirdFriday.Add(new TimeSpan(13, 30, 0));
684  })
685  },
686  // CBOE Volatility Index Futures (VIX): https://www.cboe.com/tradable_products/vix/vix_futures/specifications/
687  {Symbol.Create(Futures.Indices.VIX, SecurityType.Future, Market.CFE), (time =>
688  {
689  // Trading can occur up to 9:00 a.m. Eastern Time (ET) on the "Wednesday that is 30 days prior to
690  // the third Friday of the calendar month immediately following the month in which the contract expires".
691  var market = Market.CFE;
692  var symbol = Futures.Indices.VIX;
693  var nextThirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time.AddMonths(1));
694  var expiryDate = nextThirdFriday.AddDays(-30);
695  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
696 
697  // If the next third Friday or the Wednesday are holidays, then it is moved to the previous day.
698  if (holidays.Contains(expiryDate) || holidays.Contains(nextThirdFriday))
699  {
700  expiryDate = expiryDate.AddDays(-1);
701  }
702  // Trading hours for expiring VX futures contracts end at 8:00 a.m. Chicago time on the final settlement date.
703  return expiryDate.Add(new TimeSpan(13, 0, 0));
704  })
705  },
706  // Bloomberg Commodity Index (AW): https://www.cmegroup.com/trading/agricultural/commodity-index/bloomberg-commodity-index_contract_specifications.html
708  {
709  var market = Market.CBOT;
711  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
712  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 consecutive quarters and 4 additional Dec contract months
713  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
714  {
715  time = time.AddMonths(1);
716  }
717 
718  // 3rd Wednesday of the contract month/ 1:30pm
719  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
720  thirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(thirdWednesday, -1, holidays);
721  return thirdWednesday.Add(new TimeSpan(18, 30, 0));
722  })
723  },
724  // E-mini Nasdaq-100 Biotechnology Index (BIO): https://www.cmegroup.com/trading/equity-index/us-index/e-mini-nasdaq-biotechnology_contract_specifications.html
726  {
727  var market = Market.CME;
729  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
730  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
731  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
732  {
733  time = time.AddMonths(1);
734  }
735 
736  // Trading can occur up to 9:30 a.m. ET on the 3rd Friday of the contract month
737  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
738  thirdFriday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(thirdFriday, -1, holidays);
739 
740  return thirdFriday.Add(new TimeSpan(13, 30, 0));
741  })
742  },
743  // E-mini FTSE Emerging Index (EI): https://www.cmegroup.com/trading/equity-index/international-index/e-mini-ftse-emerging-index_contract_specifications.html
745  {
746  // Five months in the March Quarterly Cycle (Mar, Jun, Sep, Dec)
747  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
748  {
749  time = time.AddMonths(1);
750  }
751 
752  // Trading can occur up to 4:00 p.m. ET on the 3rd Friday of contract month
753  return FuturesExpiryUtilityFunctions.NthFriday(time, 3).Add(new TimeSpan(20, 0, 0));
754  })
755  },
756  // E-mini S&amp;P MidCap 400 Futures (EMD): https://www.cmegroup.com/trading/equity-index/us-index/e-mini-sandp-midcap-400_contract_specifications.html
758  {
759  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
760  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
761  {
762  time = time.AddMonths(1);
763  }
764 
765  // Trading can occur up until 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
766  return FuturesExpiryUtilityFunctions.NthFriday(time, 3).Add(new TimeSpan(13, 30, 0));
767  })
768  },
769  // S&amp;P-GSCI Commodity Index (GD): https://www.cmegroup.com/trading/agricultural/commodity-index/gsci_contract_specifications.html
771  {
772  var market = Market.CME;
773  var symbol = Futures.Indices.SPGSCICommodity;
774  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
775  // Monthly contracts
776  // Trading terminates on the11th business day of the contract month, 1:40pm.
777 
778  return FuturesExpiryUtilityFunctions.NthBusinessDay(time, 11, holidays).Add(new TimeSpan(18, 40, 0));
779  })
780  },
781  // USD-Denominated Ibovespa Index (IBV): https://www.cmegroup.com/trading/equity-index/international-index/usd-denominated-ibovespa_contract_specifications.html
783  {
784  var market = Market.CME;
786  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
787  // Four bi-monthly contracts (Feb/2, Apr/4, Jun/6, Aug/8, Oct/10, Dec/12 cycle)
788  while (!FutureExpirationCycles.GJMQVZ.Contains(time.Month))
789  {
790  time = time.AddMonths(1);
791  }
792 
793  // 5:00 p.m. Sao Paulo Time on the Wednesday closest to the 15th calendar day of the contract month. If it is a non-trading day at BM&amp;F Bovespa, trading shall terminate on the next trading day.
794  var wednesdays = (from dateRange in Enumerable.Range(1, DateTime.DaysInMonth(time.Year, time.Month))
795  where new DateTime(time.Year, time.Month, dateRange).DayOfWeek == DayOfWeek.Wednesday
796  select new DateTime(time.Year, time.Month, dateRange));
797 
798  var distanceFromFifteenthDay = wednesdays.Select(x => Math.Abs(15 - x.Day)).ToList();
799  var wednesdayIndex = distanceFromFifteenthDay.IndexOf(distanceFromFifteenthDay.Min());
800  var closestWednesday = wednesdays.ElementAt(wednesdayIndex);
801  if (holidays.Contains(closestWednesday) || !FuturesExpiryUtilityFunctions.NotHoliday(closestWednesday, holidays))
802  {
803  closestWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(closestWednesday, 1, holidays);
804  }
805 
806  return closestWednesday.Add(new TimeSpan(20, 0, 0));
807  })
808  },
809 
810  // JPY-Denominated Nikkie 225 Index Futures: https://www2.sgx.com/derivatives/products/nikkei225futuresoptions?cc=NK#Contract%20Specifications
812  {
813  // 6 nearest serial months & 32 nearest quarterly months
814  // The day before the second Friday of the contract month. Trading Hours on Last Day is normal Trading Hours (session T)
815  // T Session
816  // 7.15 am - 2.30 pm
817  var market = Market.SGX;
818  var symbol = Futures.Indices.Nikkei225Yen;
819  var secondFriday = FuturesExpiryUtilityFunctions.SecondFriday(time);
820  var priorBusinessDay = secondFriday.AddDays(-1);
821 
822  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
823 
824  while (holidays.Contains(priorBusinessDay) || !priorBusinessDay.IsCommonBusinessDay())
825  {
826  priorBusinessDay = priorBusinessDay.AddDays(-1);
827  }
828  return priorBusinessDay.Add(new TimeSpan(14, 30, 0));
829  })
830  },
831 
832  // MSCI Taiwan Index Futures: https://www2.sgx.com/derivatives/products/timsci?cc=TW
834  {
835  // 2 nearest serial months and 12 quarterly months on March, June, September and December cycle.
836  // Second last business day of the contract month. Same as T Session trading hours
837  var market = Market.SGX;
838  var symbol = Futures.Indices.MSCITaiwanIndex;
839  var lastDay = new DateTime(time.Year, time.Month, DateTime.DaysInMonth(time.Year, time.Month));
840  var priorBusinessDay = lastDay.AddDays(-1);
841 
842  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
843 
844  while (holidays.Contains(priorBusinessDay) || !priorBusinessDay.IsCommonBusinessDay())
845  {
846  priorBusinessDay = priorBusinessDay.AddDays(-1);
847  }
848  return priorBusinessDay.Add(new TimeSpan(13, 45, 0));
849  })
850  },
851 
852  // Nifty 50 Index Futures: https://www1.nseindia.com/products/content/derivatives/equities/contract_specifitns.htm
854  {
855  // 3 consecutive months trading cycle – Near-Month, Mid-Month and Far-Month.
856  // Last Thursday of the expiring contract month. If this falls on an NSE non-business day, the last trading day shall be the preceding business day.
857  // The expiring contract shall close on its last trading day at 3.30 pm.
858  var market = Market.India;
859  var symbol = Futures.Indices.Nifty50;
860  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
861 
862  var expiryday = FuturesExpiryUtilityFunctions.LastThursday(time);
863 
864  while (holidays.Contains(expiryday) || !expiryday.IsCommonBusinessDay())
865  {
866  expiryday = expiryday.AddDays(-1);
867  }
868  return expiryday.Add(new TimeSpan(15, 30, 0));
869  })
870  },
871 
872  // BankNifty Index Futures: https://www1.nseindia.com/products/content/derivatives/equities/bank_nifty_new.htm
874  {
875  // have a maximum of 3-month trading cycle - the near month , the next month and the far month.
876  // Last Thursday of the expiring contract month. If this falls on an NSE non-business day, the last trading day shall be the preceding business day.
877  // The expiring contract shall close on its last trading day at 3.30 pm.
878  var market = Market.India;
879  var symbol = Futures.Indices.BankNifty;
880  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
881 
882  var expiryday = FuturesExpiryUtilityFunctions.LastThursday(time);
883 
884  while (holidays.Contains(expiryday) || !expiryday.IsCommonBusinessDay())
885  {
886  expiryday = expiryday.AddDays(-1);
887  }
888  return expiryday.Add(new TimeSpan(15, 30, 0));
889  })
890  },
891 
892 
893  // BSE S&P Sensex Index Futures: https://www.bseindia.com/static/markets/Derivatives/DeriReports/market_information.html#!#ach6
895  {
896  // Last Thursday of the expiring contract month. If this falls on an BSE non-business day, the last trading day shall be the preceding business day.
897  // The expiring contract shall close on its last trading day at 3.30 pm.
898  var market = Market.India;
899  var symbol = Futures.Indices.BseSensex;
900  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
901 
902  var expiryday = FuturesExpiryUtilityFunctions.LastThursday(time);
903 
904  while (holidays.Contains(expiryday) || !expiryday.IsCommonBusinessDay())
905  {
906  expiryday = expiryday.AddDays(-1);
907  }
908  return expiryday.Add(new TimeSpan(15, 30, 0));
909  })
910  },
911 
912  // HSI Index Futures:https://www.hkex.com.hk/Products/Listed-Derivatives/Equity-Index/Hang-Seng-Index-(HSI)/Hang-Seng-Index-Futures?sc_lang=en#&product=HSI
914  {
915  // Short-dated Futures:
916  // Spot, next three calendar month & next three calendar quarter months; and
917  // Long-dated Futures:
918  // The three months of June and December plus the next three months of December
919 
920  // The Business Day immediately preceding the last Business Day of the Contract Month
921  var lastDay = new DateTime(time.Year, time.Month, DateTime.DaysInMonth(time.Year, time.Month));
922 
924  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
925  var priorBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay, -1, holidays);
926 
927  return priorBusinessDay.Add(new TimeSpan(16, 0, 0));
928  })
929  },
930 
931  // MSCI Europe Net Total Return (USD) Futures: https://www.theice.com/products/71512951/MSCI-Europe-NTR-Index-Future-USD & https://www.theice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_2022_TRADING_HOLIDAY_CALENDAR_20211118.pdf
933  {
934  var market = Market.NYSELIFFE;
935  var symbol = Futures.Indices.MSCIEuropeNTR;
936  // Trading terminates on the third Friday of the contract month @16:15.
937  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
938  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
939 
940  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
941 
942  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
943  })
944  },
945  // MSCI Japan Net Total Return Futures: https://www.theice.com/products/75392111/MSCI-Japan-NTR-Index-Future & https://www.theice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_2022_TRADING_HOLIDAY_CALENDAR_20211118.pdf
947  {
948  var market = Market.NYSELIFFE;
949  var symbol = Futures.Indices.MSCIJapanNTR;
950  // Trading terminates on the third Friday of the contract month @16:15.
951  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
952 
953  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
954 
955  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
956 
957  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
958  })
959  },
960  // MSCI Emerging Markets Asia Net Total Return Futures: https://www.theice.com/products/32375861/MSCI-Emerging-Markets-Asia-NTR-Index-Future & https://www.theice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_2022_TRADING_HOLIDAY_CALENDAR_20211118.pdf
962  {
963  var market = Market.NYSELIFFE;
965  // Trading terminates on the third Friday of the contract month @16:15.
966  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
967  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
968 
969  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
970 
971  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
972  })
973  },
974  // MSCI EAFE Index Futures: https://www.theice.com/products/31196848/MSCI-EAFE-Index-Future & https://www.theice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_2022_TRADING_HOLIDAY_CALENDAR_20211118.pdf
976  {
977  var market = Market.NYSELIFFE;
978  var symbol = Futures.Indices.MSCIEafeIndex;
979  // Trading terminates on the third Friday of the contract month @16:15.
980  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
981 
982  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
983 
984  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
985 
986  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
987  })
988  },
989  // MSCI Emerging Markets Index Futures: https://www.theice.com/products/31196851/MSCI-Emerging-Markets-Index-Future & https://www.theice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_2022_TRADING_HOLIDAY_CALENDAR_20211118.pdf
991  {
992  var market = Market.NYSELIFFE;
994  // Trading terminates on the third Friday of the contract month @16:15.
995  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
996  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
997 
998  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
999 
1000  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
1001  })
1002  },
1003  // MSCI USA Index Futures: https://www.theice.com/products/32375866/MSCI-USA-Index-Future & https://www.theice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_2022_TRADING_HOLIDAY_CALENDAR_20211118.pdf
1005  {
1006  var market = Market.NYSELIFFE;
1007  var symbol = Futures.Indices.MSCIUsaIndex;
1008  // Trading terminates on the third Friday of the contract month @16:15.
1009  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
1010  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1011 
1012  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
1013 
1014  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
1015  })
1016  },
1017  // Forestry Group
1018  // Random Length Lumber (LBS): https://www.cmegroup.com/trading/agricultural/lumber-and-pulp/random-length-lumber_contract_specifications.html
1020  {
1021  var market = Market.CME;
1022  var symbol = Futures.Forestry.RandomLengthLumber;
1023  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1024  // Monthly contracts (Jan, Mar, May, Jul, Sep, Nov) listed for 7 months
1025  while (!FutureExpirationCycles.FHKNUX.Contains(time.Month))
1026  {
1027  time = time.AddMonths(1);
1028  }
1029 
1030  // The business day prior to the 16th calendar day of the contract month at 12:05pm CT
1031  var sixteenth = new DateTime(time.Year,time.Month,16);
1032  return FuturesExpiryUtilityFunctions.AddBusinessDays(sixteenth, -1, holidays).Add(new TimeSpan(17, 5, 0));
1033  })
1034  },
1035  // Lumber and Softs
1036  // Lumber Futures (LBR): https://www.cmegroup.com/markets/agriculture/lumber-and-softs/lumber.contractSpecs.html
1037  {Symbol.Create(Futures.Forestry.Lumber, SecurityType.Future, Market.CME), (time =>
1038  {
1039  var market = Market.CME;
1040  var symbol = Futures.Forestry.Lumber;
1041  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1042  // Monthly contracts (Jan, Mar, May, Jul, Sep, Nov) listed for 7 months
1043  while (!FutureExpirationCycles.FHKNUX.Contains(time.Month))
1044  {
1045  time = time.AddMonths(1);
1046  }
1047 
1048  // The business day prior to the 16th calendar day of the contract month at 12:05pm CT
1049  var sixteenth = new DateTime(time.Year,time.Month, 16);
1050  return FuturesExpiryUtilityFunctions.AddBusinessDays(sixteenth, -1, holidays).Add(new TimeSpan(17, 5, 0));
1051  })
1052  },
1053  // Grains And OilSeeds Group
1054  // Chicago SRW Wheat (ZW): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/wheat_contract_specifications.html
1056  {
1057  var market = Market.CBOT;
1058  var symbol = Futures.Grains.SRWWheat;
1059  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1060  // 15 monthly contracts of Mar, May, Jul, Sep, Dec listed annually following the termination of trading in the July contract of the current year.
1061  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
1062  {
1063  time = time.AddMonths(1);
1064  }
1065 
1066  // The business day prior to the 15th calendar day of the contract month.
1067  var fifteenth = new DateTime(time.Year,time.Month,15);
1068  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1069  })
1070  },
1071  // HRW Wheat (KE): https://www.cmegroup.com/trading/agricultural/grain-and-oilseed/kc-wheat_contract_specifications.html
1073  {
1074  var market = Market.CBOT;
1075  var symbol = Futures.Grains.HRWWheat;
1076  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1077  // Monthly contracts (Mar, May, Jul, Sep, Dec) listed for 15 months
1078  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
1079  {
1080  time = time.AddMonths(1);
1081  }
1082 
1083  // The business day prior to the 15th calendar day of the contract month.
1084  var fifteenth = new DateTime(time.Year,time.Month,15);
1085  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1086  })
1087  },
1088  // Corn (ZC): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/corn_contract_specifications.html
1089  {Symbol.Create(Futures.Grains.Corn, SecurityType.Future, Market.CBOT), (time =>
1090  {
1091  var market = Market.CBOT;
1092  var symbol = Futures.Grains.Corn;
1093  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1094  // 9 monthly contracts of Mar/3, May/5, Sep/9 and 8 monthly contracts of Jul/7 and Dec/12 listed annually after the termination of trading in the December contract of the current year.
1095  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
1096  {
1097  time = time.AddMonths(1);
1098  }
1099 
1100  // The business day prior to the 15th calendar day of the contract month.
1101  var fifteenth = new DateTime(time.Year,time.Month,15);
1102  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1103  })
1104  },
1105  // Soybeans (ZS): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/soybean_contract_specifications.html
1107  {
1108  var market = Market.CBOT;
1109  var symbol = Futures.Grains.Soybeans;
1110  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1111  // 15 monthly contracts of Jan/1, Mar/3, May/5, Aug/8, Sep/9 and 8 monthly contracts of Jul/7 and Nov/11 listed annually after the termination of trading in the November contract of the current year.
1112  while (!FutureExpirationCycles.FHKNQUX.Contains(time.Month))
1113  {
1114  time = time.AddMonths(1);
1115  }
1116 
1117  // The business day prior to the 15th calendar day of the contract month.
1118  var fifteenth = new DateTime(time.Year,time.Month,15);
1119  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1120  })
1121  },
1122  // SoybeanMeal (ZM): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/soybean-meal_contract_specifications.html
1124  {
1125  var market = Market.CBOT;
1126  var symbol = Futures.Grains.SoybeanMeal;
1127  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1128  // 15 monthly contracts of Jan/1, Mar/3, May/5, Aug/8, Sep/9 and 12 monthly contracts of Jul/7, Oct/10, Dec/12 listed annually after the termination of trading in the December contract of the current year.
1129  while (!FutureExpirationCycles.FHKNQUVZ.Contains(time.Month))
1130  {
1131  time = time.AddMonths(1);
1132  }
1133 
1134  // The business day prior to the 15th calendar day of the contract month.
1135  var fifteenth = new DateTime(time.Year,time.Month,15);
1136  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1137  })
1138  },
1139  // SoybeanOil (ZL): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/soybean-oil_contract_specifications.html
1141  {
1142  var market = Market.CBOT;
1143  var symbol = Futures.Grains.SoybeanOil;
1144  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1145  // 15 monthly contracts of Jan/1, Mar/3, May/5, Aug/8, Sep/9 and 12 monthly contracts of Jul/7, Oct/10, Dec/12 listed annually after the termination of trading in the December contract of the current year.
1146  while (!FutureExpirationCycles.FHKNQUVZ.Contains(time.Month))
1147  {
1148  time = time.AddMonths(1);
1149  }
1150 
1151  // The business day prior to the 15th calendar day of the contract month.
1152  var fifteenth = new DateTime(time.Year,time.Month,15);
1153  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1154  })
1155  },
1156  // Oats (ZO): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/oats_contract_specifications.html
1157  {Symbol.Create(Futures.Grains.Oats, SecurityType.Future, Market.CBOT), (time =>
1158  {
1159  var market = Market.CBOT;
1160  var symbol = Futures.Grains.Oats;
1161  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1162  // Monthly contracts (Mar, May, Jul, Sep, Dec) listed for 10 months and 1 additional Jul and 1 additional Sep contract listed in September
1163  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
1164  {
1165  time = time.AddMonths(1);
1166  }
1167 
1168  // The business day prior to the 15th calendar day of the contract month.
1169  var fifteenth = new DateTime(time.Year,time.Month,15);
1170  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1171  })
1172  },
1173  // Black Sea Corn Financially Settled (Platts) (BCF): https://www.cmegroup.com/trading/agricultural/grain-and-oilseed/black-sea-corn-financially-settled-platts_contract_specifications.html
1175  {
1176  var market = Market.CBOT;
1178  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1179 
1180  // Monthly contracts listed for 15 consecutive months.
1181  // Trading terminates on the last business day of the contract month which is also a Platts publication date for the price assessment.
1182  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1183  })
1184  },
1185  // Black Sea Wheat Financially Settled (Platts) (BWF): https://www.cmegroup.com/trading/agricultural/grain-and-oilseed/black-sea-wheat-financially-settled-platts_contract_specifications.html
1187  {
1188  var market = Market.CBOT;
1190  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1191  // Monthly contracts listed for 15 consecutive months
1192  // Trading terminates on the last business day of the contract month which is also a Platts publication date for the price assessment.
1193  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1194  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
1195 
1196  return lastBusinessDay;
1197  })
1198  },
1199  // Currencies group
1200  // U.S. Dollar Index(R) Futures (DX): https://www.theice.com/products/194/US-Dollar-Index-Futures
1201  {Symbol.Create(Futures.Currencies.USD, SecurityType.Future, Market.ICE), (time =>
1202  {
1203  // Four months in the March/June/September/December quarterly expiration cycle
1204  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1205  {
1206  time = time.AddMonths(1);
1207  }
1208 
1209  // Last Trading Day:
1210  // Trading ceases at 10:16 Eastern time two days prior to settlement
1211  //
1212  // Final Settlement:
1213  // The US Dollar Index is physically settled on the third Wednesday of the expiration month
1214  // against six component currencies (euro, Japanese yen, British pound, Canadian dollar, Swedish
1215  // krona and Swiss franc) in their respective percentage weights in the Index.
1216  // Settlement rates may be quoted to three decimal places.
1217 
1218  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1219  var twoDaysPrior = thirdWednesday.AddDays(-2);
1220 
1221  return twoDaysPrior.Add(new TimeSpan(10, 16, 0));
1222  })
1223  },
1224  // GBP (6B): http://www.cmegroup.com/trading/fx/g10/british-pound_contract_specifications.html
1225  {Symbol.Create(Futures.Currencies.GBP, SecurityType.Future, Market.CME), (time =>
1226  {
1227  var market = Market.CME;
1228  var symbol = Futures.Currencies.GBP;
1229  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1230  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters and serial contracts listed for 3 months
1231 
1232  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1233  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1234  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1235  thirdWednesday,
1236  -2, holidays);
1237  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1238  })
1239  },
1240  // CAD (6C): http://www.cmegroup.com/trading/fx/g10/canadian-dollar_contract_specifications.html
1241  {Symbol.Create(Futures.Currencies.CAD, SecurityType.Future, Market.CME), (time =>
1242  {
1243  var market = Market.CME;
1244  var symbol = Futures.Currencies.CAD;
1245  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1246  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters and serial contracts listed for 3 months
1247 
1248  // 9:16 a.m. Central Time (CT) on the business day immediately preceding the third Wednesday of the contract month (usually Tuesday).
1249  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1250  var businessDayPrecedingThridWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -1, holidays);
1251  return businessDayPrecedingThridWednesday.Add(new TimeSpan(14,16,0));
1252  })
1253  },
1254  // JPY (6J): http://www.cmegroup.com/trading/fx/g10/japanese-yen_contract_specifications.html
1255  {Symbol.Create(Futures.Currencies.JPY, SecurityType.Future, Market.CME), (time =>
1256  {
1257  var market = Market.CME;
1258  var symbol = Futures.Currencies.JPY;
1259  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1260  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters and serial contracts listed for 3 months
1261 
1262  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1263  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1264  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1265  thirdWednesday,
1266  -2, holidays);
1267  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1268  })
1269  },
1270  // CHF (6S): http://www.cmegroup.com/trading/fx/g10/swiss-franc_contract_specifications.html
1271  {Symbol.Create(Futures.Currencies.CHF, SecurityType.Future, Market.CME), (time =>
1272  {
1273  var market = Market.CME;
1274  var symbol = Futures.Currencies.CHF;
1275  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1276  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters
1277  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1278  {
1279  time = time.AddMonths(1);
1280  }
1281 
1282  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1283  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1284  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1285  thirdWednesday,
1286  -2, holidays);
1287  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1288  })
1289  },
1290  // EUR (6E): http://www.cmegroup.com/trading/fx/g10/euro-fx_contract_specifications.html
1291  {Symbol.Create(Futures.Currencies.EUR, SecurityType.Future, Market.CME), (time =>
1292  {
1293  var market = Market.CME;
1294  var symbol = Futures.Currencies.EUR;
1295  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1296  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters and serial contracts listed for 3 months
1297 
1298  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1299  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1300  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1301  thirdWednesday,
1302  -2, holidays);
1303  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1304  })
1305  },
1306  // AUD (6A): http://www.cmegroup.com/trading/fx/g10/australian-dollar_contract_specifications.html
1307  {Symbol.Create(Futures.Currencies.AUD, SecurityType.Future, Market.CME), (time =>
1308  {
1309  var market = Market.CME;
1310  var symbol = Futures.Currencies.AUD;
1311  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1312  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters and serial contracts listed for 3 months
1313 
1314  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1315  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1316  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1317  thirdWednesday,
1318  -2, holidays);
1319  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1320  })
1321  },
1322  // NZD (6N): http://www.cmegroup.com/trading/fx/g10/new-zealand-dollar_contract_specifications.html
1323  {Symbol.Create(Futures.Currencies.NZD, SecurityType.Future, Market.CME), (time =>
1324  {
1325  var market = Market.CME;
1326  var symbol = Futures.Currencies.NZD;
1327  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1328  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 6 consecutive quarters
1329  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1330  {
1331  time = time.AddMonths(1);
1332  }
1333 
1334  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1335  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1336  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1337  thirdWednesday,
1338  -2, holidays);
1339  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1340  })
1341  },
1342  // RUB (6R): https://www.cmegroup.com/trading/fx/emerging-market/russian-ruble_contract_specifications.html
1343  {Symbol.Create(Futures.Currencies.RUB, SecurityType.Future, Market.CME), (time =>
1344  {
1345  var market = Market.CME;
1346  var symbol = Futures.Currencies.RUB;
1347  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1348  // Monthly contacts listed for 12 consecutive months and quarterly contracts (Mar, Jun, Sep, Dec) listed for16 additional quarters
1349  // 11:00 a.m. Mosccow time on the fifteenth day of the month, or, if not a business day, on the next business day for the Moscow interbank foreign exchange market.
1350  var fifteenth = new DateTime(time.Year, time.Month, 15);
1351 
1352  while (!FuturesExpiryUtilityFunctions.NotHoliday(fifteenth, holidays))
1353  {
1354  fifteenth = FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth, 1, holidays);
1355  }
1356  return fifteenth.Add(new TimeSpan(08,0,0));
1357  })
1358  },
1359  // BRL (6L): https://www.cmegroup.com/trading/fx/emerging-market/brazilian-real_contract_specifications.html
1360  {Symbol.Create(Futures.Currencies.BRL, SecurityType.Future, Market.CME), (time =>
1361  {
1362  var market = Market.CME;
1363  var symbol = Futures.Currencies.BRL;
1364  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1365  // Monthly contracts listed for 60 consecutive months
1366  // On the last business day of the month, at 9:15 a.m. CT, immediately preceding the contract month, on which the Central Bank of Brazil is scheduled to publish its final end-of-month (EOM), "Commercial exchange rate for Brazilian reais per U.S. dollar for cash delivery" (PTAX rate).
1367  var lastPrecedingBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(time, -1, holidays);
1368  lastPrecedingBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastPrecedingBusinessDay, -1, holidays);
1369 
1370  return lastPrecedingBusinessDay.Add(new TimeSpan(14,15,0));
1371  })
1372  },
1373  // MXN (6M): https://www.cmegroup.com/trading/fx/emerging-market/mexican-peso_contract_specifications.html
1374  {Symbol.Create(Futures.Currencies.MXN, SecurityType.Future, Market.CME), (time =>
1375  {
1376  var market = Market.CME;
1377  var symbol = Futures.Currencies.MXN;
1378  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1379  // Monthly contracts listed for 13 consecutive months and 2 additional quarterly contracts (Mar, Jun, Sep, Dec)
1380  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1381  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1382  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday,-2, holidays);
1383  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1384 
1385  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1386  })
1387  },
1388  // ZAR (6Z): https://www.cmegroup.com/trading/fx/emerging-market/south-african-rand_contract_specifications.html
1389  {Symbol.Create(Futures.Currencies.ZAR, SecurityType.Future, Market.CME), (time =>
1390  {
1391  var market = Market.CME;
1392  var symbol = Futures.Currencies.ZAR;
1393  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1394  // Monthly contracts listed for 13 consecutive months and quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 consecutive quarters
1395  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday)
1396  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1397  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1398  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1399 
1400  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1401  })
1402  },
1403  // AUD/CAD (ACD): https://www.cmegroup.com/trading/fx/g10/australian-dollar-canadian-dollar_contract_specifications.html
1405  {
1406  var market = Market.CME;
1407  var symbol = Futures.Currencies.AUDCAD;
1408  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1409  // Six months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1410  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1411  {
1412  time = time.AddMonths(1);
1413  }
1414 
1415  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday)
1416  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1417  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1418  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1419 
1420  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1421  })
1422  },
1423  // Australian Dollar/Japanese Yen (AJY): https://www.cmegroup.com/trading/fx/g10/australian-dollar-japanese-yen_contract_specifications.html
1425  {
1426  var market = Market.CME;
1427  var symbol = Futures.Currencies.AUDJPY;
1428  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1429  // Six months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1430  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1431  {
1432  time = time.AddMonths(1);
1433  }
1434 
1435  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1436  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1437  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1438  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1439 
1440  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1441  })
1442  },
1443  // Australian Dollar/New Zealand Dollar (ANE): https://www.cmegroup.com/trading/fx/g10/australian-dollar-new-zealand-dollar_contract_specifications.html
1445  {
1446  var market = Market.CME;
1447  var symbol = Futures.Currencies.AUDNZD;
1448  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1449  // Six months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1450  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1451  {
1452  time = time.AddMonths(1);
1453  }
1454 
1455  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1456  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1457  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1458  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1459 
1460  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1461  })
1462  },
1463  // Bitcoin (BTC): https://www.cmegroup.com/trading/equity-index/us-index/bitcoin_contract_specifications.html
1464  {Symbol.Create(Futures.Currencies.BTC, SecurityType.Future, Market.CME), (time =>
1465  {
1466  var market = Market.CME;
1467  var symbol = Futures.Currencies.BTC;
1468  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1469  // Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months. If the 6 consecutive months includes Dec, list only 1 additional Dec contract month.
1470  // Trading terminates at 4:00 p.m. London time on the last Friday of the contract month. If that day is not a business day in both the U.K. and the US, trading terminates on the preceding day that is a business day for both the U.K. and the U.S..
1471  var lastFriday =FuturesExpiryUtilityFunctions.LastFriday(time);
1472  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastFriday, -1, holidays);
1473 
1474  return lastFriday.Add(new TimeSpan(15, 0, 0));
1475  })
1476  },
1477  // Ether (ETH): https://www.cmegroup.com/markets/cryptocurrencies/ether/ether.contractSpecs.html
1478  {Symbol.Create(Futures.Currencies.ETH, SecurityType.Future, Market.CME), (time =>
1479  {
1480  var market = Market.CME;
1481  var symbol = Futures.Currencies.ETH;
1482  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1483  // Monthly contracts listed for 6 consecutive months, quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 additional quarters and a second Dec contract if only one is listed.
1484  // Trading terminates at 4:00 p.m. London time on the last Friday of the contract month that is either a London or U.S. business day. If the last Friday of the contract month day is not a business day in both London and the U.S., trading terminates on the prior London or U.S. business day.
1485  var lastFriday = FuturesExpiryUtilityFunctions.LastFriday(time);
1486  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastFriday, -1, holidays);
1487 
1488  return lastFriday.Add(new TimeSpan(15, 0, 0));
1489  })
1490  },
1491  // Canadian Dollar/Japanese Yen (CJY): https://www.cmegroup.com/trading/fx/g10/canadian-dollar-japanese-yen_contract_specifications.html
1493  {
1494  var market = Market.CME;
1495  var symbol = Futures.Currencies.CADJPY;
1496  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1497  // Six months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1498  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1499  {
1500  time = time.AddMonths(1);
1501  }
1502 
1503  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1504  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1505  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1506  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1507 
1508  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1509  })
1510  },
1511  // Standard-Size USD/Offshore RMB (CNH): https://www.cmegroup.com/trading/fx/emerging-market/usd-cnh_contract_specifications.html
1513  {
1514  var market = Market.CME;
1516  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1517 
1518  // Monthly contracts listed for 13 consecutive months and quarterly contracts (Mar, Jun, Sep, Dec) listed for the next 8 quarters.
1519  // Trading terminates on the second Hong Kong business day prior to the third Wednesday of the contract month at 11:00 a.m. Hong Kong local time.
1520  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1521  var secondBusinessDayPrecedingThirdWednesday = thirdWednesday.AddDays(-2);
1522  while (holidays.Contains(secondBusinessDayPrecedingThirdWednesday) || !secondBusinessDayPrecedingThirdWednesday.IsCommonBusinessDay())
1523  {
1524  secondBusinessDayPrecedingThirdWednesday = secondBusinessDayPrecedingThirdWednesday.AddDays(-1);
1525  }
1526 
1527  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(3,0,0));
1528  })
1529  },
1530  // E-mini Euro FX (E7): https://www.cmegroup.com/trading/fx/g10/e-mini-euro-fx_contract_specifications.html
1532  {
1533  var market = Market.CME;
1534  var symbol = Futures.Currencies.EuroFXEmini;
1535  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1536 
1537  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
1538  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1539  {
1540  time = time.AddMonths(1);
1541  }
1542 
1543  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1544  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1545  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1546  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1547 
1548  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1549  })
1550  },
1551  // Euro/Australian Dollar (EAD): https://www.cmegroup.com/trading/fx/g10/euro-fx-australian-dollar_contract_specifications.html
1553  {
1554  var market = Market.CME;
1555  var symbol = Futures.Currencies.EURAUD;
1556  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1557 
1558  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 6 consecutive quarters
1559  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1560  {
1561  time = time.AddMonths(1);
1562  }
1563 
1564  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1565  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1566  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1567  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1568 
1569  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1570  })
1571  },
1572  // Euro/Canadian Dollar (ECD): https://www.cmegroup.com/trading/fx/g10/euro-fx-canadian-dollar_contract_specifications.html
1574  {
1575  var market = Market.CME;
1576  var symbol = Futures.Currencies.EURCAD;
1577  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1578 
1579  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 6 consecutive quarters
1580  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1581  {
1582  time = time.AddMonths(1);
1583  }
1584 
1585  // Trading terminates at 9:16 a.m. CT on the second business day prior to the third Wednesday of the contract month.
1586  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1587  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1588  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1589 
1590  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1591  })
1592  },
1593  // Euro/Swedish Krona (ESK): https://www.cmegroup.com/trading/fx/g10/euro-fx-swedish-krona_contract_specifications.html
1595  {
1596  var market = Market.CME;
1597  var symbol = Futures.Currencies.EURSEK;
1598  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1599 
1600  // Six months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1601  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1602  {
1603  time = time.AddMonths(1);
1604  }
1605 
1606  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1607  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1608  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1609  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1610 
1611  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1612  })
1613  },
1614  // E-mini Japanese Yen (J7): https://www.cmegroup.com/trading/fx/g10/e-mini-japanese-yen_contract_specifications.html
1616  {
1617  var market = Market.CME;
1618  var symbol = Futures.Currencies.JapaneseYenEmini;
1619  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1620  // Two months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1621  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1622  {
1623  time = time.AddMonths(1);
1624  }
1625 
1626  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1627  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1628  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1629  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1630 
1631  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1632  })
1633  },
1634  // Financials group
1635  // Y30TreasuryBond (ZB): http://www.cmegroup.com/trading/interest-rates/us-treasury/30-year-us-treasury-bond_contract_specifications.html
1637  {
1638  var market = Market.CBOT;
1639  var symbol = Futures.Financials.Y30TreasuryBond;
1640  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1641 
1642  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 quarters
1643  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1644  {
1645  time = time.AddMonths(1);
1646  }
1647 
1648  // Seventh business day preceding the last business day of the delivery month. Trading in expiring contracts closes at 12:01 p.m. on the last trading day.
1649  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1650  var seventhBusinessDayPrecedingLastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay,-7, holidays);
1651  return seventhBusinessDayPrecedingLastBusinessDay.Add(new TimeSpan(12,01,0));
1652  })
1653  },
1654  // Y10TreasuryNote (ZN): http://www.cmegroup.com/trading/interest-rates/us-treasury/10-year-us-treasury-note_contract_specifications.html
1656  {
1657  var market = Market.CBOT;
1658  var symbol = Futures.Financials.Y10TreasuryNote;
1659  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1660 
1661  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 consecutive quarters
1662  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1663  {
1664  time = time.AddMonths(1);
1665  }
1666 
1667  // Seventh business day preceding the last business day of the delivery month. Trading in expiring contracts closes at 12:01 p.m. on the last trading day.
1668  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1669  var seventhBusinessDayPrecedingLastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay,-7, holidays);
1670  return seventhBusinessDayPrecedingLastBusinessDay.Add(new TimeSpan(12,01,0));
1671  })
1672  },
1673  // Y5TreasuryNote (ZF): http://www.cmegroup.com/trading/interest-rates/us-treasury/5-year-us-treasury-note_contract_specifications.html
1675  {
1676  var market = Market.CBOT;
1677  var symbol = Futures.Financials.Y5TreasuryNote;
1678  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1679  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 consecutive quarters
1680  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1681  {
1682  time = time.AddMonths(1);
1683  }
1684 
1685  // Last business day of the calendar month. Trading in expiring contracts closes at 12:01 p.m. on the last trading day.
1686  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1687  return lastBusinessDay.Add(new TimeSpan(12,01,0));
1688  })
1689  },
1690  // Y2TreasuryNote (ZT): http://www.cmegroup.com/trading/interest-rates/us-treasury/2-year-us-treasury-note_contract_specifications.html
1692  {
1693  var market = Market.CBOT;
1694  var symbol = Futures.Financials.Y2TreasuryNote;
1695  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1696 
1697  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 consecutive quarters
1698  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1699  {
1700  time = time.AddMonths(1);
1701  }
1702 
1703  // Last business day of the calendar month. Trading in expiring contracts closes at 12:01 p.m. on the last trading day.
1704  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1705  return lastBusinessDay.Add(new TimeSpan(12,01,0));
1706  })
1707  },
1708  // Eurodollar (GE): https://www.cmegroup.com/trading/interest-rates/stir/eurodollar_contract_specifications.html
1710  {
1711  var market = Market.CME;
1712  var symbol = Futures.Financials.EuroDollar;
1713  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1714 
1715  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 40 consecutive quarters and the nearest 4 serial contract months.
1716  // List a new quarterly contract for trading on the last trading day of the nearby expiry.
1717 
1718  // Termination of trading:
1719  // Second London bank business day before 3rd Wednesday of the contract month. Trading
1720  // in expiring contracts terminates at 11:00 a.m. London time on the last trading day.
1721 
1723  .Add(TimeSpan.FromHours(11));
1724  })
1725  },
1726  // 5-Year USD MAC Swap (F1U): https://www.cmegroup.com/trading/interest-rates/swap-futures/5-year-usd-mac-swap_contract_specifications.html
1728  {
1729  var market = Market.CBOT;
1730  var symbol = Futures.Financials.FiveYearUSDMACSwap;
1731 
1732  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
1733  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1734  {
1735  time = time.AddMonths(1);
1736  }
1737 
1738  // Second London business day before 3rd Wednesday of futures Delivery Month. Trading in expiring contracts closes at 2:00 p.m. on the last trading day.
1739  var secondBusinessDayBeforeThirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time).AddDays(-2);
1740  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1741 
1742  // Because we're using a London calendar, we need to put entries in MHDB and not use `USHolidays.Dates`
1743  while (holidays.Contains(secondBusinessDayBeforeThirdWednesday) || !secondBusinessDayBeforeThirdWednesday.IsCommonBusinessDay())
1744  {
1745  secondBusinessDayBeforeThirdWednesday = secondBusinessDayBeforeThirdWednesday.AddDays(-1);
1746  }
1747 
1748  return secondBusinessDayBeforeThirdWednesday.Add(new TimeSpan(19, 0, 0));
1749  })
1750  },
1751  // Ultra U.S. Treasury Bond (UB): https://www.cmegroup.com/trading/interest-rates/us-treasury/ultra-t-bond_contract_specifications.html
1753  {
1754  var market = Market.CBOT;
1755  var symbol = Futures.Financials.UltraUSTreasuryBond;
1756  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1757 
1758  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 consecutive quarters
1759  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1760  {
1761  time = time.AddMonths(1);
1762  }
1763 
1764  // Seventh business day preceding the last business day of the delivery month. Trading in expiring contracts closes at 12:01 p.m. on the last trading day.
1765  var sevenBusinessDaysBeforeLastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 8, holidays);
1766 
1767  return sevenBusinessDaysBeforeLastBusinessDay.Add(new TimeSpan(12, 1, 0));
1768  })
1769  },
1770  // Ultra 10-Year U.S. Treasury Note (TN): https://www.cmegroup.com/trading/interest-rates/us-treasury/ultra-10-year-us-treasury-note_contract_specifications.html
1772  {
1773  var market = Market.CBOT;
1775  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1776 
1777  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 consecutive quarters
1778  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1779  {
1780  time = time.AddMonths(1);
1781  }
1782 
1783  // Trading terminates on the 7th business day before the last business day of the contract month.
1784  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 8, holidays);
1785  })
1786  },
1787  // Energy group
1788  // Propane Non LDH Mont Belvieu (1S): https://www.cmegroup.com/trading/energy/petrochemicals/propane-non-ldh-mt-belvieu-opis-balmo-swap_contract_specifications.html
1790  {
1791  var market = Market.NYMEX;
1793  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1794 
1795  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
1796  // Trading shall cease on the last business day of the contract month (no time specified)
1797  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1798  })
1799  },
1800  // Argus Propane Far East Index BALMO (22): https://www.cmegroup.com/trading/energy/petrochemicals/argus-propane-far-east-index-balmo-swap-futures_contract_specifications.html
1802  {
1803  var market = Market.NYMEX;
1805  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1806 
1807  // Monthly BALMO contracts listed for three cconsecutive months
1808  // Trading shall cease on the last business day of the contract month. Business days are based on the Singapore Public Holiday calendar.
1809  // TODO: Might need singapore calendar
1810  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1811  })
1812  },
1813  // Mini European 3.5% Fuel Oil Barges FOB Rdam (Platts) (A0D): https://www.cmegroup.com/trading/energy/refined-products/mini-european-35pct-fuel-oil-platts-barges-fob-rdam-swap-futures_contract_specifications.html
1815  {
1816  var market = Market.NYMEX;
1818  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1819 
1820  // Monthly contracts listed for the current year and the next 4 calendar years.
1821  // Trading shall cease on the last business day of the contract month.
1822  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1823  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
1824 
1825  return lastBusinessDay;
1826  })
1827  },
1828  // Mini Singapore Fuel Oil 180 cst (Platts) (A0F): https://www.cmegroup.com/trading/energy/refined-products/mini-singapore-fuel-oil-180-cst-platts-swap-futures_contract_specifications.html
1830  {
1831  var market = Market.NYMEX;
1833  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1834 
1835  // Monthly contracts listed for the current year and the next 5 calendar years.
1836  // Trading shall cease on the last business day of the contract month.
1837  // Special case exists where the last trade occurs on US holiday, but not an exchange holiday (markets closed)
1838  // In order to fix that case, we will start from the last day of the month and go backwards checking if it's a weekday and a holiday
1839  var lastDay = new DateTime(time.Year, time.Month, DateTime.DaysInMonth(time.Year, time.Month));
1840 
1841  while (holidays.Contains(lastDay) || !lastDay.IsCommonBusinessDay())
1842  {
1843  lastDay = lastDay.AddDays(-1);
1844  }
1845 
1846  return lastDay;
1847  })
1848  },
1849  // Gulf Coast ULSD (Platts) Up-Down BALMO Futures (A1L): https://www.cmegroup.com/trading/energy/refined-products/ulsd-up-down-balmo-calendar-swap-futures_contract_specifications.html
1851  {
1852  var market = Market.NYMEX;
1854  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1855  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
1856  // Trading shall cease on the last business day of the contract month.
1857  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1858  })
1859  },
1860  // Gulf Coast Jet (Platts) Up-Down BALMO Futures (A1M): https://www.cmegroup.com/trading/energy/refined-products/jet-fuel-up-down-balmo-calendar-swap_contract_specifications.html
1862  {
1863  var market = Market.NYMEX;
1865  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1866  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
1867  // Trading shall cease on the last business day of the contract month.
1868  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1869  })
1870  },
1871  // Propane Non-LDH Mont Belvieu (OPIS) Futures (A1R): https://www.cmegroup.com/trading/energy/petrochemicals/propane-non-ldh-mt-belvieu-opis-swap_contract_specifications.html
1873  {
1874  var market = Market.NYMEX;
1876  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1877 
1878  // Monthly contracts listed for 48 consecutive months
1879  // Trading shall cease on the last business day of the contract month.
1880  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1881  })
1882  },
1883  // European Propane CIF ARA (Argus) BALMO Futures (A32): https://www.cmegroup.com/trading/energy/petrochemicals/european-propane-cif-ara-argus-balmo-swap-futures_contract_specifications.html
1885  {
1886  var market = Market.NYMEX;
1888  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1889  // Monthly BALMO contracts listed for 3 consecutive months
1890  // Trading shall cease on the last business day of the contract month.
1891  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1892  })
1893  },
1894  // Premium Unleaded Gasoline 10 ppm FOB MED (Platts) Futures (A3G): https://www.cmegroup.com/trading/energy/refined-products/premium-unleaded-10-ppm-platts-fob-med-swap_contract_specifications.html
1896  {
1897  var market = Market.NYMEX;
1899  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1900 
1901  // 48 consecutive months
1902  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1903  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
1904 
1905  return lastBusinessDay;
1906  })
1907  },
1908  // Argus Propane Far East Index Futures (A7E): https://www.cmegroup.com/trading/energy/petrochemicals/argus-propane-far-east-index-swap-futures_contract_specifications.html
1910  {
1911  var market = Market.NYMEX;
1913  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1914 
1915  // Monthly contracts listed for 48 consecutive months
1916  // Trading shall cease on the last business day of the contract month.
1917  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1918  })
1919  },
1920  // Gasoline Euro-bob Oxy NWE Barges (Argus) Crack Spread BALMO Futures (A7I): https://www.cmegroup.com/trading/energy/refined-products/gasoline-euro-bob-oxy-new-barges-crack-spread-balmo-swap-futures_contract_specifications.html
1922  {
1923  var market = Market.NYMEX;
1925  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1926 
1927  // Monthly BALMO contracts listed for 3 consecutive months
1928  // Trading ceases on the last business day of the contract month.
1929  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1930  })
1931  },
1932  // Mont Belvieu Natural Gasoline (OPIS) Futures (A7Q): https://www.cmegroup.com/trading/energy/petrochemicals/mont-belvieu-natural-gasoline-5-decimal-opis-swap_contract_specifications.html
1934  {
1935  var market = Market.NYMEX;
1937  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1938 
1939  // Monthly contracts listed for 56 consecutive months
1940  // Trading shall cease on the last business day of the contract month
1941  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1942  })
1943  },
1944  // Mont Belvieu Normal Butane (OPIS) BALMO Futures (A8J): https://www.cmegroup.com/trading/energy/petrochemicals/mont-belvieu-normal-butane-opis-balmo-swap_contract_specifications.html
1946  {
1947  var market = Market.NYMEX;
1949  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1950 
1951  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
1952  // Trading terminates on the last business day of the contract month.
1953  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1954  })
1955  },
1956  // Conway Propane (OPIS) Futures (A8K): https://www.cmegroup.com/trading/energy/petrochemicals/conway-propane-opis-swap_contract_specifications.html
1958  {
1959  var market = Market.NYMEX;
1960  var symbol = Futures.Energy.ConwayPropaneOPIS;
1961  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1962 
1963  // Monthly contracts listed for the current year and the next 4 calendar years.
1964  // Trading shall cease on the last business day of the contract month.
1965  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1966  })
1967  },
1968  // Mont Belvieu LDH Propane (OPIS) BALMO Futures (A8O): https://www.cmegroup.com/trading/energy/petrochemicals/mont-belvieu-ldh-propane-opis-balmo-swap-futures_contract_specifications.html
1970  {
1971  var market = Market.NYMEX;
1973  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1974 
1975  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
1976  // Trading shall cease on the last business day of the contract month.
1977  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1978  })
1979  },
1980  // Argus Propane Far East Index vs. European Propane CIF ARA (Argus) Futures (A91): https://www.cmegroup.com/trading/energy/petrochemicals/argus-propane-far-east-index-vs-european-propane-cif-ara-argus-swap-futures_contract_specifications.html
1982  {
1983  var market = Market.NYMEX;
1985  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1986 
1987  // Monthly contracts listed for 36 consecutive months
1988  // Trading shall cease on the last business day of the contract month.
1989  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1990  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
1991 
1992  return lastBusinessDay;
1993  })
1994  },
1995  // Argus Propane (Saudi Aramco) Futures (A9N): https://www.cmegroup.com/trading/energy/petrochemicals/argus-propane-saudi-aramco-swap-futures_contract_specifications.html
1997  {
1998  var market = Market.NYMEX;
1999  var symbol = Futures.Energy.ArgusPropaneSaudiAramco;
2000  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2001 
2002  // Monthly contracts listed for 48 consecutive months
2003  // Trading shall terminate on the last business day of the month prior to the contract month.
2004  // Business days are based on the Singapore Public Holiday Calendar.
2005  // Special case in 2021 where last traded date falls on US Holiday, but not exchange holiday
2006  var previousMonth = time.AddMonths(-1);
2007  var lastDay = new DateTime(previousMonth.Year, previousMonth.Month, DateTime.DaysInMonth(previousMonth.Year, previousMonth.Month));
2008 
2009  while (!lastDay.IsCommonBusinessDay() || holidays.Contains(lastDay))
2010  {
2011  lastDay = lastDay.AddDays(-1);
2012  }
2013 
2014  return lastDay;
2015  })
2016  },
2017  // Group Three ULSD (Platts) vs. NY Harbor ULSD Futures (AA6): https://www.cmegroup.com/trading/energy/refined-products/group-three-ultra-low-sulfur-diesel-ulsd-platts-vs-heating-oil-spread-swap_contract_specifications.html
2019  {
2020  var market = Market.NYMEX;
2022  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2023 
2024  // Trading shall cease on the last business day of the contract month.
2025  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2026  })
2027  },
2028  // Group Three Sub-octane Gasoline (Platts) vs. RBOB Futures (AA8): https://www.cmegroup.com/trading/energy/refined-products/group-three-unleaded-gasoline-platts-vs-rbob-spread-swap_contract_specifications.html
2030  {
2031  var market = Market.NYMEX;
2033  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2034 
2035  // 36 consecutive months
2036  // Trading shall cease on the last business day of the contract month
2037  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2038  })
2039  },
2040  // Singapore Fuel Oil 180 cst (Platts) BALMO Futures (ABS): https://www.cmegroup.com/trading/energy/refined-products/singapore-180cst-fuel-oil-balmo-swap_contract_specifications.html
2042  {
2043  var market = Market.NYMEX;
2045  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2046 
2047  // Monthly BALMO contracts listed for 3 consecutive months
2048  // Trading shall cease on the last business day of the contract month.
2049  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2050  })
2051  },
2052  // Singapore Fuel Oil 380 cst (Platts) BALMO Futures (ABT): https://www.cmegroup.com/trading/energy/refined-products/singapore-380cst-fuel-oil-balmo-swap_contract_specifications.html
2054  {
2055  var market = Market.NYMEX;
2057  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2058 
2059  // Monthly BALMO contracts listed for 3 consecutive months
2060  // Trading shall cease on the last business day of the contract month.
2061  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2062  })
2063  },
2064  // Mont Belvieu Ethane (OPIS) Futures (AC0): https://www.cmegroup.com/trading/energy/petrochemicals/mont-belvieu-ethane-opis-5-decimals-swap_contract_specifications.html
2066  {
2067  var market = Market.NYMEX;
2068  var symbol = Futures.Energy.MontBelvieuEthaneOPIS;
2069  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2070 
2071  // Monthly contracts listed for the current year and the next 4 calendar years.
2072  // Trading shall cease on the last business day of the contract month.
2073  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2074  })
2075  },
2076  // Mont Belvieu Normal Butane (OPIS) Futures (AD0): https://www.cmegroup.com/trading/energy/petrochemicals/mont-belvieu-normal-butane-5-decimals-swap_contract_specifications.html
2078  {
2079  var market = Market.NYMEX;
2081  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2082 
2083  // Monthly contracts listed for the current year and next 4 calendar years.
2084  // Trading shall cease on the last business day of the contract month.
2085  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2086  })
2087  },
2088  // Brent Crude Oil vs. Dubai Crude Oil (Platts) Futures (ADB): https://www.cmegroup.com/trading/energy/crude-oil/brent-dubai-swap-futures_contract_specifications.html
2090  {
2091  var market = Market.NYMEX;
2093  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2094  // Trading shall cease on the last London and Singapore business day of the contract month.
2095  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2096  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2097 
2098  return lastBusinessDay;
2099  })
2100  },
2101  // Argus LLS vs. WTI (Argus) Trade Month Futures (AE5): https://www.cmegroup.com/trading/energy/crude-oil/argus-lls-vs-wti-argus-trade-month-swap-futures_contract_specifications.html
2103  {
2104  var market = Market.NYMEX;
2106  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2107 
2108  // Trading shall cease at the close of trading on the last business day that falls on or before the 25th calendar day of the month prior to the contract month. If the 25th calendar day is a weekend or holiday, trading shall cease on the first business day prior to the 25th calendar day.
2109  var previousMonth = time.AddMonths(-1);
2110  var twentyFifthDay = new DateTime(previousMonth.Year, previousMonth.Month, 25);
2111  while (!twentyFifthDay.IsCommonBusinessDay() || holidays.Contains(twentyFifthDay))
2112  {
2113  twentyFifthDay = FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifthDay, -1, holidays);
2114  }
2115 
2116  return twentyFifthDay;
2117  })
2118  },
2119  // Singapore Gasoil (Platts) vs. Low Sulphur Gasoil (AGA): https://www.cmegroup.com/trading/energy/refined-products/gasoil-arb-singapore-gasoil-platts-vs-ice-rdam-gasoil-swap_contract_specifications.html
2121  {
2122  var market = Market.NYMEX;
2124  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2125 
2126  // Monthly contracts listed for the current year and the next 2 calendar years.
2127  // Trading ceases on the last business day of the contract month
2128  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2129  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2130 
2131  return lastBusinessDay;
2132  })
2133  },
2134  // Los Angeles CARBOB Gasoline (OPIS) vs. RBOB Gasoline (AJL): https://www.cmegroup.com/trading/energy/refined-products/los-angeles-carbob-gasoline-opis-spread-swap_contract_specifications.html
2136  {
2137  var market = Market.NYMEX;
2139  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2140 
2141  // 36 consecutive months
2142  // Trading shall cease on the last business day of the contract month
2143  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2144  })
2145  },
2146  // Los Angeles Jet (OPIS) vs. NY Harbor ULSD (AJS): https://www.cmegroup.com/trading/energy/refined-products/los-angeles-carbob-gasoline-opis-spread-swap_contract_specifications.html
2148  {
2149  var market = Market.NYMEX;
2151  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2152  // 36 consecutive months
2153  // Trading shall cease on the last business day of the contract month
2154  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2155  })
2156  },
2157  // Los Angeles CARB Diesel (OPIS) vs. NY Harbor ULSD (AKL): https://www.cmegroup.com/trading/energy/refined-products/los-angeles-carbob-diesel-opis-spread-swap_contract_specifications.html
2159  {
2160  var market = Market.NYMEX;
2162  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2163  // 3 consecutive years
2164  // Trading shall cease on the last business day of the contract month
2165  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2166  })
2167  },
2168  // European Naphtha (Platts) BALMO (AKZ): https://www.cmegroup.com/trading/energy/refined-products/european-naphtha-balmo-swap_contract_specifications.html
2170  {
2171  var market = Market.NYMEX;
2173  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2174  // Monthly BALMO contracts listed for 3 consecutive months
2175  // Trading shall cease on the last business day of the contract month
2176  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2177  })
2178  },
2179  // European Propane CIF ARA (Argus) (APS): https://www.cmegroup.com/trading/energy/petrochemicals/european-propane-cif-ara-argus-swap_contract_specifications.html
2181  {
2182  var market = Market.NYMEX;
2184  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2185  // Monthly contracts listed for the current year and the next 3 calendar years.
2186  // Trading shall cease on the last business day of the contract month
2187  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2188  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2189 
2190  return lastBusinessDay;
2191  })
2192  },
2193  // Mont Belvieu Natural Gasoline (OPIS) BALMO (AR0): https://www.cmegroup.com/trading/energy/petrochemicals/mt-belvieu-natural-gasoline-balmo-swap_contract_specifications.html
2195  {
2196  var market = Market.NYMEX;
2198  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2199  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
2200  // Trading shall cease on the last business day of the contract month
2201  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2202  })
2203  },
2204  // RBOB Gasoline Crack Spread (ARE): https://www.cmegroup.com/trading/energy/refined-products/rbob-crack-spread-swap-futures_contract_specifications.html
2206  {
2207  var market = Market.NYMEX;
2208  var symbol = Futures.Energy.RBOBGasolineCrackSpread;
2209  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2210  // The current year plus the next three calendar years
2211  // Trading shall cease on the last business day of the contract month
2212  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2213  })
2214  },
2215  // Gulf Coast HSFO (Platts) BALMO (AVZ): https://www.cmegroup.com/trading/energy/refined-products/gulf-coast-3pct-fuel-oil-balmo-swap_contract_specifications.html
2217  {
2218  var market = Market.NYMEX;
2220  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2221  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
2222  // Trading shall cease on the last business day of the contract month
2223  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2224  })
2225  },
2226  // Mars (Argus) vs. WTI Trade Month (AYV): https://www.cmegroup.com/trading/energy/crude-oil/mars-crude-oil-argus-vs-wti-trade-month-spread-swap-futures_contract_specifications.html
2228  {
2229  var market = Market.NYMEX;
2231  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2232  // Monthly contracts listed for the current year and the next 5 calendar years.
2233  // Trading shall cease at the close of trading on the last business day that falls on or before the 25th calendar day of the
2234  // month prior to the contract month. If the 25th calendar day is a weekend or holiday, trading shall cease on the
2235  // first business day prior to the 25th calendar day.
2236  var twentyFifthDayPriorMonth = new DateTime(time.Year, time.Month, 25).AddMonths(-1);
2237  while (!FuturesExpiryUtilityFunctions.NotHoliday(twentyFifthDayPriorMonth, holidays) || holidays.Contains(twentyFifthDayPriorMonth))
2238  {
2239  twentyFifthDayPriorMonth = FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifthDayPriorMonth, -1, holidays);
2240  }
2241 
2242  return twentyFifthDayPriorMonth;
2243  })
2244  },
2245  // Mars (Argus) vs. WTI Financial (AYX): https://www.cmegroup.com/trading/energy/crude-oil/mars-crude-oil-argus-vs-wti-calendar-spread-swap-futures_contract_specifications.html
2247  {
2248  var market = Market.NYMEX;
2249  var symbol = Futures.Energy.MarsArgusVsWTIFinancial;
2250  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2251  // The current year and the next five (5) consecutive calendar years.
2252  // Trading shall cease on the last business day of the contract month
2253  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2254  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2255 
2256  return lastBusinessDay;
2257  })
2258  },
2259  // Ethanol T2 FOB Rdam Including Duty (Platts) (AZ1): https://www.cmegroup.com/trading/energy/ethanol/ethanol-platts-t2-fob-rotterdam-including-duty-swap-futures_contract_specifications.html
2261  {
2262  var market = Market.NYMEX;
2264  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2265  // Monthly contracts listed for 36 consecutive months
2266  // Trading terminates on the last business day of the contract month
2267  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2268  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2269 
2270  return lastBusinessDay;
2271  })
2272  },
2273  // Mont Belvieu LDH Propane (OPIS) (B0): https://www.cmegroup.com/trading/energy/petrochemicals/mont-belvieu-propane-5-decimals-swap_contract_specifications.html
2275  {
2276  var market = Market.NYMEX;
2278  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2279  // Monthly contracts listed for the current year and the next 4 calendar years.
2280  // Trading shall cease on the last business day of the contract month
2281  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2282  })
2283  },
2284  // Gasoline Euro-bob Oxy NWE Barges (Argus) (B7H): https://www.cmegroup.com/trading/energy/refined-products/gasoline-euro-bob-oxy-new-barges-swap-futures_contract_specifications.html
2286  {
2287  var market = Market.NYMEX;
2289  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2290  // Monthly contracts listed for 36 consecutive months
2291  // Trading shall cease on the last business day of the contract month
2292  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2293  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2294 
2295  return lastBusinessDay;
2296  })
2297  },
2298  // WTI-Brent Financial (BK): https://www.cmegroup.com/trading/energy/crude-oil/wti-brent-ice-calendar-swap-futures_contract_specifications.html
2300  {
2301  var market = Market.NYMEX;
2302  var symbol = Futures.Energy.WTIBrentFinancial;
2303  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2304  // Monthly contracts listed for the current year and the next 8 calendar years.
2305  // Trading shall cease on the last business day of the contract month
2306  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2307  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2308 
2309  return lastBusinessDay;
2310  })
2311  },
2312  // 3.5% Fuel Oil Barges FOB Rdam (Platts) Crack Spread (1000mt) (BOO): https://www.cmegroup.com/trading/energy/refined-products/35pct-fuel-oil-platts-barges-fob-rdam-crack-spread-1000mt-swap-futures_contract_specifications.html
2314  {
2315  var market = Market.NYMEX;
2317  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2318  // Monthly contracts listed for the current year and the next 4 calendar years.
2319  // Trading shall cease on the last business day of the contract month
2320  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2321  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2322 
2323  return lastBusinessDay;
2324  })
2325  },
2326  // Gasoline Euro-bob Oxy NWE Barges (Argus) BALMO (BR7): https://www.cmegroup.com/trading/energy/refined-products/gasoline-euro-bob-oxy-new-barges-balmo-swap-futures_contract_specifications.html
2328  {
2329  var market = Market.NYMEX;
2331  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2332  // Monthly BALMO contracts listed for 3 consecutive months
2333  // Trading shall cease on the last business day of the contract month
2334  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2335  })
2336  },
2337  // Brent Last Day Financial (BZ): https://www.cmegroup.com/trading/energy/crude-oil/brent-crude-oil-last-day_contract_specifications.html
2339  {
2340  var market = Market.NYMEX;
2341  var symbol = Futures.Energy.BrentLastDayFinancial;
2342  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2343  // Monthly contracts listed for the current year and the next 7 calendar years and 3 additional contract months.
2344  // Trading terminates the last London business day of the month, 2 months prior to the contract month except for the February contract month which terminates the 2nd last London business day of the month, 2 months prior to the contract month.
2345  var twoMonthsPriorToContractMonth = time.AddMonths(-2);
2346 
2347  DateTime lastBusinessDay;
2348 
2349  if (twoMonthsPriorToContractMonth.Month == 2)
2350  {
2351  lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(twoMonthsPriorToContractMonth, 1, holidays);
2352  }
2353  else
2354  {
2355  lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(twoMonthsPriorToContractMonth, 1, holidays);
2356  }
2357 
2358  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2359 
2360  return lastBusinessDay;
2361  })
2362  },
2363  // CrudeOilWTI (CL): http://www.cmegroup.com/trading/energy/crude-oil/light-sweet-crude_contract_specifications.html
2365  {
2366  var market = Market.NYMEX;
2367  var symbol = Futures.Energy.CrudeOilWTI;
2368  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2369  // Monthly contracts listed for the current year and the next 10 calendar years and 2 additional contract months.
2370  // Trading in the current delivery month shall cease on the third business day prior to the twenty-fifth calendar day of the month preceding the delivery month. If the twenty-fifth calendar day of the month is a non-business day, trading shall cease on the third business day prior to the last business day preceding the twenty-fifth calendar day. In the event that the official Exchange holiday schedule changes subsequent to the listing of a Crude Oil futures, the originally listed expiration date shall remain in effect.In the event that the originally listed expiration day is declared a holiday, expiration will move to the business day immediately prior.
2371  var twentyFifth = new DateTime(time.Year,time.Month,25);
2372  twentyFifth = twentyFifth.AddMonths(-1);
2373 
2374  var businessDays = -3;
2375  if(!FuturesExpiryUtilityFunctions.NotHoliday(twentyFifth, holidays))
2376  {
2377  // if the 25th is a holiday we substract 1 extra bussiness day
2378  businessDays -= 1;
2379  }
2380  return FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifth, businessDays, holidays);
2381  })
2382  },
2383  // Gulf Coast CBOB Gasoline A2 (Platts) vs. RBOB Gasoline (CRB): https://www.cmegroup.com/trading/energy/refined-products/gulf-coast-cbob-gasoline-a2-platts-vs-rbob-spread-swap_contract_specifications.html
2385  {
2386  var market = Market.NYMEX;
2388  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2389  // 36 consecutive months
2390  // Trading shall cease on the last business day of the contract month.
2391  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2392  })
2393  },
2394  // Clearbrook Bakken Sweet Crude Oil Monthly Index (Net Energy) (CSW): https://www.cmegroup.com/trading/energy/crude-oil/clearbrook-bakken-crude-oil-index-net-energy_contract_specifications.html
2396  {
2397  // Monthly contracts listed for the current year and the next 3 calendar years.
2398  // Trading terminates one Canadian business day prior to the Notice of Shipments (NOS) date on the Enbridge Pipeline. The NOS date occurs on or about the 20th calendar day of the month, subject to confirmation by Enbridge Pipeline. The official schedule for the NOS dates will be made publicly available by Enbridge.
2399  // This report is behind a portal that requires registration (privately). As such, we cannot access the notice of shipment dates, but we can keep track
2400  // of the CME group's website in order to discover the NOS dates
2401  // Publication dates are also erratic. We must maintain a separate list from MHDB in order to keep track of these days
2402  DateTime publicationDate;
2403 
2404  if (!EnbridgeNoticeOfShipmentDates.TryGetValue(time, out publicationDate))
2405  {
2406  publicationDate = new DateTime(time.Year, time.Month, 21).AddMonths(-1);
2407  }
2408  do
2409  {
2410  publicationDate = publicationDate.AddDays(-1);
2411  }
2412  while (!publicationDate.IsCommonBusinessDay());
2413 
2414  return publicationDate;
2415  })
2416  },
2417  // WTI Financial (CSX): https://www.cmegroup.com/trading/energy/crude-oil/west-texas-intermediate-wti-crude-oil-calendar-swap-futures_contract_specifications.html
2419  {
2420  var market = Market.NYMEX;
2421  var symbol = Futures.Energy.WTIFinancial;
2422  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2423  // Monthly contracts listed for the current year and the next 8 calendar years.
2424  // Trading shall cease on the last business day of the contract month
2425  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2426  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2427 
2428  return lastBusinessDay;
2429  })
2430  },
2431  // Chicago Ethanol (Platts) (CU): https://www.cmegroup.com/trading/energy/ethanol/chicago-ethanol-platts-swap_contract_specifications.html a
2433  {
2434  var market = Market.NYMEX;
2435  var symbol = Futures.Energy.ChicagoEthanolPlatts;
2436  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2437  // Monthly contracts listed for 36 consecutive months
2438  // Trading terminates on the last business day of the contract month
2439  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2440  })
2441  },
2442  // Singapore Mogas 92 Unleaded (Platts) Brent Crack Spread (D1N): https://www.cmegroup.com/trading/energy/refined-products/singapore-mogas-92-unleaded-platts-brent-crack-spread-swap-futures_contract_specifications.html
2444  {
2445  var market = Market.NYMEX;
2447  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2448  // Monthly contracts listed for the current year and the next calendar year.
2449  // Trading shall cease on the last business day of the contract month
2450  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2451  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2452 
2453  return lastBusinessDay;
2454  })
2455  },
2456  // Dubai Crude Oil (Platts) Financial (DCB): https://www.cmegroup.com/trading/energy/crude-oil/dubai-crude-oil-calendar-swap-futures_contract_specifications.html
2458  {
2459  var market = Market.NYMEX;
2461  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2462  // Monthly contracts listed for the current year and the next five calendar years.
2463  // Trading shall cease on the last London and Singapore business day of the contract month
2464  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2465  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2466 
2467  return lastBusinessDay;
2468  })
2469  },
2470  // Japan C&amp;F Naphtha (Platts) BALMO (E6): https://www.cmegroup.com/trading/energy/refined-products/japan-naphtha-balmo-swap-futures_contract_specifications.html
2472  {
2473  var market = Market.NYMEX;
2475  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2476  // Monthly BALMO contracts listed for 3 consecutive months
2477  // Trading shall cease on the last business day of the contract month.
2478  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2479  })
2480  },
2481  // Ethanol (EH): https://www.cmegroup.com/trading/energy/ethanol/cbot-ethanol_contract_specifications.html
2482  {Symbol.Create(Futures.Energy.Ethanol, SecurityType.Future, Market.CBOT), (time =>
2483  {
2484  var market = Market.CBOT;
2485  var symbol = Futures.Energy.Ethanol;
2486  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2487  // Monthly contracts listed for 36 consecutive months
2488  // Trading terminates on 3rd business day of the contract month in "ctm"
2489 
2490  return FuturesExpiryUtilityFunctions.NthBusinessDay(time, 3, holidays);
2491  })
2492  },
2493  // European Naphtha (Platts) Crack Spread (EN): https://www.cmegroup.com/trading/energy/refined-products/european-naphtha-crack-spread-swap_contract_specifications.html
2495  {
2496  // Monthly contracts listed for the current year and the next 3 calendar years
2497  // Trading ceases on the last business day of the contract month.
2498  var market = Market.NYMEX;
2500  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2501  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2502 
2503  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2504  {
2505  lastBusinessDay = lastBusinessDay.AddDays(-1);
2506  }
2507 
2508  return lastBusinessDay;
2509  })
2510  },
2511  // European Propane CIF ARA (Argus) vs. Naphtha Cargoes CIF NWE (Platts) (EPN): https://www.cmegroup.com/trading/energy/refined-products/european-propane-cif-ara-argus-vs-naphtha-cif-nwe-platts-swap_contract_specifications.html
2513  {
2514  // Monthly contracts listed for the current year and the next 3 calendar years.
2515  // Trading shall cease on the last business day of the contract month.
2516  var market = Market.NYMEX;
2518  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2519  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2520 
2521  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2522  {
2523  lastBusinessDay = lastBusinessDay.AddDays(-1);
2524  }
2525 
2526  return lastBusinessDay;
2527  })
2528  },
2529  // Singapore Fuel Oil 380 cst (Platts) vs. European 3.5% Fuel Oil Barges FOB Rdam (Platts) (EVC): https://www.cmegroup.com/trading/energy/refined-products/singapore-fuel-oil-380-cst-platts-vs-european-35-fuel-oil-barges-fob-rdam-platts_contract_specifications.html
2531  {
2532  var market = Market.NYMEX;
2534  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2535  // Monthly contracts listed for the current year and the next 5 calendar years.
2536  // Trading terminates on the last business day of the contract month.
2537  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2538 
2539  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2540  {
2541  lastBusinessDay = lastBusinessDay.AddDays(-1);
2542  }
2543 
2544  return lastBusinessDay;
2545  })
2546  },
2547  // East-West Gasoline Spread (Platts-Argus) (EWG): https://www.cmegroup.com/trading/energy/refined-products/east-west-gasoline-spread-platts-argus-swap-futures_contract_specifications.html
2549  {
2550  var market = Market.NYMEX;
2552  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2553  // Monthly contracts listed for 12 consecutive months
2554  // Trading shall cease on the last business day of the contract month.
2555  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2556  })
2557  },
2558  // East-West Naphtha: Japan C&amp;F vs. Cargoes CIF NWE Spread (Platts) (EWN): https://www.cmegroup.com/trading/energy/refined-products/east-west-naphtha-japan-cf-vs-cargoes-cif-nwe-spread-platts-swap-futures_contract_specifications.html
2560  {
2561  // Monthly contracts listed for 36 consecutive months
2562  // Trading terminates on the last business day of the contract month.
2563  var market = Market.NYMEX;
2565  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2566  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2567 
2568  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2569  {
2570  lastBusinessDay = lastBusinessDay.AddDays(-1);
2571  }
2572 
2573  return lastBusinessDay;
2574  })
2575  },
2576  // RBOB Gasoline vs. Euro-bob Oxy NWE Barges (Argus) (350,000 gallons) (EXR): https://www.cmegroup.com/trading/energy/refined-products/rbob-gasoline-vs-euro-bob-oxy-argus-nwe-barges-1000mt-swap-futures_contract_specifications.html
2578  {
2579  var market = Market.NYMEX;
2581  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2582  // Monthly contracts listed for 36 consecutive months
2583  // Trading shall cease on the last business day of the contract month.
2584  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2585  })
2586  },
2587  // 3.5% Fuel Oil Barges FOB Rdam (Platts) Crack Spread Futures (FO): https://www.cmegroup.com/trading/energy/refined-products/northwest-europe-nwe-35pct-fuel-oil-rottderdam-crack-spread-swap_contract_specifications.html
2589  {
2590  var market = Market.NYMEX;
2592  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2593  // Monthly contracts listed for the current year and the next 4 calendar years.
2594  // Trading ceases on the last business day of the contract month.
2595  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2596 
2597  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2598  {
2599  lastBusinessDay = lastBusinessDay.AddDays(-1);
2600  }
2601 
2602  return lastBusinessDay;
2603  })
2604  },
2605  // Freight Route TC14 (Baltic) (FRC): https://www.cmegroup.com/trading/energy/freight/freight-route-tc14-baltic-futures_contract_specifications.html
2607  {
2608  var market = Market.NYMEX;
2609  var symbol = Futures.Energy.FreightRouteTC14Baltic;
2610  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2611  // Monthly contracts listed for the current year and the next 5 consecutive years.
2612  // Trading terminates on the last business day of the contract month
2613  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2614 
2615  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2616  {
2617  lastBusinessDay = lastBusinessDay.AddDays(-1);
2618  }
2619 
2620  return lastBusinessDay;
2621  })
2622  },
2623  // 1% Fuel Oil Cargoes FOB NWE (Platts) vs. 3.5% Fuel Oil Barges FOB Rdam (Platts) (FSS): https://www.cmegroup.com/trading/energy/refined-products/fuel-oil-diff-1pct-nwe-cargoes-vs-35pct-barges-swap_contract_specifications.html
2625  {
2626  // Monthly contracts listed for 52 consecutive months
2627  // Trading ceases on the last business day of the contract month.
2628  var market = Market.NYMEX;
2630  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2631  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2632 
2633  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2634  {
2635  lastBusinessDay = lastBusinessDay.AddDays(-1);
2636  }
2637 
2638  return lastBusinessDay;
2639  })
2640  },
2641  // Gulf Coast HSFO (Platts) vs. European 3.5% Fuel Oil Barges FOB Rdam (Platts) (GCU): https://www.cmegroup.com/trading/energy/refined-products/gulf-coast-no6-fuel-oil-3pct-vs-european-3point5pct-fuel-oil-barges-fob-rdam-platts-swap-futures_contract_specifications.html
2643  {
2644  var market = Market.NYMEX;
2646  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2647  // Monthly contracts listed for 36 consecutive months
2648  // Trading shall cease on the last business day of the contract month.
2649  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2650 
2651  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2652  {
2653  lastBusinessDay = lastBusinessDay.AddDays(-1);
2654  }
2655 
2656  return lastBusinessDay;
2657  })
2658  },
2659  // WTI Houston Crude Oil (HCL): https://www.cmegroup.com/trading/energy/crude-oil/wti-houston-crude-oil_contract_specifications.html
2661  {
2662  var market = Market.NYMEX;
2663  var symbol = Futures.Energy.WTIHoustonCrudeOil;
2664  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2665  // Monthly contracts listed through and including Dec-21
2666  // Trading terminates 3 business days prior to the twenty-fifth calendar day of the month prior to the contract month. If the twenty-fifth calendar day is not a business day, trading terminates 3 business days prior to the business day preceding the twenty-fifth calendar day of the month prior to the contract month.
2667  var twentyFifthDayInPriorMonth = new DateTime(time.Year, time.Month, 25).AddMonths(-1);
2668  var i = 0;
2669 
2670  while (i < 3 || !twentyFifthDayInPriorMonth.IsCommonBusinessDay() || holidays.Contains(twentyFifthDayInPriorMonth))
2671  {
2672  if (twentyFifthDayInPriorMonth.IsCommonBusinessDay() &&
2673  !holidays.Contains(twentyFifthDayInPriorMonth))
2674  {
2675  i++;
2676  }
2677  twentyFifthDayInPriorMonth = twentyFifthDayInPriorMonth.AddDays(-1);
2678  }
2679 
2680  return twentyFifthDayInPriorMonth;
2681  })
2682  },
2683  // Natural Gas (Henry Hub) Last-day Financial (HH): https://www.cmegroup.com/trading/energy/natural-gas/natural-gas-last-day_contract_specifications.html
2685  {
2686  var market = Market.NYMEX;
2688  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2689  // Monthly contracts listed for the current year and the next 12 calendar years.
2690  // Trading terminates on the third last business day of the month prior to the contract month.
2691  var previousMonth = time.AddMonths(-1);
2692  previousMonth = new DateTime(previousMonth.Year, previousMonth.Month, DateTime.DaysInMonth(previousMonth.Year, previousMonth.Month));
2693 
2694  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(previousMonth, 3, holidays);
2695  })
2696  },
2697  // HeatingOil (HO): http://www.cmegroup.com/trading/energy/refined-products/heating-oil_contract_specifications.html
2699  {
2700  var market = Market.NYMEX;
2701  var symbol = Futures.Energy.HeatingOil;
2702  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2703  // Monthly contracts listed for the current year and the next 3 calendar years and 1 additional month.
2704  // Trading in a current month shall cease on the last business day of the month preceding the delivery month.
2705  var precedingMonth = time.AddMonths(-1);
2706  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(precedingMonth, 1, holidays);
2707  })
2708  },
2709  // Natural Gas (Henry Hub) Penultimate Financial (HP): https://www.cmegroup.com/trading/energy/natural-gas/natural-gas-penultimate_contract_specifications.html
2711  {
2712  var market = Market.NYMEX;
2714  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2715  // Monthly contracts listed for the current year and the next 5 calendar years.
2716  // Trading terminates on the 4th last business day of the month prior to the contract month.
2717  var previousMonth = time.AddMonths(-1);
2718 
2719  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(previousMonth, 4, holidays);
2720  })
2721  },
2722  // WTI Houston (Argus) vs. WTI Trade Month (HTT): https://www.cmegroup.com/trading/energy/crude-oil/wti-houston-argus-vs-wti-trade-month_contract_specifications.html
2724  {
2725  var market = Market.NYMEX;
2727  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2728  // Monthly contracts listed for the current year and the next 3 calendar years.
2729  // Trading terminates on the last business day that falls on or before the 25th calendar day of the month prior to the contract month. If the 25th calendar day is a weekend or holiday, trading shall cease on the first business day prior to the 25th calendar day.
2730  var twentyFifthPreviousMonth = new DateTime(time.Year, time.Month, 25).AddMonths(-1);
2731  while (holidays.Contains(twentyFifthPreviousMonth) || !FuturesExpiryUtilityFunctions.NotHoliday(twentyFifthPreviousMonth, holidays))
2732  {
2733  twentyFifthPreviousMonth = FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifthPreviousMonth, -1, holidays);
2734  }
2735 
2736  return twentyFifthPreviousMonth;
2737  })
2738  },
2739  // Gasoline (RB): http://www.cmegroup.com/trading/energy/refined-products/rbob-gasoline_contract_specifications.html
2741  {
2742  var market = Market.NYMEX;
2743  var symbol = Futures.Energy.Gasoline;
2744  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2745  // Monthly contracts listed for the current year and the next 3 calendar years and 1 additional month.
2746  // Trading in a current delivery month shall cease on the last business day of the month preceding the delivery month.
2747  var precedingMonth = time.AddMonths(-1);
2748  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(precedingMonth, 1, holidays);
2749  })
2750  },
2751  // Natural Gas (NG) : http://www.cmegroup.com/trading/energy/natural-gas/natural-gas_contract_specifications.html
2753  {
2754  var market = Market.NYMEX;
2755  var symbol = Futures.Energy.NaturalGas;
2756  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2757  // Monthly contracts listed for the current year and the next 12 calendar years.
2758  //Trading of any delivery month shall cease three (3) business days prior to the first day of the delivery month. In the event that the official Exchange holiday schedule changes subsequent to the listing of a Natural Gas futures, the originally listed expiration date shall remain in effect.In the event that the originally listed expiration day is declared a holiday, expiration will move to the business day immediately prior.
2759  var firstDay = new DateTime(time.Year,time.Month,1);
2760  return FuturesExpiryUtilityFunctions.AddBusinessDays(firstDay, -3, holidays);
2761  })
2762  },
2763  // Brent Crude (B) : https://www.theice.com/products/219/Brent-Crude-Futures
2765  {
2766  var market = Market.ICE;
2767  var symbol = Futures.Energy.BrentCrude;
2768  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2769  // Up to 96 consecutive months
2770  //Trading shall cease at the end of the designated settlement period on the last Business Day of the second month
2771  //preceding the relevant contract month (e.g. the March contract month will expire on the last Business Day of January).
2772  //If the day on which trading is due to cease would be either: (i) the Business Day preceding Christmas Day, or
2773  //(ii) the Business Day preceding New Year’s Day, then trading shall cease on the next preceding Business Day
2774  var secondPrecedingMonth = time.AddMonths(-2);
2775  var nthLastBusinessDay = secondPrecedingMonth.Month == 12 ? 2 : 1;
2776  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(secondPrecedingMonth, nthLastBusinessDay, holidays);
2777  })
2778  },
2779  // Low Sulphur Gasoil Futures (G): https://www.theice.com/products/34361119/Low-Sulphur-Gasoil-Futures
2781  {
2782  var market = Market.ICE;
2783  var symbol = Futures.Energy.LowSulfurGasoil;
2784  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2785  // Up to 96 consecutive months
2786  //Trading shall cease at 12:00 hours London Time, 2 business days prior to the 14th calendar day of the delivery month.
2787  var fourteenthDay = new DateTime(time.Year,time.Month,14);
2788  var twelfthDay = FuturesExpiryUtilityFunctions.AddBusinessDays(fourteenthDay, -2, holidays);
2789  return twelfthDay.Add(new TimeSpan(12,0,0));
2790  })
2791  },
2792  // Meats group
2793  // LiveCattle (LE): http://www.cmegroup.com/trading/agricultural/livestock/live-cattle_contract_specifications.html
2795  {
2796  var market = Market.CME;
2797  var symbol = Futures.Meats.LiveCattle;
2798  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2799  // Monthly contracts of (Feb, Apr, Jun, Aug, Oct, Dec) listed for 9 months
2800  while (!FutureExpirationCycles.GJMQVZ.Contains(time.Month))
2801  {
2802  time = time.AddMonths(1);
2803  }
2804 
2805  //Last business day of the contract month, 12:00 p.m.
2806  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2807  return lastBusinessDay.Add(new TimeSpan(12,0,0));
2808  })
2809  },
2810  // LeanHogs (HE): http://www.cmegroup.com/trading/agricultural/livestock/lean-hogs_contract_specifications.html
2811  {Symbol.Create(Futures.Meats.LeanHogs, SecurityType.Future, Market.CME), (time =>
2812  {
2813  var market = Market.CME;
2814  var symbol = Futures.Meats.LeanHogs;
2815  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2816  /*
2817  2 monthly contracts of:
2818  Feb listed in August
2819  Apr listed in October
2820  May listed in December
2821  Jun listed in December
2822  Jul listed in February
2823  Aug listed in April
2824  Oct listed in May
2825  Dec listed in June
2826  */
2827  while (!FutureExpirationCycles.GJKMNQVZ.Contains(time.Month))
2828  {
2829  time = time.AddMonths(1);
2830  }
2831 
2832  // 10th business day of the contract month, 12:00 p.m.
2833  var lastday = new DateTime(time.Year,time.Month,1);
2834  lastday = lastday.AddDays(-1);
2835  var tenthday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastday, 10, holidays);
2836  return tenthday.Add(new TimeSpan(12,0,0));
2837  })
2838  },
2839  // FeederCattle (GF): http://www.cmegroup.com/trading/agricultural/livestock/feeder-cattle_contract_specifications.html
2841  {
2842  var market = Market.CME;
2843  var symbol = Futures.Meats.FeederCattle;
2844  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2845  // Monthly contracts of (Jan, Mar, Apr, May, Aug, Sep, Oct, Nov) listed for 8 months
2846  while (!FutureExpirationCycles.FHJKQUVX.Contains(time.Month))
2847  {
2848  time = time.AddMonths(1);
2849  }
2850 
2851  /* Trading shall terminate on the last Thursday of the contract month, except:
2852  * 1. The November contract shall terminate on the Thursday
2853  * prior to Thanksgiving Day, unless a holiday falls on
2854  * that Thursday or on any of the four weekdays prior to
2855  * that Thursday, in which case trading shall terminate on
2856  * the first prior Thursday that is not a holiday and is
2857  * not so preceded by a holiday. Weekdays shall be defined
2858  * as Monday, Tuesday, Wednesday, Thursday and Friday.
2859  * 2. Any contract month in which a holiday falls on the last
2860  * Thursday of the month or on any of the four weekdays
2861  * prior to that Thursday shall terminate on the first
2862  * prior Thursday that is not a holiday and is not so
2863  * preceded by a holiday.*/
2864  var daysInMonth = DateTime.DaysInMonth(time.Year, time.Month);
2865  // Checking condition 1
2866  if(time.Month == 11)
2867  {
2868  var priorThursday = (from day in Enumerable.Range(1, daysInMonth)
2869  where new DateTime(time.Year, time.Month, day).DayOfWeek == DayOfWeek.Thursday
2870  select new DateTime(time.Year, time.Month, day)).Reverse().ElementAt(1);
2871  while (!FuturesExpiryUtilityFunctions.NotHoliday(priorThursday, holidays) || !FuturesExpiryUtilityFunctions.NotPrecededByHoliday(priorThursday, holidays))
2872  {
2873  priorThursday = priorThursday.AddDays(-7);
2874  }
2875  return priorThursday;
2876  }
2877  // Checking Condition 2
2878  var lastThursday = (from day in Enumerable.Range(1, daysInMonth)
2879  where new DateTime(time.Year, time.Month, day).DayOfWeek == DayOfWeek.Thursday
2880  select new DateTime(time.Year, time.Month, day)).Reverse().ElementAt(0);
2881  while (!FuturesExpiryUtilityFunctions.NotHoliday(lastThursday, holidays) || !FuturesExpiryUtilityFunctions.NotPrecededByHoliday(lastThursday, holidays))
2882  {
2883  lastThursday = lastThursday.AddDays(-7);
2884  }
2885  return lastThursday;
2886  })
2887  },
2888  // Softs group
2889  // Cotton #2 (CT): https://www.theice.com/products/254/Cotton-No-2-Futures
2890  {Symbol.Create(Futures.Softs.Cotton2, SecurityType.Future, Market.ICE), (time =>
2891  {
2892  var market = Market.ICE;
2893  var symbol = Futures.Softs.Cotton2;
2894  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2895  // March, May, July, October, December
2896  while (!FutureExpirationCycles.HKNVZ.Contains(time.Month))
2897  {
2898  time = time.AddMonths(1);
2899  }
2900 
2901  // Last Trading Day:
2902  // Seventeen business days from end of spot month.
2903 
2904  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 17, holidays);
2905  })
2906  },
2907  // Orange Juice (OJ): https://www.theice.com/products/30/FCOJ-A-Futures
2909  {
2910  var market = Market.ICE;
2911  var symbol = Futures.Softs.OrangeJuice;
2912  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2913 
2914  // January, March, May, July, September, November.
2915  while (!FutureExpirationCycles.FHKNUX.Contains(time.Month))
2916  {
2917  time = time.AddMonths(1);
2918  }
2919 
2920  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 15, holidays);
2921  })
2922  },
2923  // Coffee (KC): https://www.theice.com/products/15/Coffee-C-Futures
2924  {Symbol.Create(Futures.Softs.Coffee, SecurityType.Future, Market.ICE), (time =>
2925  {
2926  var market = Market.ICE;
2927  var symbol = Futures.Softs.Coffee;
2928  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2929  // March, May, July, September, December.
2930  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
2931  {
2932  time = time.AddMonths(1);
2933  }
2934 
2935  // Last Trading Day:
2936  // One business day prior to last notice day
2937  //
2938  // Last Notice Day:
2939  // Seven business days prior to the last business day off the delivery month
2940 
2941  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 9, holidays);
2942  })
2943  },
2944  // Sugar #11 ICE (SB): https://www.theice.com/products/23/Sugar-No-11-Futures
2945  {Symbol.Create(Futures.Softs.Sugar11, SecurityType.Future, Market.ICE), (time =>
2946  {
2947  var market = Market.ICE;
2948  var symbol = Futures.Softs.Sugar11;
2949  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2950  // March, May, July and October
2951  while (!FutureExpirationCycles.HKNV.Contains(time.Month))
2952  {
2953  time = time.AddMonths(1);
2954  }
2955 
2956  // Last Trading Day:
2957  // Last business day of the month preceding the delivery month
2958 
2959  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time.AddMonths(-1), 1, holidays);
2960  })
2961  },
2962  // Sugar #11 CME (YO): https://www.cmegroup.com/trading/agricultural/softs/sugar-no11_contract_specifications.html
2964  {
2965  var market = Market.NYMEX;
2966  var symbol = Futures.Softs.Sugar11CME;
2967  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2968  // Trading is conducted in the March, May, July, and October cycle for the next 24 months.
2969  while (!FutureExpirationCycles.HKNV.Contains(time.Month))
2970  {
2971  time = time.AddMonths(1);
2972  }
2973 
2974  // Trading terminates on the day immediately preceding the first notice day of the corresponding trading month of Sugar No. 11 futures at ICE Futures U.S.
2975  var precedingMonth = time.AddMonths(-1);
2976  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(precedingMonth, 1, holidays);
2977  })
2978  },
2979  // Cocoa (CC): https://www.theice.com/products/7/Cocoa-Futures
2980  {Symbol.Create(Futures.Softs.Cocoa, SecurityType.Future, Market.ICE), (time =>
2981  {
2982  var market = Market.ICE;
2983  var symbol = Futures.Softs.Cocoa;
2984  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2985  // March, May, July, September, December
2986  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
2987  {
2988  time = time.AddMonths(1);
2989  }
2990 
2991  // Last Trading Day:
2992  // One business day prior to last notice day
2993  //
2994  // Last Notice Day:
2995  // Ten business days prior to last business day of delivery month
2996 
2997  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 12, holidays);
2998  })
2999  },
3000  // Dairy Group
3001  // Cash-settled Butter (CB): https://www.cmegroup.com/trading/agricultural/dairy/cash-settled-butter_contract_specifications.html
3003  {
3004  var market = Market.CME;
3005  var symbol = Futures.Dairy.CashSettledButter;
3006  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3007  // Monthly contracts listed for 24 consecutive months
3008  // Trading shall terminate on the business day immediately preceding the day on which the USDA announces the Butter price for that contract month. (LTD 12:10 p.m.)
3009  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
3010  })
3011  },
3012  // Cash-Settled Cheese (CSC): https://www.cmegroup.com/trading/agricultural/dairy/cheese_contract_specifications.html
3014  {
3015  var market = Market.CME;
3016  var symbol = Futures.Dairy.CashSettledCheese;
3017  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3018  // Monthly contracts listed for 24 consecutive months
3019  // Trading shall terminate on the business day immediately preceding the release date for the USDA monthly weighted average price in the U.S. for cheese. LTD close is at 12:10 p.m. Central Time
3020  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
3021  })
3022  },
3023  // Class III Milk (DC): https://www.cmegroup.com/trading/agricultural/dairy/class-iii-milk_contract_specifications.html
3025  {
3026  var market = Market.CME;
3027  var symbol = Futures.Dairy.ClassIIIMilk;
3028  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3029  // Monthly contracts listed for 24 consecutive months
3030  // Trading shall terminate on the business day immediately preceding the day on which the USDA announces the Class III price for that contract month (LTD 12:10 p.m.)
3031  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
3032  })
3033  },
3034  // Dry Whey (DY): https://www.cmegroup.com/trading/agricultural/dairy/dry-whey_contract_specifications.html
3035  {Symbol.Create(Futures.Dairy.DryWhey, SecurityType.Future, Market.CME), (time =>
3036  {
3037  var market = Market.CME;
3038  var symbol = Futures.Dairy.DryWhey;
3039  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3040  // Monthly contracts listed for 24 consecutive months
3041  // Trading shall terminate on the business day immediately preceding the day on which the USDA announces the Dry Whey price for that contract month. (LTD 12:10 p.m.)
3042  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
3043  })
3044  },
3045  // Class IV Milk (GDK): https://www.cmegroup.com/trading/agricultural/dairy/class-iv-milk_contract_specifications.html
3047  {
3048  var market = Market.CME;
3049  var symbol = Futures.Dairy.ClassIVMilk;
3050  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3051  // Monthly contracts listed for 24 consecutive months
3052  // Trading shall terminate on the business day immediately preceding the day on which the USDA announces the Class IV price for that contract month. (LTD 12:10 p.m.)
3053  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
3054  })
3055  },
3056  // Non-fat Dry Milk (GNF): https://www.cmegroup.com/trading/agricultural/dairy/nonfat-dry-milk_contract_specifications.html
3058  {
3059  var market = Market.CME;
3060  var symbol = Futures.Dairy.NonfatDryMilk;
3061  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3062  // Monthly contracts listed for 24 consecutive months
3063  // Trading shall terminate on the business day immediately preceding the day on which the USDA announces the Nonfat Dry Milk price for that contract month. (LTD 12:10 p.m.)
3064  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
3065  })
3066  },
3067  // Micro Gold Futures (MGC): https://www.cmegroup.com/markets/metals/precious/e-micro-gold.contractSpecs.html
3069  {
3070  var market = Market.COMEX;
3071  var symbol = Futures.Metals.MicroGold;
3072  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3073  // Four bi-monthly contracts (Feb/2, Apr/4, Jun/6, Aug/8, Oct/10, Dec/12 cycle)
3074  while (!FutureExpirationCycles.GJMQVZ.Contains(time.Month))
3075  {
3076  time = time.AddMonths(1);
3077  }
3078 
3079  // Monthly contracts
3080  // Trading terminates on the third last business day of the contract month.
3081  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3082  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3083 
3084  return lastBusinessDay;
3085  })
3086  },
3087  // Micro Silver Futures (SIL): https://www.cmegroup.com/markets/metals/precious/1000-oz-silver.contractSpecs.html
3089  {
3090  var market = Market.COMEX;
3091  var symbol = Futures.Metals.MicroSilver;
3092  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3093  // Monthly contracts
3094  // Trading terminates on the third last business day of the contract month.
3095  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3096  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3097 
3098  return lastBusinessDay;
3099  })
3100  },
3101  // Micro Gold TAS Futures (MGT): https://www.cmegroup.com/markets/metals/precious/e-micro-gold.contractSpecs.html
3103  {
3104  var market = Market.COMEX;
3105  var symbol = Futures.Metals.MicroGoldTAS;
3106  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3107  // Monthly contracts
3108  // Trading terminates on the third last business day of the contract month.
3109  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3110  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3111 
3112  return lastBusinessDay;
3113  })
3114  },
3115  // Micro Palladium Futures (PAM): https://www.cmegroup.com/markets/metals/precious/e-micro-palladium.contractSpecs.html
3117  {
3118  var market = Market.NYMEX;
3119  var symbol = Futures.Metals.MicroPalladium;
3120  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3121  // Monthly contracts
3122  // Trading terminates on the third last business day of the contract month.
3123  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3124  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3125 
3126  return lastBusinessDay;
3127  })
3128  },
3129  // Mini Sized NY Gold Futures: https://www.theice.com/products/31500921/Mini-Gold-Future & https://www.theice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_2022_TRADING_HOLIDAY_CALENDAR_20211118.pdf
3131  {
3132  var market = Market.NYSELIFFE;
3133  var symbol = Futures.Metals.MiniNYGold;
3134  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3135  // Trading terminates on the third last business day of the contract month @13:30
3136 
3137  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3138 
3139  return lastBusinessDay.Add(new TimeSpan(13, 30, 0));
3140  })
3141  },
3142  // Mini Sized NY Silver Futures: https://www.theice.com/products/31500921/Mini-Silver-Future & https://www.theice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_2022_TRADING_HOLIDAY_CALENDAR_20211118.pdf
3144  {
3145  var market = Market.NYSELIFFE;
3146  var symbol = Futures.Metals.MiniNYSilver;
3147  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3148  // Trading terminates on the third last business day of the contract month @13:25
3149 
3150  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3151 
3152  return lastBusinessDay.Add(new TimeSpan(13, 25, 0));
3153  })
3154  },
3155  // Gold 100 Oz Futures: https://www.theice.com/products/31499002/100-oz-Gold-Future & https://www.theice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_2022_TRADING_HOLIDAY_CALENDAR_20211118.pdf
3157  {
3158  var market = Market.NYSELIFFE;
3159  var symbol = Futures.Metals.Gold100Oz;
3160  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3161  // Trading terminates on the third last business day of the contract month @13:30
3162 
3163  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3164 
3165  return lastBusinessDay.Add(new TimeSpan(13, 30, 0));
3166  })
3167  },
3168  // Silver 5000 Oz Futures: https://www.theice.com/products/31500922/5000-oz-Silver-Future & https://www.theice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_2022_TRADING_HOLIDAY_CALENDAR_20211118.pdf
3170  {
3171  var market = Market.NYSELIFFE;
3172  var symbol = Futures.Metals.Silver5000Oz;
3173  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3174  // Trading terminates on the third last business day of the contract month @13:25
3175 
3176  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3177 
3178  return lastBusinessDay.Add(new TimeSpan(13, 25, 0));
3179  })
3180  },
3181  // Micro 10-Year Yield Futures (10Y): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-10-year-yield.contractSpecs.html
3183  {
3184  var market = Market.CBOT;
3186  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3187  // Monthly contracts
3188  // Trading terminates on the last business day of the contract month.
3189  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3190  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3191 
3192  return lastBusinessDay;
3193  })
3194  },
3195  // Micro 30-Year Yield Futures (30Y): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-30-year-yield_contract_specifications.html
3197  {
3198  var market = Market.CBOT;
3200  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3201  // Monthly contracts
3202  // Trading terminates on the last business day of the contract month.
3203  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3204  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3205 
3206  return lastBusinessDay;
3207  })
3208  },
3209  // Micro 2-Year Yield Futures (2YY): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-2-year-yield.contractSpecs.html
3211  {
3212  var market = Market.CBOT;
3213  var symbol = Futures.Financials.MicroY2TreasuryBond;
3214  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3215  // Monthly contracts
3216  // Trading terminates on the last business day of the contract month.
3217  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3218  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3219 
3220  return lastBusinessDay;
3221  })
3222  },
3223  // Micro 5-Year Yield Futures (5YY): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-5-year-yield.contractSpecs.html
3225  {
3226  var market = Market.CBOT;
3227  var symbol = Futures.Financials.MicroY5TreasuryBond;
3228  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3229  // Monthly contracts
3230  // Trading terminates on the last business day of the contract month.
3231  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3232  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3233 
3234  return lastBusinessDay;
3235  })
3236  },
3237  // Micro EUR/USD Futures (M6E): https://www.cmegroup.com/markets/fx/g10/e-micro-euro.contractSpecs.html
3239  {
3240  var market = Market.CME;
3241  var symbol = Futures.Currencies.MicroEUR;
3242  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3243  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3244  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3245  {
3246  time = time.AddMonths(1);
3247  }
3248 
3249  // Trading terminates at 9:16 a.m. CT 2 business day prior to the 3rd Wednesday of the contract quqrter.
3250  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3251  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3252  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3253 
3254  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3255  })
3256  },
3257  // Micro AUD/USD Futures (M6A): https://www.cmegroup.com/markets/fx/g10/e-micro-australian-dollar.contractSpecs.html
3259  {
3260  var market = Market.CME;
3261  var symbol = Futures.Currencies.MicroAUD;
3262  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3263  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3264  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3265  {
3266  time = time.AddMonths(1);
3267  }
3268 
3269  // On the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
3270  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3271  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3272  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3273 
3274  return secondBusinessDayPrecedingThirdWednesday;
3275  })
3276  },
3277  // Micro GBP/USD Futures (M6B): https://www.cmegroup.com/markets/fx/g10/e-micro-british-pound.contractSpecs.html
3279  {
3280  var market = Market.CME;
3281  var symbol = Futures.Currencies.MicroGBP;
3282  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3283  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3284  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3285  {
3286  time = time.AddMonths(1);
3287  }
3288 
3289  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
3290  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3291  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3292  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3293 
3294  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3295  })
3296  },
3297  // Micro CAD/USD Futures (MCD): https://www.cmegroup.com/markets/fx/g10/e-micro-canadian-dollar-us-dollar.contractSpecs.html
3299  {
3300  var market = Market.CME;
3301  var symbol = Futures.Currencies.MicroCADUSD;
3302  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3303  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3304  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3305  {
3306  time = time.AddMonths(1);
3307  }
3308 
3309  // Trading terminates 1 business day prior to the 3rd Wednesday of the contract quarter.
3310  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3311  var firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -1, holidays);
3312  firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(firstBusinessDayPrecedingThirdWednesday, -1, holidays);
3313 
3314  return firstBusinessDayPrecedingThirdWednesday;
3315  })
3316  },
3317  // Micro JPY/USD Futures (MJY): https://www.cmegroup.com/markets/fx/g10/e-micro-japanese-yen-us-dollar.contractSpecs.html
3319  {
3320  var market = Market.CME;
3321  var symbol = Futures.Currencies.MicroJPY;
3322  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3323  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3324  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3325  {
3326  time = time.AddMonths(1);
3327  }
3328 
3329  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
3330  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3331  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3332  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3333 
3334  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3335  })
3336  },
3337  // Micro CHF/USD Futures (MSF): https://www.cmegroup.com/markets/fx/g10/e-micro-swiss-franc-us-dollar.contractSpecs.html
3339  {
3340  var market = Market.CME;
3341  var symbol = Futures.Currencies.MicroCHF;
3342  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3343  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3344  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3345  {
3346  time = time.AddMonths(1);
3347  }
3348 
3349  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
3350  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3351  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3352  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3353 
3354  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3355  })
3356  },
3357  // Micro USD/JPY Futures (M6J): https://www.cmegroup.com/markets/fx/g10/micro-usd-jpy.contractSpecs.html
3359  {
3360  var market = Market.CME;
3361  var symbol = Futures.Currencies.MicroUSDJPY;
3362  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3363  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3364  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3365  {
3366  time = time.AddMonths(1);
3367  }
3368 
3369  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
3370  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3371  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3372  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3373 
3374  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3375  })
3376  },
3377  // Micro INR/USD Futures (MIR): https://www.cmegroup.com/markets/fx/g10/e-micro-indian-rupee.contractSpecs.html
3379  {
3380  var market = Market.CME;
3381  var symbol = Futures.Currencies.MicroINRUSD;
3382  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3383  // Monthly contracts listed for 12 consecutive months.
3384 
3385  // Trading terminates at 12:00 noon Mumbai time two Indian business days immediately preceding the last Indian
3386  // business day of the contract month.
3387 
3388  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3389  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3390 
3391  var secondBusinessDayPrecedingLastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay,-2, holidays);
3392  return secondBusinessDayPrecedingLastBusinessDay.Add(new TimeSpan(6,30,0));
3393  })
3394  },
3395  // Micro USD/CAD Futures (M6C): https://www.cmegroup.com/markets/fx/g10/micro-usd-cad.contractSpecs.html
3397  {
3398  var market = Market.CME;
3399  var symbol = Futures.Currencies.MicroCAD;
3400  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3401  // Two months in the March quarterly cycle (Mar, Jun, Sep, Dec)
3402  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3403  {
3404  time = time.AddMonths(1);
3405  }
3406 
3407  // Trading terminates at 9:16 a.m. CT, 1 business day prior to the third Wednesday of the contract month.
3408  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3409  var firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -1, holidays);
3410  firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(firstBusinessDayPrecedingThirdWednesday, -1, holidays);
3411 
3412  return firstBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3413  })
3414  },
3415  // Micro USD/CHF Futures (M6S): https://www.cmegroup.com/markets/fx/g10/micro-usd-chf.contractSpecs.html
3417  {
3418  var market = Market.CME;
3419  var symbol = Futures.Currencies.MicroUSDCHF;
3420  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3421  // Two months in the March quarterly cycle (Mar, Jun, Sep, Dec)
3422  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3423  {
3424  time = time.AddMonths(1);
3425  }
3426 
3427  // Trading terminates at 9:16 a.m. CT, 2 business days prior to the third Wednesday of the contract month.
3428  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3429  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3430  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3431 
3432  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3433  })
3434  },
3435  // Micro USD/CNH Futures (MNH): https://www.cmegroup.com/markets/fx/g10/e-micro-cnh.contractSpecs.html
3437  {
3438  var market = Market.CME;
3439  var symbol = Futures.Currencies.MicroUSDCNH;
3440  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3441  // Monthly contracts listed for 12 consecutive months.
3442 
3443  // Trading terminates at 11:00 a.m. Hong Kong time on the second Hong Kong business day prior
3444  // to the third Wednesday of the contract month.
3445 
3446  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3447  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday,-2, holidays);
3448  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(3,0,0));
3449  })
3450  },
3451  // Micro E-mini S&P 500 Index Futures (MES): https://www.cmegroup.com/markets/equities/sp/micro-e-mini-sandp-500.contractSpecs.html
3453  {
3454  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
3455  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3456  {
3457  time = time.AddMonths(1);
3458  }
3459 
3460  // Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
3461  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
3462  return thirdFriday.Add(new TimeSpan(13,30,0));
3463  })
3464  },
3465  // Micro E-mini Nasdaq-100 Index Futures (MNQ): https://www.cmegroup.com/markets/equities/nasdaq/micro-e-mini-nasdaq-100.contractSpecs.html
3467  {
3468  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
3469  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3470  {
3471  time = time.AddMonths(1);
3472  }
3473 
3474  // Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
3475  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
3476  return thirdFriday.Add(new TimeSpan(13,30,0));
3477  })
3478  },
3479  // Micro E-mini Russell 2000 Index Futures (M2K): https://www.cmegroup.com/markets/equities/russell/micro-e-mini-russell-2000.contractSpecs.html
3481  {
3482  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
3483  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3484  {
3485  time = time.AddMonths(1);
3486  }
3487 
3488  // Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
3489  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
3490  return thirdFriday.Add(new TimeSpan(13,30,0));
3491  })
3492  },
3493  // Micro E-mini Dow Jones Industrial Average Index Futures (MYM): https://www.cmegroup.com/markets/equities/dow-jones/micro-e-mini-dow.contractSpecs.html
3495  {
3496  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 consecutive quarters
3497  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3498  {
3499  time = time.AddMonths(1);
3500  }
3501 
3502  // Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
3503  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
3504  return thirdFriday.Add(new TimeSpan(13,30,0));
3505  })
3506  },
3507  // Micro WTI Crude Oil Futures (MCL): https://www.cmegroup.com/markets/energy/crude-oil/micro-wti-crude-oil.contractSpecs.html
3509  {
3510  var market = Market.NYMEX;
3511  var symbol = Futures.Energy.MicroCrudeOilWTI;
3512  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3513  // Monthly contracts listed for 12 consecutive months and additional Jun and Dec contract months
3514 
3515  // Trading terminates 4 business days prior to the 25th calendar day of the month prior to the
3516  // contract month (1 business day prior to CL LTD)
3517  // If the 25th calendar day is not a business day, trading terminates 5 business days before the 25th calendar day of the month prior to the contract month.
3518 
3519  var previousMonth = time.AddMonths(-1);
3520  var twentyFifthDay = new DateTime(previousMonth.Year, previousMonth.Month, 25);
3521 
3522  var businessDays = -4;
3523  if(!FuturesExpiryUtilityFunctions.NotHoliday(twentyFifthDay, holidays))
3524  {
3525  // if the 25th is a holiday we substract 1 extra bussiness day
3526  businessDays -= 1;
3527  }
3528  return FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifthDay, businessDays, holidays);
3529  })
3530  },
3531  // Micro Singapore FOB Marine Fuel 0.5% (Platts) Futures (S50): https://www.cmegroup.com/markets/energy/refined-products/micro-singapore-fob-marine-fuel-05-platts.contractSpecs.html
3533  {
3534  var market = Market.NYMEX;
3536  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3537  // Monthly contracts listed for the current year and next 3 calendar years
3538  // Add monthly contracts for a new calendar year following the termination of trading in the
3539  // December contract of the current year.
3540 
3541  // Trading terminates on the last business day of the contract month.
3542  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3543  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3544 
3545  return lastBusinessDay;
3546  })
3547  },
3548  // Micro Gasoil 0.1% Barges FOB ARA (Platts) Futures (M1B): https://www.cmegroup.com/markets/energy/refined-products/micro-gasoil-01-barges-fob-rdam-platts.contractSpecs.html
3550  {
3551  var market = Market.NYMEX;
3553  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3554  // Monthly contracts listed for 36 consecutive months
3555 
3556  // Trading terminates on the last London business day of the contract month.
3557  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3558  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3559 
3560  return lastBusinessDay;
3561  })
3562  },
3563  // Micro European FOB Rdam Marine Fuel 0.5% Barges (Platts) Futures (R50): https://www.cmegroup.com/markets/energy/refined-products/micro-european-fob-rdam-marine-fuel-05-barges-platts.contractSpecs.html
3565  {
3566  var market = Market.NYMEX;
3568  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3569  // Monthly contracts listed for the current year and next 3 calendar years.
3570  // Add monthly contracts for a new calendar year following the termination of trading
3571  // in the December contract of the current year.
3572 
3573  // Trading terminates on the last London business day of the contract month.
3574  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3575  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3576 
3577  return lastBusinessDay;
3578  })
3579  },
3580  // Micro European 3.5% Fuel Oil Barges FOB Rdam (Platts) Futures (MEF): https://www.cmegroup.com/markets/energy/refined-products/micro-european-35-fuel-oil-barges-fob-rdam-platts.contractSpecs.html
3582  {
3583  var market = Market.NYMEX;
3585  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3586  // Monthly contracts listed for the current year and 5 calendar years.Monthly contracts for a new calendar
3587  // year will be added following the termination of trading in the December contract of the current year.
3588 
3589  // Trading terminates on the last business day of the contract month.
3590  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3591  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3592 
3593  return lastBusinessDay;
3594  })
3595  },
3596  // Micro Singapore Fuel Oil 380CST (Platts) Futures (MAF): https://www.cmegroup.com/markets/energy/refined-products/micro-singapore-fuel-oil-380cst-platts.contractSpecs.html
3598  {
3599  var market = Market.NYMEX;
3601  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3602  // Monthly contracts listed for the current year and 5 calendar years.Monthly contracts for a new calendar
3603  // year will be added following the termination of trading in the December contract of the current year.
3604 
3605  // Trading terminates on the last business day of the contract month.
3606  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3607  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3608 
3609  return lastBusinessDay;
3610  })
3611  },
3612  // Micro Coal (API 5) fob Newcastle (Argus/McCloskey) Futures (M5F): https://www.cmegroup.com/markets/energy/coal/micro-coal-api-5-fob-newcastle-argus-mccloskey.contractSpecs.html
3614  {
3615  var market = Market.NYMEX;
3617  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3618  // Monthly contracts listed for the current year and the next calendar year. Monthly contracts
3619  // for a new calendar year will be added following the termination of trading in the December
3620  // contract of the current year.
3621 
3622  // Trading terminates on the last Friday of the contract month. If such Friday is a UK holiday,
3623  // trading terminates on the UK business day immediately prior to the last Friday of the contract
3624  // month unless such day is not an Exchange business day, in which case trading terminates on the
3625  // Exchange business day immediately prior.
3626 
3627  var lastFriday = FuturesExpiryUtilityFunctions.LastFriday(time);
3628 
3629  while (holidays.Contains(lastFriday))
3630  {
3631  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastFriday, -1, holidays);
3632  while (holidays.Contains(lastFriday))
3633  {
3634  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastFriday, -1, holidays);
3635  }
3636  }
3637 
3638  return lastFriday;
3639  })
3640  },
3641  // Micro European 3.5% Fuel Oil Cargoes FOB Med (Platts) Futures (M35): https://www.cmegroup.com/markets/energy/refined-products/micro-european-35-fuel-oil-cargoes-fob-med-platts.contractSpecs.html
3643  {
3644  var market = Market.NYMEX;
3646  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3647  // Monthly contracts listed for 36 consecutive months
3648 
3649  // Trading terminates on the last business day of the contract month.
3650  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3651  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3652 
3653  return lastBusinessDay;
3654  })
3655  },
3656  // Micro Ether Futures (MET): https://www.cmegroup.com/markets/cryptocurrencies/ether/micro-ether.contractSpecs.html
3658  {
3659  var market = Market.CME;
3660  var symbol = Futures.Currencies.MicroEther;
3661  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3662  // Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months.
3663 
3664  // Trading terminates at 4:00 p.m. London time on the last Friday of the contract month that
3665  // is either a London or U.S. business day. If the last Friday of the contract month day is
3666  // not a business day in both London and the U.S., trading terminates on the prior London or
3667  // U.S. business day.
3668 
3669  // BTIC: Trading terminates at 4:00 p.m. London time on the last Thursday of the contract month
3670  // that is either a London or U.S. business day. If the last Thursday of the contract month day
3671  // is not a business day in both London and the U.S., trading terminates on the prior London or U.S.
3672  // business day.
3673 
3674  var lastFriday = FuturesExpiryUtilityFunctions.LastFriday(time);
3675  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastFriday, -1, holidays);
3676 
3677  return lastFriday.Add(new TimeSpan(15, 0, 0));
3678  })
3679  },
3680  // Micro Bitcoin Futures (MBT): https://www.cmegroup.com/markets/cryptocurrencies/bitcoin/micro-bitcoin.contractSpecs.html
3682  {
3683  var market = Market.CME;
3684  var symbol = Futures.Currencies.MicroBTC;
3685  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3686  // Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months.
3687  // If the 6 consecutive months includes Dec, list only 1 additional Dec contract month.
3688 
3689  // Trading terminates at 4:00 p.m. London time on the last Friday of the contract month.
3690  // If this is not both a London and U.S. business day, trading terminates on the prior
3691  // London and the U.S. business day.
3692 
3693  // BTIC: Trading terminates at 4:00 p.m. London time on the last Thursday of the contract
3694  // month.If this is not both a London and U.S. business day, trading terminates on the prior
3695  // London and the U.S. business day.
3696 
3697  var lastFriday = FuturesExpiryUtilityFunctions.LastFriday(time);
3698  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastFriday, -1, holidays);
3699 
3700  return lastFriday.Add(new TimeSpan(15, 0, 0));
3701  })
3702  },
3703  // BTIC on Micro Ether Futures (MRB): https://www.cmegroup.com/markets/cryptocurrencies/ether/micro-ether.contractSpecs.html
3705  {
3706  // Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months.
3707 
3708  // Trading terminates at 4:00 p.m. London time on the last Friday of the contract month.
3709  // If this is not both a London and U.S. business day, trading terminates on the prior
3710  // London and the U.S. business day.
3711 
3712  // BTIC: Trading terminates at 4:00 p.m. London time on the last Thursday of the contract
3713  // month.If this is not both a London and U.S. business day, trading terminates on the prior
3714  // London and the U.S. business day.
3715 
3716  var lastThursday = FuturesExpiryUtilityFunctions.LastThursday(time);
3717 
3718  var holidays = MarketHoursDatabase.FromDataFolder()
3720  .ExchangeHours
3721  .Holidays;
3722 
3723  while (holidays.Contains(lastThursday))
3724  {
3725  lastThursday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastThursday, -1, holidays);
3726  }
3727 
3728  return lastThursday.Add(new TimeSpan(15, 0, 0));
3729  })
3730  },
3731  // BTIC on Micro Bitcoin Futures (MIB): https://www.cmegroup.com/markets/cryptocurrencies/bitcoin/micro-bitcoin.contractSpecs.html
3733  {
3734  // Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months.
3735  // If the 6 consecutive months includes Dec, list only 1 additional Dec contract month.
3736 
3737  // Trading terminates at 4:00 p.m. London time on the last Friday of the contract month.
3738  // If this is not both a London and U.S. business day, trading terminates on the prior
3739  // London and the U.S. business day.
3740 
3741  // BTIC: Trading terminates at 4:00 p.m. London time on the last Thursday of the contract
3742  // month.If this is not both a London and U.S. business day, trading terminates on the prior
3743  // London and the U.S. business day.
3744 
3745  var lastThursday = FuturesExpiryUtilityFunctions.LastThursday(time);
3746 
3747  var holidays = MarketHoursDatabase.FromDataFolder()
3749  .ExchangeHours
3750  .Holidays;
3751 
3752  while (holidays.Contains(lastThursday))
3753  {
3754  lastThursday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastThursday, -1, holidays);
3755  }
3756 
3757  return lastThursday.Add(new TimeSpan(15, 0, 0));
3758  })
3759  }
3760  };
3761  }
3762 }