@adaptic/utils 0.1.43 → 0.1.45

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.
Files changed (225) hide show
  1. package/README.md +61 -153
  2. package/dist/index.cjs +5356 -60315
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.mjs +5356 -60054
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/test.js +361 -824
  7. package/dist/test.js.map +1 -1
  8. package/dist/types/adaptic.d.ts +2 -2
  9. package/dist/types/adaptic.d.ts.map +1 -1
  10. package/dist/types/alpaca-functions.d.ts +233 -0
  11. package/dist/types/alpaca-functions.d.ts.map +1 -0
  12. package/dist/types/alpaca-market-data-api.d.ts +9 -24
  13. package/dist/types/alpaca-market-data-api.d.ts.map +1 -1
  14. package/dist/types/alpaca-trading-api.d.ts +12 -12
  15. package/dist/types/alpaca-trading-api.d.ts.map +1 -1
  16. package/dist/types/alphavantage.d.ts +1 -1
  17. package/dist/types/alphavantage.d.ts.map +1 -1
  18. package/dist/types/asset-allocation-algorithm.d.ts +1 -7
  19. package/dist/types/asset-allocation-algorithm.d.ts.map +1 -1
  20. package/dist/types/cache/stampede-protected-cache.d.ts.map +1 -1
  21. package/dist/types/crypto.d.ts +4 -4
  22. package/dist/types/crypto.d.ts.map +1 -1
  23. package/dist/types/display-manager.d.ts +1 -1
  24. package/dist/types/display-manager.d.ts.map +1 -1
  25. package/dist/types/examples/asset-allocation-example.d.ts +6 -7
  26. package/dist/types/examples/asset-allocation-example.d.ts.map +1 -1
  27. package/dist/types/format-tools.d.ts.map +1 -1
  28. package/dist/types/index.d.ts +55 -393
  29. package/dist/types/index.d.ts.map +1 -1
  30. package/dist/types/logging.d.ts +1 -1
  31. package/dist/types/logging.d.ts.map +1 -1
  32. package/dist/types/market-hours.d.ts.map +1 -1
  33. package/dist/types/market-time.d.ts +13 -75
  34. package/dist/types/market-time.d.ts.map +1 -1
  35. package/dist/types/metrics-calcs.d.ts.map +1 -1
  36. package/dist/types/misc-utils.d.ts +1 -4
  37. package/dist/types/misc-utils.d.ts.map +1 -1
  38. package/dist/types/performance-metrics.d.ts +6 -6
  39. package/dist/types/performance-metrics.d.ts.map +1 -1
  40. package/dist/types/polygon-indices.d.ts +3 -3
  41. package/dist/types/polygon-indices.d.ts.map +1 -1
  42. package/dist/types/polygon.d.ts +1 -1
  43. package/dist/types/polygon.d.ts.map +1 -1
  44. package/dist/types/price-utils.d.ts.map +1 -1
  45. package/dist/types/technical-analysis.d.ts +9 -9
  46. package/dist/types/technical-analysis.d.ts.map +1 -1
  47. package/dist/types/time-utils.d.ts.map +1 -1
  48. package/dist/types/types/adaptic-types.d.ts +1 -1
  49. package/dist/types/types/adaptic-types.d.ts.map +1 -1
  50. package/dist/types/types/alpaca-types.d.ts +89 -252
  51. package/dist/types/types/alpaca-types.d.ts.map +1 -1
  52. package/dist/types/types/alphavantage-types.d.ts +2 -2
  53. package/dist/types/types/asset-allocation-types.d.ts +11 -11
  54. package/dist/types/types/index.d.ts +8 -8
  55. package/dist/types/types/index.d.ts.map +1 -1
  56. package/dist/types/types/logging-types.d.ts +2 -2
  57. package/dist/types/types/logging-types.d.ts.map +1 -1
  58. package/dist/types/types/market-time-types.d.ts +4 -4
  59. package/dist/types/types/market-time-types.d.ts.map +1 -1
  60. package/dist/types/types/metrics-types.d.ts +4 -4
  61. package/dist/types/types/metrics-types.d.ts.map +1 -1
  62. package/dist/types/types/polygon-indices-types.d.ts +6 -6
  63. package/dist/types/types/polygon-types.d.ts +3 -3
  64. package/dist/types/types/ta-types.d.ts +3 -3
  65. package/package.json +6 -24
  66. package/dist/types/__tests__/alpaca-functions.test.d.ts +0 -2
  67. package/dist/types/__tests__/alpaca-functions.test.d.ts.map +0 -1
  68. package/dist/types/__tests__/api-endpoints.test.d.ts +0 -2
  69. package/dist/types/__tests__/api-endpoints.test.d.ts.map +0 -1
  70. package/dist/types/__tests__/asset-allocation.test.d.ts +0 -2
  71. package/dist/types/__tests__/asset-allocation.test.d.ts.map +0 -1
  72. package/dist/types/__tests__/auth-validator.test.d.ts +0 -2
  73. package/dist/types/__tests__/auth-validator.test.d.ts.map +0 -1
  74. package/dist/types/__tests__/cache.test.d.ts +0 -2
  75. package/dist/types/__tests__/cache.test.d.ts.map +0 -1
  76. package/dist/types/__tests__/errors.test.d.ts +0 -2
  77. package/dist/types/__tests__/errors.test.d.ts.map +0 -1
  78. package/dist/types/__tests__/financial-regression.test.d.ts +0 -2
  79. package/dist/types/__tests__/financial-regression.test.d.ts.map +0 -1
  80. package/dist/types/__tests__/format-tools.test.d.ts +0 -2
  81. package/dist/types/__tests__/format-tools.test.d.ts.map +0 -1
  82. package/dist/types/__tests__/http-keep-alive.test.d.ts +0 -2
  83. package/dist/types/__tests__/http-keep-alive.test.d.ts.map +0 -1
  84. package/dist/types/__tests__/http-timeout.test.d.ts +0 -2
  85. package/dist/types/__tests__/http-timeout.test.d.ts.map +0 -1
  86. package/dist/types/__tests__/logger.test.d.ts +0 -2
  87. package/dist/types/__tests__/logger.test.d.ts.map +0 -1
  88. package/dist/types/__tests__/market-time.test.d.ts +0 -2
  89. package/dist/types/__tests__/market-time.test.d.ts.map +0 -1
  90. package/dist/types/__tests__/misc-utils.test.d.ts +0 -2
  91. package/dist/types/__tests__/misc-utils.test.d.ts.map +0 -1
  92. package/dist/types/__tests__/paginator.test.d.ts +0 -2
  93. package/dist/types/__tests__/paginator.test.d.ts.map +0 -1
  94. package/dist/types/__tests__/performance-metrics.test.d.ts +0 -2
  95. package/dist/types/__tests__/performance-metrics.test.d.ts.map +0 -1
  96. package/dist/types/__tests__/polygon.test.d.ts +0 -2
  97. package/dist/types/__tests__/polygon.test.d.ts.map +0 -1
  98. package/dist/types/__tests__/price-utils.test.d.ts +0 -2
  99. package/dist/types/__tests__/price-utils.test.d.ts.map +0 -1
  100. package/dist/types/__tests__/property-based-financial.test.d.ts +0 -2
  101. package/dist/types/__tests__/property-based-financial.test.d.ts.map +0 -1
  102. package/dist/types/__tests__/rate-limiter.test.d.ts +0 -2
  103. package/dist/types/__tests__/rate-limiter.test.d.ts.map +0 -1
  104. package/dist/types/__tests__/schema-validation.test.d.ts +0 -2
  105. package/dist/types/__tests__/schema-validation.test.d.ts.map +0 -1
  106. package/dist/types/__tests__/technical-analysis.test.d.ts +0 -2
  107. package/dist/types/__tests__/technical-analysis.test.d.ts.map +0 -1
  108. package/dist/types/__tests__/time-utils.test.d.ts +0 -2
  109. package/dist/types/__tests__/time-utils.test.d.ts.map +0 -1
  110. package/dist/types/alpaca/client.d.ts +0 -95
  111. package/dist/types/alpaca/client.d.ts.map +0 -1
  112. package/dist/types/alpaca/crypto/data.d.ts +0 -281
  113. package/dist/types/alpaca/crypto/data.d.ts.map +0 -1
  114. package/dist/types/alpaca/crypto/index.d.ts +0 -75
  115. package/dist/types/alpaca/crypto/index.d.ts.map +0 -1
  116. package/dist/types/alpaca/crypto/orders.d.ts +0 -221
  117. package/dist/types/alpaca/crypto/orders.d.ts.map +0 -1
  118. package/dist/types/alpaca/index.d.ts +0 -205
  119. package/dist/types/alpaca/index.d.ts.map +0 -1
  120. package/dist/types/alpaca/legacy/account.d.ts +0 -34
  121. package/dist/types/alpaca/legacy/account.d.ts.map +0 -1
  122. package/dist/types/alpaca/legacy/assets.d.ts +0 -13
  123. package/dist/types/alpaca/legacy/assets.d.ts.map +0 -1
  124. package/dist/types/alpaca/legacy/auth.d.ts +0 -18
  125. package/dist/types/alpaca/legacy/auth.d.ts.map +0 -1
  126. package/dist/types/alpaca/legacy/index.d.ts +0 -15
  127. package/dist/types/alpaca/legacy/index.d.ts.map +0 -1
  128. package/dist/types/alpaca/legacy/market-data.d.ts +0 -32
  129. package/dist/types/alpaca/legacy/market-data.d.ts.map +0 -1
  130. package/dist/types/alpaca/legacy/orders.d.ts +0 -84
  131. package/dist/types/alpaca/legacy/orders.d.ts.map +0 -1
  132. package/dist/types/alpaca/legacy/positions.d.ts +0 -66
  133. package/dist/types/alpaca/legacy/positions.d.ts.map +0 -1
  134. package/dist/types/alpaca/legacy/utils.d.ts +0 -18
  135. package/dist/types/alpaca/legacy/utils.d.ts.map +0 -1
  136. package/dist/types/alpaca/market-data/bars.d.ts +0 -142
  137. package/dist/types/alpaca/market-data/bars.d.ts.map +0 -1
  138. package/dist/types/alpaca/market-data/index.d.ts +0 -13
  139. package/dist/types/alpaca/market-data/index.d.ts.map +0 -1
  140. package/dist/types/alpaca/market-data/news.d.ts +0 -87
  141. package/dist/types/alpaca/market-data/news.d.ts.map +0 -1
  142. package/dist/types/alpaca/market-data/quotes.d.ts +0 -85
  143. package/dist/types/alpaca/market-data/quotes.d.ts.map +0 -1
  144. package/dist/types/alpaca/market-data/trades.d.ts +0 -98
  145. package/dist/types/alpaca/market-data/trades.d.ts.map +0 -1
  146. package/dist/types/alpaca/options/contracts.d.ts +0 -279
  147. package/dist/types/alpaca/options/contracts.d.ts.map +0 -1
  148. package/dist/types/alpaca/options/data.d.ts +0 -126
  149. package/dist/types/alpaca/options/data.d.ts.map +0 -1
  150. package/dist/types/alpaca/options/index.d.ts +0 -17
  151. package/dist/types/alpaca/options/index.d.ts.map +0 -1
  152. package/dist/types/alpaca/options/orders.d.ts +0 -366
  153. package/dist/types/alpaca/options/orders.d.ts.map +0 -1
  154. package/dist/types/alpaca/options/strategies.d.ts +0 -224
  155. package/dist/types/alpaca/options/strategies.d.ts.map +0 -1
  156. package/dist/types/alpaca/streams/base-stream.d.ts +0 -143
  157. package/dist/types/alpaca/streams/base-stream.d.ts.map +0 -1
  158. package/dist/types/alpaca/streams/crypto-stream.d.ts +0 -173
  159. package/dist/types/alpaca/streams/crypto-stream.d.ts.map +0 -1
  160. package/dist/types/alpaca/streams/index.d.ts +0 -54
  161. package/dist/types/alpaca/streams/index.d.ts.map +0 -1
  162. package/dist/types/alpaca/streams/option-stream.d.ts +0 -167
  163. package/dist/types/alpaca/streams/option-stream.d.ts.map +0 -1
  164. package/dist/types/alpaca/streams/stock-stream.d.ts +0 -176
  165. package/dist/types/alpaca/streams/stock-stream.d.ts.map +0 -1
  166. package/dist/types/alpaca/streams/stream-manager.d.ts +0 -277
  167. package/dist/types/alpaca/streams/stream-manager.d.ts.map +0 -1
  168. package/dist/types/alpaca/streams/trading-stream.d.ts +0 -186
  169. package/dist/types/alpaca/streams/trading-stream.d.ts.map +0 -1
  170. package/dist/types/alpaca/streams.d.ts +0 -88
  171. package/dist/types/alpaca/streams.d.ts.map +0 -1
  172. package/dist/types/alpaca/test-imports.d.ts +0 -7
  173. package/dist/types/alpaca/test-imports.d.ts.map +0 -1
  174. package/dist/types/alpaca/trading/account.d.ts +0 -198
  175. package/dist/types/alpaca/trading/account.d.ts.map +0 -1
  176. package/dist/types/alpaca/trading/bracket-orders.d.ts +0 -162
  177. package/dist/types/alpaca/trading/bracket-orders.d.ts.map +0 -1
  178. package/dist/types/alpaca/trading/clock.d.ts +0 -99
  179. package/dist/types/alpaca/trading/clock.d.ts.map +0 -1
  180. package/dist/types/alpaca/trading/index.d.ts +0 -15
  181. package/dist/types/alpaca/trading/index.d.ts.map +0 -1
  182. package/dist/types/alpaca/trading/oco-orders.d.ts +0 -203
  183. package/dist/types/alpaca/trading/oco-orders.d.ts.map +0 -1
  184. package/dist/types/alpaca/trading/order-utils.d.ts +0 -404
  185. package/dist/types/alpaca/trading/order-utils.d.ts.map +0 -1
  186. package/dist/types/alpaca/trading/orders.d.ts +0 -199
  187. package/dist/types/alpaca/trading/orders.d.ts.map +0 -1
  188. package/dist/types/alpaca/trading/oto-orders.d.ts +0 -282
  189. package/dist/types/alpaca/trading/oto-orders.d.ts.map +0 -1
  190. package/dist/types/alpaca/trading/positions.d.ts +0 -389
  191. package/dist/types/alpaca/trading/positions.d.ts.map +0 -1
  192. package/dist/types/alpaca/trading/smart-orders.d.ts +0 -301
  193. package/dist/types/alpaca/trading/smart-orders.d.ts.map +0 -1
  194. package/dist/types/alpaca/trading/trailing-stops.d.ts +0 -240
  195. package/dist/types/alpaca/trading/trailing-stops.d.ts.map +0 -1
  196. package/dist/types/config/api-endpoints.d.ts +0 -94
  197. package/dist/types/config/api-endpoints.d.ts.map +0 -1
  198. package/dist/types/errors/index.d.ts +0 -130
  199. package/dist/types/errors/index.d.ts.map +0 -1
  200. package/dist/types/examples/rate-limiter-example.d.ts +0 -7
  201. package/dist/types/examples/rate-limiter-example.d.ts.map +0 -1
  202. package/dist/types/http-timeout.d.ts +0 -37
  203. package/dist/types/http-timeout.d.ts.map +0 -1
  204. package/dist/types/logger.d.ts +0 -56
  205. package/dist/types/logger.d.ts.map +0 -1
  206. package/dist/types/rate-limiter.d.ts +0 -171
  207. package/dist/types/rate-limiter.d.ts.map +0 -1
  208. package/dist/types/schemas/alpaca-schemas.d.ts +0 -779
  209. package/dist/types/schemas/alpaca-schemas.d.ts.map +0 -1
  210. package/dist/types/schemas/alphavantage-schemas.d.ts +0 -255
  211. package/dist/types/schemas/alphavantage-schemas.d.ts.map +0 -1
  212. package/dist/types/schemas/index.d.ts +0 -21
  213. package/dist/types/schemas/index.d.ts.map +0 -1
  214. package/dist/types/schemas/polygon-schemas.d.ts +0 -551
  215. package/dist/types/schemas/polygon-schemas.d.ts.map +0 -1
  216. package/dist/types/schemas/validate-response.d.ts +0 -88
  217. package/dist/types/schemas/validate-response.d.ts.map +0 -1
  218. package/dist/types/utils/auth-validator.d.ts +0 -32
  219. package/dist/types/utils/auth-validator.d.ts.map +0 -1
  220. package/dist/types/utils/http-keep-alive.d.ts +0 -110
  221. package/dist/types/utils/http-keep-alive.d.ts.map +0 -1
  222. package/dist/types/utils/paginator.d.ts +0 -154
  223. package/dist/types/utils/paginator.d.ts.map +0 -1
  224. package/dist/types/utils/retry.d.ts +0 -78
  225. package/dist/types/utils/retry.d.ts.map +0 -1
package/dist/test.js CHANGED
@@ -493,7 +493,7 @@ createChalk({level: stderrColor ? stderrColor.level : 0});
493
493
 
494
494
  class DisplayManager {
495
495
  static instance;
496
- promptText = "";
496
+ promptText = '';
497
497
  constructor() { }
498
498
  static getInstance() {
499
499
  if (!DisplayManager.instance) {
@@ -513,22 +513,20 @@ class DisplayManager {
513
513
  cursorTo(process.stdout, 0);
514
514
  // Format the timestamp
515
515
  const date = new Date();
516
- const timestamp = date.toLocaleString("en-US", {
517
- timeZone: "America/New_York",
518
- });
516
+ const timestamp = date.toLocaleString('en-US', { timeZone: 'America/New_York' });
519
517
  const account = options?.account;
520
518
  const symbol = options?.symbol;
521
519
  // Build the log message
522
- let logMessage = `[${timestamp}]${options?.source ? ` [${options.source}] ` : ""}${account ? ` [${account}] ` : ""}${symbol ? ` [${symbol}] ` : ""}${message}`;
520
+ let logMessage = `[${timestamp}]${options?.source ? ` [${options.source}] ` : ''}${account ? ` [${account}] ` : ''}${symbol ? ` [${symbol}] ` : ''}${message}`;
523
521
  // Add color based on type
524
- if (options?.type === "error") {
522
+ if (options?.type === 'error') {
525
523
  logMessage = chalk.red(logMessage);
526
524
  }
527
- else if (options?.type === "warn") {
525
+ else if (options?.type === 'warn') {
528
526
  logMessage = chalk.yellow(logMessage);
529
527
  }
530
528
  // Write the log message
531
- process.stdout.write(logMessage + "\n");
529
+ process.stdout.write(logMessage + '\n');
532
530
  // Log to file
533
531
  if (symbol) {
534
532
  // Log to symbol-specific file if symbol is provided
@@ -547,20 +545,20 @@ class DisplayManager {
547
545
  writeSymbolLog(symbol, date, logMessage, options) {
548
546
  try {
549
547
  // Create logs directory if it doesn't exist
550
- if (!fs.existsSync("logs")) {
551
- fs.mkdirSync("logs", { recursive: true });
548
+ if (!fs.existsSync('logs')) {
549
+ fs.mkdirSync('logs', { recursive: true });
552
550
  }
553
551
  // Format date for filename: YYYY-MM-DD
554
552
  const year = date.getFullYear();
555
- const month = String(date.getMonth() + 1).padStart(2, "0");
556
- const day = String(date.getDate()).padStart(2, "0");
553
+ const month = String(date.getMonth() + 1).padStart(2, '0');
554
+ const day = String(date.getDate()).padStart(2, '0');
557
555
  // Create filename: SYM-YYYY-MM-DD.log
558
556
  const filename = `${symbol}-${year}-${month}-${day}.log`;
559
- const filePath = path.join("logs", filename);
557
+ const filePath = path.join('logs', filename);
560
558
  // Strip ANSI color codes from log message
561
- const plainLogMessage = logMessage.replace(/\x1B\[\d+m/g, "");
559
+ const plainLogMessage = logMessage.replace(/\x1B\[\d+m/g, '');
562
560
  // Write to file (append if exists, create if not)
563
- fs.appendFileSync(filePath, plainLogMessage + "\n");
561
+ fs.appendFileSync(filePath, plainLogMessage + '\n');
564
562
  }
565
563
  catch (error) {
566
564
  // Only log to console - don't try to log to file again to avoid potential infinite loop
@@ -573,21 +571,21 @@ class DisplayManager {
573
571
  writeGenericLog(date, logMessage, options) {
574
572
  try {
575
573
  // Create logs directory if it doesn't exist
576
- if (!fs.existsSync("logs")) {
577
- fs.mkdirSync("logs", { recursive: true });
574
+ if (!fs.existsSync('logs')) {
575
+ fs.mkdirSync('logs', { recursive: true });
578
576
  }
579
577
  // Format date for filename: YYYY-MM-DD
580
578
  const year = date.getFullYear();
581
- const month = String(date.getMonth() + 1).padStart(2, "0");
582
- const day = String(date.getDate()).padStart(2, "0");
579
+ const month = String(date.getMonth() + 1).padStart(2, '0');
580
+ const day = String(date.getDate()).padStart(2, '0');
583
581
  // Create filename: system-YYYY-MM-DD.log
584
- const source = options?.source?.toLowerCase().replace(/\s+/g, "-") || "system";
582
+ const source = options?.source?.toLowerCase().replace(/\s+/g, '-') || 'system';
585
583
  const filename = `${source}-${year}-${month}-${day}.log`;
586
- const filePath = path.join("logs", filename);
584
+ const filePath = path.join('logs', filename);
587
585
  // Strip ANSI color codes from log message
588
- const plainLogMessage = logMessage.replace(/\x1B\[\d+m/g, "");
586
+ const plainLogMessage = logMessage.replace(/\x1B\[\d+m/g, '');
589
587
  // Write to file (append if exists, create if not)
590
- fs.appendFileSync(filePath, plainLogMessage + "\n");
588
+ fs.appendFileSync(filePath, plainLogMessage + '\n');
591
589
  }
592
590
  catch (error) {
593
591
  // Only log to console - don't try to log to file again to avoid potential infinite loop
@@ -615,206 +613,112 @@ class DisplayManager {
615
613
  * @param options.symbol The trading symbol associated with this log.
616
614
  * @param options.logToFile Force logging to a file even when no symbol is provided.
617
615
  */
618
- function log$2(message, options = { source: "Server", type: "info" }) {
616
+ function log$2(message, options = { source: 'Server', type: 'info' }) {
619
617
  const displayManager = DisplayManager.getInstance();
620
618
  displayManager.log(message, options);
621
619
  }
622
620
 
623
- /**
624
- * Centralized API Endpoints Configuration
625
- *
626
- * This file defines all Alpaca API base URLs to ensure consistency
627
- * across the codebase and make updates easier.
628
- *
629
- * API Version Guidelines:
630
- * - Trading API: v2 (stable, production-ready)
631
- * - Market Data (stocks): v2 (stable)
632
- * - Market Data (crypto): v1beta3 (latest beta)
633
- * - Market Data (options): v1beta1 (latest beta)
634
- * - News API: v1beta1 (latest beta)
635
- */
636
- /**
637
- * Trading API base URLs (v2)
638
- * Used for orders, positions, account management
639
- */
640
- const TRADING_API = {
641
- PAPER: "https://paper-api.alpaca.markets/v2",
642
- LIVE: "https://api.alpaca.markets/v2",
643
- };
644
- /**
645
- * Get trading API base URL for account type
646
- */
647
- function getTradingApiUrl(accountType) {
648
- return TRADING_API[accountType];
649
- }
650
- /**
651
- * Market Data API base URLs
652
- */
653
- const MARKET_DATA_API = {
654
- /** Stock market data (v2) - bars, quotes, trades */
655
- STOCKS: "https://data.alpaca.markets/v2",
656
- /** Options market data (v1beta1) */
657
- OPTIONS: "https://data.alpaca.markets/v1beta1"};
658
- /**
659
- * WebSocket stream URLs
660
- */
661
- const WEBSOCKET_STREAMS = {
662
- /** Stock market data stream (v2) */
663
- STOCKS: {
664
- PRODUCTION: "wss://stream.data.alpaca.markets/v2/sip",
665
- TEST: "wss://stream.data.alpaca.markets/v2/test",
666
- },
667
- /** Options market data stream (v1beta3) */
668
- OPTIONS: {
669
- PRODUCTION: "wss://stream.data.alpaca.markets/v1beta3/options",
670
- SANDBOX: "wss://stream.data.sandbox.alpaca.markets/v1beta3/options",
671
- },
672
- /** Crypto market data stream (v1beta3) */
673
- CRYPTO: {
674
- PRODUCTION: "wss://stream.data.alpaca.markets/v1beta3/crypto/us",
675
- SANDBOX: "wss://stream.data.sandbox.alpaca.markets/v1beta3/crypto/us",
676
- },
677
- };
678
- /**
679
- * Get stock stream WebSocket URL
680
- */
681
- function getStockStreamUrl(mode = "PRODUCTION") {
682
- return WEBSOCKET_STREAMS.STOCKS[mode];
683
- }
684
- /**
685
- * Get options stream WebSocket URL
686
- */
687
- function getOptionsStreamUrl(mode = "PRODUCTION") {
688
- return WEBSOCKET_STREAMS.OPTIONS[mode];
689
- }
690
- /**
691
- * Get crypto stream WebSocket URL
692
- */
693
- function getCryptoStreamUrl(mode = "PRODUCTION") {
694
- return WEBSOCKET_STREAMS.CRYPTO[mode];
695
- }
696
-
697
621
  // market-hours.ts
698
622
  const marketHolidays = {
699
623
  2024: {
700
- "New Year's Day": { date: "2024-01-01" },
701
- "Martin Luther King, Jr. Day": { date: "2024-01-15" },
702
- "Washington's Birthday": { date: "2024-02-19" },
703
- "Good Friday": { date: "2024-03-29" },
704
- "Memorial Day": { date: "2024-05-27" },
705
- "Juneteenth National Independence Day": { date: "2024-06-19" },
706
- "Independence Day": { date: "2024-07-04" },
707
- "Labor Day": { date: "2024-09-02" },
708
- "Thanksgiving Day": { date: "2024-11-28" },
709
- "Christmas Day": { date: "2024-12-25" },
624
+ 'New Year\'s Day': { date: '2024-01-01' },
625
+ 'Martin Luther King, Jr. Day': { date: '2024-01-15' },
626
+ 'Washington\'s Birthday': { date: '2024-02-19' },
627
+ 'Good Friday': { date: '2024-03-29' },
628
+ 'Memorial Day': { date: '2024-05-27' },
629
+ 'Juneteenth National Independence Day': { date: '2024-06-19' },
630
+ 'Independence Day': { date: '2024-07-04' },
631
+ 'Labor Day': { date: '2024-09-02' },
632
+ 'Thanksgiving Day': { date: '2024-11-28' },
633
+ 'Christmas Day': { date: '2024-12-25' }
710
634
  },
711
635
  2025: {
712
- "New Year's Day": { date: "2025-01-01" },
713
- "Jimmy Carter Memorial Day": { date: "2025-01-09" },
714
- "Martin Luther King, Jr. Day": { date: "2025-01-20" },
715
- "Washington's Birthday": { date: "2025-02-17" },
716
- "Good Friday": { date: "2025-04-18" },
717
- "Memorial Day": { date: "2025-05-26" },
718
- "Juneteenth National Independence Day": { date: "2025-06-19" },
719
- "Independence Day": { date: "2025-07-04" },
720
- "Labor Day": { date: "2025-09-01" },
721
- "Thanksgiving Day": { date: "2025-11-27" },
722
- "Christmas Day": { date: "2025-12-25" },
636
+ 'New Year\'s Day': { date: '2025-01-01' },
637
+ 'Jimmy Carter Memorial Day': { date: '2025-01-09' },
638
+ 'Martin Luther King, Jr. Day': { date: '2025-01-20' },
639
+ 'Washington\'s Birthday': { date: '2025-02-17' },
640
+ 'Good Friday': { date: '2025-04-18' },
641
+ 'Memorial Day': { date: '2025-05-26' },
642
+ 'Juneteenth National Independence Day': { date: '2025-06-19' },
643
+ 'Independence Day': { date: '2025-07-04' },
644
+ 'Labor Day': { date: '2025-09-01' },
645
+ 'Thanksgiving Day': { date: '2025-11-27' },
646
+ 'Christmas Day': { date: '2025-12-25' }
723
647
  },
724
648
  2026: {
725
- "New Year's Day": { date: "2026-01-01" },
726
- "Martin Luther King, Jr. Day": { date: "2026-01-19" },
727
- "Washington's Birthday": { date: "2026-02-16" },
728
- "Good Friday": { date: "2026-04-03" },
729
- "Memorial Day": { date: "2026-05-25" },
730
- "Juneteenth National Independence Day": { date: "2026-06-19" },
731
- "Independence Day": { date: "2026-07-03" },
732
- "Labor Day": { date: "2026-09-07" },
733
- "Thanksgiving Day": { date: "2026-11-26" },
734
- "Christmas Day": { date: "2026-12-25" },
735
- },
736
- 2027: {
737
- "New Year's Day": { date: "2027-01-01" },
738
- "Martin Luther King, Jr. Day": { date: "2027-01-18" },
739
- "Washington's Birthday": { date: "2027-02-15" },
740
- "Good Friday": { date: "2027-03-26" },
741
- "Memorial Day": { date: "2027-05-31" },
742
- "Juneteenth National Independence Day": { date: "2027-06-18" },
743
- "Independence Day": { date: "2027-07-05" },
744
- "Labor Day": { date: "2027-09-06" },
745
- "Thanksgiving Day": { date: "2027-11-25" },
746
- "Christmas Day": { date: "2027-12-24" },
747
- },
649
+ 'New Year\'s Day': { date: '2026-01-01' },
650
+ 'Martin Luther King, Jr. Day': { date: '2026-01-19' },
651
+ 'Washington\'s Birthday': { date: '2026-02-16' },
652
+ 'Good Friday': { date: '2026-04-03' },
653
+ 'Memorial Day': { date: '2026-05-25' },
654
+ 'Juneteenth National Independence Day': { date: '2026-06-19' },
655
+ 'Independence Day': { date: '2026-07-03' },
656
+ 'Labor Day': { date: '2026-09-07' },
657
+ 'Thanksgiving Day': { date: '2026-11-26' },
658
+ 'Christmas Day': { date: '2026-12-25' }
659
+ }
748
660
  };
749
661
  const marketEarlyCloses = {
750
662
  2024: {
751
- "2024-07-03": {
752
- date: "2024-07-03",
753
- time: "13:00",
754
- optionsTime: "13:15",
755
- notes: "Market closes early on Wednesday, July 3, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.",
756
- },
757
- "2024-11-29": {
758
- date: "2024-11-29",
759
- time: "13:00",
760
- optionsTime: "13:15",
761
- notes: "Market closes early on Friday, November 29, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.",
663
+ '2024-07-03': {
664
+ date: '2024-07-03',
665
+ time: '13:00',
666
+ optionsTime: '13:15',
667
+ notes: 'Market closes early on Wednesday, July 3, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.'
762
668
  },
763
- "2024-12-24": {
764
- date: "2024-12-24",
765
- time: "13:00",
766
- optionsTime: "13:15",
767
- notes: "Market closes early on Tuesday, December 24, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.",
669
+ '2024-11-29': {
670
+ date: '2024-11-29',
671
+ time: '13:00',
672
+ optionsTime: '13:15',
673
+ notes: 'Market closes early on Friday, November 29, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.'
768
674
  },
675
+ '2024-12-24': {
676
+ date: '2024-12-24',
677
+ time: '13:00',
678
+ optionsTime: '13:15',
679
+ notes: 'Market closes early on Tuesday, December 24, 2024 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.'
680
+ }
769
681
  },
770
682
  2025: {
771
- "2025-07-03": {
772
- date: "2025-07-03",
773
- time: "13:00",
774
- optionsTime: "13:15",
775
- notes: "Market closes early on Thursday, July 3, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.",
776
- },
777
- "2025-11-28": {
778
- date: "2025-11-28",
779
- time: "13:00",
780
- optionsTime: "13:15",
781
- notes: "Market closes early on Friday, November 28, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.",
683
+ '2025-07-03': {
684
+ date: '2025-07-03',
685
+ time: '13:00',
686
+ optionsTime: '13:15',
687
+ notes: 'Market closes early on Thursday, July 3, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.'
782
688
  },
783
- "2025-12-24": {
784
- date: "2025-12-24",
785
- time: "13:00",
786
- optionsTime: "13:15",
787
- notes: "Market closes early on Wednesday, December 24, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.",
689
+ '2025-11-28': {
690
+ date: '2025-11-28',
691
+ time: '13:00',
692
+ optionsTime: '13:15',
693
+ notes: 'Market closes early on Friday, November 28, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.'
788
694
  },
695
+ '2025-12-24': {
696
+ date: '2025-12-24',
697
+ time: '13:00',
698
+ optionsTime: '13:15',
699
+ notes: 'Market closes early on Wednesday, December 24, 2025 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.'
700
+ }
789
701
  },
790
702
  2026: {
791
- "2026-07-02": {
792
- date: "2026-07-02",
793
- time: "13:00",
794
- optionsTime: "13:15",
795
- notes: "Independence Day observed, market closes early at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.",
796
- },
797
- "2026-11-27": {
798
- date: "2026-11-27",
799
- time: "13:00",
800
- optionsTime: "13:15",
801
- notes: "Market closes early on Friday, November 27, 2026 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.",
802
- },
803
- "2026-12-24": {
804
- date: "2026-12-24",
805
- time: "13:00",
806
- optionsTime: "13:15",
807
- notes: "Market closes early on Thursday, December 24, 2026 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.",
703
+ '2026-07-02': {
704
+ date: '2026-07-02',
705
+ time: '13:00',
706
+ optionsTime: '13:15',
707
+ notes: 'Independence Day observed, market closes early at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.'
808
708
  },
809
- },
810
- 2027: {
811
- "2027-11-26": {
812
- date: "2027-11-26",
813
- time: "13:00",
814
- optionsTime: "13:15",
815
- notes: "Market closes early on Friday, November 26, 2027 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE National, and NYSE Texas late trading sessions will close at 5:00 p.m. Eastern Time.",
709
+ '2026-11-27': {
710
+ date: '2026-11-27',
711
+ time: '13:00',
712
+ optionsTime: '13:15',
713
+ notes: 'Market closes early on Friday, November 27, 2026 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.'
816
714
  },
817
- },
715
+ '2026-12-24': {
716
+ date: '2026-12-24',
717
+ time: '13:00',
718
+ optionsTime: '13:15',
719
+ notes: 'Market closes early on Thursday, December 24, 2026 at 1:00 p.m. (1:15 p.m. for eligible options). NYSE American Equities, NYSE Arca Equities, NYSE Chicago, and NYSE National late trading sessions will close at 5:00 p.m. Eastern Time.'
720
+ }
721
+ }
818
722
  };
819
723
 
820
724
  // market-time.ts
@@ -827,15 +731,9 @@ const marketEarlyCloses = {
827
731
  * Early extended market hours are 1:00pm-5:00pm on early close days
828
732
  */
829
733
  const MARKET_TIMES = {
830
- TIMEZONE: "America/New_York",
831
- REGULAR: {
832
- START: { HOUR: 9, MINUTE: 30},
833
- END: { HOUR: 16, MINUTE: 0},
834
- },
835
- EXTENDED: {
836
- START: { HOUR: 4, MINUTE: 0},
837
- END: { HOUR: 20, MINUTE: 0},
838
- },
734
+ TIMEZONE: 'America/New_York',
735
+ REGULAR: { START: { HOUR: 9, MINUTE: 30}, END: { HOUR: 16, MINUTE: 0} },
736
+ EXTENDED: { START: { HOUR: 4, MINUTE: 0}, END: { HOUR: 20, MINUTE: 0} },
839
737
  };
840
738
  /**
841
739
  * Utility class for handling market time-related operations
@@ -848,7 +746,7 @@ class MarketTimeUtil {
848
746
  * @param {string} [timezone='America/New_York'] - The timezone to use for market time calculations
849
747
  * @param {IntradayReporting} [intradayReporting='market_hours'] - The intraday reporting mode
850
748
  */
851
- constructor(timezone = MARKET_TIMES.TIMEZONE, intradayReporting = "market_hours") {
749
+ constructor(timezone = MARKET_TIMES.TIMEZONE, intradayReporting = 'market_hours') {
852
750
  this.validateTimezone(timezone);
853
751
  this.timezone = timezone;
854
752
  this.intradayReporting = intradayReporting;
@@ -867,37 +765,25 @@ class MarketTimeUtil {
867
765
  throw new Error(`Invalid timezone: ${timezone}`);
868
766
  }
869
767
  }
870
- formatDate(date, outputFormat = "iso") {
768
+ formatDate(date, outputFormat = 'iso') {
871
769
  switch (outputFormat) {
872
- case "unix-seconds":
770
+ case 'unix-seconds':
873
771
  return Math.floor(date.getTime() / 1000);
874
- case "unix-ms":
772
+ case 'unix-ms':
875
773
  return date.getTime();
876
- case "iso":
774
+ case 'iso':
877
775
  default:
878
776
  // return with timezone offset
879
777
  return formatInTimeZone(date, this.timezone, "yyyy-MM-dd'T'HH:mm:ssXXX");
880
778
  }
881
779
  }
882
- /**
883
- * Checks if a NY-zoned date falls on a weekend.
884
- * Expects a date already converted to market timezone via toZonedTime.
885
- * @param nyDate - Date in market timezone representation
886
- * @returns true if the date is Saturday or Sunday
887
- */
888
- isWeekendZoned(nyDate) {
889
- const day = nyDate.getDay();
780
+ isWeekend(date) {
781
+ const day = date.getDay();
890
782
  return day === 0 || day === 6;
891
783
  }
892
- /**
893
- * Checks if a NY-zoned date falls on a market holiday.
894
- * Expects a date already converted to market timezone via toZonedTime.
895
- * @param nyDate - Date in market timezone representation
896
- * @returns true if the date is a holiday
897
- */
898
- isHolidayZoned(nyDate) {
899
- const formattedDate = format(nyDate, "yyyy-MM-dd");
900
- const yearHolidays = marketHolidays[nyDate.getFullYear()];
784
+ isHoliday(date) {
785
+ const formattedDate = format(date, 'yyyy-MM-dd');
786
+ const yearHolidays = marketHolidays[date.getFullYear()];
901
787
  for (const holiday in yearHolidays) {
902
788
  if (yearHolidays[holiday].date === formattedDate) {
903
789
  return true;
@@ -905,98 +791,50 @@ class MarketTimeUtil {
905
791
  }
906
792
  return false;
907
793
  }
908
- /**
909
- * Checks if a NY-zoned date is an early close day.
910
- * Expects a date already converted to market timezone via toZonedTime.
911
- * @param nyDate - Date in market timezone representation
912
- * @returns true if the date is an early close day
913
- */
914
- isEarlyCloseDayZoned(nyDate) {
915
- const formattedDate = format(nyDate, "yyyy-MM-dd");
916
- const yearEarlyCloses = marketEarlyCloses[nyDate.getFullYear()];
794
+ isEarlyCloseDay(date) {
795
+ const formattedDate = format(date, 'yyyy-MM-dd');
796
+ const yearEarlyCloses = marketEarlyCloses[date.getFullYear()];
917
797
  return yearEarlyCloses && yearEarlyCloses[formattedDate] !== undefined;
918
798
  }
919
799
  /**
920
- * Gets the early close time for a NY-zoned date.
921
- * Expects a date already converted to market timezone via toZonedTime.
922
- * @param nyDate - Date in market timezone representation
923
- * @returns The early close time in minutes from midnight, or null if not an early close day
800
+ * Get the early close time for a given date
801
+ * @param date - The date to get the early close time for
802
+ * @returns The early close time in minutes from midnight, or null if there is no early close
924
803
  */
925
- getEarlyCloseTimeZoned(nyDate) {
926
- const formattedDate = format(nyDate, "yyyy-MM-dd");
927
- const yearEarlyCloses = marketEarlyCloses[nyDate.getFullYear()];
804
+ getEarlyCloseTime(date) {
805
+ const formattedDate = format(date, 'yyyy-MM-dd');
806
+ const yearEarlyCloses = marketEarlyCloses[date.getFullYear()];
928
807
  if (yearEarlyCloses && yearEarlyCloses[formattedDate]) {
929
- const [hours, minutes] = yearEarlyCloses[formattedDate].time
930
- .split(":")
931
- .map(Number);
808
+ const [hours, minutes] = yearEarlyCloses[formattedDate].time.split(':').map(Number);
932
809
  return hours * 60 + minutes;
933
810
  }
934
811
  return null;
935
812
  }
936
813
  /**
937
- * Checks if a NY-zoned date is a market day (not weekend, not holiday).
938
- * Expects a date already converted to market timezone via toZonedTime.
939
- * @param nyDate - Date in market timezone representation
940
- * @returns true if the date is a market day
941
- */
942
- isMarketDayZoned(nyDate) {
943
- return !this.isWeekendZoned(nyDate) && !this.isHolidayZoned(nyDate);
944
- }
945
- /**
946
- * Check if a given date is an early close day.
947
- * Handles timezone conversion from any input date.
948
- * @param date - The date to check (any timezone)
949
- * @returns true if the date is an early close day
950
- */
951
- isEarlyCloseDay(date) {
952
- const nyDate = toZonedTime(date, this.timezone);
953
- return this.isEarlyCloseDayZoned(nyDate);
954
- }
955
- /**
956
- * Get the early close time for a given date.
957
- * Handles timezone conversion from any input date.
958
- * @param date - The date to check (any timezone)
959
- * @returns The early close time in minutes from midnight, or null if there is no early close
960
- */
961
- getEarlyCloseTime(date) {
962
- const nyDate = toZonedTime(date, this.timezone);
963
- return this.getEarlyCloseTimeZoned(nyDate);
964
- }
965
- /**
966
- * Check if a given date is a market day.
967
- * Handles timezone conversion from any input date.
968
- * @param date - The date to check (any timezone)
814
+ * Check if a given date is a market day
815
+ * @param date - The date to check
969
816
  * @returns true if the date is a market day, false otherwise
970
817
  */
971
818
  isMarketDay(date) {
972
- const nyDate = toZonedTime(date, this.timezone);
973
- return this.isMarketDayZoned(nyDate);
819
+ const isWeekendDay = this.isWeekend(date);
820
+ const isHolidayDay = this.isHoliday(date);
821
+ const returner = !isWeekendDay && !isHolidayDay;
822
+ return returner;
974
823
  }
975
824
  /**
976
- * Check if a given date is within market hours.
977
- * Handles timezone conversion from any input date.
978
- * @param date - The date to check (any timezone)
825
+ * Check if a given date is within market hours
826
+ * @param date - The date to check
979
827
  * @returns true if the date is within market hours, false otherwise
980
828
  */
981
829
  isWithinMarketHours(date) {
982
- const nyDate = toZonedTime(date, this.timezone);
983
- return this.isWithinMarketHoursZoned(nyDate);
984
- }
985
- /**
986
- * Check if a NY-zoned date is within market hours.
987
- * Expects a date already converted to market timezone via toZonedTime.
988
- * @param nyDate - Date in market timezone representation
989
- * @returns true if the date is within market hours, false otherwise
990
- */
991
- isWithinMarketHoursZoned(nyDate) {
992
- // Check for weekends and holidays first
993
- if (this.isWeekendZoned(nyDate) || this.isHolidayZoned(nyDate)) {
830
+ // Check for holidays first
831
+ if (this.isHoliday(date)) {
994
832
  return false;
995
833
  }
996
- const timeInMinutes = nyDate.getHours() * 60 + nyDate.getMinutes();
834
+ const timeInMinutes = date.getHours() * 60 + date.getMinutes();
997
835
  // Check for early closure
998
- if (this.isEarlyCloseDayZoned(nyDate)) {
999
- const earlyCloseMinutes = this.getEarlyCloseTimeZoned(nyDate);
836
+ if (this.isEarlyCloseDay(date)) {
837
+ const earlyCloseMinutes = this.getEarlyCloseTime(date);
1000
838
  if (earlyCloseMinutes !== null && timeInMinutes > earlyCloseMinutes) {
1001
839
  return false;
1002
840
  }
@@ -1004,50 +842,38 @@ class MarketTimeUtil {
1004
842
  // Regular market hours logic
1005
843
  let returner;
1006
844
  switch (this.intradayReporting) {
1007
- case "extended_hours": {
1008
- const extendedStartMinutes = MARKET_TIMES.EXTENDED.START.HOUR * 60 +
1009
- MARKET_TIMES.EXTENDED.START.MINUTE;
1010
- const extendedEndMinutes = MARKET_TIMES.EXTENDED.END.HOUR * 60 +
1011
- MARKET_TIMES.EXTENDED.END.MINUTE;
845
+ case 'extended_hours': {
846
+ const extendedStartMinutes = MARKET_TIMES.EXTENDED.START.HOUR * 60 + MARKET_TIMES.EXTENDED.START.MINUTE;
847
+ const extendedEndMinutes = MARKET_TIMES.EXTENDED.END.HOUR * 60 + MARKET_TIMES.EXTENDED.END.MINUTE;
1012
848
  // Comprehensive handling of times crossing midnight
1013
- const adjustedNyDate = timeInMinutes < extendedStartMinutes
1014
- ? sub(nyDate, { days: 1 })
1015
- : nyDate;
1016
- const adjustedTimeInMinutes = adjustedNyDate.getHours() * 60 + adjustedNyDate.getMinutes();
1017
- returner =
1018
- adjustedTimeInMinutes >= extendedStartMinutes &&
1019
- adjustedTimeInMinutes <= extendedEndMinutes;
849
+ const adjustedDate = timeInMinutes < extendedStartMinutes ? sub(date, { days: 1 }) : date;
850
+ const adjustedTimeInMinutes = adjustedDate.getHours() * 60 + adjustedDate.getMinutes();
851
+ returner = adjustedTimeInMinutes >= extendedStartMinutes && adjustedTimeInMinutes <= extendedEndMinutes;
1020
852
  break;
1021
853
  }
1022
- case "continuous":
854
+ case 'continuous':
1023
855
  returner = true;
1024
856
  break;
1025
857
  default: {
1026
858
  // market_hours
1027
- const regularStartMinutes = MARKET_TIMES.REGULAR.START.HOUR * 60 +
1028
- MARKET_TIMES.REGULAR.START.MINUTE;
859
+ const regularStartMinutes = MARKET_TIMES.REGULAR.START.HOUR * 60 + MARKET_TIMES.REGULAR.START.MINUTE;
1029
860
  const regularEndMinutes = MARKET_TIMES.REGULAR.END.HOUR * 60 + MARKET_TIMES.REGULAR.END.MINUTE;
1030
- returner =
1031
- timeInMinutes >= regularStartMinutes &&
1032
- timeInMinutes <= regularEndMinutes;
861
+ returner = timeInMinutes >= regularStartMinutes && timeInMinutes <= regularEndMinutes;
1033
862
  break;
1034
863
  }
1035
864
  }
1036
865
  return returner;
1037
866
  }
1038
867
  /**
1039
- * Check if a NY-zoned date is before market hours.
1040
- * Expects a date already converted to market timezone via toZonedTime.
1041
- * @param nyDate - Date in market timezone representation
868
+ * Check if a given date is before market hours
869
+ * @param date - The date to check
1042
870
  * @returns true if the date is before market hours, false otherwise
1043
871
  */
1044
- isBeforeMarketHoursZoned(nyDate) {
1045
- const timeInMinutes = nyDate.getHours() * 60 + nyDate.getMinutes();
1046
- const startMinutes = this.intradayReporting === "extended_hours"
1047
- ? MARKET_TIMES.EXTENDED.START.HOUR * 60 +
1048
- MARKET_TIMES.EXTENDED.START.MINUTE
1049
- : MARKET_TIMES.REGULAR.START.HOUR * 60 +
1050
- MARKET_TIMES.REGULAR.START.MINUTE;
872
+ isBeforeMarketHours(date) {
873
+ const timeInMinutes = date.getHours() * 60 + date.getMinutes();
874
+ const startMinutes = this.intradayReporting === 'extended_hours'
875
+ ? MARKET_TIMES.EXTENDED.START.HOUR * 60 + MARKET_TIMES.EXTENDED.START.MINUTE
876
+ : MARKET_TIMES.REGULAR.START.HOUR * 60 + MARKET_TIMES.REGULAR.START.MINUTE;
1051
877
  return timeInMinutes < startMinutes;
1052
878
  }
1053
879
  /**
@@ -1057,7 +883,7 @@ class MarketTimeUtil {
1057
883
  */
1058
884
  getLastTradingDate(currentDate = new Date()) {
1059
885
  const nowET = toZonedTime(currentDate, this.timezone);
1060
- const isMarketDayToday = this.isMarketDayZoned(nowET);
886
+ const isMarketDayToday = this.isMarketDay(nowET);
1061
887
  const currentMinutes = nowET.getHours() * 60 + nowET.getMinutes();
1062
888
  const marketOpenMinutes = MARKET_TIMES.REGULAR.START.HOUR * 60 + MARKET_TIMES.REGULAR.START.MINUTE;
1063
889
  if (isMarketDayToday && currentMinutes >= marketOpenMinutes) {
@@ -1067,7 +893,7 @@ class MarketTimeUtil {
1067
893
  else {
1068
894
  // Before market open, or not a market day, return previous trading day
1069
895
  let lastTradingDate = sub(nowET, { days: 1 });
1070
- while (!this.isMarketDayZoned(lastTradingDate)) {
896
+ while (!this.isMarketDay(lastTradingDate)) {
1071
897
  lastTradingDate = sub(lastTradingDate, { days: 1 });
1072
898
  }
1073
899
  return lastTradingDate;
@@ -1075,7 +901,7 @@ class MarketTimeUtil {
1075
901
  }
1076
902
  getLastMarketDay(date) {
1077
903
  let currentDate = sub(date, { days: 1 });
1078
- while (!this.isMarketDayZoned(currentDate)) {
904
+ while (!this.isMarketDay(currentDate)) {
1079
905
  currentDate = sub(currentDate, { days: 1 });
1080
906
  }
1081
907
  return currentDate;
@@ -1084,7 +910,7 @@ class MarketTimeUtil {
1084
910
  const nowET = toZonedTime(currentDate, this.timezone);
1085
911
  // If today is a market day and we're after extended hours close
1086
912
  // then return today since it's a completed trading day
1087
- if (this.isMarketDayZoned(nowET)) {
913
+ if (this.isMarketDay(nowET)) {
1088
914
  const timeInMinutes = nowET.getHours() * 60 + nowET.getMinutes();
1089
915
  const extendedEndMinutes = MARKET_TIMES.EXTENDED.END.HOUR * 60 + MARKET_TIMES.EXTENDED.END.MINUTE;
1090
916
  // Check if we're after market close (including extended hours)
@@ -1108,33 +934,18 @@ class MarketTimeUtil {
1108
934
  * @property {string} yyyymmdd - The date in YYYY-MM-DD format
1109
935
  * @property {string} dateISOString - Full ISO date string
1110
936
  */
1111
- /**
1112
- * Gets the next market day from a date already in market timezone.
1113
- * @param nyDate - Date in market timezone representation
1114
- * @returns The next market day in market timezone representation
1115
- */
1116
- getNextMarketDayZoned(nyDate) {
1117
- let currentDate = add(nyDate, { days: 1 });
1118
- while (!this.isMarketDayZoned(currentDate)) {
937
+ getNextMarketDay(date) {
938
+ let currentDate = add(date, { days: 1 });
939
+ while (!this.isMarketDay(currentDate)) {
1119
940
  currentDate = add(currentDate, { days: 1 });
1120
941
  }
1121
942
  return currentDate;
1122
943
  }
1123
- /**
1124
- * Gets the next market day from a reference date.
1125
- * Handles timezone conversion from any input date.
1126
- * @param date - The reference date (any timezone)
1127
- * @returns The next market day as a Date (note: internally represented in market timezone)
1128
- */
1129
- getNextMarketDay(date) {
1130
- const nyDate = toZonedTime(date, this.timezone);
1131
- return this.getNextMarketDayZoned(nyDate);
1132
- }
1133
944
  getDayBoundaries(date) {
1134
945
  let start;
1135
946
  let end;
1136
947
  switch (this.intradayReporting) {
1137
- case "extended_hours": {
948
+ case 'extended_hours': {
1138
949
  start = set(date, {
1139
950
  hours: MARKET_TIMES.EXTENDED.START.HOUR,
1140
951
  minutes: MARKET_TIMES.EXTENDED.START.MINUTE,
@@ -1149,7 +960,7 @@ class MarketTimeUtil {
1149
960
  });
1150
961
  break;
1151
962
  }
1152
- case "continuous": {
963
+ case 'continuous': {
1153
964
  start = startOfDay(date);
1154
965
  end = endOfDay(date);
1155
966
  break;
@@ -1162,9 +973,9 @@ class MarketTimeUtil {
1162
973
  seconds: 0,
1163
974
  milliseconds: 0,
1164
975
  });
1165
- // Check for early close (date is already zoned)
1166
- if (this.isEarlyCloseDayZoned(date)) {
1167
- const earlyCloseMinutes = this.getEarlyCloseTimeZoned(date);
976
+ // Check for early close
977
+ if (this.isEarlyCloseDay(date)) {
978
+ const earlyCloseMinutes = this.getEarlyCloseTime(date);
1168
979
  if (earlyCloseMinutes !== null) {
1169
980
  const earlyCloseHours = Math.floor(earlyCloseMinutes / 60);
1170
981
  const earlyCloseMinutesRemainder = earlyCloseMinutes % 60;
@@ -1191,44 +1002,44 @@ class MarketTimeUtil {
1191
1002
  calculatePeriodStartDate(endDate, period) {
1192
1003
  let startDate;
1193
1004
  switch (period) {
1194
- case "YTD":
1005
+ case 'YTD':
1195
1006
  startDate = set(endDate, { month: 0, date: 1 });
1196
1007
  break;
1197
- case "1D":
1008
+ case '1D':
1198
1009
  startDate = this.getLastMarketDay(endDate);
1199
1010
  break;
1200
- case "3D":
1011
+ case '3D':
1201
1012
  startDate = sub(endDate, { days: 3 });
1202
1013
  break;
1203
- case "1W":
1014
+ case '1W':
1204
1015
  startDate = sub(endDate, { weeks: 1 });
1205
1016
  break;
1206
- case "2W":
1017
+ case '2W':
1207
1018
  startDate = sub(endDate, { weeks: 2 });
1208
1019
  break;
1209
- case "1M":
1020
+ case '1M':
1210
1021
  startDate = sub(endDate, { months: 1 });
1211
1022
  break;
1212
- case "3M":
1023
+ case '3M':
1213
1024
  startDate = sub(endDate, { months: 3 });
1214
1025
  break;
1215
- case "6M":
1026
+ case '6M':
1216
1027
  startDate = sub(endDate, { months: 6 });
1217
1028
  break;
1218
- case "1Y":
1029
+ case '1Y':
1219
1030
  startDate = sub(endDate, { years: 1 });
1220
1031
  break;
1221
1032
  default:
1222
1033
  throw new Error(`Invalid period: ${period}`);
1223
1034
  }
1224
- while (!this.isMarketDayZoned(startDate)) {
1225
- startDate = this.getNextMarketDayZoned(startDate);
1035
+ while (!this.isMarketDay(startDate)) {
1036
+ startDate = this.getNextMarketDay(startDate);
1226
1037
  }
1227
1038
  return startDate;
1228
1039
  }
1229
- getMarketTimePeriod({ period, end = new Date(), intraday_reporting, outputFormat = "iso", }) {
1040
+ getMarketTimePeriod({ period, end = new Date(), intraday_reporting, outputFormat = 'iso', }) {
1230
1041
  if (!period) {
1231
- throw new Error("Period is required");
1042
+ throw new Error('Period is required');
1232
1043
  }
1233
1044
  if (intraday_reporting) {
1234
1045
  this.intradayReporting = intraday_reporting;
@@ -1237,9 +1048,9 @@ class MarketTimeUtil {
1237
1048
  const zonedEndDate = toZonedTime(end, this.timezone);
1238
1049
  let startDate;
1239
1050
  let endDate;
1240
- const isCurrentMarketDay = this.isMarketDayZoned(zonedEndDate);
1241
- const isWithinHours = this.isWithinMarketHoursZoned(zonedEndDate);
1242
- const isBeforeHours = this.isBeforeMarketHoursZoned(zonedEndDate);
1051
+ const isCurrentMarketDay = this.isMarketDay(zonedEndDate);
1052
+ const isWithinHours = this.isWithinMarketHours(zonedEndDate);
1053
+ const isBeforeHours = this.isBeforeMarketHours(zonedEndDate);
1243
1054
  // First determine the end date based on current market conditions
1244
1055
  if (isCurrentMarketDay) {
1245
1056
  if (isBeforeHours) {
@@ -1273,7 +1084,7 @@ class MarketTimeUtil {
1273
1084
  const utcEnd = fromZonedTime(endDate, this.timezone);
1274
1085
  // Ensure start is not after end
1275
1086
  if (isBefore(utcEnd, utcStart)) {
1276
- throw new Error("Start date cannot be after end date");
1087
+ throw new Error('Start date cannot be after end date');
1277
1088
  }
1278
1089
  return {
1279
1090
  start: this.formatDate(utcStart, outputFormat),
@@ -1284,7 +1095,7 @@ class MarketTimeUtil {
1284
1095
  const { date = new Date() } = options;
1285
1096
  const zonedDate = toZonedTime(date, this.timezone);
1286
1097
  // Check if market is closed for the day
1287
- if (this.isWeekendZoned(zonedDate) || this.isHolidayZoned(zonedDate)) {
1098
+ if (this.isWeekend(zonedDate) || this.isHoliday(zonedDate)) {
1288
1099
  return {
1289
1100
  marketOpen: false,
1290
1101
  open: null,
@@ -1298,10 +1109,10 @@ class MarketTimeUtil {
1298
1109
  let regularCloseTime = MARKET_TIMES.REGULAR.END;
1299
1110
  const extendedOpenTime = MARKET_TIMES.EXTENDED.START;
1300
1111
  let extendedCloseTime = MARKET_TIMES.EXTENDED.END;
1301
- // Check for early close (zonedDate is already in market timezone)
1302
- const isEarlyClose = this.isEarlyCloseDayZoned(zonedDate);
1112
+ // Check for early close
1113
+ const isEarlyClose = this.isEarlyCloseDay(zonedDate);
1303
1114
  if (isEarlyClose) {
1304
- const earlyCloseMinutes = this.getEarlyCloseTimeZoned(zonedDate);
1115
+ const earlyCloseMinutes = this.getEarlyCloseTime(zonedDate);
1305
1116
  if (earlyCloseMinutes !== null) {
1306
1117
  // For regular hours, use the early close time
1307
1118
  regularCloseTime = {
@@ -1317,22 +1128,10 @@ class MarketTimeUtil {
1317
1128
  };
1318
1129
  }
1319
1130
  }
1320
- const open = fromZonedTime(set(dayStart, {
1321
- hours: regularOpenTime.HOUR,
1322
- minutes: regularOpenTime.MINUTE,
1323
- }), this.timezone);
1324
- const close = fromZonedTime(set(dayStart, {
1325
- hours: regularCloseTime.HOUR,
1326
- minutes: regularCloseTime.MINUTE,
1327
- }), this.timezone);
1328
- const openExt = fromZonedTime(set(dayStart, {
1329
- hours: extendedOpenTime.HOUR,
1330
- minutes: extendedOpenTime.MINUTE,
1331
- }), this.timezone);
1332
- const closeExt = fromZonedTime(set(dayStart, {
1333
- hours: extendedCloseTime.HOUR,
1334
- minutes: extendedCloseTime.MINUTE,
1335
- }), this.timezone);
1131
+ const open = fromZonedTime(set(dayStart, { hours: regularOpenTime.HOUR, minutes: regularOpenTime.MINUTE }), this.timezone);
1132
+ const close = fromZonedTime(set(dayStart, { hours: regularCloseTime.HOUR, minutes: regularCloseTime.MINUTE }), this.timezone);
1133
+ const openExt = fromZonedTime(set(dayStart, { hours: extendedOpenTime.HOUR, minutes: extendedOpenTime.MINUTE }), this.timezone);
1134
+ const closeExt = fromZonedTime(set(dayStart, { hours: extendedCloseTime.HOUR, minutes: extendedCloseTime.MINUTE }), this.timezone);
1336
1135
  return {
1337
1136
  marketOpen: true,
1338
1137
  open,
@@ -1355,7 +1154,7 @@ function getLastFullTradingDate(currentDate = new Date()) {
1355
1154
  // Format the date in NY timezone to ensure consistency
1356
1155
  return {
1357
1156
  date,
1358
- YYYYMMDD: formatInTimeZone(date, MARKET_TIMES.TIMEZONE, "yyyy-MM-dd"),
1157
+ YYYYMMDD: formatInTimeZone(date, MARKET_TIMES.TIMEZONE, 'yyyy-MM-dd'),
1359
1158
  };
1360
1159
  }
1361
1160
 
@@ -6329,82 +6128,13 @@ function requireWebsocketServer () {
6329
6128
 
6330
6129
  requireWebsocketServer();
6331
6130
 
6332
- /**
6333
- * API credential validation utilities
6334
- * Provides fast, synchronous validation of API credentials before making requests
6335
- */
6336
- /**
6337
- * Validates Alpaca API credentials
6338
- * @param auth - Authentication object containing API key and secret
6339
- * @param options - Validation options
6340
- * @param options.throwOnMissing - If false, missing credentials will log a warning instead of throwing (default: true)
6341
- * @throws {Error} If credentials are invalid (when throwOnMissing is true)
6342
- * @returns {boolean} True if credentials are valid, false if missing (when throwOnMissing is false)
6343
- */
6344
- function validateAlpacaCredentials(auth, options = { throwOnMissing: true }) {
6345
- const { throwOnMissing = true } = options;
6346
- // Check for missing or empty API key
6347
- if (!auth.apiKey ||
6348
- typeof auth.apiKey !== "string" ||
6349
- auth.apiKey.trim().length === 0) {
6350
- if (throwOnMissing) {
6351
- throw new Error("Invalid Alpaca API key: must be a non-empty string");
6352
- }
6353
- console.warn("[AlpacaAPI] API key not configured. Market data features will be unavailable.");
6354
- return false;
6355
- }
6356
- // Check for missing or empty API secret
6357
- if (!auth.apiSecret ||
6358
- typeof auth.apiSecret !== "string" ||
6359
- auth.apiSecret.trim().length === 0) {
6360
- if (throwOnMissing) {
6361
- throw new Error("Invalid Alpaca API secret: must be a non-empty string");
6362
- }
6363
- console.warn("[AlpacaAPI] API secret not configured. Market data features will be unavailable.");
6364
- return false;
6365
- }
6366
- // Alpaca keys are typically 20+ characters
6367
- if (auth.apiKey.length < 10) {
6368
- if (throwOnMissing) {
6369
- throw new Error("Alpaca API key appears to be too short");
6370
- }
6371
- console.warn("[AlpacaAPI] API key appears to be too short.");
6372
- return false;
6373
- }
6374
- return true;
6375
- }
6376
-
6377
- /**
6378
- * HTTP request timeout utilities
6379
- * Provides configurable timeout handling for external API calls
6380
- */
6381
- /**
6382
- * Default timeout values for different external APIs (in milliseconds)
6383
- * Can be overridden via environment variables
6384
- */
6385
- const DEFAULT_TIMEOUTS = {
6386
- ALPACA_API: parseInt(process.env.ALPACA_API_TIMEOUT || "30000", 10),
6387
- POLYGON_API: parseInt(process.env.POLYGON_API_TIMEOUT || "30000", 10),
6388
- ALPHA_VANTAGE: parseInt(process.env.ALPHA_VANTAGE_API_TIMEOUT || "30000", 10),
6389
- GENERAL: parseInt(process.env.HTTP_TIMEOUT || "30000", 10),
6390
- };
6391
- /**
6392
- * Creates an AbortSignal that times out after the specified duration
6393
- * Compatible with fetch API
6394
- * @param ms - Timeout duration in milliseconds
6395
- * @returns AbortSignal that will abort after the specified duration
6396
- */
6397
- function createTimeoutSignal(ms) {
6398
- return AbortSignal.timeout(ms);
6399
- }
6400
-
6401
- const log$1 = (message, options = { type: "info" }) => {
6402
- log$2(message, { ...options, source: "AlpacaMarketDataAPI" });
6131
+ const log$1 = (message, options = { type: 'info' }) => {
6132
+ log$2(message, { ...options, source: 'AlpacaMarketDataAPI' });
6403
6133
  };
6404
6134
  // Default settings for market data API
6405
- const DEFAULT_ADJUSTMENT = "all";
6406
- const DEFAULT_FEED = "sip";
6407
- const DEFAULT_CURRENCY = "USD";
6135
+ const DEFAULT_ADJUSTMENT = 'all';
6136
+ const DEFAULT_FEED = 'sip';
6137
+ const DEFAULT_CURRENCY = 'USD';
6408
6138
  /**
6409
6139
  * Singleton class for interacting with Alpaca Market Data API
6410
6140
  * Provides methods for fetching historical bars, latest bars, last trades, latest trades, latest quotes, and latest quote for a single symbol
@@ -6415,84 +6145,50 @@ class AlpacaMarketDataAPI extends EventEmitter {
6415
6145
  dataURL;
6416
6146
  apiURL;
6417
6147
  v1beta1url;
6418
- /** Whether API credentials are valid and available. False during build time when env vars are missing. */
6419
- credentialsValid = false;
6420
- stockStreamUrl = getStockStreamUrl("PRODUCTION"); // production values
6421
- optionStreamUrl = getOptionsStreamUrl("PRODUCTION"); // production values
6422
- cryptoStreamUrl = getCryptoStreamUrl("PRODUCTION"); // production values
6148
+ stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/sip'; // production values
6149
+ optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options'; // production values
6423
6150
  stockWs = null;
6424
6151
  optionWs = null;
6425
- cryptoWs = null;
6426
- stockSubscriptions = {
6427
- trades: [],
6428
- quotes: [],
6429
- bars: [],
6430
- };
6431
- optionSubscriptions = {
6432
- trades: [],
6433
- quotes: [],
6434
- bars: [],
6435
- };
6436
- cryptoSubscriptions = {
6437
- trades: [],
6438
- quotes: [],
6439
- bars: [],
6440
- };
6441
- setMode(mode = "production") {
6442
- if (mode === "sandbox") {
6443
- // sandbox mode
6444
- this.stockStreamUrl = WEBSOCKET_STREAMS.STOCKS.PRODUCTION; // sandbox uses production for stocks
6445
- this.optionStreamUrl = getOptionsStreamUrl("SANDBOX");
6446
- this.cryptoStreamUrl = getCryptoStreamUrl("SANDBOX");
6152
+ stockSubscriptions = { trades: [], quotes: [], bars: [] };
6153
+ optionSubscriptions = { trades: [], quotes: [], bars: [] };
6154
+ setMode(mode = 'production') {
6155
+ if (mode === 'sandbox') { // sandbox mode
6156
+ this.stockStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v2/sip';
6157
+ this.optionStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v1beta3/options';
6447
6158
  }
6448
- else if (mode === "test") {
6449
- // test mode, can only use ticker FAKEPACA
6450
- this.stockStreamUrl = getStockStreamUrl("TEST");
6451
- this.optionStreamUrl = getOptionsStreamUrl("PRODUCTION"); // there's no test mode for options
6452
- this.cryptoStreamUrl = getCryptoStreamUrl("PRODUCTION"); // there's no test mode for crypto
6159
+ else if (mode === 'test') { // test mode, can only use ticker FAKEPACA
6160
+ this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/test';
6161
+ this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options'; // there's no test mode for options
6453
6162
  }
6454
- else {
6455
- // production
6456
- this.stockStreamUrl = getStockStreamUrl("PRODUCTION");
6457
- this.optionStreamUrl = getOptionsStreamUrl("PRODUCTION");
6458
- this.cryptoStreamUrl = getCryptoStreamUrl("PRODUCTION");
6163
+ else { // production
6164
+ this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/sip';
6165
+ this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options';
6459
6166
  }
6460
6167
  }
6461
6168
  getMode() {
6462
- if (this.stockStreamUrl.includes("sandbox")) {
6463
- return "sandbox";
6169
+ if (this.stockStreamUrl.includes('sandbox')) {
6170
+ return 'sandbox';
6464
6171
  }
6465
- else if (this.stockStreamUrl.includes("test")) {
6466
- return "test";
6172
+ else if (this.stockStreamUrl.includes('test')) {
6173
+ return 'test';
6467
6174
  }
6468
6175
  else {
6469
- return "production";
6176
+ return 'production';
6470
6177
  }
6471
6178
  }
6472
6179
  constructor() {
6473
6180
  super();
6474
- // Validate credentials from environment variables before initializing
6475
- // Use throwOnMissing: false to allow initialization during build time
6476
- // when env vars are not available. Features will be unavailable until
6477
- // credentials are provided at runtime.
6478
- const apiKey = process.env.ALPACA_API_KEY || "";
6479
- const apiSecret = process.env.ALPACA_SECRET_KEY || "";
6480
- this.credentialsValid = validateAlpacaCredentials({
6481
- apiKey,
6482
- apiSecret,
6483
- isPaper: process.env.ALPACA_ACCOUNT_TYPE === "PAPER",
6484
- }, { throwOnMissing: false });
6485
- this.dataURL = MARKET_DATA_API.STOCKS;
6181
+ this.dataURL = 'https://data.alpaca.markets/v2';
6486
6182
  this.apiURL =
6487
- process.env.ALPACA_ACCOUNT_TYPE === "PAPER"
6488
- ? getTradingApiUrl("PAPER")
6489
- : getTradingApiUrl("LIVE"); // used by some, e.g. getAssets
6490
- this.v1beta1url = MARKET_DATA_API.OPTIONS; // used for options endpoints
6491
- this.setMode("production"); // sets stockStreamUrl and optionStreamUrl
6183
+ process.env.ALPACA_ACCOUNT_TYPE === 'PAPER'
6184
+ ? 'https://paper-api.alpaca.markets/v2'
6185
+ : 'https://api.alpaca.markets/v2'; // used by some, e.g. getAssets
6186
+ this.v1beta1url = 'https://data.alpaca.markets/v1beta1'; // used for options endpoints
6187
+ this.setMode('production'); // sets stockStreamUrl and optionStreamUrl
6492
6188
  this.headers = {
6493
- "APCA-API-KEY-ID": apiKey,
6494
- "APCA-API-SECRET-KEY": apiSecret,
6495
- "Content-Type": "application/json",
6189
+ 'APCA-API-KEY-ID': process.env.ALPACA_API_KEY,
6190
+ 'APCA-API-SECRET-KEY': process.env.ALPACA_SECRET_KEY,
6191
+ 'Content-Type': 'application/json',
6496
6192
  };
6497
6193
  }
6498
6194
  static getInstance() {
@@ -6508,105 +6204,57 @@ class AlpacaMarketDataAPI extends EventEmitter {
6508
6204
  return super.emit(event, ...args);
6509
6205
  }
6510
6206
  connect(streamType) {
6511
- let url;
6512
- if (streamType === "stock") {
6513
- url = this.stockStreamUrl;
6514
- }
6515
- else if (streamType === "option") {
6516
- url = this.optionStreamUrl;
6517
- }
6518
- else {
6519
- url = this.cryptoStreamUrl;
6520
- }
6207
+ const url = streamType === 'stock' ? this.stockStreamUrl : this.optionStreamUrl;
6521
6208
  const ws = new WebSocket(url);
6522
- if (streamType === "stock") {
6209
+ if (streamType === 'stock') {
6523
6210
  this.stockWs = ws;
6524
6211
  }
6525
- else if (streamType === "option") {
6526
- this.optionWs = ws;
6527
- }
6528
6212
  else {
6529
- this.cryptoWs = ws;
6213
+ this.optionWs = ws;
6530
6214
  }
6531
- ws.on("open", () => {
6532
- log$1(`${streamType} stream connected`, { type: "info" });
6215
+ ws.on('open', () => {
6216
+ log$1(`${streamType} stream connected`, { type: 'info' });
6533
6217
  const authMessage = {
6534
- action: "auth",
6218
+ action: 'auth',
6535
6219
  key: process.env.ALPACA_API_KEY,
6536
6220
  secret: process.env.ALPACA_SECRET_KEY,
6537
6221
  };
6538
6222
  ws.send(JSON.stringify(authMessage));
6539
6223
  });
6540
- ws.on("message", (data) => {
6541
- const rawData = data.toString();
6542
- let messages;
6543
- try {
6544
- messages = JSON.parse(rawData);
6545
- }
6546
- catch (e) {
6547
- log$1(`${streamType} stream received invalid JSON: ${rawData.substring(0, 200)}`, { type: "error" });
6548
- return;
6549
- }
6224
+ ws.on('message', (data) => {
6225
+ //log(`RAW MESSASGE: ${data.toString()}`);
6226
+ const messages = JSON.parse(data.toString());
6550
6227
  for (const message of messages) {
6551
- if (message.T === "success" && message.msg === "authenticated") {
6552
- log$1(`${streamType} stream authenticated`, { type: "info" });
6228
+ if (message.T === 'success' && message.msg === 'authenticated') {
6229
+ log$1(`${streamType} stream authenticated`, { type: 'info' });
6553
6230
  this.sendSubscription(streamType);
6554
6231
  }
6555
- else if (message.T === "success" && message.msg === "connected") {
6556
- log$1(`${streamType} stream connected message received`, {
6557
- type: "debug",
6558
- });
6559
- }
6560
- else if (message.T === "subscription") {
6561
- log$1(`${streamType} subscription confirmed: trades=${message.trades?.length || 0}, quotes=${message.quotes?.length || 0}, bars=${message.bars?.length || 0}`, { type: "info" });
6562
- }
6563
- else if (message.T === "error") {
6564
- log$1(`${streamType} stream error: ${message.msg} (code: ${message.code}, raw: ${JSON.stringify(message)})`, { type: "error" });
6232
+ else if (message.T === 'error') {
6233
+ log$1(`${streamType} stream error: ${message.msg}`, { type: 'error' });
6565
6234
  }
6566
6235
  else if (message.S) {
6567
6236
  super.emit(`${streamType}-${message.T}`, message);
6568
6237
  super.emit(`${streamType}-data`, message);
6569
6238
  }
6570
- else {
6571
- log$1(`${streamType} received unknown message type: ${JSON.stringify(message)}`, { type: "debug" });
6572
- }
6573
6239
  }
6574
6240
  });
6575
- ws.on("close", () => {
6576
- log$1(`${streamType} stream disconnected`, { type: "warn" });
6577
- if (streamType === "stock") {
6241
+ ws.on('close', () => {
6242
+ log$1(`${streamType} stream disconnected`, { type: 'warn' });
6243
+ if (streamType === 'stock') {
6578
6244
  this.stockWs = null;
6579
6245
  }
6580
- else if (streamType === "option") {
6581
- this.optionWs = null;
6582
- }
6583
6246
  else {
6584
- this.cryptoWs = null;
6247
+ this.optionWs = null;
6585
6248
  }
6586
6249
  // Optional: implement reconnect logic
6587
6250
  });
6588
- ws.on("error", (error) => {
6589
- log$1(`${streamType} stream error: ${error.message}`, { type: "error" });
6251
+ ws.on('error', (error) => {
6252
+ log$1(`${streamType} stream error: ${error.message}`, { type: 'error' });
6590
6253
  });
6591
6254
  }
6592
6255
  sendSubscription(streamType) {
6593
- let ws;
6594
- let subscriptions;
6595
- if (streamType === "stock") {
6596
- ws = this.stockWs;
6597
- subscriptions = this.stockSubscriptions;
6598
- }
6599
- else if (streamType === "option") {
6600
- ws = this.optionWs;
6601
- subscriptions = this.optionSubscriptions;
6602
- }
6603
- else {
6604
- ws = this.cryptoWs;
6605
- subscriptions = this.cryptoSubscriptions;
6606
- }
6607
- log$1(`sendSubscription called for ${streamType} (wsReady=${ws?.readyState === WebSocket.OPEN}, trades=${subscriptions.trades?.length || 0}, quotes=${subscriptions.quotes?.length || 0}, bars=${subscriptions.bars?.length || 0})`, {
6608
- type: "debug",
6609
- });
6256
+ const ws = streamType === 'stock' ? this.stockWs : this.optionWs;
6257
+ const subscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;
6610
6258
  if (ws && ws.readyState === WebSocket.OPEN) {
6611
6259
  const subMessagePayload = {};
6612
6260
  if (subscriptions.trades.length > 0) {
@@ -6620,40 +6268,21 @@ class AlpacaMarketDataAPI extends EventEmitter {
6620
6268
  }
6621
6269
  if (Object.keys(subMessagePayload).length > 0) {
6622
6270
  const subMessage = {
6623
- action: "subscribe",
6271
+ action: 'subscribe',
6624
6272
  ...subMessagePayload,
6625
6273
  };
6626
- const messageJson = JSON.stringify(subMessage);
6627
- log$1(`Sending ${streamType} subscription: ${messageJson}`, {
6628
- type: "info",
6629
- });
6630
- ws.send(messageJson);
6631
- }
6632
- else {
6633
- log$1(`No ${streamType} subscriptions to send (all arrays empty)`, {
6634
- type: "debug",
6635
- });
6274
+ ws.send(JSON.stringify(subMessage));
6636
6275
  }
6637
6276
  }
6638
- else {
6639
- log$1(`Cannot send ${streamType} subscription: WebSocket not ready`, {
6640
- type: "warn",
6641
- });
6642
- }
6643
6277
  }
6644
6278
  connectStockStream() {
6645
6279
  if (!this.stockWs) {
6646
- this.connect("stock");
6280
+ this.connect('stock');
6647
6281
  }
6648
6282
  }
6649
6283
  connectOptionStream() {
6650
6284
  if (!this.optionWs) {
6651
- this.connect("option");
6652
- }
6653
- }
6654
- connectCryptoStream() {
6655
- if (!this.cryptoWs) {
6656
- this.connect("crypto");
6285
+ this.connect('option');
6657
6286
  }
6658
6287
  }
6659
6288
  disconnectStockStream() {
@@ -6666,95 +6295,41 @@ class AlpacaMarketDataAPI extends EventEmitter {
6666
6295
  this.optionWs.close();
6667
6296
  }
6668
6297
  }
6669
- disconnectCryptoStream() {
6670
- if (this.cryptoWs) {
6671
- this.cryptoWs.close();
6672
- }
6673
- }
6674
- /**
6675
- * Check if a specific stream is connected
6676
- * @param streamType - The type of stream to check
6677
- * @returns True if the stream is connected
6678
- */
6679
- isStreamConnected(streamType) {
6680
- if (streamType === "stock") {
6681
- return (this.stockWs !== null && this.stockWs.readyState === WebSocket.OPEN);
6682
- }
6683
- else if (streamType === "option") {
6684
- return (this.optionWs !== null && this.optionWs.readyState === WebSocket.OPEN);
6685
- }
6686
- else {
6687
- return (this.cryptoWs !== null && this.cryptoWs.readyState === WebSocket.OPEN);
6688
- }
6689
- }
6690
6298
  subscribe(streamType, subscriptions) {
6691
- let currentSubscriptions;
6692
- if (streamType === "stock") {
6693
- currentSubscriptions = this.stockSubscriptions;
6694
- }
6695
- else if (streamType === "option") {
6696
- currentSubscriptions = this.optionSubscriptions;
6697
- }
6698
- else {
6699
- currentSubscriptions = this.cryptoSubscriptions;
6700
- }
6299
+ const currentSubscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;
6701
6300
  Object.entries(subscriptions).forEach(([key, value]) => {
6702
6301
  if (value) {
6703
- currentSubscriptions[key] = [
6704
- ...new Set([...(currentSubscriptions[key] || []), ...value]),
6705
- ];
6302
+ currentSubscriptions[key] = [...new Set([...(currentSubscriptions[key] || []), ...value])];
6706
6303
  }
6707
6304
  });
6708
6305
  this.sendSubscription(streamType);
6709
6306
  }
6710
6307
  unsubscribe(streamType, subscriptions) {
6711
- let currentSubscriptions;
6712
- if (streamType === "stock") {
6713
- currentSubscriptions = this.stockSubscriptions;
6714
- }
6715
- else if (streamType === "option") {
6716
- currentSubscriptions = this.optionSubscriptions;
6717
- }
6718
- else {
6719
- currentSubscriptions = this.cryptoSubscriptions;
6720
- }
6308
+ const currentSubscriptions = streamType === 'stock' ? this.stockSubscriptions : this.optionSubscriptions;
6721
6309
  Object.entries(subscriptions).forEach(([key, value]) => {
6722
6310
  if (value) {
6723
- currentSubscriptions[key] = (currentSubscriptions[key] || []).filter((s) => !value.includes(s));
6311
+ currentSubscriptions[key] = (currentSubscriptions[key] || []).filter(s => !value.includes(s));
6724
6312
  }
6725
6313
  });
6726
6314
  const unsubMessage = {
6727
- action: "unsubscribe",
6315
+ action: 'unsubscribe',
6728
6316
  ...subscriptions,
6729
6317
  };
6730
- let ws;
6731
- if (streamType === "stock") {
6732
- ws = this.stockWs;
6733
- }
6734
- else if (streamType === "option") {
6735
- ws = this.optionWs;
6736
- }
6737
- else {
6738
- ws = this.cryptoWs;
6739
- }
6318
+ const ws = streamType === 'stock' ? this.stockWs : this.optionWs;
6740
6319
  if (ws && ws.readyState === WebSocket.OPEN) {
6741
6320
  ws.send(JSON.stringify(unsubMessage));
6742
6321
  }
6743
6322
  }
6744
- async makeRequest(endpoint, method = "GET", params, baseUrlName = "data") {
6745
- const baseUrl = baseUrlName === "data"
6746
- ? this.dataURL
6747
- : baseUrlName === "api"
6748
- ? this.apiURL
6749
- : this.v1beta1url;
6323
+ async makeRequest(endpoint, method = 'GET', params, baseUrlName = 'data') {
6324
+ const baseUrl = baseUrlName === 'data' ? this.dataURL : baseUrlName === 'api' ? this.apiURL : this.v1beta1url;
6750
6325
  const url = new URL(`${baseUrl}${endpoint}`);
6751
6326
  try {
6752
6327
  if (params) {
6753
6328
  Object.entries(params).forEach(([key, value]) => {
6754
6329
  if (Array.isArray(value)) {
6755
- url.searchParams.append(key, value.join(","));
6330
+ url.searchParams.append(key, value.join(','));
6756
6331
  }
6757
- else if (value !== undefined && value !== null) {
6332
+ else if (value !== undefined) {
6758
6333
  url.searchParams.append(key, value.toString());
6759
6334
  }
6760
6335
  });
@@ -6762,13 +6337,10 @@ class AlpacaMarketDataAPI extends EventEmitter {
6762
6337
  const response = await fetch(url.toString(), {
6763
6338
  method,
6764
6339
  headers: this.headers,
6765
- signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
6766
6340
  });
6767
6341
  if (!response.ok) {
6768
6342
  const errorText = await response.text();
6769
- log$1(`Market Data API error (${response.status}): ${errorText}`, {
6770
- type: "error",
6771
- });
6343
+ log$1(`Market Data API error (${response.status}): ${errorText}`, { type: 'error' });
6772
6344
  throw new Error(`Market Data API error (${response.status}): ${errorText}`);
6773
6345
  }
6774
6346
  const data = await response.json();
@@ -6776,9 +6348,9 @@ class AlpacaMarketDataAPI extends EventEmitter {
6776
6348
  }
6777
6349
  catch (err) {
6778
6350
  const error = err;
6779
- log$1(`Error in makeRequest: ${error.message}. Endpoint: ${endpoint}. Url: ${url.toString()}`, { type: "error" });
6351
+ log$1(`Error in makeRequest: ${error.message}. Endpoint: ${endpoint}. Url: ${url.toString()}`, { type: 'error' });
6780
6352
  if (error instanceof TypeError) {
6781
- log$1(`Network error details: ${error.stack}`, { type: "error" });
6353
+ log$1(`Network error details: ${error.stack}`, { type: 'error' });
6782
6354
  }
6783
6355
  throw error;
6784
6356
  }
@@ -6791,19 +6363,19 @@ class AlpacaMarketDataAPI extends EventEmitter {
6791
6363
  */
6792
6364
  async getHistoricalBars(params) {
6793
6365
  const symbols = params.symbols;
6794
- const symbolsStr = symbols.join(",");
6366
+ const symbolsStr = symbols.join(',');
6795
6367
  let allBars = {};
6796
6368
  let pageToken = null;
6797
6369
  let hasMorePages = true;
6798
6370
  let totalBarsCount = 0;
6799
6371
  let pageCount = 0;
6800
- let currency = "";
6372
+ let currency = '';
6801
6373
  // Initialize bar arrays for each symbol
6802
- symbols.forEach((symbol) => {
6374
+ symbols.forEach(symbol => {
6803
6375
  allBars[symbol] = [];
6804
6376
  });
6805
- log$1(`Starting historical bars fetch for ${symbolsStr} (${params.timeframe}, ${params.start || "no start"} to ${params.end || "no end"})`, {
6806
- type: "info",
6377
+ log$1(`Starting historical bars fetch for ${symbolsStr} (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`, {
6378
+ type: 'info'
6807
6379
  });
6808
6380
  while (hasMorePages) {
6809
6381
  pageCount++;
@@ -6813,11 +6385,9 @@ class AlpacaMarketDataAPI extends EventEmitter {
6813
6385
  feed: DEFAULT_FEED,
6814
6386
  ...(pageToken && { page_token: pageToken }),
6815
6387
  };
6816
- const response = await this.makeRequest("/stocks/bars", "GET", requestParams);
6388
+ const response = await this.makeRequest('/stocks/bars', 'GET', requestParams);
6817
6389
  if (!response.bars) {
6818
- log$1(`No bars data found in response for ${symbolsStr}`, {
6819
- type: "warn",
6820
- });
6390
+ log$1(`No bars data found in response for ${symbolsStr}`, { type: 'warn' });
6821
6391
  break;
6822
6392
  }
6823
6393
  // Track currency from first response
@@ -6833,7 +6403,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6833
6403
  allBars[symbol] = [...allBars[symbol], ...bars];
6834
6404
  pageBarsCount += bars.length;
6835
6405
  // Track date range for this page
6836
- bars.forEach((bar) => {
6406
+ bars.forEach(bar => {
6837
6407
  const barDate = new Date(bar.t);
6838
6408
  if (!earliestTimestamp || barDate < earliestTimestamp) {
6839
6409
  earliestTimestamp = barDate;
@@ -6849,23 +6419,21 @@ class AlpacaMarketDataAPI extends EventEmitter {
6849
6419
  hasMorePages = !!pageToken;
6850
6420
  // Enhanced logging with date range and progress info
6851
6421
  const dateRangeStr = earliestTimestamp && latestTimestamp
6852
- ? `${earliestTimestamp.toLocaleDateString("en-US", { timeZone: "America/New_York" })} to ${latestTimestamp.toLocaleDateString("en-US", { timeZone: "America/New_York" })}`
6853
- : "unknown range";
6854
- log$1(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbolsStr}, date range: ${dateRangeStr}${hasMorePages ? ", more pages available" : ", complete"}`, {
6855
- type: "info",
6422
+ ? `${earliestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${latestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
6423
+ : 'unknown range';
6424
+ log$1(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbolsStr}, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {
6425
+ type: 'info'
6856
6426
  });
6857
6427
  // Prevent infinite loops
6858
6428
  if (pageCount > 1000) {
6859
- log$1(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: "warn" });
6429
+ log$1(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
6860
6430
  break;
6861
6431
  }
6862
6432
  }
6863
6433
  // Final summary
6864
- const symbolCounts = Object.entries(allBars)
6865
- .map(([symbol, bars]) => `${symbol}: ${bars.length}`)
6866
- .join(", ");
6434
+ const symbolCounts = Object.entries(allBars).map(([symbol, bars]) => `${symbol}: ${bars.length}`).join(', ');
6867
6435
  log$1(`Historical bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages (${symbolCounts})`, {
6868
- type: "info",
6436
+ type: 'info'
6869
6437
  });
6870
6438
  return {
6871
6439
  bars: allBars,
@@ -6881,7 +6449,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6881
6449
 
6882
6450
  */
6883
6451
  async getLatestBars(symbols, currency) {
6884
- return this.makeRequest("/stocks/bars/latest", "GET", {
6452
+ return this.makeRequest('/stocks/bars/latest', 'GET', {
6885
6453
  symbols,
6886
6454
  feed: DEFAULT_FEED,
6887
6455
  currency: currency || DEFAULT_CURRENCY,
@@ -6893,7 +6461,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6893
6461
  * @returns Last trade details including price, size, exchange, and conditions
6894
6462
  */
6895
6463
  async getLastTrade(symbol) {
6896
- return this.makeRequest(`/v1/last/stocks/${symbol}`, "GET");
6464
+ return this.makeRequest(`/v1/last/stocks/${symbol}`, 'GET');
6897
6465
  }
6898
6466
  /**
6899
6467
  * Get the most recent trades for requested symbols
@@ -6904,7 +6472,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6904
6472
 
6905
6473
  */
6906
6474
  async getLatestTrades(symbols, feed, currency) {
6907
- return this.makeRequest("/stocks/trades/latest", "GET", {
6475
+ return this.makeRequest('/stocks/trades/latest', 'GET', {
6908
6476
  symbols,
6909
6477
  feed: feed || DEFAULT_FEED,
6910
6478
  currency: currency || DEFAULT_CURRENCY,
@@ -6920,15 +6488,13 @@ class AlpacaMarketDataAPI extends EventEmitter {
6920
6488
  async getLatestQuotes(symbols, feed, currency) {
6921
6489
  // Return empty response if symbols array is empty to avoid API error
6922
6490
  if (!symbols || symbols.length === 0) {
6923
- log$1("No symbols provided to getLatestQuotes, returning empty response", {
6924
- type: "warn",
6925
- });
6491
+ log$1('No symbols provided to getLatestQuotes, returning empty response', { type: 'warn' });
6926
6492
  return {
6927
6493
  quotes: {},
6928
6494
  currency: currency || DEFAULT_CURRENCY,
6929
6495
  };
6930
6496
  }
6931
- return this.makeRequest("/stocks/quotes/latest", "GET", {
6497
+ return this.makeRequest('/stocks/quotes/latest', 'GET', {
6932
6498
  symbols,
6933
6499
  feed: feed || DEFAULT_FEED,
6934
6500
  currency: currency || DEFAULT_CURRENCY,
@@ -6942,7 +6508,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6942
6508
  * @returns Latest quote data with symbol and currency information
6943
6509
  */
6944
6510
  async getLatestQuote(symbol, feed, currency) {
6945
- return this.makeRequest(`/stocks/${symbol}/quotes/latest`, "GET", {
6511
+ return this.makeRequest(`/stocks/${symbol}/quotes/latest`, 'GET', {
6946
6512
  feed: feed || DEFAULT_FEED,
6947
6513
  currency,
6948
6514
  });
@@ -6958,16 +6524,13 @@ class AlpacaMarketDataAPI extends EventEmitter {
6958
6524
  const prevMarketDate = getLastFullTradingDate(date);
6959
6525
  const response = await this.getHistoricalBars({
6960
6526
  symbols: [symbol],
6961
- timeframe: "1Day",
6527
+ timeframe: '1Day',
6962
6528
  start: prevMarketDate.date.toISOString(),
6963
6529
  end: prevMarketDate.date.toISOString(),
6964
6530
  limit: 1,
6965
6531
  });
6966
6532
  if (!response.bars[symbol] || response.bars[symbol].length === 0) {
6967
- log$1(`No previous close data available for ${symbol}`, {
6968
- type: "error",
6969
- symbol,
6970
- });
6533
+ log$1(`No previous close data available for ${symbol}`, { type: 'error', symbol });
6971
6534
  return null;
6972
6535
  }
6973
6536
  return response.bars[symbol][0];
@@ -6982,7 +6545,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6982
6545
  async getHourlyPrices(symbol, start, end) {
6983
6546
  const response = await this.getHistoricalBars({
6984
6547
  symbols: [symbol],
6985
- timeframe: "1Hour",
6548
+ timeframe: '1Hour',
6986
6549
  start: new Date(start).toISOString(),
6987
6550
  end: new Date(end).toISOString(),
6988
6551
  limit: 96, // Last 96 hours (4 days)
@@ -6999,7 +6562,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6999
6562
  async getHalfHourlyPrices(symbol, start, end) {
7000
6563
  const response = await this.getHistoricalBars({
7001
6564
  symbols: [symbol],
7002
- timeframe: "30Min",
6565
+ timeframe: '30Min',
7003
6566
  start: new Date(start).toISOString(),
7004
6567
  end: new Date(end).toISOString(),
7005
6568
  limit: 16 * 2 * 4, // last 4 days, 16 hours per day, 2 bars per hour
@@ -7016,7 +6579,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7016
6579
  async getDailyPrices(symbol, start, end) {
7017
6580
  const response = await this.getHistoricalBars({
7018
6581
  symbols: [symbol],
7019
- timeframe: "1Day",
6582
+ timeframe: '1Day',
7020
6583
  start: new Date(start).toISOString(),
7021
6584
  end: new Date(end).toISOString(),
7022
6585
  limit: 100, // Last 100 days
@@ -7048,7 +6611,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7048
6611
  */
7049
6612
  static analyzeBars(bars) {
7050
6613
  if (!bars || bars.length === 0) {
7051
- return "No price data available";
6614
+ return 'No price data available';
7052
6615
  }
7053
6616
  const firstBar = bars[0];
7054
6617
  const lastBar = bars[bars.length - 1];
@@ -7073,7 +6636,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7073
6636
  */
7074
6637
  async getAssets(params) {
7075
6638
  // Endpoint: GET /v2/assets
7076
- return this.makeRequest("/assets", "GET", params, "api"); // use apiURL
6639
+ return this.makeRequest('/assets', 'GET', params, 'api'); // use apiURL
7077
6640
  }
7078
6641
  /**
7079
6642
  * Get a single asset by symbol or asset_id
@@ -7083,7 +6646,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7083
6646
  */
7084
6647
  async getAsset(symbolOrAssetId) {
7085
6648
  // Endpoint: GET /v2/assets/{symbol_or_asset_id}
7086
- return this.makeRequest(`/assets/${encodeURIComponent(symbolOrAssetId)}`, "GET", undefined, "api");
6649
+ return this.makeRequest(`/assets/${encodeURIComponent(symbolOrAssetId)}`, 'GET', undefined, 'api');
7087
6650
  }
7088
6651
  // ===== OPTIONS MARKET DATA METHODS =====
7089
6652
  /**
@@ -7095,7 +6658,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7095
6658
  */
7096
6659
  async getOptionsChain(params) {
7097
6660
  const { underlying_symbol, ...queryParams } = params;
7098
- return this.makeRequest(`/options/snapshots/${encodeURIComponent(underlying_symbol)}`, "GET", queryParams, "v1beta1");
6661
+ return this.makeRequest(`/options/snapshots/${encodeURIComponent(underlying_symbol)}`, 'GET', queryParams, 'v1beta1');
7099
6662
  }
7100
6663
  /**
7101
6664
  * Get the most recent trades for requested option contract symbols
@@ -7107,7 +6670,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7107
6670
  async getLatestOptionsTrades(params) {
7108
6671
  // Remove limit and page_token as they're not supported by this endpoint
7109
6672
  const { limit, page_token, ...requestParams } = params;
7110
- return this.makeRequest("/options/trades/latest", "GET", requestParams, "v1beta1");
6673
+ return this.makeRequest('/options/trades/latest', 'GET', requestParams, 'v1beta1');
7111
6674
  }
7112
6675
  /**
7113
6676
  * Get the most recent quotes for requested option contract symbols
@@ -7119,7 +6682,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7119
6682
  async getLatestOptionsQuotes(params) {
7120
6683
  // Remove limit and page_token as they're not supported by this endpoint
7121
6684
  const { limit, page_token, ...requestParams } = params;
7122
- return this.makeRequest("/options/quotes/latest", "GET", requestParams, "v1beta1");
6685
+ return this.makeRequest('/options/quotes/latest', 'GET', requestParams, 'v1beta1');
7123
6686
  }
7124
6687
  /**
7125
6688
  * Get historical OHLCV bars for option contract symbols
@@ -7131,18 +6694,18 @@ class AlpacaMarketDataAPI extends EventEmitter {
7131
6694
  */
7132
6695
  async getHistoricalOptionsBars(params) {
7133
6696
  const symbols = params.symbols;
7134
- const symbolsStr = symbols.join(",");
6697
+ const symbolsStr = symbols.join(',');
7135
6698
  let allBars = {};
7136
6699
  let pageToken = null;
7137
6700
  let hasMorePages = true;
7138
6701
  let totalBarsCount = 0;
7139
6702
  let pageCount = 0;
7140
6703
  // Initialize bar arrays for each symbol
7141
- symbols.forEach((symbol) => {
6704
+ symbols.forEach(symbol => {
7142
6705
  allBars[symbol] = [];
7143
6706
  });
7144
- log$1(`Starting historical options bars fetch for ${symbolsStr} (${params.timeframe}, ${params.start || "no start"} to ${params.end || "no end"})`, {
7145
- type: "info",
6707
+ log$1(`Starting historical options bars fetch for ${symbolsStr} (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`, {
6708
+ type: 'info'
7146
6709
  });
7147
6710
  while (hasMorePages) {
7148
6711
  pageCount++;
@@ -7150,11 +6713,9 @@ class AlpacaMarketDataAPI extends EventEmitter {
7150
6713
  ...params,
7151
6714
  ...(pageToken && { page_token: pageToken }),
7152
6715
  };
7153
- const response = await this.makeRequest("/options/bars", "GET", requestParams, "v1beta1");
6716
+ const response = await this.makeRequest('/options/bars', 'GET', requestParams, 'v1beta1');
7154
6717
  if (!response.bars) {
7155
- log$1(`No options bars data found in response for ${symbolsStr}`, {
7156
- type: "warn",
7157
- });
6718
+ log$1(`No options bars data found in response for ${symbolsStr}`, { type: 'warn' });
7158
6719
  break;
7159
6720
  }
7160
6721
  // Combine bars for each symbol
@@ -7166,7 +6727,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7166
6727
  allBars[symbol] = [...allBars[symbol], ...bars];
7167
6728
  pageBarsCount += bars.length;
7168
6729
  // Track date range for this page
7169
- bars.forEach((bar) => {
6730
+ bars.forEach(bar => {
7170
6731
  const barDate = new Date(bar.t);
7171
6732
  if (!earliestTimestamp || barDate < earliestTimestamp) {
7172
6733
  earliestTimestamp = barDate;
@@ -7182,23 +6743,21 @@ class AlpacaMarketDataAPI extends EventEmitter {
7182
6743
  hasMorePages = !!pageToken;
7183
6744
  // Enhanced logging with date range and progress info
7184
6745
  const dateRangeStr = earliestTimestamp && latestTimestamp
7185
- ? `${earliestTimestamp.toLocaleDateString("en-US", { timeZone: "America/New_York" })} to ${latestTimestamp.toLocaleDateString("en-US", { timeZone: "America/New_York" })}`
7186
- : "unknown range";
7187
- log$1(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} option bars (total: ${totalBarsCount.toLocaleString()}) for ${symbolsStr}, date range: ${dateRangeStr}${hasMorePages ? ", more pages available" : ", complete"}`, {
7188
- type: "info",
6746
+ ? `${earliestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${latestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
6747
+ : 'unknown range';
6748
+ log$1(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} option bars (total: ${totalBarsCount.toLocaleString()}) for ${symbolsStr}, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {
6749
+ type: 'info'
7189
6750
  });
7190
6751
  // Prevent infinite loops
7191
6752
  if (pageCount > 1000) {
7192
- log$1(`Stopping options bars pagination after ${pageCount} pages to prevent infinite loop`, { type: "warn" });
6753
+ log$1(`Stopping options bars pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
7193
6754
  break;
7194
6755
  }
7195
6756
  }
7196
6757
  // Final summary
7197
- const symbolCounts = Object.entries(allBars)
7198
- .map(([symbol, bars]) => `${symbol}: ${bars.length}`)
7199
- .join(", ");
6758
+ const symbolCounts = Object.entries(allBars).map(([symbol, bars]) => `${symbol}: ${bars.length}`).join(', ');
7200
6759
  log$1(`Historical options bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages (${symbolCounts})`, {
7201
- type: "info",
6760
+ type: 'info'
7202
6761
  });
7203
6762
  return {
7204
6763
  bars: allBars,
@@ -7215,18 +6774,18 @@ class AlpacaMarketDataAPI extends EventEmitter {
7215
6774
  */
7216
6775
  async getHistoricalOptionsTrades(params) {
7217
6776
  const symbols = params.symbols;
7218
- const symbolsStr = symbols.join(",");
6777
+ const symbolsStr = symbols.join(',');
7219
6778
  let allTrades = {};
7220
6779
  let pageToken = null;
7221
6780
  let hasMorePages = true;
7222
6781
  let totalTradesCount = 0;
7223
6782
  let pageCount = 0;
7224
6783
  // Initialize trades arrays for each symbol
7225
- symbols.forEach((symbol) => {
6784
+ symbols.forEach(symbol => {
7226
6785
  allTrades[symbol] = [];
7227
6786
  });
7228
- log$1(`Starting historical options trades fetch for ${symbolsStr} (${params.start || "no start"} to ${params.end || "no end"})`, {
7229
- type: "info",
6787
+ log$1(`Starting historical options trades fetch for ${symbolsStr} (${params.start || 'no start'} to ${params.end || 'no end'})`, {
6788
+ type: 'info'
7230
6789
  });
7231
6790
  while (hasMorePages) {
7232
6791
  pageCount++;
@@ -7234,11 +6793,9 @@ class AlpacaMarketDataAPI extends EventEmitter {
7234
6793
  ...params,
7235
6794
  ...(pageToken && { page_token: pageToken }),
7236
6795
  };
7237
- const response = await this.makeRequest("/options/trades", "GET", requestParams, "v1beta1");
6796
+ const response = await this.makeRequest('/options/trades', 'GET', requestParams, 'v1beta1');
7238
6797
  if (!response.trades) {
7239
- log$1(`No options trades data found in response for ${symbolsStr}`, {
7240
- type: "warn",
7241
- });
6798
+ log$1(`No options trades data found in response for ${symbolsStr}`, { type: 'warn' });
7242
6799
  break;
7243
6800
  }
7244
6801
  // Combine trades for each symbol
@@ -7250,7 +6807,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7250
6807
  allTrades[symbol] = [...allTrades[symbol], ...trades];
7251
6808
  pageTradesCount += trades.length;
7252
6809
  // Track date range for this page
7253
- trades.forEach((trade) => {
6810
+ trades.forEach(trade => {
7254
6811
  const tradeDate = new Date(trade.t);
7255
6812
  if (!earliestTimestamp || tradeDate < earliestTimestamp) {
7256
6813
  earliestTimestamp = tradeDate;
@@ -7266,23 +6823,21 @@ class AlpacaMarketDataAPI extends EventEmitter {
7266
6823
  hasMorePages = !!pageToken;
7267
6824
  // Enhanced logging with date range and progress info
7268
6825
  const dateRangeStr = earliestTimestamp && latestTimestamp
7269
- ? `${earliestTimestamp.toLocaleDateString("en-US", { timeZone: "America/New_York" })} to ${latestTimestamp.toLocaleDateString("en-US", { timeZone: "America/New_York" })}`
7270
- : "unknown range";
7271
- log$1(`Page ${pageCount}: Fetched ${pageTradesCount.toLocaleString()} option trades (total: ${totalTradesCount.toLocaleString()}) for ${symbolsStr}, date range: ${dateRangeStr}${hasMorePages ? ", more pages available" : ", complete"}`, {
7272
- type: "info",
6826
+ ? `${earliestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${latestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
6827
+ : 'unknown range';
6828
+ log$1(`Page ${pageCount}: Fetched ${pageTradesCount.toLocaleString()} option trades (total: ${totalTradesCount.toLocaleString()}) for ${symbolsStr}, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {
6829
+ type: 'info'
7273
6830
  });
7274
6831
  // Prevent infinite loops
7275
6832
  if (pageCount > 1000) {
7276
- log$1(`Stopping options trades pagination after ${pageCount} pages to prevent infinite loop`, { type: "warn" });
6833
+ log$1(`Stopping options trades pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
7277
6834
  break;
7278
6835
  }
7279
6836
  }
7280
6837
  // Final summary
7281
- const symbolCounts = Object.entries(allTrades)
7282
- .map(([symbol, trades]) => `${symbol}: ${trades.length}`)
7283
- .join(", ");
6838
+ const symbolCounts = Object.entries(allTrades).map(([symbol, trades]) => `${symbol}: ${trades.length}`).join(', ');
7284
6839
  log$1(`Historical options trades fetch complete: ${totalTradesCount.toLocaleString()} total trades across ${pageCount} pages (${symbolCounts})`, {
7285
- type: "info",
6840
+ type: 'info'
7286
6841
  });
7287
6842
  return {
7288
6843
  trades: allTrades,
@@ -7300,7 +6855,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7300
6855
  async getOptionsSnapshot(params) {
7301
6856
  // Remove limit and page_token as they may not be supported by this endpoint
7302
6857
  const { limit, page_token, ...requestParams } = params;
7303
- return this.makeRequest("/options/snapshots", "GET", requestParams, "v1beta1");
6858
+ return this.makeRequest('/options/snapshots', 'GET', requestParams, 'v1beta1');
7304
6859
  }
7305
6860
  /**
7306
6861
  * Get condition codes for options trades or quotes
@@ -7311,7 +6866,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7311
6866
  * @see https://docs.alpaca.markets/reference/optionmetaconditions
7312
6867
  */
7313
6868
  async getOptionsConditionCodes(tickType) {
7314
- return this.makeRequest(`/options/meta/conditions/${tickType}`, "GET", undefined, "v1beta1");
6869
+ return this.makeRequest(`/options/meta/conditions/${tickType}`, 'GET', undefined, 'v1beta1');
7315
6870
  }
7316
6871
  /**
7317
6872
  * Get exchange codes for options
@@ -7321,7 +6876,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7321
6876
  * @see https://docs.alpaca.markets/reference/optionmetaexchanges
7322
6877
  */
7323
6878
  async getOptionsExchangeCodes() {
7324
- return this.makeRequest("/options/meta/exchanges", "GET", undefined, "v1beta1");
6879
+ return this.makeRequest('/options/meta/exchanges', 'GET', undefined, 'v1beta1');
7325
6880
  }
7326
6881
  /**
7327
6882
  * Analyzes an array of option bars and returns a summary string
@@ -7330,7 +6885,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7330
6885
  */
7331
6886
  static analyzeOptionBars(bars) {
7332
6887
  if (!bars || bars.length === 0) {
7333
- return "No option price data available";
6888
+ return 'No option price data available';
7334
6889
  }
7335
6890
  const firstBar = bars[0];
7336
6891
  const lastBar = bars[bars.length - 1];
@@ -7354,7 +6909,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7354
6909
  */
7355
6910
  static formatOptionGreeks(greeks) {
7356
6911
  if (!greeks) {
7357
- return "No greeks data available";
6912
+ return 'No greeks data available';
7358
6913
  }
7359
6914
  const parts = [];
7360
6915
  if (greeks.delta !== undefined)
@@ -7367,7 +6922,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7367
6922
  parts.push(`Vega: ${greeks.vega.toFixed(4)}`);
7368
6923
  if (greeks.rho !== undefined)
7369
6924
  parts.push(`Rho: ${greeks.rho.toFixed(4)}`);
7370
- return parts.length > 0 ? parts.join(", ") : "No greeks data available";
6925
+ return parts.length > 0 ? parts.join(', ') : 'No greeks data available';
7371
6926
  }
7372
6927
  /**
7373
6928
  * Interprets condition codes using the provided condition codes mapping
@@ -7377,14 +6932,12 @@ class AlpacaMarketDataAPI extends EventEmitter {
7377
6932
  */
7378
6933
  static interpretConditionCodes(conditionCodes, conditionCodesMap) {
7379
6934
  if (!conditionCodes || conditionCodes.length === 0) {
7380
- return "No conditions";
6935
+ return 'No conditions';
7381
6936
  }
7382
6937
  const descriptions = conditionCodes
7383
6938
  .map((code) => conditionCodesMap[code] || `Unknown (${code})`)
7384
6939
  .filter((desc) => desc !== undefined);
7385
- return descriptions.length > 0
7386
- ? descriptions.join(", ")
7387
- : "No condition descriptions available";
6940
+ return descriptions.length > 0 ? descriptions.join(', ') : 'No condition descriptions available';
7388
6941
  }
7389
6942
  /**
7390
6943
  * Gets the exchange name from exchange code using the provided exchange codes mapping
@@ -7393,7 +6946,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7393
6946
  * @returns Exchange name or formatted unknown exchange
7394
6947
  */
7395
6948
  static getExchangeName(exchangeCode, exchangeCodesMap) {
7396
- return (exchangeCodesMap[exchangeCode] || `Unknown Exchange (${exchangeCode})`);
6949
+ return exchangeCodesMap[exchangeCode] || `Unknown Exchange (${exchangeCode})`;
7397
6950
  }
7398
6951
  /**
7399
6952
  * Fetches news articles from Alpaca API for a symbol, paginating through all results.
@@ -7406,7 +6959,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7406
6959
  start: new Date(Date.now() - 24 * 60 * 60 * 1000),
7407
6960
  end: new Date(),
7408
6961
  limit: 10,
7409
- sort: "desc",
6962
+ sort: 'desc',
7410
6963
  include_content: true,
7411
6964
  };
7412
6965
  const mergedParams = { ...defaultParams, ...params };
@@ -7420,52 +6973,38 @@ class AlpacaMarketDataAPI extends EventEmitter {
7420
6973
  if (!content)
7421
6974
  return undefined;
7422
6975
  // Remove excessive whitespace, newlines, and trim
7423
- return content.replace(/\s+/g, " ").trim();
6976
+ return content.replace(/\s+/g, ' ').trim();
7424
6977
  }
7425
6978
  while (hasMorePages) {
7426
6979
  const queryParams = new URLSearchParams({
7427
- ...(mergedParams.start && {
7428
- start: new Date(mergedParams.start).toISOString(),
7429
- }),
7430
- ...(mergedParams.end && {
7431
- end: new Date(mergedParams.end).toISOString(),
7432
- }),
6980
+ ...(mergedParams.start && { start: new Date(mergedParams.start).toISOString() }),
6981
+ ...(mergedParams.end && { end: new Date(mergedParams.end).toISOString() }),
7433
6982
  ...(symbol && { symbols: symbol }),
7434
- ...(mergedParams.limit && {
7435
- limit: Math.min(50, maxLimit - fetchedCount).toString(),
7436
- }),
6983
+ ...(mergedParams.limit && { limit: Math.min(50, maxLimit - fetchedCount).toString() }),
7437
6984
  ...(mergedParams.sort && { sort: mergedParams.sort }),
7438
- ...(mergedParams.include_content !== undefined
7439
- ? { include_content: mergedParams.include_content.toString() }
7440
- : {}),
6985
+ ...(mergedParams.include_content !== undefined ? { include_content: mergedParams.include_content.toString() } : {}),
7441
6986
  ...(pageToken && { page_token: pageToken }),
7442
6987
  });
7443
6988
  const url = `${this.v1beta1url}/news?${queryParams}`;
7444
- log$1(`Fetching news from: ${url}`, { type: "debug", symbol });
6989
+ log$1(`Fetching news from: ${url}`, { type: 'debug', symbol });
7445
6990
  const response = await fetch(url, {
7446
- method: "GET",
6991
+ method: 'GET',
7447
6992
  headers: this.headers,
7448
6993
  });
7449
6994
  if (!response.ok) {
7450
6995
  const errorText = await response.text();
7451
- log$1(`Alpaca news API error (${response.status}): ${errorText}`, {
7452
- type: "error",
7453
- symbol,
7454
- });
6996
+ log$1(`Alpaca news API error (${response.status}): ${errorText}`, { type: 'error', symbol });
7455
6997
  throw new Error(`Alpaca news API error (${response.status}): ${errorText}`);
7456
6998
  }
7457
6999
  const data = await response.json();
7458
7000
  if (!data.news || !Array.isArray(data.news)) {
7459
- log$1(`No news data found in Alpaca response for ${symbol}`, {
7460
- type: "warn",
7461
- symbol,
7462
- });
7001
+ log$1(`No news data found in Alpaca response for ${symbol}`, { type: 'warn', symbol });
7463
7002
  break;
7464
7003
  }
7465
7004
  const transformedNews = data.news.map((article) => ({
7466
7005
  symbols: article.symbols,
7467
7006
  title: article.headline,
7468
- summary: cleanContent(article.summary) ?? "",
7007
+ summary: cleanContent(article.summary) ?? '',
7469
7008
  content: article.content ? cleanContent(article.content) : undefined,
7470
7009
  url: article.url,
7471
7010
  source: article.source,
@@ -7478,7 +7017,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7478
7017
  fetchedCount = newsArticles.length;
7479
7018
  pageToken = data.next_page_token || null;
7480
7019
  hasMorePages = !!pageToken && (!maxLimit || fetchedCount < maxLimit);
7481
- log$1(`Fetched ${transformedNews.length} news articles (total: ${fetchedCount}) for ${symbol}. More pages: ${hasMorePages}`, { type: "debug", symbol });
7020
+ log$1(`Fetched ${transformedNews.length} news articles (total: ${fetchedCount}) for ${symbol}. More pages: ${hasMorePages}`, { type: 'debug', symbol });
7482
7021
  if (maxLimit && fetchedCount >= maxLimit) {
7483
7022
  newsArticles = newsArticles.slice(0, maxLimit);
7484
7023
  break;
@@ -7509,11 +7048,11 @@ const marketDataAPI = AlpacaMarketDataAPI.getInstance();
7509
7048
  */
7510
7049
  function formatCurrency(value) {
7511
7050
  if (isNaN(value)) {
7512
- return "$0.00";
7051
+ return '$0.00';
7513
7052
  }
7514
- return new Intl.NumberFormat("en-US", {
7515
- style: "currency",
7516
- currency: "USD",
7053
+ return new Intl.NumberFormat('en-US', {
7054
+ style: 'currency',
7055
+ currency: 'USD',
7517
7056
  }).format(value);
7518
7057
  }
7519
7058
  /**
@@ -7526,13 +7065,13 @@ function formatCurrency(value) {
7526
7065
  */
7527
7066
  function formatNumber(value) {
7528
7067
  if (isNaN(value)) {
7529
- return "0";
7068
+ return '0';
7530
7069
  }
7531
- return new Intl.NumberFormat("en-US").format(value);
7070
+ return new Intl.NumberFormat('en-US').format(value);
7532
7071
  }
7533
7072
 
7534
7073
  const log = (message) => {
7535
- console.log(`[${new Date().toLocaleString("en-US", { timeZone: "America/New_York" })}] ${message}`);
7074
+ console.log(`[${new Date().toLocaleString('en-US', { timeZone: 'America/New_York' })}] ${message}`);
7536
7075
  };
7537
7076
  // async function testCreateEquitiesTrade() {
7538
7077
  // try {
@@ -7756,18 +7295,18 @@ const log = (message) => {
7756
7295
  // testing retrieving pre-market data (just 9:00am to 9:30am on 1 july 2025 for SPY) using the market data api
7757
7296
  async function testPreMarketData() {
7758
7297
  try {
7759
- log("Starting pre-market data test for SPY (9:00am-9:30am, July 1, 2025)...");
7298
+ log('Starting pre-market data test for SPY (9:00am-9:30am, July 1, 2025)...');
7760
7299
  // Set up the time range in America/New_York, convert to UTC ISO strings
7761
- const symbol = "SPY";
7762
- const nyTimeZone = "America/New_York";
7300
+ const symbol = 'SPY';
7301
+ const nyTimeZone = 'America/New_York';
7763
7302
  // 9:00am and 9:30am in NY time
7764
- const startNY = new Date("2025-07-01T09:00:00-04:00");
7765
- const endNY = new Date("2025-07-01T09:30:00-04:00");
7303
+ const startNY = new Date('2025-07-01T09:00:00-04:00');
7304
+ const endNY = new Date('2025-07-01T09:30:00-04:00');
7766
7305
  const startUTC = startNY.toISOString();
7767
7306
  const endUTC = endNY.toISOString();
7768
7307
  const barsResponse = await marketDataAPI.getHistoricalBars({
7769
7308
  symbols: [symbol],
7770
- timeframe: "1Min",
7309
+ timeframe: '1Min',
7771
7310
  start: startUTC,
7772
7311
  end: endUTC,
7773
7312
  limit: 1000,
@@ -7775,21 +7314,19 @@ async function testPreMarketData() {
7775
7314
  const bars = barsResponse.bars[symbol] || [];
7776
7315
  log(`Fetched ${bars.length} 1-min bars for SPY from 9:00am to 9:30am (NY) on 2025-07-01.`);
7777
7316
  if (bars.length === 0) {
7778
- log("No pre-market bars returned.");
7317
+ log('No pre-market bars returned.');
7779
7318
  return;
7780
7319
  }
7781
7320
  // Print each bar
7782
7321
  bars.forEach((bar, i) => {
7783
- const barTime = new Date(bar.t).toLocaleString("en-US", {
7784
- timeZone: nyTimeZone,
7785
- });
7322
+ const barTime = new Date(bar.t).toLocaleString('en-US', { timeZone: nyTimeZone });
7786
7323
  log(`Bar ${i + 1}: ${barTime} | O: ${formatCurrency(bar.o)} H: ${formatCurrency(bar.h)} L: ${formatCurrency(bar.l)} C: ${formatCurrency(bar.c)} V: ${formatNumber(bar.v)} VWAP: ${formatCurrency(bar.vw)} N: ${bar.n}`);
7787
7324
  });
7788
7325
  // Print summary
7789
7326
  const summary = AlpacaMarketDataAPI.analyzeBars(bars);
7790
7327
  if (summary)
7791
7328
  log(`Summary: ${summary}`);
7792
- log("Pre-market data test complete.");
7329
+ log('Pre-market data test complete.');
7793
7330
  }
7794
7331
  catch (error) {
7795
7332
  log(`❌ Error in testPreMarketData: ${error instanceof Error ? error.message : error}`);