@discomedia/utils 1.0.19 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -160,6 +160,11 @@ const MARKET_CONFIG = {
160
160
  },
161
161
  };
162
162
  // Helper: Get NY offset for a given UTC date (DST rules for US)
163
+ /**
164
+ * Returns the NY timezone offset (in hours) for a given UTC date, accounting for US DST rules.
165
+ * @param date - UTC date
166
+ * @returns offset in hours (-5 for EST, -4 for EDT)
167
+ */
163
168
  function getNYOffset(date) {
164
169
  // US DST starts 2nd Sunday in March, ends 1st Sunday in November
165
170
  const year = date.getUTCFullYear();
@@ -172,6 +177,14 @@ function getNYOffset(date) {
172
177
  return MARKET_CONFIG.UTC_OFFSET_STANDARD;
173
178
  }
174
179
  // Helper: Get nth weekday of month in UTC
180
+ /**
181
+ * Returns the nth weekday of a given month in UTC.
182
+ * @param year - Year
183
+ * @param month - 1-based month (e.g. March = 3)
184
+ * @param weekday - 0=Sunday, 1=Monday, ...
185
+ * @param n - nth occurrence
186
+ * @returns Date object for the nth weekday
187
+ */
175
188
  function getNthWeekdayOfMonth(year, month, weekday, n) {
176
189
  let count = 0;
177
190
  for (let d = 1; d <= 31; d++) {
@@ -188,6 +201,11 @@ function getNthWeekdayOfMonth(year, month, weekday, n) {
188
201
  return new Date(Date.UTC(year, month - 1, 28));
189
202
  }
190
203
  // Helper: Convert UTC date to NY time (returns new Date object)
204
+ /**
205
+ * Converts a UTC date to NY time (returns a new Date object).
206
+ * @param date - UTC date
207
+ * @returns Date object in NY time
208
+ */
191
209
  function toNYTime(date) {
192
210
  const offset = getNYOffset(date);
193
211
  // NY offset in hours
@@ -196,6 +214,11 @@ function toNYTime(date) {
196
214
  return new Date(nyMillis);
197
215
  }
198
216
  // Helper: Convert NY time to UTC (returns new Date object)
217
+ /**
218
+ * Converts a NY time date to UTC (returns a new Date object).
219
+ * @param date - NY time date
220
+ * @returns Date object in UTC
221
+ */
199
222
  function fromNYTime(date) {
200
223
  const offset = getNYOffset(date);
201
224
  const nyMillis = date.getTime();
@@ -203,6 +226,12 @@ function fromNYTime(date) {
203
226
  return new Date(utcMillis);
204
227
  }
205
228
  // Helper: Format date in ISO, unix, etc.
229
+ /**
230
+ * Formats a date in ISO, unix-seconds, or unix-ms format.
231
+ * @param date - Date object
232
+ * @param outputFormat - Output format ('iso', 'unix-seconds', 'unix-ms')
233
+ * @returns Formatted date string or number
234
+ */
206
235
  function formatDate(date, outputFormat = 'iso') {
207
236
  switch (outputFormat) {
208
237
  case 'unix-seconds':
@@ -215,15 +244,33 @@ function formatDate(date, outputFormat = 'iso') {
215
244
  }
216
245
  }
217
246
  // Helper: Format date in NY locale string
247
+ /**
248
+ * Formats a date in NY locale string.
249
+ * @param date - Date object
250
+ * @returns NY locale string
251
+ */
218
252
  function formatNYLocale(date) {
219
253
  return date.toLocaleString('en-US', { timeZone: 'America/New_York' });
220
254
  }
221
255
  // Market calendar logic
256
+ /**
257
+ * Market calendar logic for holidays, weekends, and market days.
258
+ */
222
259
  class MarketCalendar {
260
+ /**
261
+ * Checks if a date is a weekend in NY time.
262
+ * @param date - Date object
263
+ * @returns true if weekend, false otherwise
264
+ */
223
265
  isWeekend(date) {
224
266
  const day = toNYTime(date).getUTCDay();
225
267
  return day === 0 || day === 6;
226
268
  }
269
+ /**
270
+ * Checks if a date is a market holiday in NY time.
271
+ * @param date - Date object
272
+ * @returns true if holiday, false otherwise
273
+ */
227
274
  isHoliday(date) {
228
275
  const nyDate = toNYTime(date);
229
276
  const year = nyDate.getUTCFullYear();
@@ -233,8 +280,13 @@ class MarketCalendar {
233
280
  const yearHolidays = marketHolidays[year];
234
281
  if (!yearHolidays)
235
282
  return false;
236
- return Object.values(yearHolidays).some(holiday => holiday.date === formattedDate);
283
+ return Object.values(yearHolidays).some((holiday) => holiday.date === formattedDate);
237
284
  }
285
+ /**
286
+ * Checks if a date is an early close day in NY time.
287
+ * @param date - Date object
288
+ * @returns true if early close, false otherwise
289
+ */
238
290
  isEarlyCloseDay(date) {
239
291
  const nyDate = toNYTime(date);
240
292
  const year = nyDate.getUTCFullYear();
@@ -244,6 +296,11 @@ class MarketCalendar {
244
296
  const yearEarlyCloses = marketEarlyCloses[year];
245
297
  return yearEarlyCloses && yearEarlyCloses[formattedDate] !== undefined;
246
298
  }
299
+ /**
300
+ * Gets the early close time (in minutes from midnight) for a given date.
301
+ * @param date - Date object
302
+ * @returns minutes from midnight or null
303
+ */
247
304
  getEarlyCloseTime(date) {
248
305
  const nyDate = toNYTime(date);
249
306
  const year = nyDate.getUTCFullYear();
@@ -257,9 +314,19 @@ class MarketCalendar {
257
314
  }
258
315
  return null;
259
316
  }
317
+ /**
318
+ * Checks if a date is a market day (not weekend or holiday).
319
+ * @param date - Date object
320
+ * @returns true if market day, false otherwise
321
+ */
260
322
  isMarketDay(date) {
261
323
  return !this.isWeekend(date) && !this.isHoliday(date);
262
324
  }
325
+ /**
326
+ * Gets the next market day after the given date.
327
+ * @param date - Date object
328
+ * @returns Date object for next market day
329
+ */
263
330
  getNextMarketDay(date) {
264
331
  let nextDay = new Date(date.getTime() + 24 * 60 * 60 * 1000);
265
332
  while (!this.isMarketDay(nextDay)) {
@@ -267,6 +334,11 @@ class MarketCalendar {
267
334
  }
268
335
  return nextDay;
269
336
  }
337
+ /**
338
+ * Gets the previous market day before the given date.
339
+ * @param date - Date object
340
+ * @returns Date object for previous market day
341
+ */
270
342
  getPreviousMarketDay(date) {
271
343
  let prevDay = new Date(date.getTime() - 24 * 60 * 60 * 1000);
272
344
  while (!this.isMarketDay(prevDay)) {
@@ -276,6 +348,11 @@ class MarketCalendar {
276
348
  }
277
349
  }
278
350
  // Market open/close times
351
+ /**
352
+ * Returns market open/close times for a given date, including extended and early closes.
353
+ * @param date - Date object
354
+ * @returns MarketOpenCloseResult
355
+ */
279
356
  function getMarketTimes(date) {
280
357
  const calendar = new MarketCalendar();
281
358
  const nyDate = toNYTime(date);
@@ -313,7 +390,13 @@ function getMarketTimes(date) {
313
390
  };
314
391
  }
315
392
  // Is within market hours
316
- function isWithinMarketHoursImpl(date, intradayReporting = 'market_hours') {
393
+ /**
394
+ * Checks if a date/time is within market hours, extended hours, or continuous.
395
+ * @param date - Date object
396
+ * @param intradayReporting - 'market_hours', 'extended_hours', or 'continuous'
397
+ * @returns true if within hours, false otherwise
398
+ */
399
+ function isWithinMarketHours(date, intradayReporting = 'market_hours') {
317
400
  const calendar = new MarketCalendar();
318
401
  if (!calendar.isMarketDay(date))
319
402
  return false;
@@ -341,6 +424,11 @@ function isWithinMarketHoursImpl(date, intradayReporting = 'market_hours') {
341
424
  }
342
425
  }
343
426
  // Get last full trading date
427
+ /**
428
+ * Returns the last full trading date (market close) for a given date.
429
+ * @param currentDate - Date object (default: now)
430
+ * @returns Date object for last full trading date
431
+ */
344
432
  function getLastFullTradingDateImpl(currentDate = new Date()) {
345
433
  const calendar = new MarketCalendar();
346
434
  const nyDate = toNYTime(currentDate);
@@ -351,7 +439,9 @@ function getLastFullTradingDateImpl(currentDate = new Date()) {
351
439
  marketCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
352
440
  }
353
441
  // If not a market day, or before open, or during market hours, return previous market day's close
354
- if (!calendar.isMarketDay(currentDate) || minutes < marketOpenMinutes || (minutes >= marketOpenMinutes && minutes < marketCloseMinutes)) {
442
+ if (!calendar.isMarketDay(currentDate) ||
443
+ minutes < marketOpenMinutes ||
444
+ (minutes >= marketOpenMinutes && minutes < marketCloseMinutes)) {
355
445
  const prevMarketDay = calendar.getPreviousMarketDay(currentDate);
356
446
  let prevCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
357
447
  if (calendar.isEarlyCloseDay(prevMarketDay)) {
@@ -373,6 +463,12 @@ function getLastFullTradingDateImpl(currentDate = new Date()) {
373
463
  return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));
374
464
  }
375
465
  // Get day boundaries
466
+ /**
467
+ * Returns the start and end boundaries for a market day, extended hours, or continuous.
468
+ * @param date - Date object
469
+ * @param intradayReporting - 'market_hours', 'extended_hours', or 'continuous'
470
+ * @returns Object with start and end Date
471
+ */
376
472
  function getDayBoundaries(date, intradayReporting = 'market_hours') {
377
473
  const calendar = new MarketCalendar();
378
474
  const nyDate = toNYTime(date);
@@ -408,6 +504,12 @@ function getDayBoundaries(date, intradayReporting = 'market_hours') {
408
504
  return { start, end };
409
505
  }
410
506
  // Period calculator
507
+ /**
508
+ * Calculates the start date for a given period ending at endDate.
509
+ * @param endDate - Date object
510
+ * @param period - Period string
511
+ * @returns Date object for period start
512
+ */
411
513
  function calculatePeriodStartDate(endDate, period) {
412
514
  const calendar = new MarketCalendar();
413
515
  let startDate;
@@ -449,8 +551,13 @@ function calculatePeriodStartDate(endDate, period) {
449
551
  return startDate;
450
552
  }
451
553
  // Get market time period
554
+ /**
555
+ * Returns the start and end dates for a market time period.
556
+ * @param params - MarketTimeParams
557
+ * @returns PeriodDates object
558
+ */
452
559
  function getMarketTimePeriod(params) {
453
- const { period, end = new Date(), intraday_reporting = 'market_hours', outputFormat = 'iso', } = params;
560
+ const { period, end = new Date(), intraday_reporting = 'market_hours', outputFormat = 'iso' } = params;
454
561
  if (!period)
455
562
  throw new Error('Period is required');
456
563
  const calendar = new MarketCalendar();
@@ -495,6 +602,11 @@ function getMarketTimePeriod(params) {
495
602
  };
496
603
  }
497
604
  // Market status
605
+ /**
606
+ * Returns the current market status for a given date.
607
+ * @param date - Date object (default: now)
608
+ * @returns MarketStatus object
609
+ */
498
610
  function getMarketStatusImpl(date = new Date()) {
499
611
  const calendar = new MarketCalendar();
500
612
  const nyDate = toNYTime(date);
@@ -508,7 +620,8 @@ function getMarketStatusImpl(date = new Date()) {
508
620
  let extendedEndMinutes = MARKET_CONFIG.TIMES.EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_END.minute;
509
621
  if (isEarlyCloseDay) {
510
622
  marketCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
511
- extendedEndMinutes = MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute;
623
+ extendedEndMinutes =
624
+ MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute;
512
625
  }
513
626
  let status;
514
627
  let nextStatus;
@@ -565,10 +678,20 @@ function getMarketStatusImpl(date = new Date()) {
565
678
  };
566
679
  }
567
680
  // API exports
681
+ /**
682
+ * Returns market open/close times for a given date.
683
+ * @param options - { date?: Date }
684
+ * @returns MarketOpenCloseResult
685
+ */
568
686
  function getMarketOpenClose(options = {}) {
569
687
  const { date = new Date() } = options;
570
688
  return getMarketTimes(date);
571
689
  }
690
+ /**
691
+ * Returns the start and end dates for a market time period as Date objects.
692
+ * @param params - MarketTimeParams
693
+ * @returns Object with start and end Date
694
+ */
572
695
  function getStartAndEndDates(params = {}) {
573
696
  const { start, end } = getMarketTimePeriod(params);
574
697
  return {
@@ -579,46 +702,103 @@ function getStartAndEndDates(params = {}) {
579
702
  /**
580
703
  * Returns the last full trading date as a Date object.
581
704
  */
705
+ /**
706
+ * Returns the last full trading date as a Date object.
707
+ * @param currentDate - Date object (default: now)
708
+ * @returns Date object for last full trading date
709
+ */
582
710
  function getLastFullTradingDate(currentDate = new Date()) {
583
711
  return getLastFullTradingDateImpl(currentDate);
584
712
  }
713
+ /**
714
+ * Returns the next market day after the reference date.
715
+ * @param referenceDate - Date object (default: now)
716
+ * @returns Object with date, yyyymmdd string, and ISO string
717
+ */
585
718
  function getNextMarketDay({ referenceDate } = {}) {
586
719
  const calendar = new MarketCalendar();
587
- const startDate = referenceDate || new Date();
720
+ const startDate = referenceDate ?? new Date();
721
+ // Find the next trading day (UTC Date object)
588
722
  const nextDate = calendar.getNextMarketDay(startDate);
589
- const yyyymmdd = `${nextDate.getUTCFullYear()}-${String(nextDate.getUTCMonth() + 1).padStart(2, '0')}-${String(nextDate.getUTCDate()).padStart(2, '0')}`;
723
+ // Convert to NY time before extracting Y-M-D parts
724
+ const nyNext = toNYTime(nextDate);
725
+ const yyyymmdd = `${nyNext.getUTCFullYear()}-${String(nyNext.getUTCMonth() + 1).padStart(2, '0')}-${String(nyNext.getUTCDate()).padStart(2, '0')}`;
590
726
  return {
591
- date: nextDate,
592
- yyyymmdd,
727
+ date: nextDate, // raw Date, unchanged
728
+ yyyymmdd, // correct trading date string
593
729
  dateISOString: nextDate.toISOString(),
594
730
  };
595
731
  }
732
+ /**
733
+ * Returns the previous market day before the reference date.
734
+ * @param referenceDate - Date object (default: now)
735
+ * @returns Object with date, yyyymmdd string, and ISO string
736
+ */
737
+ function getPreviousMarketDay({ referenceDate } = {}) {
738
+ const calendar = new MarketCalendar();
739
+ const startDate = referenceDate || new Date();
740
+ const prevDate = calendar.getPreviousMarketDay(startDate);
741
+ // convert to NY time first
742
+ const nyPrev = toNYTime(prevDate); // ← already in this file
743
+ const yyyymmdd = `${nyPrev.getUTCFullYear()}-${String(nyPrev.getUTCMonth() + 1).padStart(2, '0')}-${String(nyPrev.getUTCDate()).padStart(2, '0')}`;
744
+ return {
745
+ date: prevDate,
746
+ yyyymmdd,
747
+ dateISOString: prevDate.toISOString(),
748
+ };
749
+ }
596
750
  /**
597
751
  * Returns the trading date for a given time. Note: Just trims the date string; does not validate if the date is a market day.
598
752
  * @param time - a string, number (unix timestamp), or Date object representing the time
599
753
  * @returns the trading date as a string in YYYY-MM-DD format
600
754
  */
755
+ /**
756
+ * Returns the trading date for a given time in YYYY-MM-DD format (NY time).
757
+ * @param time - string, number, or Date
758
+ * @returns trading date string
759
+ */
601
760
  function getTradingDate(time) {
602
761
  const date = typeof time === 'number' ? new Date(time) : typeof time === 'string' ? new Date(time) : time;
603
762
  const nyDate = toNYTime(date);
604
763
  return `${nyDate.getUTCFullYear()}-${String(nyDate.getUTCMonth() + 1).padStart(2, '0')}-${String(nyDate.getUTCDate()).padStart(2, '0')}`;
605
764
  }
765
+ /**
766
+ * Returns the NY timezone offset string for a given date.
767
+ * @param date - Date object (default: now)
768
+ * @returns '-04:00' for EDT, '-05:00' for EST
769
+ */
606
770
  function getNYTimeZone(date) {
607
771
  const offset = getNYOffset(date || new Date());
608
772
  return offset === -4 ? '-04:00' : '-05:00';
609
773
  }
774
+ /**
775
+ * Returns the current market status for a given date.
776
+ * @param options - { date?: Date }
777
+ * @returns MarketStatus object
778
+ */
610
779
  function getMarketStatus(options = {}) {
611
780
  const { date = new Date() } = options;
612
781
  return getMarketStatusImpl(date);
613
782
  }
614
- function isWithinMarketHours(date, intradayReporting = 'market_hours') {
615
- return isWithinMarketHoursImpl(date, intradayReporting);
783
+ /**
784
+ * Checks if a date is a market day.
785
+ * @param date - Date object
786
+ * @returns true if market day, false otherwise
787
+ */
788
+ function isMarketDay(date) {
789
+ const calendar = new MarketCalendar();
790
+ return calendar.isMarketDay(date);
616
791
  }
617
792
  /**
618
793
  * Returns full trading days from market open to market close.
619
794
  * endDate is always the most recent market close (previous day's close if before open, today's close if after open).
620
795
  * days: 1 or not specified = that day's open; 2 = previous market day's open, etc.
621
796
  */
797
+ /**
798
+ * Returns full trading days from market open to market close.
799
+ * @param options - { endDate?: Date, days?: number }
800
+ * @returns Object with startDate and endDate
801
+ */
622
802
  function getTradingStartAndEndDates(options = {}) {
623
803
  const { endDate = new Date(), days = 1 } = options;
624
804
  const calendar = new MarketCalendar();
@@ -628,7 +808,9 @@ function getTradingStartAndEndDates(options = {}) {
628
808
  const marketOpenMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;
629
809
  const marketCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
630
810
  const minutes = nyEnd.getUTCHours() * 60 + nyEnd.getUTCMinutes();
631
- if (!calendar.isMarketDay(endDate) || minutes < marketOpenMinutes || (minutes >= marketOpenMinutes && minutes < marketCloseMinutes)) {
811
+ if (!calendar.isMarketDay(endDate) ||
812
+ minutes < marketOpenMinutes ||
813
+ (minutes >= marketOpenMinutes && minutes < marketCloseMinutes)) {
632
814
  // Before market open, not a market day, or during market hours: use previous market day
633
815
  endMarketDay = calendar.getPreviousMarketDay(endDate);
634
816
  }
@@ -654,32 +836,102 @@ function getTradingStartAndEndDates(options = {}) {
654
836
  const startOpen = getMarketOpenClose({ date: startMarketDay }).open;
655
837
  return { startDate: startOpen, endDate: endClose };
656
838
  }
839
+ /**
840
+ * Counts trading time between two dates (passed as standard Date objects), excluding weekends and holidays, and closed market hours, using other functions in this library.
841
+ *
842
+ * This function calculates the actual trading time between two dates by:
843
+ * 1. Iterating through each calendar day between startDate and endDate (inclusive)
844
+ * 2. For each day that is a market day (not weekend/holiday), getting market open/close times
845
+ * 3. Calculating the overlap between the time range and market hours for that day
846
+ * 4. Summing up all the trading minutes across all days
847
+ *
848
+ * The function automatically handles:
849
+ * - Weekends (Saturday/Sunday) - skipped entirely
850
+ * - Market holidays - skipped entirely
851
+ * - Early close days (e.g. day before holidays) - uses early close time
852
+ * - Times outside market hours - only counts time within 9:30am-4pm ET (or early close)
853
+ *
854
+ * Examples:
855
+ * - 12pm to 3:30pm same day = 3.5 hours = 210 minutes = 0.54 days
856
+ * - 9:30am to 4pm same day = 6.5 hours = 390 minutes = 1 day
857
+ * - Friday 2pm to Monday 2pm = 6.5 hours (Friday 2pm-4pm + Monday 9:30am-2pm)
858
+ *
859
+ * @param startDate - Start date/time
860
+ * @param endDate - End date/time (default: now)
861
+ * @returns Object containing:
862
+ * - days: Trading time as fraction of full trading days (6.5 hours = 1 day)
863
+ * - hours: Trading time in hours
864
+ * - minutes: Trading time in minutes
865
+ */
866
+ function countTradingDays(startDate, endDate = new Date()) {
867
+ const calendar = new MarketCalendar();
868
+ // Ensure start is before end
869
+ if (startDate.getTime() > endDate.getTime()) {
870
+ throw new Error('Start date must be before end date');
871
+ }
872
+ let totalMinutes = 0;
873
+ // Get the NY dates for iteration
874
+ const startNY = toNYTime(startDate);
875
+ const endNY = toNYTime(endDate);
876
+ // Create date at start of first day (in NY time)
877
+ const currentNY = new Date(Date.UTC(startNY.getUTCFullYear(), startNY.getUTCMonth(), startNY.getUTCDate(), 0, 0, 0, 0));
878
+ // Iterate through each calendar day
879
+ while (currentNY.getTime() <= endNY.getTime()) {
880
+ const currentUTC = fromNYTime(currentNY);
881
+ // Check if this is a market day
882
+ if (calendar.isMarketDay(currentUTC)) {
883
+ // Get market hours for this day
884
+ const marketTimes = getMarketTimes(currentUTC);
885
+ if (marketTimes.marketOpen && marketTimes.open && marketTimes.close) {
886
+ // Calculate the overlap between our time range and market hours
887
+ const dayStart = Math.max(startDate.getTime(), marketTimes.open.getTime());
888
+ const dayEnd = Math.min(endDate.getTime(), marketTimes.close.getTime());
889
+ // Only count if there's actual overlap
890
+ if (dayStart < dayEnd) {
891
+ totalMinutes += (dayEnd - dayStart) / (1000 * 60);
892
+ }
893
+ }
894
+ }
895
+ // Move to next day
896
+ currentNY.setUTCDate(currentNY.getUTCDate() + 1);
897
+ }
898
+ // Convert to days, hours, minutes
899
+ const MINUTES_PER_TRADING_DAY = 390; // 6.5 hours
900
+ const days = totalMinutes / MINUTES_PER_TRADING_DAY;
901
+ const hours = totalMinutes / 60;
902
+ const minutes = totalMinutes;
903
+ return {
904
+ days: Math.round(days * 1000) / 1000, // Round to 3 decimal places
905
+ hours: Math.round(hours * 100) / 100, // Round to 2 decimal places
906
+ minutes: Math.round(minutes),
907
+ };
908
+ }
657
909
  // Export MARKET_TIMES for compatibility
658
910
  const MARKET_TIMES = {
659
911
  TIMEZONE: MARKET_CONFIG.TIMEZONE,
660
912
  PRE: {
661
913
  START: { HOUR: 4, MINUTE: 0, MINUTES: 240 },
662
- END: { HOUR: 9, MINUTE: 30, MINUTES: 570 }
914
+ END: { HOUR: 9, MINUTE: 30, MINUTES: 570 },
663
915
  },
664
916
  EARLY_MORNING: {
665
917
  START: { HOUR: 9, MINUTE: 30, MINUTES: 570 },
666
- END: { HOUR: 10, MINUTE: 0, MINUTES: 600 }
918
+ END: { HOUR: 10, MINUTE: 0, MINUTES: 600 },
667
919
  },
668
920
  EARLY_CLOSE_BEFORE_HOLIDAY: {
669
921
  START: { HOUR: 9, MINUTE: 30, MINUTES: 570 },
670
- END: { HOUR: 13, MINUTE: 0, MINUTES: 780 }
922
+ END: { HOUR: 13, MINUTE: 0, MINUTES: 780 },
671
923
  },
672
924
  EARLY_EXTENDED_BEFORE_HOLIDAY: {
673
925
  START: { HOUR: 13, MINUTE: 0, MINUTES: 780 },
674
- END: { HOUR: 17, MINUTE: 0, MINUTES: 1020 }
926
+ END: { HOUR: 17, MINUTE: 0, MINUTES: 1020 },
675
927
  },
676
928
  REGULAR: {
677
929
  START: { HOUR: 9, MINUTE: 30, MINUTES: 570 },
678
- END: { HOUR: 16, MINUTE: 0, MINUTES: 960 }
930
+ END: { HOUR: 16, MINUTE: 0, MINUTES: 960 },
679
931
  },
680
932
  EXTENDED: {
681
933
  START: { HOUR: 4, MINUTE: 0, MINUTES: 240 },
682
- END: { HOUR: 20, MINUTE: 0, MINUTES: 1200 }
934
+ END: { HOUR: 20, MINUTE: 0, MINUTES: 1200 },
683
935
  },
684
936
  };
685
937
 
@@ -1081,6 +1333,12 @@ class Queue {
1081
1333
  current = current.next;
1082
1334
  }
1083
1335
  }
1336
+
1337
+ * drain() {
1338
+ while (this.#head) {
1339
+ yield this.dequeue();
1340
+ }
1341
+ }
1084
1342
  }
1085
1343
 
1086
1344
  function pLimit(concurrency) {
@@ -2110,7 +2368,7 @@ const safeJSON = (text) => {
2110
2368
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2111
2369
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2112
2370
 
2113
- const VERSION = '5.10.1'; // x-release-please-version
2371
+ const VERSION = '5.10.2'; // x-release-please-version
2114
2372
 
2115
2373
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2116
2374
  const isRunningInBrowser = () => {
@@ -15230,7 +15488,7 @@ var config = {};
15230
15488
 
15231
15489
  var main = {exports: {}};
15232
15490
 
15233
- var version = "17.2.0";
15491
+ var version = "17.2.1";
15234
15492
  var require$$4 = {
15235
15493
  version: version};
15236
15494
 
@@ -15249,9 +15507,12 @@ function requireMain () {
15249
15507
 
15250
15508
  // Array of tips to display randomly
15251
15509
  const TIPS = [
15252
- '🔐 encrypt with dotenvx: https://dotenvx.com',
15510
+ '🔐 encrypt with Dotenvx: https://dotenvx.com',
15253
15511
  '🔐 prevent committing .env to code: https://dotenvx.com/precommit',
15254
15512
  '🔐 prevent building .env in docker: https://dotenvx.com/prebuild',
15513
+ '📡 observe env with Radar: https://dotenvx.com/radar',
15514
+ '📡 auto-backup env with Radar: https://dotenvx.com/radar',
15515
+ '📡 version env with Radar: https://dotenvx.com/radar',
15255
15516
  '🛠️ run anywhere with `dotenvx run -- yourcommand`',
15256
15517
  '⚙️ specify custom .env file path with { path: \'/custom/path/.env\' }',
15257
15518
  '⚙️ enable debug logging with { debug: true }',
@@ -15552,7 +15813,7 @@ function requireMain () {
15552
15813
  }
15553
15814
  }
15554
15815
 
15555
- _log(`injecting env (${keysCount}) from ${shortPaths.join(',')} ${dim(`(tip: ${_getRandomTip()})`)}`);
15816
+ _log(`injecting env (${keysCount}) from ${shortPaths.join(',')} ${dim(`-- tip: ${_getRandomTip()}`)}`);
15556
15817
  }
15557
15818
 
15558
15819
  if (lastError) {
@@ -18033,10 +18294,15 @@ const disco = {
18033
18294
  getMarketOpenClose: getMarketOpenClose,
18034
18295
  getLastFullTradingDate: getLastFullTradingDate,
18035
18296
  getNextMarketDay: getNextMarketDay,
18297
+ getPreviousMarketDay: getPreviousMarketDay,
18298
+ getMarketTimePeriod: getMarketTimePeriod,
18036
18299
  getMarketStatus: getMarketStatus,
18037
18300
  getNYTimeZone: getNYTimeZone,
18038
18301
  getTradingDate: getTradingDate,
18039
18302
  getTradingStartAndEndDates: getTradingStartAndEndDates,
18303
+ isMarketDay: isMarketDay,
18304
+ isWithinMarketHours: isWithinMarketHours,
18305
+ countTradingDays: countTradingDays,
18040
18306
  MARKET_TIMES: MARKET_TIMES,
18041
18307
  },
18042
18308
  utils: {