17 using System.Collections.Generic;
29 .ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
31 private static readonly HashSet<string> _dairyUnderlying =
new HashSet<string>
46 public static HashSet<DateTime>
GetHolidays(
string market,
string symbol)
61 public static DateTime
AddBusinessDays(DateTime time,
int n, HashSet<DateTime> holidays)
65 var businessDays = -n;
69 var previousDay = time.AddDays(-totalDays);
70 if (!holidays.Contains(previousDay.Date) && previousDay.IsCommonBusinessDay())
75 if (businessDays > 0) totalDays++;
76 }
while (businessDays > 0);
78 return time.AddDays(-totalDays);
86 var previousDay = time.AddDays(totalDays);
87 if (!holidays.Contains(previousDay.Date) && previousDay.IsCommonBusinessDay())
92 if (businessDays > 0) totalDays++;
93 }
while (businessDays > 0);
95 return time.AddDays(totalDays);
108 if (holidayList.Contains(time))
127 var daysInMonth = DateTime.DaysInMonth(time.Year, time.Month);
128 var lastDayOfMonth =
new DateTime(time.Year, time.Month, daysInMonth);
129 var holidays = holidayList.Select(x => x.Date);
133 throw new ArgumentOutOfRangeException(nameof(n), Invariant(
134 $
"Number of days ({n}) is larger than the size of month({daysInMonth})"
138 var businessDays = n;
142 var previousDay = lastDayOfMonth.AddDays(-totalDays);
143 if (
NotHoliday(previousDay, holidays) && !holidays.Contains(previousDay))
147 if (businessDays > 0) totalDays++;
148 }
while (businessDays > 0);
150 return lastDayOfMonth.AddDays(-totalDays);
160 public static DateTime
NthBusinessDay(DateTime time,
int nthBusinessDay, IEnumerable<DateTime> holidayList)
162 var daysInMonth = DateTime.DaysInMonth(time.Year, time.Month);
163 var holidays = holidayList.Select(x => x.Date);
164 if (nthBusinessDay > daysInMonth)
166 throw new ArgumentOutOfRangeException(Invariant(
167 $
"Argument nthBusinessDay (${nthBusinessDay}) is larger than the amount of days in the current month (${daysInMonth})"
170 if (nthBusinessDay < 1)
172 throw new ArgumentOutOfRangeException(Invariant(
173 $
"Argument nthBusinessDay (${nthBusinessDay}) is less than one. Provide a number greater than one and less than the days in month"
177 var calculatedTime =
new DateTime(time.Year, time.Month, 1);
179 var daysCounted = calculatedTime.IsCommonBusinessDay() ? 1 : 0;
184 while (daysCounted < nthBusinessDay || holidays.Contains(calculatedTime) || !calculatedTime.IsCommonBusinessDay())
189 if (holidays.Contains(calculatedTime))
192 if (i == 0 && calculatedTime.DayOfWeek == DayOfWeek.Friday)
197 calculatedTime = calculatedTime.AddDays(1);
199 if (i != 0 && calculatedTime.IsCommonBusinessDay())
207 calculatedTime = calculatedTime.AddDays(1);
209 if (!holidays.Contains(calculatedTime) &&
NotHoliday(calculatedTime, holidays))
216 return calculatedTime;
239 public static DateTime
NthFriday(DateTime time,
int n) =>
NthWeekday(time, n, DayOfWeek.Friday);
255 public static DateTime
NthWeekday(DateTime time,
int n, DayOfWeek dayOfWeek)
259 throw new ArgumentOutOfRangeException(nameof(n),
"'n' lower than 1 or greater than 5");
262 var daysInMonth = DateTime.DaysInMonth(time.Year, time.Month);
263 return (from day in Enumerable.Range(1, daysInMonth)
264 where
new DateTime(time.Year, time.Month, day).DayOfWeek == dayOfWeek
265 select
new DateTime(time.Year, time.Month, day)).ElementAt(n - 1);
275 public static DateTime
LastWeekday(DateTime time, DayOfWeek dayOfWeek)
278 var daysInMonth = DateTime.DaysInMonth(time.Year, time.Month);
279 return (from day in Enumerable.Range(1, daysInMonth).Reverse()
280 where
new DateTime(time.Year, time.Month, day).DayOfWeek == dayOfWeek
281 select
new DateTime(time.Year, time.Month, day)).First();
304 public static bool NotHoliday(DateTime time, IEnumerable<DateTime> holidayList)
306 return time.IsCommonBusinessDay() && !holidayList.Contains(time.Date);
317 if (thursday.DayOfWeek != DayOfWeek.Thursday)
319 throw new ArgumentException(
"Input to NotPrecededByHolidays must be a Thursday");
323 for (var i = 1; i <= 3; i++)
325 if (!
NotHoliday(thursday.AddDays(-i), holidayList))
331 if (!
NotHoliday(thursday.AddDays(-6), holidayList))
345 public static DateTime
DairyLastTradeDate(DateTime time, IEnumerable<DateTime> holidayList, TimeSpan? lastTradeTime =
null)
348 var contractMonth =
new DateTime(time.Year, time.Month, 1);
349 var lastTradeTs = lastTradeTime ??
new TimeSpan(17, 10, 0);
355 publicationDate = publicationDate.AddDays(-1);
357 while (holidayList.Contains(publicationDate) || publicationDate.DayOfWeek == DayOfWeek.Saturday);
361 publicationDate = contractMonth.AddMonths(1);
368 return publicationDate.Add(lastTradeTs);
379 if (futureExpiryDate !=
null && _dairyUnderlying.Contains(underlying))
382 var dairyReportDate = futureExpiryDate.Value.Date.AddDays(1);
383 if (_reverseDairyReportDates.ContainsKey(dairyReportDate))
385 var contractMonth = _reverseDairyReportDates[dairyReportDate];
387 return ((contractMonth.Year - dairyReportDate.Year) * 12) + contractMonth.Month - dairyReportDate.Month;
393 return ExpiriesPriorMonth.TryGetValue(underlying, out
int value) ? value : 0;
409 int h = (c - c / 4 - (8 * c + 13) / 25 + 19 * g + 15) % 30;
410 int i = h - h / 28 * (1 - h / 28 * (29 / (h + 1)) * ((21 - g) / 11));
412 int day = i - (year + year / 4 + i + 2 - c + c / 4) % 7 + 28;
421 return new DateTime(year, month, day).AddDays(-2);
424 private static readonly Dictionary<string, int> ExpiriesPriorMonth =
new Dictionary<string, int>
428 { Futures.Energy.BrentCrude, 2 },
429 { Futures.Energy.BrentLastDayFinancial, 2 },
430 { Futures.Energy.CrudeOilWTI, 1 },
431 { Futures.Energy.MicroCrudeOilWTI, 1 },
432 { Futures.Energy.Gasoline, 1 },
433 { Futures.Energy.HeatingOil, 1 },
434 { Futures.Energy.MarsArgusVsWTITradeMonth, 1 },
435 { Futures.Energy.NaturalGas, 1 },
436 { Futures.Energy.NaturalGasHenryHubLastDayFinancial, 1 },
437 { Futures.Energy.NaturalGasHenryHubPenultimateFinancial, 1 },
438 { Futures.Energy.WTIHoustonArgusVsWTITradeMonth, 1 },
439 { Futures.Energy.WTIHoustonCrudeOil, 1 },
440 { Futures.Softs.Sugar11, 1 },
441 { Futures.Softs.Sugar11CME, 1 }