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  // NASDAQ100EMini (NQ): http://www.cmegroup.com/trading/equity-index/us-index/e-mini-nasdaq-100_contract_specifications.html
358  {
359  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
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  // Dow30EMini (YM): http://www.cmegroup.com/trading/equity-index/us-index/e-mini-dow_contract_specifications.html
372  {
373  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 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  // Russell2000EMini (RTY): https://www.cmegroup.com/trading/equity-index/us-index/e-mini-russell-2000_contract_specifications.html
386  {
387  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 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  // Nikkei225Dollar (NKD): https://www.cmegroup.com/trading/equity-index/international-index/nikkei-225-dollar_contract_specifications.html
400  {
401  var market = Market.CME;
402  var symbol = Futures.Indices.Nikkei225Dollar;
403  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
404  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 12 quarters, and 3 additional Dec contract months
405  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
406  {
407  time = time.AddMonths(1);
408  }
409 
410  // Trading terminates at 5:00 p.m. Eastern Time (ET) on Business Day prior to 2nd Friday of the contract month.
411  var secondFriday = FuturesExpiryUtilityFunctions.SecondFriday(time);
412  var priorBusinessDay = secondFriday.AddDays(-1);
413  while (!FuturesExpiryUtilityFunctions.NotHoliday(priorBusinessDay, holidays))
414  {
415  priorBusinessDay = priorBusinessDay.AddDays(-1);
416  }
417  return priorBusinessDay.Add(TimeSpan.FromHours(21));
418  })
419  },
420  // Nikkei225YenCME (NIY): https://www.cmegroup.com/markets/equities/international-indices/nikkei-225-yen.contractSpecs.html
422  {
423  var market = Market.CME;
424  var symbol = Futures.Indices.Nikkei225YenCME;
425  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
426  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 12 quarters, serial contract listed for 3 months, and 3 additional Dec contract months
427  // Trading terminates at 5:00 p.m. Eastern Time (ET) on Business Day prior to 2nd Friday of the contract month.
428  var secondFriday = FuturesExpiryUtilityFunctions.SecondFriday(time);
429  var priorBusinessDay = secondFriday.AddDays(-1);
430  while (!FuturesExpiryUtilityFunctions.NotHoliday(priorBusinessDay, holidays))
431  {
432  priorBusinessDay = priorBusinessDay.AddDays(-1);
433  }
434  return priorBusinessDay.Add(TimeSpan.FromHours(21));
435  })
436  },
437  // Nikkei225YenEMini (ENY): https://www.cmegroup.com/markets/equities/international-indices/emini-nikkei-225-yen.contractSpecs.html
439  {
440  var market = Market.CME;
441  var symbol = Futures.Indices.Nikkei225YenEMini;
442  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
443  // Four months in the March Quarterly Cycle (Mar, Jun, Sep, Dec)
444  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
445  {
446  time = time.AddMonths(1);
447  }
448 
449  // Trading terminates at 5:00 p.m. Eastern Time (ET) on Business Day prior to 2nd Friday of the contract month.
450  var secondFriday = FuturesExpiryUtilityFunctions.SecondFriday(time);
451  var priorBusinessDay = secondFriday.AddDays(-1);
452  while (!FuturesExpiryUtilityFunctions.NotHoliday(priorBusinessDay, holidays))
453  {
454  priorBusinessDay = priorBusinessDay.AddDays(-1);
455  }
456  return priorBusinessDay.Add(TimeSpan.FromHours(21));
457  })
458  },
459  // FTSEChina50EMini (FT5): https://www.cmegroup.com/markets/equities/international-indices/e-mini-ftse-china-50-index.contractSpecs.html
461  {
462  var market = Market.CME;
463  var symbol = Futures.Indices.FTSEChina50EMini;
464  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
465  //Contracts listed for the 2 nearest serial and 4 quarterly months.
466  //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
467  var secondLastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time,2, holidays);
468 
469  while (!FuturesExpiryUtilityFunctions.NotHoliday(secondLastBusinessDay, holidays))
470  {
471  secondLastBusinessDay = secondLastBusinessDay.AddDays(-1);
472  }
473  return secondLastBusinessDay.Add(TimeSpan.FromHours(6));
474  })
475  },
476  // FTSE100EMini (FT1): https://www.cmegroup.com/markets/equities/international-indices/e-mini-ftse-100-index.contractSpecs.html
478  {
479  var market = Market.CME;
480  var symbol = Futures.Indices.FTSE100EMini;
481  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
482  //Contracts listed for five months in the March Quarterly Cycle (Mar, Jun, Sep, Dec)
483  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
484  {
485  time = time.AddMonths(1);
486  }
487 
488  //Trading terminates on the third Friday of the contract month
489  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
490 
491  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
492  {
493  thirdFriday = thirdFriday.AddDays(-1);
494  }
495  return thirdFriday;
496  })
497  },
498  // SPEurop350ESGEMini (E3G): https://www.cmegroup.com/markets/equities/international-indices/e-mini-sp-europe-350-esg-index.contractSpecs.html
500  {
501  var market = Market.CME;
502  var symbol = Futures.Indices.SPEurop350ESGEMini;
503  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
504  //Contracts listed for 5 months in the March Quarterly Cycle (Mar, Jun, Sep, Dec)
505  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
506  {
507  time = time.AddMonths(1);
508  }
509 
510  //Trading terminates on the 3rd Friday of contract delivery month.
511  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
512 
513  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
514  {
515  thirdFriday = thirdFriday.AddDays(-1);
516  }
517  return thirdFriday;
518  })
519  },
520  // FTSE100USDEMini (FTU): https://www.cmegroup.com/markets/equities/international-indices/e-mini-sp-europe-350-esg-index.contractSpecs.html
522  {
523  var market = Market.CME;
524  var symbol = Futures.Indices.FTSE100USDEMini;
525  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
526  //Contracts listed for five months in the March Quarterly Cycle (Mar, Jun, Sep, Dec)
527  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
528  {
529  time = time.AddMonths(1);
530  }
531 
532  //Trading terminates on the third Friday of the contract month.
533  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
534 
535  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
536  {
537  thirdFriday = thirdFriday.AddDays(-1);
538  }
539  return thirdFriday;
540  })
541  },
542  // TOPIXUSD (TPD): https://www.cmegroup.com/markets/equities/international-indices/usd-denominated-topix-index.contractSpecs.html
544  {
545  var market = Market.CME;
546  var symbol = Futures.Indices.TOPIXUSD;
547  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
548  //Quarterly Contracts listed for (Mar, Jun, Sep, Dec) for 5 months
549  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
550  {
551  time = time.AddMonths(1);
552  }
553 
554  //Trading terminates at 5:00 p.m. ET on the Thursday prior to the second Friday of the contract month.
555  var secondFriday = FuturesExpiryUtilityFunctions.NthFriday(time,2);
556  var thursdaypriorsecondFriday = secondFriday.AddDays(-1);
557 
558  while (!FuturesExpiryUtilityFunctions.NotHoliday(thursdaypriorsecondFriday, holidays))
559  {
560  thursdaypriorsecondFriday = thursdaypriorsecondFriday.AddDays(-1);
561  }
562  return thursdaypriorsecondFriday.Add(TimeSpan.FromHours(21));
563  })
564  },
565  // TOPIXYEN (TPY): https://www.cmegroup.com/markets/equities/international-indices/usd-denominated-topix-index.contractSpecs.html
567  {
568  var market = Market.CME;
569  var symbol = Futures.Indices.TOPIXYEN;
570  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
571  //Quarterly Contracts listed for (Mar, Jun, Sep, Dec) for 5 months
572  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
573  {
574  time = time.AddMonths(1);
575  }
576 
577  //Trading terminates at 5:00 p.m. ET on the Thursday prior to the second Friday of the contract month.
578  var secondFriday = FuturesExpiryUtilityFunctions.NthFriday(time,2);
579  var thursdaypriorsecondFriday = secondFriday.AddDays(-1);
580 
581  while (!FuturesExpiryUtilityFunctions.NotHoliday(thursdaypriorsecondFriday, holidays))
582  {
583  thursdaypriorsecondFriday = thursdaypriorsecondFriday.AddDays(-1);
584  }
585  return thursdaypriorsecondFriday.Add(TimeSpan.FromHours(21));
586  })
587  },
588  // DowJonesRealEstate (RX): https://www.cmegroup.com/markets/equities/dow-jones/dow-jones-rei.contractSpecs.html
590  {
591  var market = Market.CME;
592  var symbol = Futures.Indices.DowJonesRealEstate;
593  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
594  //Quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 consecutive quarters
595  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
596  {
597  time = time.AddMonths(1);
598  }
599  //Trading can occur up to 9:30 a.m. ET on the 3rd Friday of the contract month
600  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
601 
602  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
603  {
604  thirdFriday = thirdFriday.AddDays(-1);
605  }
606  return thirdFriday.Add(new TimeSpan(13, 30, 0));
607  })
608  },
609  // SP500EMiniESG (ESG): https://www.cmegroup.com/markets/equities/sp/e-mini-sandp-500-esg-index.contractSpecs.html
611  {
612  var market = Market.CME;
613  var symbol = Futures.Indices.SP500EMiniESG;
614  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
615  //Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
616  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
617  {
618  time = time.AddMonths(1);
619  }
620  //Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
621  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
622 
623  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
624  {
625  thirdFriday = thirdFriday.AddDays(-1);
626  }
627  return thirdFriday.Add(new TimeSpan(13, 30, 0));
628  })
629  },
630  // Russell1000EMini (RS1): https://www.cmegroup.com/markets/equities/russell/e-mini-russell-1000-index.contractSpecs.html
632  {
633  var market = Market.CME;
634  var symbol = Futures.Indices.Russell1000EMini;
635  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
636  //Quarterly contracts (Mar, Jun, Sep, Dec) lisrted for 5 consecutive quarters
637  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
638  {
639  time = time.AddMonths(1);
640  }
641  //Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
642  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
643 
644  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
645  {
646  thirdFriday = thirdFriday.AddDays(-1);
647  }
648  return thirdFriday.Add(new TimeSpan(13, 30, 0));
649  })
650  },
651  // SP500AnnualDividendIndex (SDA): https://www.cmegroup.com/markets/equities/sp/sp-500-annual-dividend-index.contractSpecs.html
653  {
654  var market = Market.CME;
656  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
657  //Annual contracts (December) listed for 11 consecutive years
658  while (!FutureExpirationCycles.December.Contains(time.Month))
659  {
660  time = time.AddMonths(1);
661  }
662  //Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
663  var thirdFriday = FuturesExpiryUtilityFunctions.NthFriday(time,3);
664 
665  while (!FuturesExpiryUtilityFunctions.NotHoliday(thirdFriday, holidays))
666  {
667  thirdFriday = thirdFriday.AddDays(-1);
668  }
669  return thirdFriday.Add(new TimeSpan(13, 30, 0));
670  })
671  },
672  // CBOE Volatility Index Futures (VIX): https://www.cboe.com/tradable_products/vix/vix_futures/specifications/
673  {Symbol.Create(Futures.Indices.VIX, SecurityType.Future, Market.CFE), (time =>
674  {
675  // Trading can occur up to 9:00 a.m. Eastern Time (ET) on the "Wednesday that is 30 days prior to
676  // the third Friday of the calendar month immediately following the month in which the contract expires".
677  var market = Market.CFE;
678  var symbol = Futures.Indices.VIX;
679  var nextThirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time.AddMonths(1));
680  var expiryDate = nextThirdFriday.AddDays(-30);
681  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
682 
683  // If the next third Friday or the Wednesday are holidays, then it is moved to the previous day.
684  if (holidays.Contains(expiryDate) || holidays.Contains(nextThirdFriday))
685  {
686  expiryDate = expiryDate.AddDays(-1);
687  }
688  // Trading hours for expiring VX futures contracts end at 8:00 a.m. Chicago time on the final settlement date.
689  return expiryDate.Add(new TimeSpan(13, 0, 0));
690  })
691  },
692  // Bloomberg Commodity Index (AW): https://www.cmegroup.com/trading/agricultural/commodity-index/bloomberg-commodity-index_contract_specifications.html
694  {
695  var market = Market.CBOT;
697  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
698  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 consecutive quarters and 4 additional Dec contract months
699  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
700  {
701  time = time.AddMonths(1);
702  }
703 
704  // 3rd Wednesday of the contract month/ 1:30pm
705  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
706  thirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(thirdWednesday, -1, holidays);
707  return thirdWednesday.Add(new TimeSpan(18, 30, 0));
708  })
709  },
710  // E-mini Nasdaq-100 Biotechnology Index (BIO): https://www.cmegroup.com/trading/equity-index/us-index/e-mini-nasdaq-biotechnology_contract_specifications.html
712  {
713  var market = Market.CME;
715  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
716  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
717  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
718  {
719  time = time.AddMonths(1);
720  }
721 
722  // Trading can occur up to 9:30 a.m. ET on the 3rd Friday of the contract month
723  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
724  thirdFriday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(thirdFriday, -1, holidays);
725 
726  return thirdFriday.Add(new TimeSpan(13, 30, 0));
727  })
728  },
729  // E-mini FTSE Emerging Index (EI): https://www.cmegroup.com/trading/equity-index/international-index/e-mini-ftse-emerging-index_contract_specifications.html
731  {
732  // Five months in the March Quarterly Cycle (Mar, Jun, Sep, Dec)
733  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
734  {
735  time = time.AddMonths(1);
736  }
737 
738  // Trading can occur up to 4:00 p.m. ET on the 3rd Friday of contract month
739  return FuturesExpiryUtilityFunctions.NthFriday(time, 3).Add(new TimeSpan(20, 0, 0));
740  })
741  },
742  // 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
744  {
745  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
746  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
747  {
748  time = time.AddMonths(1);
749  }
750 
751  // Trading can occur up until 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
752  return FuturesExpiryUtilityFunctions.NthFriday(time, 3).Add(new TimeSpan(13, 30, 0));
753  })
754  },
755  // S&amp;P-GSCI Commodity Index (GD): https://www.cmegroup.com/trading/agricultural/commodity-index/gsci_contract_specifications.html
757  {
758  var market = Market.CME;
759  var symbol = Futures.Indices.SPGSCICommodity;
760  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
761  // Monthly contracts
762  // Trading terminates on the11th business day of the contract month, 1:40pm.
763 
764  return FuturesExpiryUtilityFunctions.NthBusinessDay(time, 11, holidays).Add(new TimeSpan(18, 40, 0));
765  })
766  },
767  // USD-Denominated Ibovespa Index (IBV): https://www.cmegroup.com/trading/equity-index/international-index/usd-denominated-ibovespa_contract_specifications.html
769  {
770  var market = Market.CME;
772  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
773  // Four bi-monthly contracts (Feb/2, Apr/4, Jun/6, Aug/8, Oct/10, Dec/12 cycle)
774  while (!FutureExpirationCycles.GJMQVZ.Contains(time.Month))
775  {
776  time = time.AddMonths(1);
777  }
778 
779  // 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.
780  var wednesdays = (from dateRange in Enumerable.Range(1, DateTime.DaysInMonth(time.Year, time.Month))
781  where new DateTime(time.Year, time.Month, dateRange).DayOfWeek == DayOfWeek.Wednesday
782  select new DateTime(time.Year, time.Month, dateRange));
783 
784  var distanceFromFifteenthDay = wednesdays.Select(x => Math.Abs(15 - x.Day)).ToList();
785  var wednesdayIndex = distanceFromFifteenthDay.IndexOf(distanceFromFifteenthDay.Min());
786  var closestWednesday = wednesdays.ElementAt(wednesdayIndex);
787  if (holidays.Contains(closestWednesday) || !FuturesExpiryUtilityFunctions.NotHoliday(closestWednesday, holidays))
788  {
789  closestWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(closestWednesday, 1, holidays);
790  }
791 
792  return closestWednesday.Add(new TimeSpan(20, 0, 0));
793  })
794  },
795 
796  // JPY-Denominated Nikkie 225 Index Futures: https://www2.sgx.com/derivatives/products/nikkei225futuresoptions?cc=NK#Contract%20Specifications
798  {
799  // 6 nearest serial months & 32 nearest quarterly months
800  // The day before the second Friday of the contract month. Trading Hours on Last Day is normal Trading Hours (session T)
801  // T Session
802  // 7.15 am - 2.30 pm
803  var market = Market.SGX;
804  var symbol = Futures.Indices.Nikkei225Yen;
805  var secondFriday = FuturesExpiryUtilityFunctions.SecondFriday(time);
806  var priorBusinessDay = secondFriday.AddDays(-1);
807 
808  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
809 
810  while (holidays.Contains(priorBusinessDay) || !priorBusinessDay.IsCommonBusinessDay())
811  {
812  priorBusinessDay = priorBusinessDay.AddDays(-1);
813  }
814  return priorBusinessDay.Add(new TimeSpan(14, 30, 0));
815  })
816  },
817 
818  // MSCI Taiwan Index Futures: https://www2.sgx.com/derivatives/products/timsci?cc=TW
820  {
821  // 2 nearest serial months and 12 quarterly months on March, June, September and December cycle.
822  // Second last business day of the contract month. Same as T Session trading hours
823  var market = Market.SGX;
824  var symbol = Futures.Indices.MSCITaiwanIndex;
825  var lastDay = new DateTime(time.Year, time.Month, DateTime.DaysInMonth(time.Year, time.Month));
826  var priorBusinessDay = lastDay.AddDays(-1);
827 
828  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
829 
830  while (holidays.Contains(priorBusinessDay) || !priorBusinessDay.IsCommonBusinessDay())
831  {
832  priorBusinessDay = priorBusinessDay.AddDays(-1);
833  }
834  return priorBusinessDay.Add(new TimeSpan(13, 45, 0));
835  })
836  },
837 
838  // Nifty 50 Index Futures: https://www1.nseindia.com/products/content/derivatives/equities/contract_specifitns.htm
840  {
841  // 3 consecutive months trading cycle – Near-Month, Mid-Month and Far-Month.
842  // 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.
843  // The expiring contract shall close on its last trading day at 3.30 pm.
844  var market = Market.India;
845  var symbol = Futures.Indices.Nifty50;
846  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
847 
848  var expiryday = FuturesExpiryUtilityFunctions.LastThursday(time);
849 
850  while (holidays.Contains(expiryday) || !expiryday.IsCommonBusinessDay())
851  {
852  expiryday = expiryday.AddDays(-1);
853  }
854  return expiryday.Add(new TimeSpan(15, 30, 0));
855  })
856  },
857 
858  // BankNifty Index Futures: https://www1.nseindia.com/products/content/derivatives/equities/bank_nifty_new.htm
860  {
861  // have a maximum of 3-month trading cycle - the near month , the next month and the far month.
862  // 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.
863  // The expiring contract shall close on its last trading day at 3.30 pm.
864  var market = Market.India;
865  var symbol = Futures.Indices.BankNifty;
866  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
867 
868  var expiryday = FuturesExpiryUtilityFunctions.LastThursday(time);
869 
870  while (holidays.Contains(expiryday) || !expiryday.IsCommonBusinessDay())
871  {
872  expiryday = expiryday.AddDays(-1);
873  }
874  return expiryday.Add(new TimeSpan(15, 30, 0));
875  })
876  },
877 
878 
879  // BSE S&P Sensex Index Futures: https://www.bseindia.com/static/markets/Derivatives/DeriReports/market_information.html#!#ach6
881  {
882  // 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.
883  // The expiring contract shall close on its last trading day at 3.30 pm.
884  var market = Market.India;
885  var symbol = Futures.Indices.BseSensex;
886  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
887 
888  var expiryday = FuturesExpiryUtilityFunctions.LastThursday(time);
889 
890  while (holidays.Contains(expiryday) || !expiryday.IsCommonBusinessDay())
891  {
892  expiryday = expiryday.AddDays(-1);
893  }
894  return expiryday.Add(new TimeSpan(15, 30, 0));
895  })
896  },
897 
898  // 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
900  {
901  var market = Market.NYSELIFFE;
902  var symbol = Futures.Indices.MSCIEuropeNTR;
903  // Trading terminates on the third Friday of the contract month @16:15.
904  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
905  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
906 
907  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
908 
909  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
910  })
911  },
912  // 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
914  {
915  var market = Market.NYSELIFFE;
916  var symbol = Futures.Indices.MSCIJapanNTR;
917  // Trading terminates on the third Friday of the contract month @16:15.
918  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
919 
920  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
921 
922  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
923 
924  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
925  })
926  },
927  // 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
929  {
930  var market = Market.NYSELIFFE;
932  // Trading terminates on the third Friday of the contract month @16:15.
933  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
934  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
935 
936  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
937 
938  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
939  })
940  },
941  // 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
943  {
944  var market = Market.NYSELIFFE;
945  var symbol = Futures.Indices.MSCIEafeIndex;
946  // Trading terminates on the third Friday of the contract month @16:15.
947  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
948 
949  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
950 
951  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
952 
953  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
954  })
955  },
956  // 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
958  {
959  var market = Market.NYSELIFFE;
961  // Trading terminates on the third Friday of the contract month @16:15.
962  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
963  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
964 
965  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
966 
967  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
968  })
969  },
970  // 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
972  {
973  var market = Market.NYSELIFFE;
974  var symbol = Futures.Indices.MSCIUsaIndex;
975  // Trading terminates on the third Friday of the contract month @16:15.
976  var lastTradingDay = FuturesExpiryUtilityFunctions.ThirdFriday(time);
977  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
978 
979  lastTradingDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastTradingDay, -1, holidays);
980 
981  return lastTradingDay.Add(new TimeSpan(16, 15, 0));
982  })
983  },
984  // Forestry Group
985  // Random Length Lumber (LBS): https://www.cmegroup.com/trading/agricultural/lumber-and-pulp/random-length-lumber_contract_specifications.html
987  {
988  var market = Market.CME;
989  var symbol = Futures.Forestry.RandomLengthLumber;
990  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
991  // Monthly contracts (Jan, Mar, May, Jul, Sep, Nov) listed for 7 months
992  while (!FutureExpirationCycles.FHKNUX.Contains(time.Month))
993  {
994  time = time.AddMonths(1);
995  }
996 
997  // The business day prior to the 16th calendar day of the contract month at 12:05pm CT
998  var sixteenth = new DateTime(time.Year,time.Month,16);
999  return FuturesExpiryUtilityFunctions.AddBusinessDays(sixteenth, -1, holidays).Add(new TimeSpan(17, 5, 0));
1000  })
1001  },
1002  // Lumber and Softs
1003  // Lumber Futures (LBR): https://www.cmegroup.com/markets/agriculture/lumber-and-softs/lumber.contractSpecs.html
1004  {Symbol.Create(Futures.Forestry.Lumber, SecurityType.Future, Market.CME), (time =>
1005  {
1006  var market = Market.CME;
1007  var symbol = Futures.Forestry.Lumber;
1008  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1009  // Monthly contracts (Jan, Mar, May, Jul, Sep, Nov) listed for 7 months
1010  while (!FutureExpirationCycles.FHKNUX.Contains(time.Month))
1011  {
1012  time = time.AddMonths(1);
1013  }
1014 
1015  // The business day prior to the 16th calendar day of the contract month at 12:05pm CT
1016  var sixteenth = new DateTime(time.Year,time.Month, 16);
1017  return FuturesExpiryUtilityFunctions.AddBusinessDays(sixteenth, -1, holidays).Add(new TimeSpan(17, 5, 0));
1018  })
1019  },
1020  // Grains And OilSeeds Group
1021  // Chicago SRW Wheat (ZW): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/wheat_contract_specifications.html
1023  {
1024  var market = Market.CBOT;
1025  var symbol = Futures.Grains.SRWWheat;
1026  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1027  // 15 monthly contracts of Mar, May, Jul, Sep, Dec listed annually following the termination of trading in the July contract of the current year.
1028  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
1029  {
1030  time = time.AddMonths(1);
1031  }
1032 
1033  // The business day prior to the 15th calendar day of the contract month.
1034  var fifteenth = new DateTime(time.Year,time.Month,15);
1035  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1036  })
1037  },
1038  // HRW Wheat (KE): https://www.cmegroup.com/trading/agricultural/grain-and-oilseed/kc-wheat_contract_specifications.html
1040  {
1041  var market = Market.CBOT;
1042  var symbol = Futures.Grains.HRWWheat;
1043  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1044  // Monthly contracts (Mar, May, Jul, Sep, Dec) listed for 15 months
1045  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
1046  {
1047  time = time.AddMonths(1);
1048  }
1049 
1050  // The business day prior to the 15th calendar day of the contract month.
1051  var fifteenth = new DateTime(time.Year,time.Month,15);
1052  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1053  })
1054  },
1055  // Corn (ZC): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/corn_contract_specifications.html
1056  {Symbol.Create(Futures.Grains.Corn, SecurityType.Future, Market.CBOT), (time =>
1057  {
1058  var market = Market.CBOT;
1059  var symbol = Futures.Grains.Corn;
1060  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1061  // 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.
1062  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
1063  {
1064  time = time.AddMonths(1);
1065  }
1066 
1067  // The business day prior to the 15th calendar day of the contract month.
1068  var fifteenth = new DateTime(time.Year,time.Month,15);
1069  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1070  })
1071  },
1072  // Soybeans (ZS): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/soybean_contract_specifications.html
1074  {
1075  var market = Market.CBOT;
1076  var symbol = Futures.Grains.Soybeans;
1077  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1078  // 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.
1079  while (!FutureExpirationCycles.FHKNQUX.Contains(time.Month))
1080  {
1081  time = time.AddMonths(1);
1082  }
1083 
1084  // The business day prior to the 15th calendar day of the contract month.
1085  var fifteenth = new DateTime(time.Year,time.Month,15);
1086  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1087  })
1088  },
1089  // SoybeanMeal (ZM): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/soybean-meal_contract_specifications.html
1091  {
1092  var market = Market.CBOT;
1093  var symbol = Futures.Grains.SoybeanMeal;
1094  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1095  // 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.
1096  while (!FutureExpirationCycles.FHKNQUVZ.Contains(time.Month))
1097  {
1098  time = time.AddMonths(1);
1099  }
1100 
1101  // The business day prior to the 15th calendar day of the contract month.
1102  var fifteenth = new DateTime(time.Year,time.Month,15);
1103  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1104  })
1105  },
1106  // SoybeanOil (ZL): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/soybean-oil_contract_specifications.html
1108  {
1109  var market = Market.CBOT;
1110  var symbol = Futures.Grains.SoybeanOil;
1111  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1112  // 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.
1113  while (!FutureExpirationCycles.FHKNQUVZ.Contains(time.Month))
1114  {
1115  time = time.AddMonths(1);
1116  }
1117 
1118  // The business day prior to the 15th calendar day of the contract month.
1119  var fifteenth = new DateTime(time.Year,time.Month,15);
1120  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1121  })
1122  },
1123  // Oats (ZO): http://www.cmegroup.com/trading/agricultural/grain-and-oilseed/oats_contract_specifications.html
1124  {Symbol.Create(Futures.Grains.Oats, SecurityType.Future, Market.CBOT), (time =>
1125  {
1126  var market = Market.CBOT;
1127  var symbol = Futures.Grains.Oats;
1128  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1129  // Monthly contracts (Mar, May, Jul, Sep, Dec) listed for 10 months and 1 additional Jul and 1 additional Sep contract listed in September
1130  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
1131  {
1132  time = time.AddMonths(1);
1133  }
1134 
1135  // The business day prior to the 15th calendar day of the contract month.
1136  var fifteenth = new DateTime(time.Year,time.Month,15);
1137  return FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth,-1, holidays);
1138  })
1139  },
1140  // 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
1142  {
1143  var market = Market.CBOT;
1145  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1146 
1147  // Monthly contracts listed for 15 consecutive months.
1148  // Trading terminates on the last business day of the contract month which is also a Platts publication date for the price assessment.
1149  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1150  })
1151  },
1152  // 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
1154  {
1155  var market = Market.CBOT;
1157  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1158  // Monthly contracts listed for 15 consecutive months
1159  // Trading terminates on the last business day of the contract month which is also a Platts publication date for the price assessment.
1160  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1161  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
1162 
1163  return lastBusinessDay;
1164  })
1165  },
1166  // Currencies group
1167  // U.S. Dollar Index(R) Futures (DX): https://www.theice.com/products/194/US-Dollar-Index-Futures
1168  {Symbol.Create(Futures.Currencies.USD, SecurityType.Future, Market.ICE), (time =>
1169  {
1170  // Four months in the March/June/September/December quarterly expiration cycle
1171  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1172  {
1173  time = time.AddMonths(1);
1174  }
1175 
1176  // Last Trading Day:
1177  // Trading ceases at 10:16 Eastern time two days prior to settlement
1178  //
1179  // Final Settlement:
1180  // The US Dollar Index is physically settled on the third Wednesday of the expiration month
1181  // against six component currencies (euro, Japanese yen, British pound, Canadian dollar, Swedish
1182  // krona and Swiss franc) in their respective percentage weights in the Index.
1183  // Settlement rates may be quoted to three decimal places.
1184 
1185  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1186  var twoDaysPrior = thirdWednesday.AddDays(-2);
1187 
1188  return twoDaysPrior.Add(new TimeSpan(10, 16, 0));
1189  })
1190  },
1191  // GBP (6B): http://www.cmegroup.com/trading/fx/g10/british-pound_contract_specifications.html
1192  {Symbol.Create(Futures.Currencies.GBP, SecurityType.Future, Market.CME), (time =>
1193  {
1194  var market = Market.CME;
1195  var symbol = Futures.Currencies.GBP;
1196  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1197  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters and serial contracts listed for 3 months
1198 
1199  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1200  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1201  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1202  thirdWednesday,
1203  -2, holidays);
1204  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1205  })
1206  },
1207  // CAD (6C): http://www.cmegroup.com/trading/fx/g10/canadian-dollar_contract_specifications.html
1208  {Symbol.Create(Futures.Currencies.CAD, SecurityType.Future, Market.CME), (time =>
1209  {
1210  var market = Market.CME;
1211  var symbol = Futures.Currencies.CAD;
1212  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1213  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters and serial contracts listed for 3 months
1214 
1215  // 9:16 a.m. Central Time (CT) on the business day immediately preceding the third Wednesday of the contract month (usually Tuesday).
1216  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1217  var businessDayPrecedingThridWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -1, holidays);
1218  return businessDayPrecedingThridWednesday.Add(new TimeSpan(14,16,0));
1219  })
1220  },
1221  // JPY (6J): http://www.cmegroup.com/trading/fx/g10/japanese-yen_contract_specifications.html
1222  {Symbol.Create(Futures.Currencies.JPY, SecurityType.Future, Market.CME), (time =>
1223  {
1224  var market = Market.CME;
1225  var symbol = Futures.Currencies.JPY;
1226  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1227  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters and serial contracts listed for 3 months
1228 
1229  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1230  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1231  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1232  thirdWednesday,
1233  -2, holidays);
1234  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1235  })
1236  },
1237  // CHF (6S): http://www.cmegroup.com/trading/fx/g10/swiss-franc_contract_specifications.html
1238  {Symbol.Create(Futures.Currencies.CHF, SecurityType.Future, Market.CME), (time =>
1239  {
1240  var market = Market.CME;
1241  var symbol = Futures.Currencies.CHF;
1242  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1243  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters
1244  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1245  {
1246  time = time.AddMonths(1);
1247  }
1248 
1249  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1250  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1251  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1252  thirdWednesday,
1253  -2, holidays);
1254  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1255  })
1256  },
1257  // EUR (6E): http://www.cmegroup.com/trading/fx/g10/euro-fx_contract_specifications.html
1258  {Symbol.Create(Futures.Currencies.EUR, SecurityType.Future, Market.CME), (time =>
1259  {
1260  var market = Market.CME;
1261  var symbol = Futures.Currencies.EUR;
1262  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1263  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters and serial contracts listed for 3 months
1264 
1265  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1266  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1267  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1268  thirdWednesday,
1269  -2, holidays);
1270  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1271  })
1272  },
1273  // AUD (6A): http://www.cmegroup.com/trading/fx/g10/australian-dollar_contract_specifications.html
1274  {Symbol.Create(Futures.Currencies.AUD, SecurityType.Future, Market.CME), (time =>
1275  {
1276  var market = Market.CME;
1277  var symbol = Futures.Currencies.AUD;
1278  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1279  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 20 consecutive quarters and serial contracts listed for 3 months
1280 
1281  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1282  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1283  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1284  thirdWednesday,
1285  -2, holidays);
1286  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1287  })
1288  },
1289  // NZD (6N): http://www.cmegroup.com/trading/fx/g10/new-zealand-dollar_contract_specifications.html
1290  {Symbol.Create(Futures.Currencies.NZD, SecurityType.Future, Market.CME), (time =>
1291  {
1292  var market = Market.CME;
1293  var symbol = Futures.Currencies.NZD;
1294  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1295  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 6 consecutive quarters
1296  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1297  {
1298  time = time.AddMonths(1);
1299  }
1300 
1301  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1302  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1303  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(
1304  thirdWednesday,
1305  -2, holidays);
1306  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1307  })
1308  },
1309  // RUB (6R): https://www.cmegroup.com/trading/fx/emerging-market/russian-ruble_contract_specifications.html
1310  {Symbol.Create(Futures.Currencies.RUB, SecurityType.Future, Market.CME), (time =>
1311  {
1312  var market = Market.CME;
1313  var symbol = Futures.Currencies.RUB;
1314  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1315  // Monthly contacts listed for 12 consecutive months and quarterly contracts (Mar, Jun, Sep, Dec) listed for16 additional quarters
1316  // 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.
1317  var fifteenth = new DateTime(time.Year, time.Month, 15);
1318 
1319  while (!FuturesExpiryUtilityFunctions.NotHoliday(fifteenth, holidays))
1320  {
1321  fifteenth = FuturesExpiryUtilityFunctions.AddBusinessDays(fifteenth, 1, holidays);
1322  }
1323  return fifteenth.Add(new TimeSpan(08,0,0));
1324  })
1325  },
1326  // BRL (6L): https://www.cmegroup.com/trading/fx/emerging-market/brazilian-real_contract_specifications.html
1327  {Symbol.Create(Futures.Currencies.BRL, SecurityType.Future, Market.CME), (time =>
1328  {
1329  var market = Market.CME;
1330  var symbol = Futures.Currencies.BRL;
1331  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1332  // Monthly contracts listed for 60 consecutive months
1333  // 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).
1334  var lastPrecedingBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(time, -1, holidays);
1335  lastPrecedingBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastPrecedingBusinessDay, -1, holidays);
1336 
1337  return lastPrecedingBusinessDay.Add(new TimeSpan(14,15,0));
1338  })
1339  },
1340  // MXN (6M): https://www.cmegroup.com/trading/fx/emerging-market/mexican-peso_contract_specifications.html
1341  {Symbol.Create(Futures.Currencies.MXN, SecurityType.Future, Market.CME), (time =>
1342  {
1343  var market = Market.CME;
1344  var symbol = Futures.Currencies.MXN;
1345  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1346  // Monthly contracts listed for 13 consecutive months and 2 additional quarterly contracts (Mar, Jun, Sep, Dec)
1347  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1348  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1349  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday,-2, holidays);
1350  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1351 
1352  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1353  })
1354  },
1355  // ZAR (6Z): https://www.cmegroup.com/trading/fx/emerging-market/south-african-rand_contract_specifications.html
1356  {Symbol.Create(Futures.Currencies.ZAR, SecurityType.Future, Market.CME), (time =>
1357  {
1358  var market = Market.CME;
1359  var symbol = Futures.Currencies.ZAR;
1360  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1361  // Monthly contracts listed for 13 consecutive months and quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 consecutive quarters
1362  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday)
1363  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1364  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1365  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1366 
1367  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1368  })
1369  },
1370  // AUD/CAD (ACD): https://www.cmegroup.com/trading/fx/g10/australian-dollar-canadian-dollar_contract_specifications.html
1372  {
1373  var market = Market.CME;
1374  var symbol = Futures.Currencies.AUDCAD;
1375  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1376  // Six months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1377  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1378  {
1379  time = time.AddMonths(1);
1380  }
1381 
1382  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday)
1383  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1384  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1385  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1386 
1387  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14,16,0));
1388  })
1389  },
1390  // Australian Dollar/Japanese Yen (AJY): https://www.cmegroup.com/trading/fx/g10/australian-dollar-japanese-yen_contract_specifications.html
1392  {
1393  var market = Market.CME;
1394  var symbol = Futures.Currencies.AUDJPY;
1395  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1396  // Six months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1397  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1398  {
1399  time = time.AddMonths(1);
1400  }
1401 
1402  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1403  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1404  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1405  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1406 
1407  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1408  })
1409  },
1410  // Australian Dollar/New Zealand Dollar (ANE): https://www.cmegroup.com/trading/fx/g10/australian-dollar-new-zealand-dollar_contract_specifications.html
1412  {
1413  var market = Market.CME;
1414  var symbol = Futures.Currencies.AUDNZD;
1415  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1416  // Six months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1417  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1418  {
1419  time = time.AddMonths(1);
1420  }
1421 
1422  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1423  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1424  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1425  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1426 
1427  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1428  })
1429  },
1430  // Bitcoin (BTC): https://www.cmegroup.com/trading/equity-index/us-index/bitcoin_contract_specifications.html
1431  {Symbol.Create(Futures.Currencies.BTC, SecurityType.Future, Market.CME), (time =>
1432  {
1433  var market = Market.CME;
1434  var symbol = Futures.Currencies.BTC;
1435  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1436  // 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.
1437  // 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..
1438  var lastFriday =FuturesExpiryUtilityFunctions.LastFriday(time);
1439  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastFriday, -1, holidays);
1440 
1441  return lastFriday.Add(new TimeSpan(15, 0, 0));
1442  })
1443  },
1444  // Ether (ETH): https://www.cmegroup.com/markets/cryptocurrencies/ether/ether.contractSpecs.html
1445  {Symbol.Create(Futures.Currencies.ETH, SecurityType.Future, Market.CME), (time =>
1446  {
1447  var market = Market.CME;
1448  var symbol = Futures.Currencies.ETH;
1449  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1450  // 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.
1451  // 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.
1452  var lastFriday = FuturesExpiryUtilityFunctions.LastFriday(time);
1453  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastFriday, -1, holidays);
1454 
1455  return lastFriday.Add(new TimeSpan(15, 0, 0));
1456  })
1457  },
1458  // Canadian Dollar/Japanese Yen (CJY): https://www.cmegroup.com/trading/fx/g10/canadian-dollar-japanese-yen_contract_specifications.html
1460  {
1461  var market = Market.CME;
1462  var symbol = Futures.Currencies.CADJPY;
1463  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1464  // Six months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1465  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1466  {
1467  time = time.AddMonths(1);
1468  }
1469 
1470  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1471  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1472  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1473  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1474 
1475  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1476  })
1477  },
1478  // Standard-Size USD/Offshore RMB (CNH): https://www.cmegroup.com/trading/fx/emerging-market/usd-cnh_contract_specifications.html
1480  {
1481  var market = Market.CME;
1483  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1484 
1485  // Monthly contracts listed for 13 consecutive months and quarterly contracts (Mar, Jun, Sep, Dec) listed for the next 8 quarters.
1486  // 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.
1487  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1488  var secondBusinessDayPrecedingThirdWednesday = thirdWednesday.AddDays(-2);
1489  while (holidays.Contains(secondBusinessDayPrecedingThirdWednesday) || !secondBusinessDayPrecedingThirdWednesday.IsCommonBusinessDay())
1490  {
1491  secondBusinessDayPrecedingThirdWednesday = secondBusinessDayPrecedingThirdWednesday.AddDays(-1);
1492  }
1493 
1494  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(3,0,0));
1495  })
1496  },
1497  // E-mini Euro FX (E7): https://www.cmegroup.com/trading/fx/g10/e-mini-euro-fx_contract_specifications.html
1499  {
1500  var market = Market.CME;
1501  var symbol = Futures.Currencies.EuroFXEmini;
1502  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1503 
1504  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
1505  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1506  {
1507  time = time.AddMonths(1);
1508  }
1509 
1510  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1511  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1512  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1513  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1514 
1515  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1516  })
1517  },
1518  // Euro/Australian Dollar (EAD): https://www.cmegroup.com/trading/fx/g10/euro-fx-australian-dollar_contract_specifications.html
1520  {
1521  var market = Market.CME;
1522  var symbol = Futures.Currencies.EURAUD;
1523  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1524 
1525  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 6 consecutive quarters
1526  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1527  {
1528  time = time.AddMonths(1);
1529  }
1530 
1531  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1532  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1533  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1534  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1535 
1536  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1537  })
1538  },
1539  // Euro/Canadian Dollar (ECD): https://www.cmegroup.com/trading/fx/g10/euro-fx-canadian-dollar_contract_specifications.html
1541  {
1542  var market = Market.CME;
1543  var symbol = Futures.Currencies.EURCAD;
1544  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1545 
1546  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 6 consecutive quarters
1547  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1548  {
1549  time = time.AddMonths(1);
1550  }
1551 
1552  // Trading terminates at 9:16 a.m. CT on the second business day prior to the third Wednesday of the contract month.
1553  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1554  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1555  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1556 
1557  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1558  })
1559  },
1560  // Euro/Swedish Krona (ESK): https://www.cmegroup.com/trading/fx/g10/euro-fx-swedish-krona_contract_specifications.html
1562  {
1563  var market = Market.CME;
1564  var symbol = Futures.Currencies.EURSEK;
1565  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1566 
1567  // Six months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1568  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1569  {
1570  time = time.AddMonths(1);
1571  }
1572 
1573  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1574  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1575  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1576  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1577 
1578  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1579  })
1580  },
1581  // E-mini Japanese Yen (J7): https://www.cmegroup.com/trading/fx/g10/e-mini-japanese-yen_contract_specifications.html
1583  {
1584  var market = Market.CME;
1585  var symbol = Futures.Currencies.JapaneseYenEmini;
1586  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1587  // Two months in the March quarterly cycle (Mar, Jun, Sep, Dec)
1588  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1589  {
1590  time = time.AddMonths(1);
1591  }
1592 
1593  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
1594  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
1595  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
1596  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
1597 
1598  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
1599  })
1600  },
1601  // Financials group
1602  // Y30TreasuryBond (ZB): http://www.cmegroup.com/trading/interest-rates/us-treasury/30-year-us-treasury-bond_contract_specifications.html
1604  {
1605  var market = Market.CBOT;
1606  var symbol = Futures.Financials.Y30TreasuryBond;
1607  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1608 
1609  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 quarters
1610  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1611  {
1612  time = time.AddMonths(1);
1613  }
1614 
1615  // 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.
1616  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1617  var seventhBusinessDayPrecedingLastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay,-7, holidays);
1618  return seventhBusinessDayPrecedingLastBusinessDay.Add(new TimeSpan(12,01,0));
1619  })
1620  },
1621  // Y10TreasuryNote (ZN): http://www.cmegroup.com/trading/interest-rates/us-treasury/10-year-us-treasury-note_contract_specifications.html
1623  {
1624  var market = Market.CBOT;
1625  var symbol = Futures.Financials.Y10TreasuryNote;
1626  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1627 
1628  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 consecutive quarters
1629  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1630  {
1631  time = time.AddMonths(1);
1632  }
1633 
1634  // 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.
1635  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1636  var seventhBusinessDayPrecedingLastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay,-7, holidays);
1637  return seventhBusinessDayPrecedingLastBusinessDay.Add(new TimeSpan(12,01,0));
1638  })
1639  },
1640  // Y5TreasuryNote (ZF): http://www.cmegroup.com/trading/interest-rates/us-treasury/5-year-us-treasury-note_contract_specifications.html
1642  {
1643  var market = Market.CBOT;
1644  var symbol = Futures.Financials.Y5TreasuryNote;
1645  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1646  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 consecutive quarters
1647  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1648  {
1649  time = time.AddMonths(1);
1650  }
1651 
1652  // Last business day of the calendar month. Trading in expiring contracts closes at 12:01 p.m. on the last trading day.
1653  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1654  return lastBusinessDay.Add(new TimeSpan(12,01,0));
1655  })
1656  },
1657  // Y2TreasuryNote (ZT): http://www.cmegroup.com/trading/interest-rates/us-treasury/2-year-us-treasury-note_contract_specifications.html
1659  {
1660  var market = Market.CBOT;
1661  var symbol = Futures.Financials.Y2TreasuryNote;
1662  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1663 
1664  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 consecutive quarters
1665  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1666  {
1667  time = time.AddMonths(1);
1668  }
1669 
1670  // Last business day of the calendar month. Trading in expiring contracts closes at 12:01 p.m. on the last trading day.
1671  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1672  return lastBusinessDay.Add(new TimeSpan(12,01,0));
1673  })
1674  },
1675  // Eurodollar (GE): https://www.cmegroup.com/trading/interest-rates/stir/eurodollar_contract_specifications.html
1677  {
1678  var market = Market.CME;
1679  var symbol = Futures.Financials.EuroDollar;
1680  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1681 
1682  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 40 consecutive quarters and the nearest 4 serial contract months.
1683  // List a new quarterly contract for trading on the last trading day of the nearby expiry.
1684 
1685  // Termination of trading:
1686  // Second London bank business day before 3rd Wednesday of the contract month. Trading
1687  // in expiring contracts terminates at 11:00 a.m. London time on the last trading day.
1688 
1690  .Add(TimeSpan.FromHours(11));
1691  })
1692  },
1693  // 5-Year USD MAC Swap (F1U): https://www.cmegroup.com/trading/interest-rates/swap-futures/5-year-usd-mac-swap_contract_specifications.html
1695  {
1696  var market = Market.CBOT;
1697  var symbol = Futures.Financials.FiveYearUSDMACSwap;
1698 
1699  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
1700  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1701  {
1702  time = time.AddMonths(1);
1703  }
1704 
1705  // 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.
1706  var secondBusinessDayBeforeThirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time).AddDays(-2);
1707  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1708 
1709  // Because we're using a London calendar, we need to put entries in MHDB and not use `USHolidays.Dates`
1710  while (holidays.Contains(secondBusinessDayBeforeThirdWednesday) || !secondBusinessDayBeforeThirdWednesday.IsCommonBusinessDay())
1711  {
1712  secondBusinessDayBeforeThirdWednesday = secondBusinessDayBeforeThirdWednesday.AddDays(-1);
1713  }
1714 
1715  return secondBusinessDayBeforeThirdWednesday.Add(new TimeSpan(19, 0, 0));
1716  })
1717  },
1718  // Ultra U.S. Treasury Bond (UB): https://www.cmegroup.com/trading/interest-rates/us-treasury/ultra-t-bond_contract_specifications.html
1720  {
1721  var market = Market.CBOT;
1722  var symbol = Futures.Financials.UltraUSTreasuryBond;
1723  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1724 
1725  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 consecutive quarters
1726  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1727  {
1728  time = time.AddMonths(1);
1729  }
1730 
1731  // 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.
1732  var sevenBusinessDaysBeforeLastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 8, holidays);
1733 
1734  return sevenBusinessDaysBeforeLastBusinessDay.Add(new TimeSpan(12, 1, 0));
1735  })
1736  },
1737  // 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
1739  {
1740  var market = Market.CBOT;
1742  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1743 
1744  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 3 consecutive quarters
1745  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
1746  {
1747  time = time.AddMonths(1);
1748  }
1749 
1750  // Trading terminates on the 7th business day before the last business day of the contract month.
1751  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 8, holidays);
1752  })
1753  },
1754  // Energies group
1755  // Propane Non LDH Mont Belvieu (1S): https://www.cmegroup.com/trading/energy/petrochemicals/propane-non-ldh-mt-belvieu-opis-balmo-swap_contract_specifications.html
1757  {
1758  var market = Market.NYMEX;
1760  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1761 
1762  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
1763  // Trading shall cease on the last business day of the contract month (no time specified)
1764  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1765  })
1766  },
1767  // 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
1769  {
1770  var market = Market.NYMEX;
1772  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1773 
1774  // Monthly BALMO contracts listed for three cconsecutive months
1775  // Trading shall cease on the last business day of the contract month. Business days are based on the Singapore Public Holiday calendar.
1776  // TODO: Might need singapore calendar
1777  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1778  })
1779  },
1780  // 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
1782  {
1783  var market = Market.NYMEX;
1785  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1786 
1787  // Monthly contracts listed for the current year and the next 4 calendar years.
1788  // Trading shall cease on the last business day of the contract month.
1789  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1790  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
1791 
1792  return lastBusinessDay;
1793  })
1794  },
1795  // 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
1797  {
1798  var market = Market.NYMEX;
1800  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1801 
1802  // Monthly contracts listed for the current year and the next 5 calendar years.
1803  // Trading shall cease on the last business day of the contract month.
1804  // Special case exists where the last trade occurs on US holiday, but not an exchange holiday (markets closed)
1805  // 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
1806  var lastDay = new DateTime(time.Year, time.Month, DateTime.DaysInMonth(time.Year, time.Month));
1807 
1808  while (holidays.Contains(lastDay) || !lastDay.IsCommonBusinessDay())
1809  {
1810  lastDay = lastDay.AddDays(-1);
1811  }
1812 
1813  return lastDay;
1814  })
1815  },
1816  // 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
1818  {
1819  var market = Market.NYMEX;
1821  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1822  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
1823  // Trading shall cease on the last business day of the contract month.
1824  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1825  })
1826  },
1827  // 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
1829  {
1830  var market = Market.NYMEX;
1832  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1833  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
1834  // Trading shall cease on the last business day of the contract month.
1835  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1836  })
1837  },
1838  // 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
1840  {
1841  var market = Market.NYMEX;
1843  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1844 
1845  // Monthly contracts listed for 48 consecutive months
1846  // Trading shall cease on the last business day of the contract month.
1847  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1848  })
1849  },
1850  // 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
1852  {
1853  var market = Market.NYMEX;
1855  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1856  // Monthly BALMO contracts listed for 3 consecutive months
1857  // Trading shall cease on the last business day of the contract month.
1858  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1859  })
1860  },
1861  // 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
1863  {
1864  var market = Market.NYMEX;
1866  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1867 
1868  // 48 consecutive months
1869  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1870  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
1871 
1872  return lastBusinessDay;
1873  })
1874  },
1875  // Argus Propane Far East Index Futures (A7E): https://www.cmegroup.com/trading/energy/petrochemicals/argus-propane-far-east-index-swap-futures_contract_specifications.html
1877  {
1878  var market = Market.NYMEX;
1880  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1881 
1882  // Monthly contracts listed for 48 consecutive months
1883  // Trading shall cease on the last business day of the contract month.
1884  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1885  })
1886  },
1887  // 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
1889  {
1890  var market = Market.NYMEX;
1892  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1893 
1894  // Monthly BALMO contracts listed for 3 consecutive months
1895  // Trading ceases on the last business day of the contract month.
1896  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1897  })
1898  },
1899  // 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
1901  {
1902  var market = Market.NYMEX;
1904  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1905 
1906  // Monthly contracts listed for 56 consecutive months
1907  // Trading shall cease on the last business day of the contract month
1908  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1909  })
1910  },
1911  // 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
1913  {
1914  var market = Market.NYMEX;
1916  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1917 
1918  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
1919  // Trading terminates on the last business day of the contract month.
1920  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1921  })
1922  },
1923  // Conway Propane (OPIS) Futures (A8K): https://www.cmegroup.com/trading/energy/petrochemicals/conway-propane-opis-swap_contract_specifications.html
1925  {
1926  var market = Market.NYMEX;
1927  var symbol = Futures.Energies.ConwayPropaneOPIS;
1928  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1929 
1930  // Monthly contracts listed for the current year and the next 4 calendar years.
1931  // Trading shall cease on the last business day of the contract month.
1932  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1933  })
1934  },
1935  // 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
1937  {
1938  var market = Market.NYMEX;
1940  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1941 
1942  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
1943  // Trading shall cease on the last business day of the contract month.
1944  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1945  })
1946  },
1947  // 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
1949  {
1950  var market = Market.NYMEX;
1952  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1953 
1954  // Monthly contracts listed for 36 consecutive months
1955  // Trading shall cease on the last business day of the contract month.
1956  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1957  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
1958 
1959  return lastBusinessDay;
1960  })
1961  },
1962  // Argus Propane (Saudi Aramco) Futures (A9N): https://www.cmegroup.com/trading/energy/petrochemicals/argus-propane-saudi-aramco-swap-futures_contract_specifications.html
1964  {
1965  var market = Market.NYMEX;
1967  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1968 
1969  // Monthly contracts listed for 48 consecutive months
1970  // Trading shall terminate on the last business day of the month prior to the contract month.
1971  // Business days are based on the Singapore Public Holiday Calendar.
1972  // Special case in 2021 where last traded date falls on US Holiday, but not exchange holiday
1973  var previousMonth = time.AddMonths(-1);
1974  var lastDay = new DateTime(previousMonth.Year, previousMonth.Month, DateTime.DaysInMonth(previousMonth.Year, previousMonth.Month));
1975 
1976  while (!lastDay.IsCommonBusinessDay() || holidays.Contains(lastDay))
1977  {
1978  lastDay = lastDay.AddDays(-1);
1979  }
1980 
1981  return lastDay;
1982  })
1983  },
1984  // 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
1986  {
1987  var market = Market.NYMEX;
1989  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
1990 
1991  // Trading shall cease on the last business day of the contract month.
1992  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
1993  })
1994  },
1995  // 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
1997  {
1998  var market = Market.NYMEX;
2000  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2001 
2002  // 36 consecutive months
2003  // Trading shall cease on the last business day of the contract month
2004  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2005  })
2006  },
2007  // 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
2009  {
2010  var market = Market.NYMEX;
2012  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2013 
2014  // Monthly BALMO contracts listed for 3 consecutive months
2015  // Trading shall cease on the last business day of the contract month.
2016  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2017  })
2018  },
2019  // 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
2021  {
2022  var market = Market.NYMEX;
2024  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2025 
2026  // Monthly BALMO contracts listed for 3 consecutive months
2027  // Trading shall cease on the last business day of the contract month.
2028  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2029  })
2030  },
2031  // Mont Belvieu Ethane (OPIS) Futures (AC0): https://www.cmegroup.com/trading/energy/petrochemicals/mont-belvieu-ethane-opis-5-decimals-swap_contract_specifications.html
2033  {
2034  var market = Market.NYMEX;
2035  var symbol = Futures.Energies.MontBelvieuEthaneOPIS;
2036  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2037 
2038  // Monthly contracts listed for the current year and the next 4 calendar years.
2039  // Trading shall cease on the last business day of the contract month.
2040  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2041  })
2042  },
2043  // Mont Belvieu Normal Butane (OPIS) Futures (AD0): https://www.cmegroup.com/trading/energy/petrochemicals/mont-belvieu-normal-butane-5-decimals-swap_contract_specifications.html
2045  {
2046  var market = Market.NYMEX;
2048  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2049 
2050  // Monthly contracts listed for the current year and next 4 calendar years.
2051  // Trading shall cease on the last business day of the contract month.
2052  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2053  })
2054  },
2055  // 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
2057  {
2058  var market = Market.NYMEX;
2060  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2061  // Trading shall cease on the last London and Singapore business day of the contract month.
2062  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2063  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2064 
2065  return lastBusinessDay;
2066  })
2067  },
2068  // 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
2070  {
2071  var market = Market.NYMEX;
2073  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2074 
2075  // 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.
2076  var previousMonth = time.AddMonths(-1);
2077  var twentyFifthDay = new DateTime(previousMonth.Year, previousMonth.Month, 25);
2078  while (!twentyFifthDay.IsCommonBusinessDay() || holidays.Contains(twentyFifthDay))
2079  {
2080  twentyFifthDay = FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifthDay, -1, holidays);
2081  }
2082 
2083  return twentyFifthDay;
2084  })
2085  },
2086  // 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
2088  {
2089  var market = Market.NYMEX;
2091  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2092 
2093  // Monthly contracts listed for the current year and the next 2 calendar years.
2094  // Trading ceases on the last 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  // 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
2103  {
2104  var market = Market.NYMEX;
2106  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2107 
2108  // 36 consecutive months
2109  // Trading shall cease on the last business day of the contract month
2110  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2111  })
2112  },
2113  // 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
2115  {
2116  var market = Market.NYMEX;
2118  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2119  // 36 consecutive months
2120  // Trading shall cease on the last business day of the contract month
2121  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2122  })
2123  },
2124  // 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
2126  {
2127  var market = Market.NYMEX;
2129  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2130  // 3 consecutive years
2131  // Trading shall cease on the last business day of the contract month
2132  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2133  })
2134  },
2135  // European Naphtha (Platts) BALMO (AKZ): https://www.cmegroup.com/trading/energy/refined-products/european-naphtha-balmo-swap_contract_specifications.html
2137  {
2138  var market = Market.NYMEX;
2140  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2141  // Monthly BALMO contracts listed for 3 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  // European Propane CIF ARA (Argus) (APS): https://www.cmegroup.com/trading/energy/petrochemicals/european-propane-cif-ara-argus-swap_contract_specifications.html
2148  {
2149  var market = Market.NYMEX;
2151  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2152  // Monthly contracts listed for the current year and the next 3 calendar years.
2153  // Trading shall cease on the last business day of the contract month
2154  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2155  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2156 
2157  return lastBusinessDay;
2158  })
2159  },
2160  // Mont Belvieu Natural Gasoline (OPIS) BALMO (AR0): https://www.cmegroup.com/trading/energy/petrochemicals/mt-belvieu-natural-gasoline-balmo-swap_contract_specifications.html
2162  {
2163  var market = Market.NYMEX;
2165  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2166  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
2167  // Trading shall cease on the last business day of the contract month
2168  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2169  })
2170  },
2171  // RBOB Gasoline Crack Spread (ARE): https://www.cmegroup.com/trading/energy/refined-products/rbob-crack-spread-swap-futures_contract_specifications.html
2173  {
2174  var market = Market.NYMEX;
2176  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2177  // The current year plus the next three calendar years
2178  // Trading shall cease on the last business day of the contract month
2179  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2180  })
2181  },
2182  // Gulf Coast HSFO (Platts) BALMO (AVZ): https://www.cmegroup.com/trading/energy/refined-products/gulf-coast-3pct-fuel-oil-balmo-swap_contract_specifications.html
2184  {
2185  var market = Market.NYMEX;
2187  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2188  // Monthly BALMO contracts listed for the current month and the following month listed 10 business days prior to the start of the contract month
2189  // Trading shall cease on the last business day of the contract month
2190  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2191  })
2192  },
2193  // 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
2195  {
2196  var market = Market.NYMEX;
2198  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2199  // Monthly contracts listed for the current year and the next 5 calendar years.
2200  // Trading shall cease at the close of trading on the last business day that falls on or before the 25th calendar day of the
2201  // month prior to the contract month. If the 25th calendar day is a weekend or holiday, trading shall cease on the
2202  // first business day prior to the 25th calendar day.
2203  var twentyFifthDayPriorMonth = new DateTime(time.Year, time.Month, 25).AddMonths(-1);
2204  while (!FuturesExpiryUtilityFunctions.NotHoliday(twentyFifthDayPriorMonth, holidays) || holidays.Contains(twentyFifthDayPriorMonth))
2205  {
2206  twentyFifthDayPriorMonth = FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifthDayPriorMonth, -1, holidays);
2207  }
2208 
2209  return twentyFifthDayPriorMonth;
2210  })
2211  },
2212  // 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
2214  {
2215  var market = Market.NYMEX;
2217  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2218  // The current year and the next five (5) consecutive calendar years.
2219  // Trading shall cease on the last business day of the contract month
2220  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2221  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2222 
2223  return lastBusinessDay;
2224  })
2225  },
2226  // 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
2228  {
2229  var market = Market.NYMEX;
2231  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2232  // Monthly contracts listed for 36 consecutive months
2233  // Trading terminates on the last business day of the contract month
2234  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2235  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2236 
2237  return lastBusinessDay;
2238  })
2239  },
2240  // Mont Belvieu LDH Propane (OPIS) (B0): https://www.cmegroup.com/trading/energy/petrochemicals/mont-belvieu-propane-5-decimals-swap_contract_specifications.html
2242  {
2243  var market = Market.NYMEX;
2245  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2246  // Monthly contracts listed for the current year and the next 4 calendar years.
2247  // Trading shall cease on the last business day of the contract month
2248  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2249  })
2250  },
2251  // 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
2253  {
2254  var market = Market.NYMEX;
2256  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2257  // Monthly contracts listed for 36 consecutive months
2258  // Trading shall cease on the last business day of the contract month
2259  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2260  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2261 
2262  return lastBusinessDay;
2263  })
2264  },
2265  // WTI-Brent Financial (BK): https://www.cmegroup.com/trading/energy/crude-oil/wti-brent-ice-calendar-swap-futures_contract_specifications.html
2267  {
2268  var market = Market.NYMEX;
2269  var symbol = Futures.Energies.WTIBrentFinancial;
2270  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2271  // Monthly contracts listed for the current year and the next 8 calendar years.
2272  // Trading shall cease on the last business day of the contract month
2273  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2274  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2275 
2276  return lastBusinessDay;
2277  })
2278  },
2279  // 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
2281  {
2282  var market = Market.NYMEX;
2284  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2285  // Monthly contracts listed for the current year and the next 4 calendar years.
2286  // Trading shall cease on the last business day of the contract month
2287  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2288  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2289 
2290  return lastBusinessDay;
2291  })
2292  },
2293  // 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
2295  {
2296  var market = Market.NYMEX;
2298  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2299  // Monthly BALMO contracts listed for 3 consecutive months
2300  // Trading shall cease on the last business day of the contract month
2301  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2302  })
2303  },
2304  // Brent Last Day Financial (BZ): https://www.cmegroup.com/trading/energy/crude-oil/brent-crude-oil-last-day_contract_specifications.html
2306  {
2307  var market = Market.NYMEX;
2308  var symbol = Futures.Energies.BrentLastDayFinancial;
2309  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2310  // Monthly contracts listed for the current year and the next 7 calendar years and 3 additional contract months.
2311  // 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.
2312  var twoMonthsPriorToContractMonth = time.AddMonths(-2);
2313 
2314  DateTime lastBusinessDay;
2315 
2316  if (twoMonthsPriorToContractMonth.Month == 2)
2317  {
2318  lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(twoMonthsPriorToContractMonth, 1, holidays);
2319  }
2320  else
2321  {
2322  lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(twoMonthsPriorToContractMonth, 1, holidays);
2323  }
2324 
2325  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2326 
2327  return lastBusinessDay;
2328  })
2329  },
2330  // CrudeOilWTI (CL): http://www.cmegroup.com/trading/energy/crude-oil/light-sweet-crude_contract_specifications.html
2332  {
2333  var market = Market.NYMEX;
2334  var symbol = Futures.Energies.CrudeOilWTI;
2335  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2336  // Monthly contracts listed for the current year and the next 10 calendar years and 2 additional contract months.
2337  // 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.
2338  var twentyFifth = new DateTime(time.Year,time.Month,25);
2339  twentyFifth = twentyFifth.AddMonths(-1);
2340 
2341  var businessDays = -3;
2342  if(!FuturesExpiryUtilityFunctions.NotHoliday(twentyFifth, holidays))
2343  {
2344  // if the 25th is a holiday we substract 1 extra bussiness day
2345  businessDays -= 1;
2346  }
2347  return FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifth, businessDays, holidays);
2348  })
2349  },
2350  // 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
2352  {
2353  var market = Market.NYMEX;
2355  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2356  // 36 consecutive months
2357  // Trading shall cease on the last business day of the contract month.
2358  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2359  })
2360  },
2361  // 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
2363  {
2364  // Monthly contracts listed for the current year and the next 3 calendar years.
2365  // 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.
2366  // 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
2367  // of the CME group's website in order to discover the NOS dates
2368  // Publication dates are also erratic. We must maintain a separate list from MHDB in order to keep track of these days
2369  DateTime publicationDate;
2370 
2371  if (!EnbridgeNoticeOfShipmentDates.TryGetValue(time, out publicationDate))
2372  {
2373  publicationDate = new DateTime(time.Year, time.Month, 21).AddMonths(-1);
2374  }
2375  do
2376  {
2377  publicationDate = publicationDate.AddDays(-1);
2378  }
2379  while (!publicationDate.IsCommonBusinessDay());
2380 
2381  return publicationDate;
2382  })
2383  },
2384  // WTI Financial (CSX): https://www.cmegroup.com/trading/energy/crude-oil/west-texas-intermediate-wti-crude-oil-calendar-swap-futures_contract_specifications.html
2386  {
2387  var market = Market.NYMEX;
2388  var symbol = Futures.Energies.WTIFinancial;
2389  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2390  // Monthly contracts listed for the current year and the next 8 calendar years.
2391  // Trading shall cease on the last business day of the contract month
2392  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2393  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2394 
2395  return lastBusinessDay;
2396  })
2397  },
2398  // Chicago Ethanol (Platts) (CU): https://www.cmegroup.com/trading/energy/ethanol/chicago-ethanol-platts-swap_contract_specifications.html a
2400  {
2401  var market = Market.NYMEX;
2402  var symbol = Futures.Energies.ChicagoEthanolPlatts;
2403  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2404  // Monthly contracts listed for 36 consecutive months
2405  // Trading terminates on the last business day of the contract month
2406  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2407  })
2408  },
2409  // 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
2411  {
2412  var market = Market.NYMEX;
2414  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2415  // Monthly contracts listed for the current year and the next calendar year.
2416  // Trading shall cease on the last business day of the contract month
2417  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2418  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2419 
2420  return lastBusinessDay;
2421  })
2422  },
2423  // Dubai Crude Oil (Platts) Financial (DCB): https://www.cmegroup.com/trading/energy/crude-oil/dubai-crude-oil-calendar-swap-futures_contract_specifications.html
2425  {
2426  var market = Market.NYMEX;
2428  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2429  // Monthly contracts listed for the current year and the next five calendar years.
2430  // Trading shall cease on the last London and Singapore business day of the contract month
2431  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2432  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
2433 
2434  return lastBusinessDay;
2435  })
2436  },
2437  // Japan C&amp;F Naphtha (Platts) BALMO (E6): https://www.cmegroup.com/trading/energy/refined-products/japan-naphtha-balmo-swap-futures_contract_specifications.html
2439  {
2440  var market = Market.NYMEX;
2442  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2443  // Monthly BALMO contracts listed for 3 consecutive months
2444  // Trading shall cease on the last business day of the contract month.
2445  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2446  })
2447  },
2448  // Ethanol (EH): https://www.cmegroup.com/trading/energy/ethanol/cbot-ethanol_contract_specifications.html
2450  {
2451  var market = Market.CBOT;
2452  var symbol = Futures.Energies.Ethanol;
2453  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2454  // Monthly contracts listed for 36 consecutive months
2455  // Trading terminates on 3rd business day of the contract month in "ctm"
2456 
2457  return FuturesExpiryUtilityFunctions.NthBusinessDay(time, 3, holidays);
2458  })
2459  },
2460  // European Naphtha (Platts) Crack Spread (EN): https://www.cmegroup.com/trading/energy/refined-products/european-naphtha-crack-spread-swap_contract_specifications.html
2462  {
2463  // Monthly contracts listed for the current year and the next 3 calendar years
2464  // Trading ceases on the last business day of the contract month.
2465  var market = Market.NYMEX;
2467  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2468  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2469 
2470  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2471  {
2472  lastBusinessDay = lastBusinessDay.AddDays(-1);
2473  }
2474 
2475  return lastBusinessDay;
2476  })
2477  },
2478  // 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
2480  {
2481  // Monthly contracts listed for the current year and the next 3 calendar years.
2482  // Trading shall cease on the last business day of the contract month.
2483  var market = Market.NYMEX;
2485  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2486  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2487 
2488  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2489  {
2490  lastBusinessDay = lastBusinessDay.AddDays(-1);
2491  }
2492 
2493  return lastBusinessDay;
2494  })
2495  },
2496  // 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
2498  {
2499  var market = Market.NYMEX;
2501  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2502  // Monthly contracts listed for the current year and the next 5 calendar years.
2503  // Trading terminates on the last business day of the contract month.
2504  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2505 
2506  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2507  {
2508  lastBusinessDay = lastBusinessDay.AddDays(-1);
2509  }
2510 
2511  return lastBusinessDay;
2512  })
2513  },
2514  // 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
2516  {
2517  var market = Market.NYMEX;
2519  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2520  // Monthly contracts listed for 12 consecutive months
2521  // Trading shall cease on the last business day of the contract month.
2522  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2523  })
2524  },
2525  // 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
2527  {
2528  // Monthly contracts listed for 36 consecutive months
2529  // Trading terminates on the last business day of the contract month.
2530  var market = Market.NYMEX;
2532  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2533  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2534 
2535  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2536  {
2537  lastBusinessDay = lastBusinessDay.AddDays(-1);
2538  }
2539 
2540  return lastBusinessDay;
2541  })
2542  },
2543  // 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
2545  {
2546  var market = Market.NYMEX;
2548  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2549  // Monthly contracts listed for 36 consecutive months
2550  // Trading shall cease on the last business day of the contract month.
2551  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2552  })
2553  },
2554  // 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
2556  {
2557  var market = Market.NYMEX;
2559  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2560  // Monthly contracts listed for the current year and the next 4 calendar years.
2561  // Trading ceases on the last business day of the contract month.
2562  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2563 
2564  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2565  {
2566  lastBusinessDay = lastBusinessDay.AddDays(-1);
2567  }
2568 
2569  return lastBusinessDay;
2570  })
2571  },
2572  // Freight Route TC14 (Baltic) (FRC): https://www.cmegroup.com/trading/energy/freight/freight-route-tc14-baltic-futures_contract_specifications.html
2574  {
2575  var market = Market.NYMEX;
2577  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2578  // Monthly contracts listed for the current year and the next 5 consecutive years.
2579  // Trading terminates on the last business day of the contract month
2580  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2581 
2582  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2583  {
2584  lastBusinessDay = lastBusinessDay.AddDays(-1);
2585  }
2586 
2587  return lastBusinessDay;
2588  })
2589  },
2590  // 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
2592  {
2593  // Monthly contracts listed for 52 consecutive months
2594  // Trading ceases on the last business day of the contract month.
2595  var market = Market.NYMEX;
2597  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2598  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2599 
2600  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2601  {
2602  lastBusinessDay = lastBusinessDay.AddDays(-1);
2603  }
2604 
2605  return lastBusinessDay;
2606  })
2607  },
2608  // 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
2610  {
2611  var market = Market.NYMEX;
2613  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2614  // Monthly contracts listed for 36 consecutive months
2615  // Trading shall cease on the last business day of the contract month.
2616  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2617 
2618  while (holidays.Contains(lastBusinessDay) || !lastBusinessDay.IsCommonBusinessDay())
2619  {
2620  lastBusinessDay = lastBusinessDay.AddDays(-1);
2621  }
2622 
2623  return lastBusinessDay;
2624  })
2625  },
2626  // WTI Houston Crude Oil (HCL): https://www.cmegroup.com/trading/energy/crude-oil/wti-houston-crude-oil_contract_specifications.html
2628  {
2629  var market = Market.NYMEX;
2630  var symbol = Futures.Energies.WTIHoustonCrudeOil;
2631  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2632  // Monthly contracts listed through and including Dec-21
2633  // 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.
2634  var twentyFifthDayInPriorMonth = new DateTime(time.Year, time.Month, 25).AddMonths(-1);
2635  var i = 0;
2636 
2637  while (i < 3 || !twentyFifthDayInPriorMonth.IsCommonBusinessDay() || holidays.Contains(twentyFifthDayInPriorMonth))
2638  {
2639  if (twentyFifthDayInPriorMonth.IsCommonBusinessDay() &&
2640  !holidays.Contains(twentyFifthDayInPriorMonth))
2641  {
2642  i++;
2643  }
2644  twentyFifthDayInPriorMonth = twentyFifthDayInPriorMonth.AddDays(-1);
2645  }
2646 
2647  return twentyFifthDayInPriorMonth;
2648  })
2649  },
2650  // Natural Gas (Henry Hub) Last-day Financial (HH): https://www.cmegroup.com/trading/energy/natural-gas/natural-gas-last-day_contract_specifications.html
2652  {
2653  var market = Market.NYMEX;
2655  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2656  // Monthly contracts listed for the current year and the next 12 calendar years.
2657  // Trading terminates on the third last business day of the month prior to the contract month.
2658  var previousMonth = time.AddMonths(-1);
2659  previousMonth = new DateTime(previousMonth.Year, previousMonth.Month, DateTime.DaysInMonth(previousMonth.Year, previousMonth.Month));
2660 
2661  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(previousMonth, 3, holidays);
2662  })
2663  },
2664  // HeatingOil (HO): http://www.cmegroup.com/trading/energy/refined-products/heating-oil_contract_specifications.html
2666  {
2667  var market = Market.NYMEX;
2668  var symbol = Futures.Energies.HeatingOil;
2669  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2670  // Monthly contracts listed for the current year and the next 3 calendar years and 1 additional month.
2671  // Trading in a current month shall cease on the last business day of the month preceding the delivery month.
2672  var precedingMonth = time.AddMonths(-1);
2673  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(precedingMonth, 1, holidays);
2674  })
2675  },
2676  // Natural Gas (Henry Hub) Penultimate Financial (HP): https://www.cmegroup.com/trading/energy/natural-gas/natural-gas-penultimate_contract_specifications.html
2678  {
2679  var market = Market.NYMEX;
2681  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2682  // Monthly contracts listed for the current year and the next 5 calendar years.
2683  // Trading terminates on the 4th last business day of the month prior to the contract month.
2684  var previousMonth = time.AddMonths(-1);
2685 
2686  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(previousMonth, 4, holidays);
2687  })
2688  },
2689  // 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
2691  {
2692  var market = Market.NYMEX;
2694  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2695  // Monthly contracts listed for the current year and the next 3 calendar years.
2696  // 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.
2697  var twentyFifthPreviousMonth = new DateTime(time.Year, time.Month, 25).AddMonths(-1);
2698  while (holidays.Contains(twentyFifthPreviousMonth) || !FuturesExpiryUtilityFunctions.NotHoliday(twentyFifthPreviousMonth, holidays))
2699  {
2700  twentyFifthPreviousMonth = FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifthPreviousMonth, -1, holidays);
2701  }
2702 
2703  return twentyFifthPreviousMonth;
2704  })
2705  },
2706  // Gasoline (RB): http://www.cmegroup.com/trading/energy/refined-products/rbob-gasoline_contract_specifications.html
2708  {
2709  var market = Market.NYMEX;
2710  var symbol = Futures.Energies.Gasoline;
2711  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2712  // Monthly contracts listed for the current year and the next 3 calendar years and 1 additional month.
2713  // Trading in a current delivery month shall cease on the last business day of the month preceding the delivery month.
2714  var precedingMonth = time.AddMonths(-1);
2715  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(precedingMonth, 1, holidays);
2716  })
2717  },
2718  // Natural Gas (NG) : http://www.cmegroup.com/trading/energy/natural-gas/natural-gas_contract_specifications.html
2720  {
2721  var market = Market.NYMEX;
2722  var symbol = Futures.Energies.NaturalGas;
2723  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2724  // Monthly contracts listed for the current year and the next 12 calendar years.
2725  //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.
2726  var firstDay = new DateTime(time.Year,time.Month,1);
2727  return FuturesExpiryUtilityFunctions.AddBusinessDays(firstDay, -3, holidays);
2728  })
2729  },
2730  // Brent Crude (B) : https://www.theice.com/products/219/Brent-Crude-Futures
2732  {
2733  var market = Market.ICE;
2734  var symbol = Futures.Energies.BrentCrude;
2735  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2736  // Up to 96 consecutive months
2737  //Trading shall cease at the end of the designated settlement period on the last Business Day of the second month
2738  //preceding the relevant contract month (e.g. the March contract month will expire on the last Business Day of January).
2739  //If the day on which trading is due to cease would be either: (i) the Business Day preceding Christmas Day, or
2740  //(ii) the Business Day preceding New Year’s Day, then trading shall cease on the next preceding Business Day
2741  var secondPrecedingMonth = time.AddMonths(-2);
2742  var nthLastBusinessDay = secondPrecedingMonth.Month == 12 ? 2 : 1;
2743  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(secondPrecedingMonth, nthLastBusinessDay, holidays);
2744  })
2745  },
2746  // Low Sulphur Gasoil Futures (G): https://www.theice.com/products/34361119/Low-Sulphur-Gasoil-Futures
2748  {
2749  var market = Market.ICE;
2750  var symbol = Futures.Energies.LowSulfurGasoil;
2751  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2752  // Up to 96 consecutive months
2753  //Trading shall cease at 12:00 hours London Time, 2 business days prior to the 14th calendar day of the delivery month.
2754  var fourteenthDay = new DateTime(time.Year,time.Month,14);
2755  var twelfthDay = FuturesExpiryUtilityFunctions.AddBusinessDays(fourteenthDay, -2, holidays);
2756  return twelfthDay.Add(new TimeSpan(12,0,0));
2757  })
2758  },
2759  // Meats group
2760  // LiveCattle (LE): http://www.cmegroup.com/trading/agricultural/livestock/live-cattle_contract_specifications.html
2762  {
2763  var market = Market.CME;
2764  var symbol = Futures.Meats.LiveCattle;
2765  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2766  // Monthly contracts of (Feb, Apr, Jun, Aug, Oct, Dec) listed for 9 months
2767  while (!FutureExpirationCycles.GJMQVZ.Contains(time.Month))
2768  {
2769  time = time.AddMonths(1);
2770  }
2771 
2772  //Last business day of the contract month, 12:00 p.m.
2773  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
2774  return lastBusinessDay.Add(new TimeSpan(12,0,0));
2775  })
2776  },
2777  // LeanHogs (HE): http://www.cmegroup.com/trading/agricultural/livestock/lean-hogs_contract_specifications.html
2778  {Symbol.Create(Futures.Meats.LeanHogs, SecurityType.Future, Market.CME), (time =>
2779  {
2780  var market = Market.CME;
2781  var symbol = Futures.Meats.LeanHogs;
2782  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2783  /*
2784  2 monthly contracts of:
2785  Feb listed in August
2786  Apr listed in October
2787  May listed in December
2788  Jun listed in December
2789  Jul listed in February
2790  Aug listed in April
2791  Oct listed in May
2792  Dec listed in June
2793  */
2794  while (!FutureExpirationCycles.GJKMNQVZ.Contains(time.Month))
2795  {
2796  time = time.AddMonths(1);
2797  }
2798 
2799  // 10th business day of the contract month, 12:00 p.m.
2800  var lastday = new DateTime(time.Year,time.Month,1);
2801  lastday = lastday.AddDays(-1);
2802  var tenthday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastday, 10, holidays);
2803  return tenthday.Add(new TimeSpan(12,0,0));
2804  })
2805  },
2806  // FeederCattle (GF): http://www.cmegroup.com/trading/agricultural/livestock/feeder-cattle_contract_specifications.html
2808  {
2809  var market = Market.CME;
2810  var symbol = Futures.Meats.FeederCattle;
2811  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2812  // Monthly contracts of (Jan, Mar, Apr, May, Aug, Sep, Oct, Nov) listed for 8 months
2813  while (!FutureExpirationCycles.FHJKQUVX.Contains(time.Month))
2814  {
2815  time = time.AddMonths(1);
2816  }
2817 
2818  /* Trading shall terminate on the last Thursday of the contract month, except:
2819  * 1. The November contract shall terminate on the Thursday
2820  * prior to Thanksgiving Day, unless a holiday falls on
2821  * that Thursday or on any of the four weekdays prior to
2822  * that Thursday, in which case trading shall terminate on
2823  * the first prior Thursday that is not a holiday and is
2824  * not so preceded by a holiday. Weekdays shall be defined
2825  * as Monday, Tuesday, Wednesday, Thursday and Friday.
2826  * 2. Any contract month in which a holiday falls on the last
2827  * Thursday of the month or on any of the four weekdays
2828  * prior to that Thursday shall terminate on the first
2829  * prior Thursday that is not a holiday and is not so
2830  * preceded by a holiday.*/
2831  var daysInMonth = DateTime.DaysInMonth(time.Year, time.Month);
2832  // Checking condition 1
2833  if(time.Month == 11)
2834  {
2835  var priorThursday = (from day in Enumerable.Range(1, daysInMonth)
2836  where new DateTime(time.Year, time.Month, day).DayOfWeek == DayOfWeek.Thursday
2837  select new DateTime(time.Year, time.Month, day)).Reverse().ElementAt(1);
2838  while (!FuturesExpiryUtilityFunctions.NotHoliday(priorThursday, holidays) || !FuturesExpiryUtilityFunctions.NotPrecededByHoliday(priorThursday, holidays))
2839  {
2840  priorThursday = priorThursday.AddDays(-7);
2841  }
2842  return priorThursday;
2843  }
2844  // Checking Condition 2
2845  var lastThursday = (from day in Enumerable.Range(1, daysInMonth)
2846  where new DateTime(time.Year, time.Month, day).DayOfWeek == DayOfWeek.Thursday
2847  select new DateTime(time.Year, time.Month, day)).Reverse().ElementAt(0);
2848  while (!FuturesExpiryUtilityFunctions.NotHoliday(lastThursday, holidays) || !FuturesExpiryUtilityFunctions.NotPrecededByHoliday(lastThursday, holidays))
2849  {
2850  lastThursday = lastThursday.AddDays(-7);
2851  }
2852  return lastThursday;
2853  })
2854  },
2855  // Softs group
2856  // Cotton #2 (CT): https://www.theice.com/products/254/Cotton-No-2-Futures
2857  {Symbol.Create(Futures.Softs.Cotton2, SecurityType.Future, Market.ICE), (time =>
2858  {
2859  var market = Market.ICE;
2860  var symbol = Futures.Softs.Cotton2;
2861  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2862  // March, May, July, October, December
2863  while (!FutureExpirationCycles.HKNVZ.Contains(time.Month))
2864  {
2865  time = time.AddMonths(1);
2866  }
2867 
2868  // Last Trading Day:
2869  // Seventeen business days from end of spot month.
2870 
2871  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 17, holidays);
2872  })
2873  },
2874  // Orange Juice (OJ): https://www.theice.com/products/30/FCOJ-A-Futures
2876  {
2877  var market = Market.ICE;
2878  var symbol = Futures.Softs.OrangeJuice;
2879  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2880 
2881  // January, March, May, July, September, November.
2882  while (!FutureExpirationCycles.FHKNUX.Contains(time.Month))
2883  {
2884  time = time.AddMonths(1);
2885  }
2886 
2887  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 15, holidays);
2888  })
2889  },
2890  // Coffee (KC): https://www.theice.com/products/15/Coffee-C-Futures
2891  {Symbol.Create(Futures.Softs.Coffee, SecurityType.Future, Market.ICE), (time =>
2892  {
2893  var market = Market.ICE;
2894  var symbol = Futures.Softs.Coffee;
2895  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2896  // March, May, July, September, December.
2897  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
2898  {
2899  time = time.AddMonths(1);
2900  }
2901 
2902  // Last Trading Day:
2903  // One business day prior to last notice day
2904  //
2905  // Last Notice Day:
2906  // Seven business days prior to the last business day off the delivery month
2907 
2908  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 9, holidays);
2909  })
2910  },
2911  // Sugar #11 ICE (SB): https://www.theice.com/products/23/Sugar-No-11-Futures
2912  {Symbol.Create(Futures.Softs.Sugar11, SecurityType.Future, Market.ICE), (time =>
2913  {
2914  var market = Market.ICE;
2915  var symbol = Futures.Softs.Sugar11;
2916  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2917  // March, May, July and October
2918  while (!FutureExpirationCycles.HKNV.Contains(time.Month))
2919  {
2920  time = time.AddMonths(1);
2921  }
2922 
2923  // Last Trading Day:
2924  // Last business day of the month preceding the delivery month
2925 
2926  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time.AddMonths(-1), 1, holidays);
2927  })
2928  },
2929  // Sugar #11 CME (YO): https://www.cmegroup.com/trading/agricultural/softs/sugar-no11_contract_specifications.html
2931  {
2932  var market = Market.NYMEX;
2933  var symbol = Futures.Softs.Sugar11CME;
2934  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2935  // Trading is conducted in the March, May, July, and October cycle for the next 24 months.
2936  while (!FutureExpirationCycles.HKNV.Contains(time.Month))
2937  {
2938  time = time.AddMonths(1);
2939  }
2940 
2941  // 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.
2942  var precedingMonth = time.AddMonths(-1);
2943  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(precedingMonth, 1, holidays);
2944  })
2945  },
2946  // Cocoa (CC): https://www.theice.com/products/7/Cocoa-Futures
2947  {Symbol.Create(Futures.Softs.Cocoa, SecurityType.Future, Market.ICE), (time =>
2948  {
2949  var market = Market.ICE;
2950  var symbol = Futures.Softs.Cocoa;
2951  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2952  // March, May, July, September, December
2953  while (!FutureExpirationCycles.HKNUZ.Contains(time.Month))
2954  {
2955  time = time.AddMonths(1);
2956  }
2957 
2958  // Last Trading Day:
2959  // One business day prior to last notice day
2960  //
2961  // Last Notice Day:
2962  // Ten business days prior to last business day of delivery month
2963 
2964  return FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 12, holidays);
2965  })
2966  },
2967  // Dairy Group
2968  // Cash-settled Butter (CB): https://www.cmegroup.com/trading/agricultural/dairy/cash-settled-butter_contract_specifications.html
2970  {
2971  var market = Market.CME;
2972  var symbol = Futures.Dairy.CashSettledButter;
2973  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2974  // Monthly contracts listed for 24 consecutive months
2975  // 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.)
2976  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
2977  })
2978  },
2979  // Cash-Settled Cheese (CSC): https://www.cmegroup.com/trading/agricultural/dairy/cheese_contract_specifications.html
2981  {
2982  var market = Market.CME;
2983  var symbol = Futures.Dairy.CashSettledCheese;
2984  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2985  // Monthly contracts listed for 24 consecutive months
2986  // 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
2987  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
2988  })
2989  },
2990  // Class III Milk (DC): https://www.cmegroup.com/trading/agricultural/dairy/class-iii-milk_contract_specifications.html
2992  {
2993  var market = Market.CME;
2994  var symbol = Futures.Dairy.ClassIIIMilk;
2995  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
2996  // Monthly contracts listed for 24 consecutive months
2997  // 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.)
2998  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
2999  })
3000  },
3001  // Dry Whey (DY): https://www.cmegroup.com/trading/agricultural/dairy/dry-whey_contract_specifications.html
3002  {Symbol.Create(Futures.Dairy.DryWhey, SecurityType.Future, Market.CME), (time =>
3003  {
3004  var market = Market.CME;
3005  var symbol = Futures.Dairy.DryWhey;
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 Dry Whey price for that contract month. (LTD 12:10 p.m.)
3009  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
3010  })
3011  },
3012  // Class IV Milk (GDK): https://www.cmegroup.com/trading/agricultural/dairy/class-iv-milk_contract_specifications.html
3014  {
3015  var market = Market.CME;
3016  var symbol = Futures.Dairy.ClassIVMilk;
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 day on which the USDA announces the Class IV price for that contract month. (LTD 12:10 p.m.)
3020  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
3021  })
3022  },
3023  // Non-fat Dry Milk (GNF): https://www.cmegroup.com/trading/agricultural/dairy/nonfat-dry-milk_contract_specifications.html
3025  {
3026  var market = Market.CME;
3027  var symbol = Futures.Dairy.NonfatDryMilk;
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 Nonfat Dry Milk price for that contract month. (LTD 12:10 p.m.)
3031  return FuturesExpiryUtilityFunctions.DairyLastTradeDate(time, holidays);
3032  })
3033  },
3034  // Micro Gold Futures (MGC): https://www.cmegroup.com/markets/metals/precious/e-micro-gold.contractSpecs.html
3036  {
3037  var market = Market.COMEX;
3038  var symbol = Futures.Metals.MicroGold;
3039  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3040  // Monthly contracts
3041  // Trading terminates on the third last business day of the contract month.
3042  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3043  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3044 
3045  return lastBusinessDay;
3046  })
3047  },
3048  // Micro Silver Futures (SIL): https://www.cmegroup.com/markets/metals/precious/1000-oz-silver.contractSpecs.html
3050  {
3051  var market = Market.COMEX;
3052  var symbol = Futures.Metals.MicroSilver;
3053  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3054  // Monthly contracts
3055  // Trading terminates on the third last business day of the contract month.
3056  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3057  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3058 
3059  return lastBusinessDay;
3060  })
3061  },
3062  // Micro Gold TAS Futures (MGT): https://www.cmegroup.com/markets/metals/precious/e-micro-gold.contractSpecs.html
3064  {
3065  var market = Market.COMEX;
3066  var symbol = Futures.Metals.MicroGoldTAS;
3067  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3068  // Monthly contracts
3069  // Trading terminates on the third last business day of the contract month.
3070  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3071  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3072 
3073  return lastBusinessDay;
3074  })
3075  },
3076  // Micro Palladium Futures (PAM): https://www.cmegroup.com/markets/metals/precious/e-micro-palladium.contractSpecs.html
3078  {
3079  var market = Market.NYMEX;
3080  var symbol = Futures.Metals.MicroPalladium;
3081  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3082  // Monthly contracts
3083  // Trading terminates on the third last business day of the contract month.
3084  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3085  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3086 
3087  return lastBusinessDay;
3088  })
3089  },
3090  // 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
3092  {
3093  var market = Market.NYSELIFFE;
3094  var symbol = Futures.Metals.MiniNYGold;
3095  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3096  // Trading terminates on the third last business day of the contract month @13:30
3097 
3098  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3099 
3100  return lastBusinessDay.Add(new TimeSpan(13, 30, 0));
3101  })
3102  },
3103  // 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
3105  {
3106  var market = Market.NYSELIFFE;
3107  var symbol = Futures.Metals.MiniNYSilver;
3108  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3109  // Trading terminates on the third last business day of the contract month @13:25
3110 
3111  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3112 
3113  return lastBusinessDay.Add(new TimeSpan(13, 25, 0));
3114  })
3115  },
3116  // 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
3118  {
3119  var market = Market.NYSELIFFE;
3120  var symbol = Futures.Metals.Gold100Oz;
3121  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3122  // Trading terminates on the third last business day of the contract month @13:30
3123 
3124  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3125 
3126  return lastBusinessDay.Add(new TimeSpan(13, 30, 0));
3127  })
3128  },
3129  // 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
3131  {
3132  var market = Market.NYSELIFFE;
3133  var symbol = Futures.Metals.Silver5000Oz;
3134  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3135  // Trading terminates on the third last business day of the contract month @13:25
3136 
3137  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 3, holidays);
3138 
3139  return lastBusinessDay.Add(new TimeSpan(13, 25, 0));
3140  })
3141  },
3142  // Micro 10-Year Yield Futures (10Y): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-10-year-yield.contractSpecs.html
3144  {
3145  var market = Market.CBOT;
3147  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3148  // Monthly contracts
3149  // Trading terminates on the last business day of the contract month.
3150  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3151  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3152 
3153  return lastBusinessDay;
3154  })
3155  },
3156  // Micro 30-Year Yield Futures (30Y): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-30-year-yield_contract_specifications.html
3158  {
3159  var market = Market.CBOT;
3161  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3162  // Monthly contracts
3163  // Trading terminates on the last business day of the contract month.
3164  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3165  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3166 
3167  return lastBusinessDay;
3168  })
3169  },
3170  // Micro 2-Year Yield Futures (2YY): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-2-year-yield.contractSpecs.html
3172  {
3173  var market = Market.CBOT;
3174  var symbol = Futures.Financials.MicroY2TreasuryBond;
3175  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3176  // Monthly contracts
3177  // Trading terminates on the last business day of the contract month.
3178  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3179  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3180 
3181  return lastBusinessDay;
3182  })
3183  },
3184  // Micro 5-Year Yield Futures (5YY): https://www.cmegroup.com/markets/interest-rates/us-treasury/micro-5-year-yield.contractSpecs.html
3186  {
3187  var market = Market.CBOT;
3188  var symbol = Futures.Financials.MicroY5TreasuryBond;
3189  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3190  // Monthly contracts
3191  // Trading terminates on the last business day of the contract month.
3192  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3193  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3194 
3195  return lastBusinessDay;
3196  })
3197  },
3198  // Micro EUR/USD Futures (M6E): https://www.cmegroup.com/markets/fx/g10/e-micro-euro.contractSpecs.html
3200  {
3201  var market = Market.CME;
3202  var symbol = Futures.Currencies.MicroEUR;
3203  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3204  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3205  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3206  {
3207  time = time.AddMonths(1);
3208  }
3209 
3210  // Trading terminates at 9:16 a.m. CT 2 business day prior to the 3rd Wednesday of the contract quqrter.
3211  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3212  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3213  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3214 
3215  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3216  })
3217  },
3218  // Micro AUD/USD Futures (M6A): https://www.cmegroup.com/markets/fx/g10/e-micro-australian-dollar.contractSpecs.html
3220  {
3221  var market = Market.CME;
3222  var symbol = Futures.Currencies.MicroAUD;
3223  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3224  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3225  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3226  {
3227  time = time.AddMonths(1);
3228  }
3229 
3230  // On the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
3231  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3232  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3233  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3234 
3235  return secondBusinessDayPrecedingThirdWednesday;
3236  })
3237  },
3238  // Micro GBP/USD Futures (M6B): https://www.cmegroup.com/markets/fx/g10/e-micro-british-pound.contractSpecs.html
3240  {
3241  var market = Market.CME;
3242  var symbol = Futures.Currencies.MicroGBP;
3243  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3244  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3245  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3246  {
3247  time = time.AddMonths(1);
3248  }
3249 
3250  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
3251  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3252  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3253  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3254 
3255  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3256  })
3257  },
3258  // Micro CAD/USD Futures (MCD): https://www.cmegroup.com/markets/fx/g10/e-micro-canadian-dollar-us-dollar.contractSpecs.html
3260  {
3261  var market = Market.CME;
3262  var symbol = Futures.Currencies.MicroCADUSD;
3263  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3264  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3265  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3266  {
3267  time = time.AddMonths(1);
3268  }
3269 
3270  // Trading terminates 1 business day prior to the 3rd Wednesday of the contract quarter.
3271  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3272  var firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -1, holidays);
3273  firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(firstBusinessDayPrecedingThirdWednesday, -1, holidays);
3274 
3275  return firstBusinessDayPrecedingThirdWednesday;
3276  })
3277  },
3278  // Micro JPY/USD Futures (MJY): https://www.cmegroup.com/markets/fx/g10/e-micro-japanese-yen-us-dollar.contractSpecs.html
3280  {
3281  var market = Market.CME;
3282  var symbol = Futures.Currencies.MicroJPY;
3283  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3284  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3285  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3286  {
3287  time = time.AddMonths(1);
3288  }
3289 
3290  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
3291  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3292  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3293  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3294 
3295  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3296  })
3297  },
3298  // Micro CHF/USD Futures (MSF): https://www.cmegroup.com/markets/fx/g10/e-micro-swiss-franc-us-dollar.contractSpecs.html
3300  {
3301  var market = Market.CME;
3302  var symbol = Futures.Currencies.MicroCHF;
3303  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3304  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3305  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3306  {
3307  time = time.AddMonths(1);
3308  }
3309 
3310  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
3311  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3312  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3313  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3314 
3315  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3316  })
3317  },
3318  // Micro USD/JPY Futures (M6J): https://www.cmegroup.com/markets/fx/g10/micro-usd-jpy.contractSpecs.html
3320  {
3321  var market = Market.CME;
3322  var symbol = Futures.Currencies.MicroUSDJPY;
3323  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3324  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 2 consecutive quarters
3325  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3326  {
3327  time = time.AddMonths(1);
3328  }
3329 
3330  // 9:16 a.m. Central Time (CT) on the second business day immediately preceding the third Wednesday of the contract month (usually Monday).
3331  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3332  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3333  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3334 
3335  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3336  })
3337  },
3338  // Micro INR/USD Futures (MIR): https://www.cmegroup.com/markets/fx/g10/e-micro-indian-rupee.contractSpecs.html
3340  {
3341  var market = Market.CME;
3342  var symbol = Futures.Currencies.MicroINRUSD;
3343  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3344  // Monthly contracts listed for 12 consecutive months.
3345 
3346  // Trading terminates at 12:00 noon Mumbai time two Indian business days immediately preceding the last Indian
3347  // business day of the contract month.
3348 
3349  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3350  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3351 
3352  var secondBusinessDayPrecedingLastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(lastBusinessDay,-2, holidays);
3353  return secondBusinessDayPrecedingLastBusinessDay.Add(new TimeSpan(6,30,0));
3354  })
3355  },
3356  // Micro USD/CAD Futures (M6C): https://www.cmegroup.com/markets/fx/g10/micro-usd-cad.contractSpecs.html
3358  {
3359  var market = Market.CME;
3360  var symbol = Futures.Currencies.MicroCAD;
3361  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3362  // Two months in the March quarterly cycle (Mar, Jun, Sep, Dec)
3363  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3364  {
3365  time = time.AddMonths(1);
3366  }
3367 
3368  // Trading terminates at 9:16 a.m. CT, 1 business day prior to the third Wednesday of the contract month.
3369  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3370  var firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -1, holidays);
3371  firstBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(firstBusinessDayPrecedingThirdWednesday, -1, holidays);
3372 
3373  return firstBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3374  })
3375  },
3376  // Micro USD/CHF Futures (M6S): https://www.cmegroup.com/markets/fx/g10/micro-usd-chf.contractSpecs.html
3378  {
3379  var market = Market.CME;
3380  var symbol = Futures.Currencies.MicroUSDCHF;
3381  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3382  // Two months in the March quarterly cycle (Mar, Jun, Sep, Dec)
3383  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3384  {
3385  time = time.AddMonths(1);
3386  }
3387 
3388  // Trading terminates at 9:16 a.m. CT, 2 business days prior to the third Wednesday of the contract month.
3389  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3390  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday, -2, holidays);
3391  secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(secondBusinessDayPrecedingThirdWednesday, -1, holidays);
3392 
3393  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(14, 16, 0));
3394  })
3395  },
3396  // Micro USD/CNH Futures (MNH): https://www.cmegroup.com/markets/fx/g10/e-micro-cnh.contractSpecs.html
3398  {
3399  var market = Market.CME;
3400  var symbol = Futures.Currencies.MicroUSDCNH;
3401  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3402  // Monthly contracts listed for 12 consecutive months.
3403 
3404  // Trading terminates at 11:00 a.m. Hong Kong time on the second Hong Kong business day prior
3405  // to the third Wednesday of the contract month.
3406 
3407  var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(time);
3408  var secondBusinessDayPrecedingThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(thirdWednesday,-2, holidays);
3409  return secondBusinessDayPrecedingThirdWednesday.Add(new TimeSpan(3,0,0));
3410  })
3411  },
3412  // Micro E-mini S&P 500 Index Futures (MES): https://www.cmegroup.com/markets/equities/sp/micro-e-mini-sandp-500.contractSpecs.html
3414  {
3415  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
3416  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3417  {
3418  time = time.AddMonths(1);
3419  }
3420 
3421  // Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
3422  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
3423  return thirdFriday.Add(new TimeSpan(13,30,0));
3424  })
3425  },
3426  // Micro E-mini Nasdaq-100 Index Futures (MNQ): https://www.cmegroup.com/markets/equities/nasdaq/micro-e-mini-nasdaq-100.contractSpecs.html
3428  {
3429  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
3430  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3431  {
3432  time = time.AddMonths(1);
3433  }
3434 
3435  // Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
3436  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
3437  return thirdFriday.Add(new TimeSpan(13,30,0));
3438  })
3439  },
3440  // Micro E-mini Russell 2000 Index Futures (M2K): https://www.cmegroup.com/markets/equities/russell/micro-e-mini-russell-2000.contractSpecs.html
3442  {
3443  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 5 consecutive quarters
3444  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3445  {
3446  time = time.AddMonths(1);
3447  }
3448 
3449  // Trading terminates at 9:30 a.m. ET on the 3rd Friday of the contract month.
3450  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
3451  return thirdFriday.Add(new TimeSpan(13,30,0));
3452  })
3453  },
3454  // Micro E-mini Dow Jones Industrial Average Index Futures (MYM): https://www.cmegroup.com/markets/equities/dow-jones/micro-e-mini-dow.contractSpecs.html
3456  {
3457  // Quarterly contracts (Mar, Jun, Sep, Dec) listed for 4 consecutive quarters
3458  while (!FutureExpirationCycles.HMUZ.Contains(time.Month))
3459  {
3460  time = time.AddMonths(1);
3461  }
3462 
3463  // Trading can occur up to 9:30 a.m. Eastern Time (ET) on the 3rd Friday of the contract month
3464  var thirdFriday = FuturesExpiryUtilityFunctions.ThirdFriday(time);
3465  return thirdFriday.Add(new TimeSpan(13,30,0));
3466  })
3467  },
3468  // Micro WTI Crude Oil Futures (MCL): https://www.cmegroup.com/markets/energy/crude-oil/micro-wti-crude-oil.contractSpecs.html
3470  {
3471  var market = Market.NYMEX;
3472  var symbol = Futures.Energies.MicroCrudeOilWTI;
3473  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3474  // Monthly contracts listed for 12 consecutive months and additional Jun and Dec contract months
3475 
3476  // Trading terminates 4 business days prior to the 25th calendar day of the month prior to the
3477  // contract month (1 business day prior to CL LTD)
3478  // 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.
3479 
3480  var previousMonth = time.AddMonths(-1);
3481  var twentyFifthDay = new DateTime(previousMonth.Year, previousMonth.Month, 25);
3482 
3483  var businessDays = -4;
3484  if(!FuturesExpiryUtilityFunctions.NotHoliday(twentyFifthDay, holidays))
3485  {
3486  // if the 25th is a holiday we substract 1 extra bussiness day
3487  businessDays -= 1;
3488  }
3489  return FuturesExpiryUtilityFunctions.AddBusinessDays(twentyFifthDay, businessDays, holidays);
3490  })
3491  },
3492  // 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
3494  {
3495  var market = Market.NYMEX;
3497  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3498  // Monthly contracts listed for the current year and next 3 calendar years
3499  // Add monthly contracts for a new calendar year following the termination of trading in the
3500  // December contract of the current year.
3501 
3502  // Trading terminates on the last business day of the contract month.
3503  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3504  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3505 
3506  return lastBusinessDay;
3507  })
3508  },
3509  // 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
3511  {
3512  var market = Market.NYMEX;
3514  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3515  // Monthly contracts listed for 36 consecutive months
3516 
3517  // Trading terminates on the last London business day of the contract month.
3518  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3519  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3520 
3521  return lastBusinessDay;
3522  })
3523  },
3524  // 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
3526  {
3527  var market = Market.NYMEX;
3529  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3530  // Monthly contracts listed for the current year and next 3 calendar years.
3531  // Add monthly contracts for a new calendar year following the termination of trading
3532  // in the December contract of the current year.
3533 
3534  // Trading terminates on the last London business day of the contract month.
3535  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3536  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3537 
3538  return lastBusinessDay;
3539  })
3540  },
3541  // 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
3543  {
3544  var market = Market.NYMEX;
3546  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3547  // Monthly contracts listed for the current year and 5 calendar years.Monthly contracts for a new calendar
3548  // year will be added following the termination of trading in the December contract of the current year.
3549 
3550  // Trading terminates on the last business day of the contract month.
3551  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3552  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3553 
3554  return lastBusinessDay;
3555  })
3556  },
3557  // Micro Singapore Fuel Oil 380CST (Platts) Futures (MAF): https://www.cmegroup.com/markets/energy/refined-products/micro-singapore-fuel-oil-380cst-platts.contractSpecs.html
3559  {
3560  var market = Market.NYMEX;
3562  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3563  // Monthly contracts listed for the current year and 5 calendar years.Monthly contracts for a new calendar
3564  // year will be added following the termination of trading in the December contract of the current year.
3565 
3566  // Trading terminates on the last business day of the contract month.
3567  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3568  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3569 
3570  return lastBusinessDay;
3571  })
3572  },
3573  // 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
3575  {
3576  var market = Market.NYMEX;
3578  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3579  // Monthly contracts listed for the current year and the next calendar year. Monthly contracts
3580  // for a new calendar year will be added following the termination of trading in the December
3581  // contract of the current year.
3582 
3583  // Trading terminates on the last Friday of the contract month. If such Friday is a UK holiday,
3584  // trading terminates on the UK business day immediately prior to the last Friday of the contract
3585  // month unless such day is not an Exchange business day, in which case trading terminates on the
3586  // Exchange business day immediately prior.
3587 
3588  var lastFriday = FuturesExpiryUtilityFunctions.LastFriday(time);
3589 
3590  while (holidays.Contains(lastFriday))
3591  {
3592  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastFriday, -1, holidays);
3593  while (holidays.Contains(lastFriday))
3594  {
3595  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDays(lastFriday, -1, holidays);
3596  }
3597  }
3598 
3599  return lastFriday;
3600  })
3601  },
3602  // 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
3604  {
3605  var market = Market.NYMEX;
3607  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3608  // Monthly contracts listed for 36 consecutive months
3609 
3610  // Trading terminates on the last business day of the contract month.
3611  var lastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(time, 1, holidays);
3612  lastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastBusinessDay, -1, holidays);
3613 
3614  return lastBusinessDay;
3615  })
3616  },
3617  // Micro Ether Futures (MET): https://www.cmegroup.com/markets/cryptocurrencies/ether/micro-ether.contractSpecs.html
3619  {
3620  var market = Market.CME;
3621  var symbol = Futures.Currencies.MicroEther;
3622  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3623  // Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months.
3624 
3625  // Trading terminates at 4:00 p.m. London time on the last Friday of the contract month that
3626  // is either a London or U.S. business day. If the last Friday of the contract month day is
3627  // not a business day in both London and the U.S., trading terminates on the prior London or
3628  // U.S. business day.
3629 
3630  // BTIC: Trading terminates at 4:00 p.m. London time on the last Thursday of the contract month
3631  // that is either a London or U.S. business day. If the last Thursday of the contract month day
3632  // is not a business day in both London and the U.S., trading terminates on the prior London or U.S.
3633  // business day.
3634 
3635  var lastFriday = FuturesExpiryUtilityFunctions.LastFriday(time);
3636  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastFriday, -1, holidays);
3637 
3638  return lastFriday.Add(new TimeSpan(15, 0, 0));
3639  })
3640  },
3641  // Micro Bitcoin Futures (MBT): https://www.cmegroup.com/markets/cryptocurrencies/bitcoin/micro-bitcoin.contractSpecs.html
3643  {
3644  var market = Market.CME;
3645  var symbol = Futures.Currencies.MicroBTC;
3646  var holidays = FuturesExpiryUtilityFunctions.GetHolidays(market, symbol);
3647  // Monthly contracts listed for 6 consecutive months and 2 additional Dec contract months.
3648  // If the 6 consecutive months includes Dec, list only 1 additional Dec contract month.
3649 
3650  // Trading terminates at 4:00 p.m. London time on the last Friday of the contract month.
3651  // If this is not both a London and U.S. business day, trading terminates on the prior
3652  // London and the U.S. business day.
3653 
3654  // BTIC: Trading terminates at 4:00 p.m. London time on the last Thursday of the contract
3655  // month.If this is not both a London and U.S. business day, trading terminates on the prior
3656  // London and the U.S. business day.
3657 
3658  var lastFriday = FuturesExpiryUtilityFunctions.LastFriday(time);
3659  lastFriday = FuturesExpiryUtilityFunctions.AddBusinessDaysIfHoliday(lastFriday, -1, holidays);
3660 
3661  return lastFriday.Add(new TimeSpan(15, 0, 0));
3662  })
3663  }
3664  };
3665  }
3666 }