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