@discomedia/utils 1.0.18 → 1.0.19
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-frontend.cjs +104 -304
- package/dist/index-frontend.cjs.map +1 -1
- package/dist/index-frontend.mjs +104 -304
- package/dist/index-frontend.mjs.map +1 -1
- package/dist/index.cjs +410 -579
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +410 -579
- package/dist/index.mjs.map +1 -1
- package/dist/package.json +1 -1
- package/dist/test.js +13086 -475
- package/dist/test.js.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/market-time.d.ts +15 -154
- package/dist/types/market-time.d.ts.map +1 -1
- package/dist/types/test.d.ts +1 -1
- package/dist/types/test.d.ts.map +1 -1
- package/dist/types-frontend/index.d.ts.map +1 -1
- package/dist/types-frontend/market-time.d.ts +15 -154
- package/dist/types-frontend/market-time.d.ts.map +1 -1
- package/dist/types-frontend/test.d.ts +1 -1
- package/dist/types-frontend/test.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index-frontend.mjs
CHANGED
|
@@ -11,8 +11,6 @@ import require$$0$1 from 'buffer';
|
|
|
11
11
|
import require$$0$4 from 'fs';
|
|
12
12
|
import require$$1$1 from 'path';
|
|
13
13
|
import require$$2$1 from 'os';
|
|
14
|
-
import { startOfDay, set, endOfDay, add, sub } from 'date-fns';
|
|
15
|
-
import { toZonedTime, fromZonedTime, formatInTimeZone } from 'date-fns-tz';
|
|
16
14
|
|
|
17
15
|
var Types = /*#__PURE__*/Object.freeze({
|
|
18
16
|
__proto__: null
|
|
@@ -13479,64 +13477,90 @@ const marketEarlyCloses = {
|
|
|
13479
13477
|
},
|
|
13480
13478
|
};
|
|
13481
13479
|
|
|
13482
|
-
//
|
|
13483
|
-
// ===== CONFIGURATION =====
|
|
13484
|
-
/**
|
|
13485
|
-
* Market configuration constants
|
|
13486
|
-
*/
|
|
13480
|
+
// Constants for NY market times (Eastern Time)
|
|
13487
13481
|
const MARKET_CONFIG = {
|
|
13488
|
-
|
|
13482
|
+
UTC_OFFSET_STANDARD: -5, // EST
|
|
13483
|
+
UTC_OFFSET_DST: -4, // EDT
|
|
13489
13484
|
TIMES: {
|
|
13490
|
-
EXTENDED_START: { hour: 4, minute: 0 },
|
|
13491
13485
|
MARKET_OPEN: { hour: 9, minute: 30 },
|
|
13492
13486
|
MARKET_CLOSE: { hour: 16, minute: 0 },
|
|
13493
|
-
EARLY_CLOSE: { hour: 13, minute: 0 },
|
|
13494
|
-
EXTENDED_END: { hour: 20, minute: 0 },
|
|
13495
|
-
EARLY_EXTENDED_END: { hour: 17, minute: 0 },
|
|
13496
|
-
},
|
|
13487
|
+
EARLY_CLOSE: { hour: 13, minute: 0 }},
|
|
13497
13488
|
};
|
|
13498
|
-
//
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13489
|
+
// Helper: Get NY offset for a given UTC date (DST rules for US)
|
|
13490
|
+
function getNYOffset(date) {
|
|
13491
|
+
// US DST starts 2nd Sunday in March, ends 1st Sunday in November
|
|
13492
|
+
const year = date.getUTCFullYear();
|
|
13493
|
+
const dstStart = getNthWeekdayOfMonth(year, 3, 0, 2); // March, Sunday, 2nd
|
|
13494
|
+
const dstEnd = getNthWeekdayOfMonth(year, 11, 0, 1); // November, Sunday, 1st
|
|
13495
|
+
const utcTime = date.getTime();
|
|
13496
|
+
if (utcTime >= dstStart.getTime() && utcTime < dstEnd.getTime()) {
|
|
13497
|
+
return MARKET_CONFIG.UTC_OFFSET_DST;
|
|
13498
|
+
}
|
|
13499
|
+
return MARKET_CONFIG.UTC_OFFSET_STANDARD;
|
|
13500
|
+
}
|
|
13501
|
+
// Helper: Get nth weekday of month in UTC
|
|
13502
|
+
function getNthWeekdayOfMonth(year, month, weekday, n) {
|
|
13503
|
+
let count = 0;
|
|
13504
|
+
for (let d = 1; d <= 31; d++) {
|
|
13505
|
+
const date = new Date(Date.UTC(year, month - 1, d));
|
|
13506
|
+
if (date.getUTCMonth() !== month - 1)
|
|
13507
|
+
break;
|
|
13508
|
+
if (date.getUTCDay() === weekday) {
|
|
13509
|
+
count++;
|
|
13510
|
+
if (count === n)
|
|
13511
|
+
return date;
|
|
13512
|
+
}
|
|
13513
|
+
}
|
|
13514
|
+
// fallback: last day of month
|
|
13515
|
+
return new Date(Date.UTC(year, month - 1, 28));
|
|
13516
|
+
}
|
|
13517
|
+
// Helper: Convert UTC date to NY time (returns new Date object)
|
|
13518
|
+
function toNYTime(date) {
|
|
13519
|
+
const offset = getNYOffset(date);
|
|
13520
|
+
// NY offset in hours
|
|
13521
|
+
const utcMillis = date.getTime();
|
|
13522
|
+
const nyMillis = utcMillis + offset * 60 * 60 * 1000;
|
|
13523
|
+
return new Date(nyMillis);
|
|
13524
|
+
}
|
|
13525
|
+
// Helper: Convert NY time to UTC (returns new Date object)
|
|
13526
|
+
function fromNYTime(date) {
|
|
13527
|
+
const offset = getNYOffset(date);
|
|
13528
|
+
const nyMillis = date.getTime();
|
|
13529
|
+
const utcMillis = nyMillis - offset * 60 * 60 * 1000;
|
|
13530
|
+
return new Date(utcMillis);
|
|
13531
|
+
}
|
|
13532
|
+
// Market calendar logic
|
|
13502
13533
|
class MarketCalendar {
|
|
13503
|
-
timezone;
|
|
13504
|
-
constructor(timezone = MARKET_CONFIG.TIMEZONE) {
|
|
13505
|
-
this.timezone = timezone;
|
|
13506
|
-
}
|
|
13507
|
-
/**
|
|
13508
|
-
* Check if a date is a weekend
|
|
13509
|
-
*/
|
|
13510
13534
|
isWeekend(date) {
|
|
13511
|
-
const day = date.
|
|
13512
|
-
return day === 0 || day === 6;
|
|
13535
|
+
const day = toNYTime(date).getUTCDay();
|
|
13536
|
+
return day === 0 || day === 6;
|
|
13513
13537
|
}
|
|
13514
|
-
/**
|
|
13515
|
-
* Check if a date is a market holiday
|
|
13516
|
-
*/
|
|
13517
13538
|
isHoliday(date) {
|
|
13518
|
-
const
|
|
13519
|
-
const year =
|
|
13539
|
+
const nyDate = toNYTime(date);
|
|
13540
|
+
const year = nyDate.getUTCFullYear();
|
|
13541
|
+
const month = nyDate.getUTCMonth() + 1;
|
|
13542
|
+
const day = nyDate.getUTCDate();
|
|
13543
|
+
const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
13520
13544
|
const yearHolidays = marketHolidays[year];
|
|
13521
13545
|
if (!yearHolidays)
|
|
13522
13546
|
return false;
|
|
13523
13547
|
return Object.values(yearHolidays).some(holiday => holiday.date === formattedDate);
|
|
13524
13548
|
}
|
|
13525
|
-
/**
|
|
13526
|
-
* Check if a date is an early close day
|
|
13527
|
-
*/
|
|
13528
13549
|
isEarlyCloseDay(date) {
|
|
13529
|
-
const
|
|
13530
|
-
const year =
|
|
13550
|
+
const nyDate = toNYTime(date);
|
|
13551
|
+
const year = nyDate.getUTCFullYear();
|
|
13552
|
+
const month = nyDate.getUTCMonth() + 1;
|
|
13553
|
+
const day = nyDate.getUTCDate();
|
|
13554
|
+
const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
13531
13555
|
const yearEarlyCloses = marketEarlyCloses[year];
|
|
13532
13556
|
return yearEarlyCloses && yearEarlyCloses[formattedDate] !== undefined;
|
|
13533
13557
|
}
|
|
13534
|
-
/**
|
|
13535
|
-
* Get the early close time for a date (in minutes from midnight)
|
|
13536
|
-
*/
|
|
13537
13558
|
getEarlyCloseTime(date) {
|
|
13538
|
-
const
|
|
13539
|
-
const year =
|
|
13559
|
+
const nyDate = toNYTime(date);
|
|
13560
|
+
const year = nyDate.getUTCFullYear();
|
|
13561
|
+
const month = nyDate.getUTCMonth() + 1;
|
|
13562
|
+
const day = nyDate.getUTCDate();
|
|
13563
|
+
const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
13540
13564
|
const yearEarlyCloses = marketEarlyCloses[year];
|
|
13541
13565
|
if (yearEarlyCloses && yearEarlyCloses[formattedDate]) {
|
|
13542
13566
|
const [hours, minutes] = yearEarlyCloses[formattedDate].time.split(':').map(Number);
|
|
@@ -13544,285 +13568,61 @@ class MarketCalendar {
|
|
|
13544
13568
|
}
|
|
13545
13569
|
return null;
|
|
13546
13570
|
}
|
|
13547
|
-
/**
|
|
13548
|
-
* Check if a date is a market day (not weekend or holiday)
|
|
13549
|
-
*/
|
|
13550
13571
|
isMarketDay(date) {
|
|
13551
13572
|
return !this.isWeekend(date) && !this.isHoliday(date);
|
|
13552
13573
|
}
|
|
13553
|
-
/**
|
|
13554
|
-
* Get the next market day from a given date
|
|
13555
|
-
*/
|
|
13556
13574
|
getNextMarketDay(date) {
|
|
13557
|
-
let nextDay =
|
|
13575
|
+
let nextDay = new Date(date.getTime() + 24 * 60 * 60 * 1000);
|
|
13558
13576
|
while (!this.isMarketDay(nextDay)) {
|
|
13559
|
-
nextDay =
|
|
13577
|
+
nextDay = new Date(nextDay.getTime() + 24 * 60 * 60 * 1000);
|
|
13560
13578
|
}
|
|
13561
13579
|
return nextDay;
|
|
13562
13580
|
}
|
|
13563
|
-
/**
|
|
13564
|
-
* Get the previous market day from a given date
|
|
13565
|
-
*/
|
|
13566
13581
|
getPreviousMarketDay(date) {
|
|
13567
|
-
let prevDay =
|
|
13582
|
+
let prevDay = new Date(date.getTime() - 24 * 60 * 60 * 1000);
|
|
13568
13583
|
while (!this.isMarketDay(prevDay)) {
|
|
13569
|
-
prevDay =
|
|
13584
|
+
prevDay = new Date(prevDay.getTime() - 24 * 60 * 60 * 1000);
|
|
13570
13585
|
}
|
|
13571
13586
|
return prevDay;
|
|
13572
13587
|
}
|
|
13573
13588
|
}
|
|
13574
|
-
//
|
|
13575
|
-
|
|
13576
|
-
|
|
13577
|
-
|
|
13578
|
-
|
|
13579
|
-
|
|
13580
|
-
|
|
13581
|
-
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
|
|
13587
|
-
|
|
13588
|
-
|
|
13589
|
-
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
|
|
13593
|
-
|
|
13594
|
-
|
|
13595
|
-
|
|
13596
|
-
|
|
13597
|
-
|
|
13598
|
-
|
|
13599
|
-
|
|
13600
|
-
|
|
13601
|
-
|
|
13602
|
-
|
|
13603
|
-
|
|
13604
|
-
|
|
13605
|
-
const parts = dtf.formatToParts(date);
|
|
13606
|
-
const tz = parts.find(p => p.type === 'timeZoneName')?.value;
|
|
13607
|
-
if (!tz) {
|
|
13608
|
-
throw new Error('Could not determine New York offset');
|
|
13609
|
-
}
|
|
13610
|
-
const shortOffset = tz.replace('GMT', '');
|
|
13611
|
-
if (shortOffset === '-4') {
|
|
13612
|
-
return '-04:00';
|
|
13613
|
-
}
|
|
13614
|
-
else if (shortOffset === '-5') {
|
|
13615
|
-
return '-05:00';
|
|
13616
|
-
}
|
|
13617
|
-
else {
|
|
13618
|
-
throw new Error(`Unexpected timezone offset: ${shortOffset}`);
|
|
13619
|
-
}
|
|
13620
|
-
}
|
|
13621
|
-
/**
|
|
13622
|
-
* Get trading date in YYYY-MM-DD format
|
|
13623
|
-
*/
|
|
13624
|
-
getTradingDate(time) {
|
|
13625
|
-
let date;
|
|
13626
|
-
if (typeof time === 'number') {
|
|
13627
|
-
date = new Date(time);
|
|
13628
|
-
}
|
|
13629
|
-
else if (typeof time === 'string') {
|
|
13630
|
-
date = new Date(time);
|
|
13631
|
-
}
|
|
13632
|
-
else {
|
|
13633
|
-
date = time;
|
|
13634
|
-
}
|
|
13635
|
-
return formatInTimeZone(date, this.timezone, 'yyyy-MM-dd');
|
|
13636
|
-
}
|
|
13589
|
+
// Get last full trading date
|
|
13590
|
+
function getLastFullTradingDateImpl(currentDate = new Date()) {
|
|
13591
|
+
const calendar = new MarketCalendar();
|
|
13592
|
+
const nyDate = toNYTime(currentDate);
|
|
13593
|
+
const minutes = nyDate.getUTCHours() * 60 + nyDate.getUTCMinutes();
|
|
13594
|
+
const marketOpenMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;
|
|
13595
|
+
let marketCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
|
|
13596
|
+
if (calendar.isEarlyCloseDay(currentDate)) {
|
|
13597
|
+
marketCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
|
|
13598
|
+
}
|
|
13599
|
+
// If not a market day, or before open, or during market hours, return previous market day's close
|
|
13600
|
+
if (!calendar.isMarketDay(currentDate) || minutes < marketOpenMinutes || (minutes >= marketOpenMinutes && minutes < marketCloseMinutes)) {
|
|
13601
|
+
const prevMarketDay = calendar.getPreviousMarketDay(currentDate);
|
|
13602
|
+
let prevCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
|
|
13603
|
+
if (calendar.isEarlyCloseDay(prevMarketDay)) {
|
|
13604
|
+
prevCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
|
|
13605
|
+
}
|
|
13606
|
+
const year = prevMarketDay.getUTCFullYear();
|
|
13607
|
+
const month = prevMarketDay.getUTCMonth();
|
|
13608
|
+
const day = prevMarketDay.getUTCDate();
|
|
13609
|
+
const closeHour = Math.floor(prevCloseMinutes / 60);
|
|
13610
|
+
const closeMinute = prevCloseMinutes % 60;
|
|
13611
|
+
return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));
|
|
13612
|
+
}
|
|
13613
|
+
// After market close or after extended hours, return today's close
|
|
13614
|
+
const year = nyDate.getUTCFullYear();
|
|
13615
|
+
const month = nyDate.getUTCMonth();
|
|
13616
|
+
const day = nyDate.getUTCDate();
|
|
13617
|
+
const closeHour = Math.floor(marketCloseMinutes / 60);
|
|
13618
|
+
const closeMinute = marketCloseMinutes % 60;
|
|
13619
|
+
return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));
|
|
13637
13620
|
}
|
|
13638
|
-
// ===== MARKET TIME CALCULATOR =====
|
|
13639
13621
|
/**
|
|
13640
|
-
*
|
|
13641
|
-
*/
|
|
13642
|
-
class MarketTimeCalculator {
|
|
13643
|
-
calendar;
|
|
13644
|
-
timezone;
|
|
13645
|
-
constructor(timezone = MARKET_CONFIG.TIMEZONE) {
|
|
13646
|
-
this.timezone = timezone;
|
|
13647
|
-
this.calendar = new MarketCalendar(timezone);
|
|
13648
|
-
}
|
|
13649
|
-
/**
|
|
13650
|
-
* Get market open/close times for a date
|
|
13651
|
-
*/
|
|
13652
|
-
getMarketTimes(date) {
|
|
13653
|
-
const zonedDate = toZonedTime(date, this.timezone);
|
|
13654
|
-
// Market closed on weekends and holidays
|
|
13655
|
-
if (!this.calendar.isMarketDay(zonedDate)) {
|
|
13656
|
-
return {
|
|
13657
|
-
marketOpen: false,
|
|
13658
|
-
open: null,
|
|
13659
|
-
close: null,
|
|
13660
|
-
openExt: null,
|
|
13661
|
-
closeExt: null,
|
|
13662
|
-
};
|
|
13663
|
-
}
|
|
13664
|
-
const dayStart = startOfDay(zonedDate);
|
|
13665
|
-
// Regular market times
|
|
13666
|
-
const open = fromZonedTime(set(dayStart, { hours: MARKET_CONFIG.TIMES.MARKET_OPEN.hour, minutes: MARKET_CONFIG.TIMES.MARKET_OPEN.minute }), this.timezone);
|
|
13667
|
-
let close = fromZonedTime(set(dayStart, { hours: MARKET_CONFIG.TIMES.MARKET_CLOSE.hour, minutes: MARKET_CONFIG.TIMES.MARKET_CLOSE.minute }), this.timezone);
|
|
13668
|
-
// Extended hours
|
|
13669
|
-
const openExt = fromZonedTime(set(dayStart, { hours: MARKET_CONFIG.TIMES.EXTENDED_START.hour, minutes: MARKET_CONFIG.TIMES.EXTENDED_START.minute }), this.timezone);
|
|
13670
|
-
let closeExt = fromZonedTime(set(dayStart, { hours: MARKET_CONFIG.TIMES.EXTENDED_END.hour, minutes: MARKET_CONFIG.TIMES.EXTENDED_END.minute }), this.timezone);
|
|
13671
|
-
// Handle early close days
|
|
13672
|
-
if (this.calendar.isEarlyCloseDay(zonedDate)) {
|
|
13673
|
-
close = fromZonedTime(set(dayStart, { hours: MARKET_CONFIG.TIMES.EARLY_CLOSE.hour, minutes: MARKET_CONFIG.TIMES.EARLY_CLOSE.minute }), this.timezone);
|
|
13674
|
-
closeExt = fromZonedTime(set(dayStart, { hours: MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour, minutes: MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute }), this.timezone);
|
|
13675
|
-
}
|
|
13676
|
-
return {
|
|
13677
|
-
marketOpen: true,
|
|
13678
|
-
open,
|
|
13679
|
-
close,
|
|
13680
|
-
openExt,
|
|
13681
|
-
closeExt,
|
|
13682
|
-
};
|
|
13683
|
-
}
|
|
13684
|
-
/**
|
|
13685
|
-
* Check if a time is within market hours based on intraday reporting mode
|
|
13686
|
-
*/
|
|
13687
|
-
isWithinMarketHours(date, intradayReporting = 'market_hours') {
|
|
13688
|
-
const zonedDate = toZonedTime(date, this.timezone);
|
|
13689
|
-
// Not a market day
|
|
13690
|
-
if (!this.calendar.isMarketDay(zonedDate)) {
|
|
13691
|
-
return false;
|
|
13692
|
-
}
|
|
13693
|
-
const timeInMinutes = zonedDate.getHours() * 60 + zonedDate.getMinutes();
|
|
13694
|
-
switch (intradayReporting) {
|
|
13695
|
-
case 'extended_hours': {
|
|
13696
|
-
const startMinutes = MARKET_CONFIG.TIMES.EXTENDED_START.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_START.minute;
|
|
13697
|
-
let endMinutes = MARKET_CONFIG.TIMES.EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_END.minute;
|
|
13698
|
-
// Handle early close
|
|
13699
|
-
if (this.calendar.isEarlyCloseDay(zonedDate)) {
|
|
13700
|
-
endMinutes = MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute;
|
|
13701
|
-
}
|
|
13702
|
-
return timeInMinutes >= startMinutes && timeInMinutes <= endMinutes;
|
|
13703
|
-
}
|
|
13704
|
-
case 'continuous':
|
|
13705
|
-
return true;
|
|
13706
|
-
default: {
|
|
13707
|
-
// 'market_hours'
|
|
13708
|
-
const startMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;
|
|
13709
|
-
let endMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
|
|
13710
|
-
// Handle early close
|
|
13711
|
-
if (this.calendar.isEarlyCloseDay(zonedDate)) {
|
|
13712
|
-
endMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
|
|
13713
|
-
}
|
|
13714
|
-
return timeInMinutes >= startMinutes && timeInMinutes <= endMinutes;
|
|
13715
|
-
}
|
|
13716
|
-
}
|
|
13717
|
-
}
|
|
13718
|
-
/**
|
|
13719
|
-
* Get the last full trading date
|
|
13720
|
-
*/
|
|
13721
|
-
getLastFullTradingDate(currentDate = new Date(), extendedHours = true) {
|
|
13722
|
-
const nowET = toZonedTime(currentDate, this.timezone);
|
|
13723
|
-
if (this.calendar.isMarketDay(nowET)) {
|
|
13724
|
-
const timeInMinutes = nowET.getHours() * 60 + nowET.getMinutes();
|
|
13725
|
-
let endMinutes;
|
|
13726
|
-
if (extendedHours) {
|
|
13727
|
-
endMinutes = MARKET_CONFIG.TIMES.EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_END.minute;
|
|
13728
|
-
if (this.calendar.isEarlyCloseDay(nowET)) {
|
|
13729
|
-
endMinutes = MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute;
|
|
13730
|
-
}
|
|
13731
|
-
}
|
|
13732
|
-
else {
|
|
13733
|
-
endMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
|
|
13734
|
-
if (this.calendar.isEarlyCloseDay(nowET)) {
|
|
13735
|
-
endMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
|
|
13736
|
-
}
|
|
13737
|
-
}
|
|
13738
|
-
if (timeInMinutes >= endMinutes) {
|
|
13739
|
-
return fromZonedTime(set(nowET, { hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }), this.timezone);
|
|
13740
|
-
}
|
|
13741
|
-
}
|
|
13742
|
-
// Return the last completed trading day
|
|
13743
|
-
const lastMarketDay = this.calendar.getPreviousMarketDay(nowET);
|
|
13744
|
-
return fromZonedTime(set(lastMarketDay, { hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }), this.timezone);
|
|
13745
|
-
}
|
|
13746
|
-
/**
|
|
13747
|
-
* Get day boundaries based on intraday reporting mode
|
|
13748
|
-
*/
|
|
13749
|
-
getDayBoundaries(date, intradayReporting = 'market_hours') {
|
|
13750
|
-
const zonedDate = toZonedTime(date, this.timezone);
|
|
13751
|
-
let start;
|
|
13752
|
-
let end;
|
|
13753
|
-
switch (intradayReporting) {
|
|
13754
|
-
case 'extended_hours': {
|
|
13755
|
-
start = set(zonedDate, {
|
|
13756
|
-
hours: MARKET_CONFIG.TIMES.EXTENDED_START.hour,
|
|
13757
|
-
minutes: MARKET_CONFIG.TIMES.EXTENDED_START.minute,
|
|
13758
|
-
seconds: 0,
|
|
13759
|
-
milliseconds: 0,
|
|
13760
|
-
});
|
|
13761
|
-
end = set(zonedDate, {
|
|
13762
|
-
hours: MARKET_CONFIG.TIMES.EXTENDED_END.hour,
|
|
13763
|
-
minutes: MARKET_CONFIG.TIMES.EXTENDED_END.minute,
|
|
13764
|
-
seconds: 59,
|
|
13765
|
-
milliseconds: 999,
|
|
13766
|
-
});
|
|
13767
|
-
// Handle early close
|
|
13768
|
-
if (this.calendar.isEarlyCloseDay(zonedDate)) {
|
|
13769
|
-
end = set(zonedDate, {
|
|
13770
|
-
hours: MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour,
|
|
13771
|
-
minutes: MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute,
|
|
13772
|
-
seconds: 59,
|
|
13773
|
-
milliseconds: 999,
|
|
13774
|
-
});
|
|
13775
|
-
}
|
|
13776
|
-
break;
|
|
13777
|
-
}
|
|
13778
|
-
case 'continuous': {
|
|
13779
|
-
start = startOfDay(zonedDate);
|
|
13780
|
-
end = endOfDay(zonedDate);
|
|
13781
|
-
break;
|
|
13782
|
-
}
|
|
13783
|
-
default: {
|
|
13784
|
-
// 'market_hours'
|
|
13785
|
-
start = set(zonedDate, {
|
|
13786
|
-
hours: MARKET_CONFIG.TIMES.MARKET_OPEN.hour,
|
|
13787
|
-
minutes: MARKET_CONFIG.TIMES.MARKET_OPEN.minute,
|
|
13788
|
-
seconds: 0,
|
|
13789
|
-
milliseconds: 0,
|
|
13790
|
-
});
|
|
13791
|
-
end = set(zonedDate, {
|
|
13792
|
-
hours: MARKET_CONFIG.TIMES.MARKET_CLOSE.hour,
|
|
13793
|
-
minutes: MARKET_CONFIG.TIMES.MARKET_CLOSE.minute,
|
|
13794
|
-
seconds: 59,
|
|
13795
|
-
milliseconds: 999,
|
|
13796
|
-
});
|
|
13797
|
-
// Handle early close
|
|
13798
|
-
if (this.calendar.isEarlyCloseDay(zonedDate)) {
|
|
13799
|
-
end = set(zonedDate, {
|
|
13800
|
-
hours: MARKET_CONFIG.TIMES.EARLY_CLOSE.hour,
|
|
13801
|
-
minutes: MARKET_CONFIG.TIMES.EARLY_CLOSE.minute,
|
|
13802
|
-
seconds: 59,
|
|
13803
|
-
milliseconds: 999,
|
|
13804
|
-
});
|
|
13805
|
-
}
|
|
13806
|
-
break;
|
|
13807
|
-
}
|
|
13808
|
-
}
|
|
13809
|
-
return {
|
|
13810
|
-
start: fromZonedTime(start, this.timezone),
|
|
13811
|
-
end: fromZonedTime(end, this.timezone),
|
|
13812
|
-
};
|
|
13813
|
-
}
|
|
13814
|
-
}
|
|
13815
|
-
const marketTimeCalculator = new MarketTimeCalculator();
|
|
13816
|
-
const timeFormatter = new TimeFormatter();
|
|
13817
|
-
/**
|
|
13818
|
-
* Get the last full trading date
|
|
13622
|
+
* Returns the last full trading date as a Date object.
|
|
13819
13623
|
*/
|
|
13820
13624
|
function getLastFullTradingDate(currentDate = new Date()) {
|
|
13821
|
-
|
|
13822
|
-
return {
|
|
13823
|
-
date,
|
|
13824
|
-
YYYYMMDD: timeFormatter.getTradingDate(date),
|
|
13825
|
-
};
|
|
13625
|
+
return getLastFullTradingDateImpl(currentDate);
|
|
13826
13626
|
}
|
|
13827
13627
|
|
|
13828
13628
|
const log = (message, options = { type: 'info' }) => {
|
|
@@ -14222,8 +14022,8 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
14222
14022
|
const response = await this.getHistoricalBars({
|
|
14223
14023
|
symbols: [symbol],
|
|
14224
14024
|
timeframe: '1Day',
|
|
14225
|
-
start: prevMarketDate.
|
|
14226
|
-
end: prevMarketDate.
|
|
14025
|
+
start: prevMarketDate.toISOString(),
|
|
14026
|
+
end: prevMarketDate.toISOString(),
|
|
14227
14027
|
limit: 1,
|
|
14228
14028
|
});
|
|
14229
14029
|
if (!response.bars[symbol] || response.bars[symbol].length === 0) {
|