@discomedia/utils 1.0.18 → 1.0.20
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/README.md +5 -0
- package/dist/index-frontend.cjs +162 -288
- package/dist/index-frontend.cjs.map +1 -1
- package/dist/index-frontend.mjs +162 -288
- package/dist/index-frontend.mjs.map +1 -1
- package/dist/index.cjs +610 -543
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +610 -543
- package/dist/index.mjs.map +1 -1
- package/dist/package.json +5 -9
- package/dist/test.js +17818 -445
- package/dist/test.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/market-time.d.ts +96 -138
- 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 +1 -0
- package/dist/types-frontend/index.d.ts.map +1 -1
- package/dist/types-frontend/market-time.d.ts +96 -138
- 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 +5 -9
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
|
|
@@ -249,7 +247,7 @@ const safeJSON = (text) => {
|
|
|
249
247
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
250
248
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
251
249
|
|
|
252
|
-
const VERSION = '5.10.
|
|
250
|
+
const VERSION = '5.10.2'; // x-release-please-version
|
|
253
251
|
|
|
254
252
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
255
253
|
const isRunningInBrowser = () => {
|
|
@@ -12854,7 +12852,7 @@ var config = {};
|
|
|
12854
12852
|
|
|
12855
12853
|
var main = {exports: {}};
|
|
12856
12854
|
|
|
12857
|
-
var version = "17.2.
|
|
12855
|
+
var version = "17.2.1";
|
|
12858
12856
|
var require$$4 = {
|
|
12859
12857
|
version: version};
|
|
12860
12858
|
|
|
@@ -12873,9 +12871,12 @@ function requireMain () {
|
|
|
12873
12871
|
|
|
12874
12872
|
// Array of tips to display randomly
|
|
12875
12873
|
const TIPS = [
|
|
12876
|
-
'🔐 encrypt with
|
|
12874
|
+
'🔐 encrypt with Dotenvx: https://dotenvx.com',
|
|
12877
12875
|
'🔐 prevent committing .env to code: https://dotenvx.com/precommit',
|
|
12878
12876
|
'🔐 prevent building .env in docker: https://dotenvx.com/prebuild',
|
|
12877
|
+
'📡 observe env with Radar: https://dotenvx.com/radar',
|
|
12878
|
+
'📡 auto-backup env with Radar: https://dotenvx.com/radar',
|
|
12879
|
+
'📡 version env with Radar: https://dotenvx.com/radar',
|
|
12879
12880
|
'🛠️ run anywhere with `dotenvx run -- yourcommand`',
|
|
12880
12881
|
'⚙️ specify custom .env file path with { path: \'/custom/path/.env\' }',
|
|
12881
12882
|
'⚙️ enable debug logging with { debug: true }',
|
|
@@ -13176,7 +13177,7 @@ function requireMain () {
|
|
|
13176
13177
|
}
|
|
13177
13178
|
}
|
|
13178
13179
|
|
|
13179
|
-
_log(`injecting env (${keysCount}) from ${shortPaths.join(',')} ${dim(
|
|
13180
|
+
_log(`injecting env (${keysCount}) from ${shortPaths.join(',')} ${dim(`-- tip: ${_getRandomTip()}`)}`);
|
|
13180
13181
|
}
|
|
13181
13182
|
|
|
13182
13183
|
if (lastError) {
|
|
@@ -13479,64 +13480,136 @@ const marketEarlyCloses = {
|
|
|
13479
13480
|
},
|
|
13480
13481
|
};
|
|
13481
13482
|
|
|
13482
|
-
//
|
|
13483
|
-
// ===== CONFIGURATION =====
|
|
13484
|
-
/**
|
|
13485
|
-
* Market configuration constants
|
|
13486
|
-
*/
|
|
13483
|
+
// Constants for NY market times (Eastern Time)
|
|
13487
13484
|
const MARKET_CONFIG = {
|
|
13488
|
-
|
|
13485
|
+
UTC_OFFSET_STANDARD: -5, // EST
|
|
13486
|
+
UTC_OFFSET_DST: -4, // EDT
|
|
13489
13487
|
TIMES: {
|
|
13490
|
-
EXTENDED_START: { hour: 4, minute: 0 },
|
|
13491
13488
|
MARKET_OPEN: { hour: 9, minute: 30 },
|
|
13492
13489
|
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
|
-
},
|
|
13490
|
+
EARLY_CLOSE: { hour: 13, minute: 0 }},
|
|
13497
13491
|
};
|
|
13498
|
-
//
|
|
13492
|
+
// Helper: Get NY offset for a given UTC date (DST rules for US)
|
|
13499
13493
|
/**
|
|
13500
|
-
*
|
|
13494
|
+
* Returns the NY timezone offset (in hours) for a given UTC date, accounting for US DST rules.
|
|
13495
|
+
* @param date - UTC date
|
|
13496
|
+
* @returns offset in hours (-5 for EST, -4 for EDT)
|
|
13501
13497
|
*/
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13498
|
+
function getNYOffset(date) {
|
|
13499
|
+
// US DST starts 2nd Sunday in March, ends 1st Sunday in November
|
|
13500
|
+
const year = date.getUTCFullYear();
|
|
13501
|
+
const dstStart = getNthWeekdayOfMonth(year, 3, 0, 2); // March, Sunday, 2nd
|
|
13502
|
+
const dstEnd = getNthWeekdayOfMonth(year, 11, 0, 1); // November, Sunday, 1st
|
|
13503
|
+
const utcTime = date.getTime();
|
|
13504
|
+
if (utcTime >= dstStart.getTime() && utcTime < dstEnd.getTime()) {
|
|
13505
|
+
return MARKET_CONFIG.UTC_OFFSET_DST;
|
|
13506
|
+
}
|
|
13507
|
+
return MARKET_CONFIG.UTC_OFFSET_STANDARD;
|
|
13508
|
+
}
|
|
13509
|
+
// Helper: Get nth weekday of month in UTC
|
|
13510
|
+
/**
|
|
13511
|
+
* Returns the nth weekday of a given month in UTC.
|
|
13512
|
+
* @param year - Year
|
|
13513
|
+
* @param month - 1-based month (e.g. March = 3)
|
|
13514
|
+
* @param weekday - 0=Sunday, 1=Monday, ...
|
|
13515
|
+
* @param n - nth occurrence
|
|
13516
|
+
* @returns Date object for the nth weekday
|
|
13517
|
+
*/
|
|
13518
|
+
function getNthWeekdayOfMonth(year, month, weekday, n) {
|
|
13519
|
+
let count = 0;
|
|
13520
|
+
for (let d = 1; d <= 31; d++) {
|
|
13521
|
+
const date = new Date(Date.UTC(year, month - 1, d));
|
|
13522
|
+
if (date.getUTCMonth() !== month - 1)
|
|
13523
|
+
break;
|
|
13524
|
+
if (date.getUTCDay() === weekday) {
|
|
13525
|
+
count++;
|
|
13526
|
+
if (count === n)
|
|
13527
|
+
return date;
|
|
13528
|
+
}
|
|
13506
13529
|
}
|
|
13530
|
+
// fallback: last day of month
|
|
13531
|
+
return new Date(Date.UTC(year, month - 1, 28));
|
|
13532
|
+
}
|
|
13533
|
+
// Helper: Convert UTC date to NY time (returns new Date object)
|
|
13534
|
+
/**
|
|
13535
|
+
* Converts a UTC date to NY time (returns a new Date object).
|
|
13536
|
+
* @param date - UTC date
|
|
13537
|
+
* @returns Date object in NY time
|
|
13538
|
+
*/
|
|
13539
|
+
function toNYTime(date) {
|
|
13540
|
+
const offset = getNYOffset(date);
|
|
13541
|
+
// NY offset in hours
|
|
13542
|
+
const utcMillis = date.getTime();
|
|
13543
|
+
const nyMillis = utcMillis + offset * 60 * 60 * 1000;
|
|
13544
|
+
return new Date(nyMillis);
|
|
13545
|
+
}
|
|
13546
|
+
// Helper: Convert NY time to UTC (returns new Date object)
|
|
13547
|
+
/**
|
|
13548
|
+
* Converts a NY time date to UTC (returns a new Date object).
|
|
13549
|
+
* @param date - NY time date
|
|
13550
|
+
* @returns Date object in UTC
|
|
13551
|
+
*/
|
|
13552
|
+
function fromNYTime(date) {
|
|
13553
|
+
const offset = getNYOffset(date);
|
|
13554
|
+
const nyMillis = date.getTime();
|
|
13555
|
+
const utcMillis = nyMillis - offset * 60 * 60 * 1000;
|
|
13556
|
+
return new Date(utcMillis);
|
|
13557
|
+
}
|
|
13558
|
+
// Market calendar logic
|
|
13559
|
+
/**
|
|
13560
|
+
* Market calendar logic for holidays, weekends, and market days.
|
|
13561
|
+
*/
|
|
13562
|
+
class MarketCalendar {
|
|
13507
13563
|
/**
|
|
13508
|
-
*
|
|
13564
|
+
* Checks if a date is a weekend in NY time.
|
|
13565
|
+
* @param date - Date object
|
|
13566
|
+
* @returns true if weekend, false otherwise
|
|
13509
13567
|
*/
|
|
13510
13568
|
isWeekend(date) {
|
|
13511
|
-
const day = date.
|
|
13512
|
-
return day === 0 || day === 6;
|
|
13569
|
+
const day = toNYTime(date).getUTCDay();
|
|
13570
|
+
return day === 0 || day === 6;
|
|
13513
13571
|
}
|
|
13514
13572
|
/**
|
|
13515
|
-
*
|
|
13573
|
+
* Checks if a date is a market holiday in NY time.
|
|
13574
|
+
* @param date - Date object
|
|
13575
|
+
* @returns true if holiday, false otherwise
|
|
13516
13576
|
*/
|
|
13517
13577
|
isHoliday(date) {
|
|
13518
|
-
const
|
|
13519
|
-
const year =
|
|
13578
|
+
const nyDate = toNYTime(date);
|
|
13579
|
+
const year = nyDate.getUTCFullYear();
|
|
13580
|
+
const month = nyDate.getUTCMonth() + 1;
|
|
13581
|
+
const day = nyDate.getUTCDate();
|
|
13582
|
+
const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
13520
13583
|
const yearHolidays = marketHolidays[year];
|
|
13521
13584
|
if (!yearHolidays)
|
|
13522
13585
|
return false;
|
|
13523
13586
|
return Object.values(yearHolidays).some(holiday => holiday.date === formattedDate);
|
|
13524
13587
|
}
|
|
13525
13588
|
/**
|
|
13526
|
-
*
|
|
13589
|
+
* Checks if a date is an early close day in NY time.
|
|
13590
|
+
* @param date - Date object
|
|
13591
|
+
* @returns true if early close, false otherwise
|
|
13527
13592
|
*/
|
|
13528
13593
|
isEarlyCloseDay(date) {
|
|
13529
|
-
const
|
|
13530
|
-
const year =
|
|
13594
|
+
const nyDate = toNYTime(date);
|
|
13595
|
+
const year = nyDate.getUTCFullYear();
|
|
13596
|
+
const month = nyDate.getUTCMonth() + 1;
|
|
13597
|
+
const day = nyDate.getUTCDate();
|
|
13598
|
+
const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
13531
13599
|
const yearEarlyCloses = marketEarlyCloses[year];
|
|
13532
13600
|
return yearEarlyCloses && yearEarlyCloses[formattedDate] !== undefined;
|
|
13533
13601
|
}
|
|
13534
13602
|
/**
|
|
13535
|
-
*
|
|
13603
|
+
* Gets the early close time (in minutes from midnight) for a given date.
|
|
13604
|
+
* @param date - Date object
|
|
13605
|
+
* @returns minutes from midnight or null
|
|
13536
13606
|
*/
|
|
13537
13607
|
getEarlyCloseTime(date) {
|
|
13538
|
-
const
|
|
13539
|
-
const year =
|
|
13608
|
+
const nyDate = toNYTime(date);
|
|
13609
|
+
const year = nyDate.getUTCFullYear();
|
|
13610
|
+
const month = nyDate.getUTCMonth() + 1;
|
|
13611
|
+
const day = nyDate.getUTCDate();
|
|
13612
|
+
const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
13540
13613
|
const yearEarlyCloses = marketEarlyCloses[year];
|
|
13541
13614
|
if (yearEarlyCloses && yearEarlyCloses[formattedDate]) {
|
|
13542
13615
|
const [hours, minutes] = yearEarlyCloses[formattedDate].time.split(':').map(Number);
|
|
@@ -13545,284 +13618,85 @@ class MarketCalendar {
|
|
|
13545
13618
|
return null;
|
|
13546
13619
|
}
|
|
13547
13620
|
/**
|
|
13548
|
-
*
|
|
13621
|
+
* Checks if a date is a market day (not weekend or holiday).
|
|
13622
|
+
* @param date - Date object
|
|
13623
|
+
* @returns true if market day, false otherwise
|
|
13549
13624
|
*/
|
|
13550
13625
|
isMarketDay(date) {
|
|
13551
13626
|
return !this.isWeekend(date) && !this.isHoliday(date);
|
|
13552
13627
|
}
|
|
13553
13628
|
/**
|
|
13554
|
-
*
|
|
13629
|
+
* Gets the next market day after the given date.
|
|
13630
|
+
* @param date - Date object
|
|
13631
|
+
* @returns Date object for next market day
|
|
13555
13632
|
*/
|
|
13556
13633
|
getNextMarketDay(date) {
|
|
13557
|
-
let nextDay =
|
|
13634
|
+
let nextDay = new Date(date.getTime() + 24 * 60 * 60 * 1000);
|
|
13558
13635
|
while (!this.isMarketDay(nextDay)) {
|
|
13559
|
-
nextDay =
|
|
13636
|
+
nextDay = new Date(nextDay.getTime() + 24 * 60 * 60 * 1000);
|
|
13560
13637
|
}
|
|
13561
13638
|
return nextDay;
|
|
13562
13639
|
}
|
|
13563
13640
|
/**
|
|
13564
|
-
*
|
|
13641
|
+
* Gets the previous market day before the given date.
|
|
13642
|
+
* @param date - Date object
|
|
13643
|
+
* @returns Date object for previous market day
|
|
13565
13644
|
*/
|
|
13566
13645
|
getPreviousMarketDay(date) {
|
|
13567
|
-
let prevDay =
|
|
13646
|
+
let prevDay = new Date(date.getTime() - 24 * 60 * 60 * 1000);
|
|
13568
13647
|
while (!this.isMarketDay(prevDay)) {
|
|
13569
|
-
prevDay =
|
|
13648
|
+
prevDay = new Date(prevDay.getTime() - 24 * 60 * 60 * 1000);
|
|
13570
13649
|
}
|
|
13571
13650
|
return prevDay;
|
|
13572
13651
|
}
|
|
13573
13652
|
}
|
|
13574
|
-
//
|
|
13653
|
+
// Get last full trading date
|
|
13575
13654
|
/**
|
|
13576
|
-
*
|
|
13655
|
+
* Returns the last full trading date (market close) for a given date.
|
|
13656
|
+
* @param currentDate - Date object (default: now)
|
|
13657
|
+
* @returns Date object for last full trading date
|
|
13577
13658
|
*/
|
|
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
|
-
|
|
13606
|
-
|
|
13607
|
-
|
|
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
|
-
}
|
|
13659
|
+
function getLastFullTradingDateImpl(currentDate = new Date()) {
|
|
13660
|
+
const calendar = new MarketCalendar();
|
|
13661
|
+
const nyDate = toNYTime(currentDate);
|
|
13662
|
+
const minutes = nyDate.getUTCHours() * 60 + nyDate.getUTCMinutes();
|
|
13663
|
+
const marketOpenMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;
|
|
13664
|
+
let marketCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
|
|
13665
|
+
if (calendar.isEarlyCloseDay(currentDate)) {
|
|
13666
|
+
marketCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
|
|
13667
|
+
}
|
|
13668
|
+
// If not a market day, or before open, or during market hours, return previous market day's close
|
|
13669
|
+
if (!calendar.isMarketDay(currentDate) || minutes < marketOpenMinutes || (minutes >= marketOpenMinutes && minutes < marketCloseMinutes)) {
|
|
13670
|
+
const prevMarketDay = calendar.getPreviousMarketDay(currentDate);
|
|
13671
|
+
let prevCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
|
|
13672
|
+
if (calendar.isEarlyCloseDay(prevMarketDay)) {
|
|
13673
|
+
prevCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
|
|
13674
|
+
}
|
|
13675
|
+
const year = prevMarketDay.getUTCFullYear();
|
|
13676
|
+
const month = prevMarketDay.getUTCMonth();
|
|
13677
|
+
const day = prevMarketDay.getUTCDate();
|
|
13678
|
+
const closeHour = Math.floor(prevCloseMinutes / 60);
|
|
13679
|
+
const closeMinute = prevCloseMinutes % 60;
|
|
13680
|
+
return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));
|
|
13681
|
+
}
|
|
13682
|
+
// After market close or after extended hours, return today's close
|
|
13683
|
+
const year = nyDate.getUTCFullYear();
|
|
13684
|
+
const month = nyDate.getUTCMonth();
|
|
13685
|
+
const day = nyDate.getUTCDate();
|
|
13686
|
+
const closeHour = Math.floor(marketCloseMinutes / 60);
|
|
13687
|
+
const closeMinute = marketCloseMinutes % 60;
|
|
13688
|
+
return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));
|
|
13637
13689
|
}
|
|
13638
|
-
// ===== MARKET TIME CALCULATOR =====
|
|
13639
13690
|
/**
|
|
13640
|
-
*
|
|
13691
|
+
* Returns the last full trading date as a Date object.
|
|
13641
13692
|
*/
|
|
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
13693
|
/**
|
|
13818
|
-
*
|
|
13694
|
+
* Returns the last full trading date as a Date object.
|
|
13695
|
+
* @param currentDate - Date object (default: now)
|
|
13696
|
+
* @returns Date object for last full trading date
|
|
13819
13697
|
*/
|
|
13820
13698
|
function getLastFullTradingDate(currentDate = new Date()) {
|
|
13821
|
-
|
|
13822
|
-
return {
|
|
13823
|
-
date,
|
|
13824
|
-
YYYYMMDD: timeFormatter.getTradingDate(date),
|
|
13825
|
-
};
|
|
13699
|
+
return getLastFullTradingDateImpl(currentDate);
|
|
13826
13700
|
}
|
|
13827
13701
|
|
|
13828
13702
|
const log = (message, options = { type: 'info' }) => {
|
|
@@ -14222,8 +14096,8 @@ class AlpacaMarketDataAPI extends EventEmitter {
|
|
|
14222
14096
|
const response = await this.getHistoricalBars({
|
|
14223
14097
|
symbols: [symbol],
|
|
14224
14098
|
timeframe: '1Day',
|
|
14225
|
-
start: prevMarketDate.
|
|
14226
|
-
end: prevMarketDate.
|
|
14099
|
+
start: prevMarketDate.toISOString(),
|
|
14100
|
+
end: prevMarketDate.toISOString(),
|
|
14227
14101
|
limit: 1,
|
|
14228
14102
|
});
|
|
14229
14103
|
if (!response.bars[symbol] || response.bars[symbol].length === 0) {
|