@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/README.md
CHANGED
|
@@ -12,6 +12,11 @@ NPM repo: https://www.npmjs.com/package/@discomedia/utils
|
|
|
12
12
|
npm install @discomedia/utils
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
> **Note:**
|
|
16
|
+
> The [`tslib`](https://www.npmjs.com/package/tslib) package is required for building this library on GitHub Actions and other CI environments.
|
|
17
|
+
> It is included as a dependency because Rollup and TypeScript emit helpers that require `tslib` at build time.
|
|
18
|
+
> Do not remove `tslib` from dependencies, or CI builds will fail.
|
|
19
|
+
|
|
15
20
|
## Usage
|
|
16
21
|
|
|
17
22
|
This package provides two different entry points depending on your environment:
|
package/dist/index-frontend.cjs
CHANGED
|
@@ -13,8 +13,6 @@ var require$$0$1 = require('buffer');
|
|
|
13
13
|
var require$$0$4 = require('fs');
|
|
14
14
|
var require$$1$1 = require('path');
|
|
15
15
|
var require$$2$1 = require('os');
|
|
16
|
-
var dateFns = require('date-fns');
|
|
17
|
-
var dateFnsTz = require('date-fns-tz');
|
|
18
16
|
|
|
19
17
|
var Types = /*#__PURE__*/Object.freeze({
|
|
20
18
|
__proto__: null
|
|
@@ -251,7 +249,7 @@ const safeJSON = (text) => {
|
|
|
251
249
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
252
250
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
253
251
|
|
|
254
|
-
const VERSION = '5.10.
|
|
252
|
+
const VERSION = '5.10.2'; // x-release-please-version
|
|
255
253
|
|
|
256
254
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
257
255
|
const isRunningInBrowser = () => {
|
|
@@ -12856,7 +12854,7 @@ var config = {};
|
|
|
12856
12854
|
|
|
12857
12855
|
var main = {exports: {}};
|
|
12858
12856
|
|
|
12859
|
-
var version = "17.2.
|
|
12857
|
+
var version = "17.2.1";
|
|
12860
12858
|
var require$$4 = {
|
|
12861
12859
|
version: version};
|
|
12862
12860
|
|
|
@@ -12875,9 +12873,12 @@ function requireMain () {
|
|
|
12875
12873
|
|
|
12876
12874
|
// Array of tips to display randomly
|
|
12877
12875
|
const TIPS = [
|
|
12878
|
-
'🔐 encrypt with
|
|
12876
|
+
'🔐 encrypt with Dotenvx: https://dotenvx.com',
|
|
12879
12877
|
'🔐 prevent committing .env to code: https://dotenvx.com/precommit',
|
|
12880
12878
|
'🔐 prevent building .env in docker: https://dotenvx.com/prebuild',
|
|
12879
|
+
'📡 observe env with Radar: https://dotenvx.com/radar',
|
|
12880
|
+
'📡 auto-backup env with Radar: https://dotenvx.com/radar',
|
|
12881
|
+
'📡 version env with Radar: https://dotenvx.com/radar',
|
|
12881
12882
|
'🛠️ run anywhere with `dotenvx run -- yourcommand`',
|
|
12882
12883
|
'⚙️ specify custom .env file path with { path: \'/custom/path/.env\' }',
|
|
12883
12884
|
'⚙️ enable debug logging with { debug: true }',
|
|
@@ -13178,7 +13179,7 @@ function requireMain () {
|
|
|
13178
13179
|
}
|
|
13179
13180
|
}
|
|
13180
13181
|
|
|
13181
|
-
_log(`injecting env (${keysCount}) from ${shortPaths.join(',')} ${dim(
|
|
13182
|
+
_log(`injecting env (${keysCount}) from ${shortPaths.join(',')} ${dim(`-- tip: ${_getRandomTip()}`)}`);
|
|
13182
13183
|
}
|
|
13183
13184
|
|
|
13184
13185
|
if (lastError) {
|
|
@@ -13481,64 +13482,136 @@ const marketEarlyCloses = {
|
|
|
13481
13482
|
},
|
|
13482
13483
|
};
|
|
13483
13484
|
|
|
13484
|
-
//
|
|
13485
|
-
// ===== CONFIGURATION =====
|
|
13486
|
-
/**
|
|
13487
|
-
* Market configuration constants
|
|
13488
|
-
*/
|
|
13485
|
+
// Constants for NY market times (Eastern Time)
|
|
13489
13486
|
const MARKET_CONFIG = {
|
|
13490
|
-
|
|
13487
|
+
UTC_OFFSET_STANDARD: -5, // EST
|
|
13488
|
+
UTC_OFFSET_DST: -4, // EDT
|
|
13491
13489
|
TIMES: {
|
|
13492
|
-
EXTENDED_START: { hour: 4, minute: 0 },
|
|
13493
13490
|
MARKET_OPEN: { hour: 9, minute: 30 },
|
|
13494
13491
|
MARKET_CLOSE: { hour: 16, minute: 0 },
|
|
13495
|
-
EARLY_CLOSE: { hour: 13, minute: 0 },
|
|
13496
|
-
EXTENDED_END: { hour: 20, minute: 0 },
|
|
13497
|
-
EARLY_EXTENDED_END: { hour: 17, minute: 0 },
|
|
13498
|
-
},
|
|
13492
|
+
EARLY_CLOSE: { hour: 13, minute: 0 }},
|
|
13499
13493
|
};
|
|
13500
|
-
//
|
|
13494
|
+
// Helper: Get NY offset for a given UTC date (DST rules for US)
|
|
13501
13495
|
/**
|
|
13502
|
-
*
|
|
13496
|
+
* Returns the NY timezone offset (in hours) for a given UTC date, accounting for US DST rules.
|
|
13497
|
+
* @param date - UTC date
|
|
13498
|
+
* @returns offset in hours (-5 for EST, -4 for EDT)
|
|
13503
13499
|
*/
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13500
|
+
function getNYOffset(date) {
|
|
13501
|
+
// US DST starts 2nd Sunday in March, ends 1st Sunday in November
|
|
13502
|
+
const year = date.getUTCFullYear();
|
|
13503
|
+
const dstStart = getNthWeekdayOfMonth(year, 3, 0, 2); // March, Sunday, 2nd
|
|
13504
|
+
const dstEnd = getNthWeekdayOfMonth(year, 11, 0, 1); // November, Sunday, 1st
|
|
13505
|
+
const utcTime = date.getTime();
|
|
13506
|
+
if (utcTime >= dstStart.getTime() && utcTime < dstEnd.getTime()) {
|
|
13507
|
+
return MARKET_CONFIG.UTC_OFFSET_DST;
|
|
13508
|
+
}
|
|
13509
|
+
return MARKET_CONFIG.UTC_OFFSET_STANDARD;
|
|
13510
|
+
}
|
|
13511
|
+
// Helper: Get nth weekday of month in UTC
|
|
13512
|
+
/**
|
|
13513
|
+
* Returns the nth weekday of a given month in UTC.
|
|
13514
|
+
* @param year - Year
|
|
13515
|
+
* @param month - 1-based month (e.g. March = 3)
|
|
13516
|
+
* @param weekday - 0=Sunday, 1=Monday, ...
|
|
13517
|
+
* @param n - nth occurrence
|
|
13518
|
+
* @returns Date object for the nth weekday
|
|
13519
|
+
*/
|
|
13520
|
+
function getNthWeekdayOfMonth(year, month, weekday, n) {
|
|
13521
|
+
let count = 0;
|
|
13522
|
+
for (let d = 1; d <= 31; d++) {
|
|
13523
|
+
const date = new Date(Date.UTC(year, month - 1, d));
|
|
13524
|
+
if (date.getUTCMonth() !== month - 1)
|
|
13525
|
+
break;
|
|
13526
|
+
if (date.getUTCDay() === weekday) {
|
|
13527
|
+
count++;
|
|
13528
|
+
if (count === n)
|
|
13529
|
+
return date;
|
|
13530
|
+
}
|
|
13508
13531
|
}
|
|
13532
|
+
// fallback: last day of month
|
|
13533
|
+
return new Date(Date.UTC(year, month - 1, 28));
|
|
13534
|
+
}
|
|
13535
|
+
// Helper: Convert UTC date to NY time (returns new Date object)
|
|
13536
|
+
/**
|
|
13537
|
+
* Converts a UTC date to NY time (returns a new Date object).
|
|
13538
|
+
* @param date - UTC date
|
|
13539
|
+
* @returns Date object in NY time
|
|
13540
|
+
*/
|
|
13541
|
+
function toNYTime(date) {
|
|
13542
|
+
const offset = getNYOffset(date);
|
|
13543
|
+
// NY offset in hours
|
|
13544
|
+
const utcMillis = date.getTime();
|
|
13545
|
+
const nyMillis = utcMillis + offset * 60 * 60 * 1000;
|
|
13546
|
+
return new Date(nyMillis);
|
|
13547
|
+
}
|
|
13548
|
+
// Helper: Convert NY time to UTC (returns new Date object)
|
|
13549
|
+
/**
|
|
13550
|
+
* Converts a NY time date to UTC (returns a new Date object).
|
|
13551
|
+
* @param date - NY time date
|
|
13552
|
+
* @returns Date object in UTC
|
|
13553
|
+
*/
|
|
13554
|
+
function fromNYTime(date) {
|
|
13555
|
+
const offset = getNYOffset(date);
|
|
13556
|
+
const nyMillis = date.getTime();
|
|
13557
|
+
const utcMillis = nyMillis - offset * 60 * 60 * 1000;
|
|
13558
|
+
return new Date(utcMillis);
|
|
13559
|
+
}
|
|
13560
|
+
// Market calendar logic
|
|
13561
|
+
/**
|
|
13562
|
+
* Market calendar logic for holidays, weekends, and market days.
|
|
13563
|
+
*/
|
|
13564
|
+
class MarketCalendar {
|
|
13509
13565
|
/**
|
|
13510
|
-
*
|
|
13566
|
+
* Checks if a date is a weekend in NY time.
|
|
13567
|
+
* @param date - Date object
|
|
13568
|
+
* @returns true if weekend, false otherwise
|
|
13511
13569
|
*/
|
|
13512
13570
|
isWeekend(date) {
|
|
13513
|
-
const day = date.
|
|
13514
|
-
return day === 0 || day === 6;
|
|
13571
|
+
const day = toNYTime(date).getUTCDay();
|
|
13572
|
+
return day === 0 || day === 6;
|
|
13515
13573
|
}
|
|
13516
13574
|
/**
|
|
13517
|
-
*
|
|
13575
|
+
* Checks if a date is a market holiday in NY time.
|
|
13576
|
+
* @param date - Date object
|
|
13577
|
+
* @returns true if holiday, false otherwise
|
|
13518
13578
|
*/
|
|
13519
13579
|
isHoliday(date) {
|
|
13520
|
-
const
|
|
13521
|
-
const year =
|
|
13580
|
+
const nyDate = toNYTime(date);
|
|
13581
|
+
const year = nyDate.getUTCFullYear();
|
|
13582
|
+
const month = nyDate.getUTCMonth() + 1;
|
|
13583
|
+
const day = nyDate.getUTCDate();
|
|
13584
|
+
const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
13522
13585
|
const yearHolidays = marketHolidays[year];
|
|
13523
13586
|
if (!yearHolidays)
|
|
13524
13587
|
return false;
|
|
13525
13588
|
return Object.values(yearHolidays).some(holiday => holiday.date === formattedDate);
|
|
13526
13589
|
}
|
|
13527
13590
|
/**
|
|
13528
|
-
*
|
|
13591
|
+
* Checks if a date is an early close day in NY time.
|
|
13592
|
+
* @param date - Date object
|
|
13593
|
+
* @returns true if early close, false otherwise
|
|
13529
13594
|
*/
|
|
13530
13595
|
isEarlyCloseDay(date) {
|
|
13531
|
-
const
|
|
13532
|
-
const year =
|
|
13596
|
+
const nyDate = toNYTime(date);
|
|
13597
|
+
const year = nyDate.getUTCFullYear();
|
|
13598
|
+
const month = nyDate.getUTCMonth() + 1;
|
|
13599
|
+
const day = nyDate.getUTCDate();
|
|
13600
|
+
const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
13533
13601
|
const yearEarlyCloses = marketEarlyCloses[year];
|
|
13534
13602
|
return yearEarlyCloses && yearEarlyCloses[formattedDate] !== undefined;
|
|
13535
13603
|
}
|
|
13536
13604
|
/**
|
|
13537
|
-
*
|
|
13605
|
+
* Gets the early close time (in minutes from midnight) for a given date.
|
|
13606
|
+
* @param date - Date object
|
|
13607
|
+
* @returns minutes from midnight or null
|
|
13538
13608
|
*/
|
|
13539
13609
|
getEarlyCloseTime(date) {
|
|
13540
|
-
const
|
|
13541
|
-
const year =
|
|
13610
|
+
const nyDate = toNYTime(date);
|
|
13611
|
+
const year = nyDate.getUTCFullYear();
|
|
13612
|
+
const month = nyDate.getUTCMonth() + 1;
|
|
13613
|
+
const day = nyDate.getUTCDate();
|
|
13614
|
+
const formattedDate = `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
13542
13615
|
const yearEarlyCloses = marketEarlyCloses[year];
|
|
13543
13616
|
if (yearEarlyCloses && yearEarlyCloses[formattedDate]) {
|
|
13544
13617
|
const [hours, minutes] = yearEarlyCloses[formattedDate].time.split(':').map(Number);
|
|
@@ -13547,284 +13620,85 @@ class MarketCalendar {
|
|
|
13547
13620
|
return null;
|
|
13548
13621
|
}
|
|
13549
13622
|
/**
|
|
13550
|
-
*
|
|
13623
|
+
* Checks if a date is a market day (not weekend or holiday).
|
|
13624
|
+
* @param date - Date object
|
|
13625
|
+
* @returns true if market day, false otherwise
|
|
13551
13626
|
*/
|
|
13552
13627
|
isMarketDay(date) {
|
|
13553
13628
|
return !this.isWeekend(date) && !this.isHoliday(date);
|
|
13554
13629
|
}
|
|
13555
13630
|
/**
|
|
13556
|
-
*
|
|
13631
|
+
* Gets the next market day after the given date.
|
|
13632
|
+
* @param date - Date object
|
|
13633
|
+
* @returns Date object for next market day
|
|
13557
13634
|
*/
|
|
13558
13635
|
getNextMarketDay(date) {
|
|
13559
|
-
let nextDay =
|
|
13636
|
+
let nextDay = new Date(date.getTime() + 24 * 60 * 60 * 1000);
|
|
13560
13637
|
while (!this.isMarketDay(nextDay)) {
|
|
13561
|
-
nextDay =
|
|
13638
|
+
nextDay = new Date(nextDay.getTime() + 24 * 60 * 60 * 1000);
|
|
13562
13639
|
}
|
|
13563
13640
|
return nextDay;
|
|
13564
13641
|
}
|
|
13565
13642
|
/**
|
|
13566
|
-
*
|
|
13643
|
+
* Gets the previous market day before the given date.
|
|
13644
|
+
* @param date - Date object
|
|
13645
|
+
* @returns Date object for previous market day
|
|
13567
13646
|
*/
|
|
13568
13647
|
getPreviousMarketDay(date) {
|
|
13569
|
-
let prevDay =
|
|
13648
|
+
let prevDay = new Date(date.getTime() - 24 * 60 * 60 * 1000);
|
|
13570
13649
|
while (!this.isMarketDay(prevDay)) {
|
|
13571
|
-
prevDay =
|
|
13650
|
+
prevDay = new Date(prevDay.getTime() - 24 * 60 * 60 * 1000);
|
|
13572
13651
|
}
|
|
13573
13652
|
return prevDay;
|
|
13574
13653
|
}
|
|
13575
13654
|
}
|
|
13576
|
-
//
|
|
13655
|
+
// Get last full trading date
|
|
13577
13656
|
/**
|
|
13578
|
-
*
|
|
13657
|
+
* Returns the last full trading date (market close) for a given date.
|
|
13658
|
+
* @param currentDate - Date object (default: now)
|
|
13659
|
+
* @returns Date object for last full trading date
|
|
13579
13660
|
*/
|
|
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
|
-
|
|
13609
|
-
|
|
13610
|
-
throw new Error('Could not determine New York offset');
|
|
13611
|
-
}
|
|
13612
|
-
const shortOffset = tz.replace('GMT', '');
|
|
13613
|
-
if (shortOffset === '-4') {
|
|
13614
|
-
return '-04:00';
|
|
13615
|
-
}
|
|
13616
|
-
else if (shortOffset === '-5') {
|
|
13617
|
-
return '-05:00';
|
|
13618
|
-
}
|
|
13619
|
-
else {
|
|
13620
|
-
throw new Error(`Unexpected timezone offset: ${shortOffset}`);
|
|
13621
|
-
}
|
|
13622
|
-
}
|
|
13623
|
-
/**
|
|
13624
|
-
* Get trading date in YYYY-MM-DD format
|
|
13625
|
-
*/
|
|
13626
|
-
getTradingDate(time) {
|
|
13627
|
-
let date;
|
|
13628
|
-
if (typeof time === 'number') {
|
|
13629
|
-
date = new Date(time);
|
|
13630
|
-
}
|
|
13631
|
-
else if (typeof time === 'string') {
|
|
13632
|
-
date = new Date(time);
|
|
13633
|
-
}
|
|
13634
|
-
else {
|
|
13635
|
-
date = time;
|
|
13636
|
-
}
|
|
13637
|
-
return dateFnsTz.formatInTimeZone(date, this.timezone, 'yyyy-MM-dd');
|
|
13638
|
-
}
|
|
13661
|
+
function getLastFullTradingDateImpl(currentDate = new Date()) {
|
|
13662
|
+
const calendar = new MarketCalendar();
|
|
13663
|
+
const nyDate = toNYTime(currentDate);
|
|
13664
|
+
const minutes = nyDate.getUTCHours() * 60 + nyDate.getUTCMinutes();
|
|
13665
|
+
const marketOpenMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;
|
|
13666
|
+
let marketCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
|
|
13667
|
+
if (calendar.isEarlyCloseDay(currentDate)) {
|
|
13668
|
+
marketCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
|
|
13669
|
+
}
|
|
13670
|
+
// If not a market day, or before open, or during market hours, return previous market day's close
|
|
13671
|
+
if (!calendar.isMarketDay(currentDate) || minutes < marketOpenMinutes || (minutes >= marketOpenMinutes && minutes < marketCloseMinutes)) {
|
|
13672
|
+
const prevMarketDay = calendar.getPreviousMarketDay(currentDate);
|
|
13673
|
+
let prevCloseMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
|
|
13674
|
+
if (calendar.isEarlyCloseDay(prevMarketDay)) {
|
|
13675
|
+
prevCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
|
|
13676
|
+
}
|
|
13677
|
+
const year = prevMarketDay.getUTCFullYear();
|
|
13678
|
+
const month = prevMarketDay.getUTCMonth();
|
|
13679
|
+
const day = prevMarketDay.getUTCDate();
|
|
13680
|
+
const closeHour = Math.floor(prevCloseMinutes / 60);
|
|
13681
|
+
const closeMinute = prevCloseMinutes % 60;
|
|
13682
|
+
return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));
|
|
13683
|
+
}
|
|
13684
|
+
// After market close or after extended hours, return today's close
|
|
13685
|
+
const year = nyDate.getUTCFullYear();
|
|
13686
|
+
const month = nyDate.getUTCMonth();
|
|
13687
|
+
const day = nyDate.getUTCDate();
|
|
13688
|
+
const closeHour = Math.floor(marketCloseMinutes / 60);
|
|
13689
|
+
const closeMinute = marketCloseMinutes % 60;
|
|
13690
|
+
return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));
|
|
13639
13691
|
}
|
|
13640
|
-
// ===== MARKET TIME CALCULATOR =====
|
|
13641
13692
|
/**
|
|
13642
|
-
*
|
|
13693
|
+
* Returns the last full trading date as a Date object.
|
|
13643
13694
|
*/
|
|
13644
|
-
class MarketTimeCalculator {
|
|
13645
|
-
calendar;
|
|
13646
|
-
timezone;
|
|
13647
|
-
constructor(timezone = MARKET_CONFIG.TIMEZONE) {
|
|
13648
|
-
this.timezone = timezone;
|
|
13649
|
-
this.calendar = new MarketCalendar(timezone);
|
|
13650
|
-
}
|
|
13651
|
-
/**
|
|
13652
|
-
* Get market open/close times for a date
|
|
13653
|
-
*/
|
|
13654
|
-
getMarketTimes(date) {
|
|
13655
|
-
const zonedDate = dateFnsTz.toZonedTime(date, this.timezone);
|
|
13656
|
-
// Market closed on weekends and holidays
|
|
13657
|
-
if (!this.calendar.isMarketDay(zonedDate)) {
|
|
13658
|
-
return {
|
|
13659
|
-
marketOpen: false,
|
|
13660
|
-
open: null,
|
|
13661
|
-
close: null,
|
|
13662
|
-
openExt: null,
|
|
13663
|
-
closeExt: null,
|
|
13664
|
-
};
|
|
13665
|
-
}
|
|
13666
|
-
const dayStart = dateFns.startOfDay(zonedDate);
|
|
13667
|
-
// Regular market times
|
|
13668
|
-
const open = dateFnsTz.fromZonedTime(dateFns.set(dayStart, { hours: MARKET_CONFIG.TIMES.MARKET_OPEN.hour, minutes: MARKET_CONFIG.TIMES.MARKET_OPEN.minute }), this.timezone);
|
|
13669
|
-
let close = dateFnsTz.fromZonedTime(dateFns.set(dayStart, { hours: MARKET_CONFIG.TIMES.MARKET_CLOSE.hour, minutes: MARKET_CONFIG.TIMES.MARKET_CLOSE.minute }), this.timezone);
|
|
13670
|
-
// Extended hours
|
|
13671
|
-
const openExt = dateFnsTz.fromZonedTime(dateFns.set(dayStart, { hours: MARKET_CONFIG.TIMES.EXTENDED_START.hour, minutes: MARKET_CONFIG.TIMES.EXTENDED_START.minute }), this.timezone);
|
|
13672
|
-
let closeExt = dateFnsTz.fromZonedTime(dateFns.set(dayStart, { hours: MARKET_CONFIG.TIMES.EXTENDED_END.hour, minutes: MARKET_CONFIG.TIMES.EXTENDED_END.minute }), this.timezone);
|
|
13673
|
-
// Handle early close days
|
|
13674
|
-
if (this.calendar.isEarlyCloseDay(zonedDate)) {
|
|
13675
|
-
close = dateFnsTz.fromZonedTime(dateFns.set(dayStart, { hours: MARKET_CONFIG.TIMES.EARLY_CLOSE.hour, minutes: MARKET_CONFIG.TIMES.EARLY_CLOSE.minute }), this.timezone);
|
|
13676
|
-
closeExt = dateFnsTz.fromZonedTime(dateFns.set(dayStart, { hours: MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour, minutes: MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute }), this.timezone);
|
|
13677
|
-
}
|
|
13678
|
-
return {
|
|
13679
|
-
marketOpen: true,
|
|
13680
|
-
open,
|
|
13681
|
-
close,
|
|
13682
|
-
openExt,
|
|
13683
|
-
closeExt,
|
|
13684
|
-
};
|
|
13685
|
-
}
|
|
13686
|
-
/**
|
|
13687
|
-
* Check if a time is within market hours based on intraday reporting mode
|
|
13688
|
-
*/
|
|
13689
|
-
isWithinMarketHours(date, intradayReporting = 'market_hours') {
|
|
13690
|
-
const zonedDate = dateFnsTz.toZonedTime(date, this.timezone);
|
|
13691
|
-
// Not a market day
|
|
13692
|
-
if (!this.calendar.isMarketDay(zonedDate)) {
|
|
13693
|
-
return false;
|
|
13694
|
-
}
|
|
13695
|
-
const timeInMinutes = zonedDate.getHours() * 60 + zonedDate.getMinutes();
|
|
13696
|
-
switch (intradayReporting) {
|
|
13697
|
-
case 'extended_hours': {
|
|
13698
|
-
const startMinutes = MARKET_CONFIG.TIMES.EXTENDED_START.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_START.minute;
|
|
13699
|
-
let endMinutes = MARKET_CONFIG.TIMES.EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_END.minute;
|
|
13700
|
-
// Handle early close
|
|
13701
|
-
if (this.calendar.isEarlyCloseDay(zonedDate)) {
|
|
13702
|
-
endMinutes = MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute;
|
|
13703
|
-
}
|
|
13704
|
-
return timeInMinutes >= startMinutes && timeInMinutes <= endMinutes;
|
|
13705
|
-
}
|
|
13706
|
-
case 'continuous':
|
|
13707
|
-
return true;
|
|
13708
|
-
default: {
|
|
13709
|
-
// 'market_hours'
|
|
13710
|
-
const startMinutes = MARKET_CONFIG.TIMES.MARKET_OPEN.hour * 60 + MARKET_CONFIG.TIMES.MARKET_OPEN.minute;
|
|
13711
|
-
let endMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
|
|
13712
|
-
// Handle early close
|
|
13713
|
-
if (this.calendar.isEarlyCloseDay(zonedDate)) {
|
|
13714
|
-
endMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
|
|
13715
|
-
}
|
|
13716
|
-
return timeInMinutes >= startMinutes && timeInMinutes <= endMinutes;
|
|
13717
|
-
}
|
|
13718
|
-
}
|
|
13719
|
-
}
|
|
13720
|
-
/**
|
|
13721
|
-
* Get the last full trading date
|
|
13722
|
-
*/
|
|
13723
|
-
getLastFullTradingDate(currentDate = new Date(), extendedHours = true) {
|
|
13724
|
-
const nowET = dateFnsTz.toZonedTime(currentDate, this.timezone);
|
|
13725
|
-
if (this.calendar.isMarketDay(nowET)) {
|
|
13726
|
-
const timeInMinutes = nowET.getHours() * 60 + nowET.getMinutes();
|
|
13727
|
-
let endMinutes;
|
|
13728
|
-
if (extendedHours) {
|
|
13729
|
-
endMinutes = MARKET_CONFIG.TIMES.EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EXTENDED_END.minute;
|
|
13730
|
-
if (this.calendar.isEarlyCloseDay(nowET)) {
|
|
13731
|
-
endMinutes = MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour * 60 + MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute;
|
|
13732
|
-
}
|
|
13733
|
-
}
|
|
13734
|
-
else {
|
|
13735
|
-
endMinutes = MARKET_CONFIG.TIMES.MARKET_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.MARKET_CLOSE.minute;
|
|
13736
|
-
if (this.calendar.isEarlyCloseDay(nowET)) {
|
|
13737
|
-
endMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
|
|
13738
|
-
}
|
|
13739
|
-
}
|
|
13740
|
-
if (timeInMinutes >= endMinutes) {
|
|
13741
|
-
return dateFnsTz.fromZonedTime(dateFns.set(nowET, { hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }), this.timezone);
|
|
13742
|
-
}
|
|
13743
|
-
}
|
|
13744
|
-
// Return the last completed trading day
|
|
13745
|
-
const lastMarketDay = this.calendar.getPreviousMarketDay(nowET);
|
|
13746
|
-
return dateFnsTz.fromZonedTime(dateFns.set(lastMarketDay, { hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }), this.timezone);
|
|
13747
|
-
}
|
|
13748
|
-
/**
|
|
13749
|
-
* Get day boundaries based on intraday reporting mode
|
|
13750
|
-
*/
|
|
13751
|
-
getDayBoundaries(date, intradayReporting = 'market_hours') {
|
|
13752
|
-
const zonedDate = dateFnsTz.toZonedTime(date, this.timezone);
|
|
13753
|
-
let start;
|
|
13754
|
-
let end;
|
|
13755
|
-
switch (intradayReporting) {
|
|
13756
|
-
case 'extended_hours': {
|
|
13757
|
-
start = dateFns.set(zonedDate, {
|
|
13758
|
-
hours: MARKET_CONFIG.TIMES.EXTENDED_START.hour,
|
|
13759
|
-
minutes: MARKET_CONFIG.TIMES.EXTENDED_START.minute,
|
|
13760
|
-
seconds: 0,
|
|
13761
|
-
milliseconds: 0,
|
|
13762
|
-
});
|
|
13763
|
-
end = dateFns.set(zonedDate, {
|
|
13764
|
-
hours: MARKET_CONFIG.TIMES.EXTENDED_END.hour,
|
|
13765
|
-
minutes: MARKET_CONFIG.TIMES.EXTENDED_END.minute,
|
|
13766
|
-
seconds: 59,
|
|
13767
|
-
milliseconds: 999,
|
|
13768
|
-
});
|
|
13769
|
-
// Handle early close
|
|
13770
|
-
if (this.calendar.isEarlyCloseDay(zonedDate)) {
|
|
13771
|
-
end = dateFns.set(zonedDate, {
|
|
13772
|
-
hours: MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.hour,
|
|
13773
|
-
minutes: MARKET_CONFIG.TIMES.EARLY_EXTENDED_END.minute,
|
|
13774
|
-
seconds: 59,
|
|
13775
|
-
milliseconds: 999,
|
|
13776
|
-
});
|
|
13777
|
-
}
|
|
13778
|
-
break;
|
|
13779
|
-
}
|
|
13780
|
-
case 'continuous': {
|
|
13781
|
-
start = dateFns.startOfDay(zonedDate);
|
|
13782
|
-
end = dateFns.endOfDay(zonedDate);
|
|
13783
|
-
break;
|
|
13784
|
-
}
|
|
13785
|
-
default: {
|
|
13786
|
-
// 'market_hours'
|
|
13787
|
-
start = dateFns.set(zonedDate, {
|
|
13788
|
-
hours: MARKET_CONFIG.TIMES.MARKET_OPEN.hour,
|
|
13789
|
-
minutes: MARKET_CONFIG.TIMES.MARKET_OPEN.minute,
|
|
13790
|
-
seconds: 0,
|
|
13791
|
-
milliseconds: 0,
|
|
13792
|
-
});
|
|
13793
|
-
end = dateFns.set(zonedDate, {
|
|
13794
|
-
hours: MARKET_CONFIG.TIMES.MARKET_CLOSE.hour,
|
|
13795
|
-
minutes: MARKET_CONFIG.TIMES.MARKET_CLOSE.minute,
|
|
13796
|
-
seconds: 59,
|
|
13797
|
-
milliseconds: 999,
|
|
13798
|
-
});
|
|
13799
|
-
// Handle early close
|
|
13800
|
-
if (this.calendar.isEarlyCloseDay(zonedDate)) {
|
|
13801
|
-
end = dateFns.set(zonedDate, {
|
|
13802
|
-
hours: MARKET_CONFIG.TIMES.EARLY_CLOSE.hour,
|
|
13803
|
-
minutes: MARKET_CONFIG.TIMES.EARLY_CLOSE.minute,
|
|
13804
|
-
seconds: 59,
|
|
13805
|
-
milliseconds: 999,
|
|
13806
|
-
});
|
|
13807
|
-
}
|
|
13808
|
-
break;
|
|
13809
|
-
}
|
|
13810
|
-
}
|
|
13811
|
-
return {
|
|
13812
|
-
start: dateFnsTz.fromZonedTime(start, this.timezone),
|
|
13813
|
-
end: dateFnsTz.fromZonedTime(end, this.timezone),
|
|
13814
|
-
};
|
|
13815
|
-
}
|
|
13816
|
-
}
|
|
13817
|
-
const marketTimeCalculator = new MarketTimeCalculator();
|
|
13818
|
-
const timeFormatter = new TimeFormatter();
|
|
13819
13695
|
/**
|
|
13820
|
-
*
|
|
13696
|
+
* Returns the last full trading date as a Date object.
|
|
13697
|
+
* @param currentDate - Date object (default: now)
|
|
13698
|
+
* @returns Date object for last full trading date
|
|
13821
13699
|
*/
|
|
13822
13700
|
function getLastFullTradingDate(currentDate = new Date()) {
|
|
13823
|
-
|
|
13824
|
-
return {
|
|
13825
|
-
date,
|
|
13826
|
-
YYYYMMDD: timeFormatter.getTradingDate(date),
|
|
13827
|
-
};
|
|
13701
|
+
return getLastFullTradingDateImpl(currentDate);
|
|
13828
13702
|
}
|
|
13829
13703
|
|
|
13830
13704
|
const log = (message, options = { type: 'info' }) => {
|
|
@@ -14224,8 +14098,8 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
|
|
|
14224
14098
|
const response = await this.getHistoricalBars({
|
|
14225
14099
|
symbols: [symbol],
|
|
14226
14100
|
timeframe: '1Day',
|
|
14227
|
-
start: prevMarketDate.
|
|
14228
|
-
end: prevMarketDate.
|
|
14101
|
+
start: prevMarketDate.toISOString(),
|
|
14102
|
+
end: prevMarketDate.toISOString(),
|
|
14229
14103
|
limit: 1,
|
|
14230
14104
|
});
|
|
14231
14105
|
if (!response.bars[symbol] || response.bars[symbol].length === 0) {
|