@adaptic/utils 0.1.44 → 0.1.46

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 (204) hide show
  1. package/dist/index.cjs +4558 -59031
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.mjs +4554 -58772
  4. package/dist/index.mjs.map +1 -1
  5. package/dist/test.js +218 -563
  6. package/dist/test.js.map +1 -1
  7. package/dist/types/adaptic.d.ts.map +1 -1
  8. package/dist/types/alpaca-functions.d.ts +233 -0
  9. package/dist/types/alpaca-functions.d.ts.map +1 -0
  10. package/dist/types/alpaca-market-data-api.d.ts +10 -12
  11. package/dist/types/alpaca-market-data-api.d.ts.map +1 -1
  12. package/dist/types/alpaca-trading-api.d.ts +2 -2
  13. package/dist/types/alpaca-trading-api.d.ts.map +1 -1
  14. package/dist/types/alphavantage.d.ts.map +1 -1
  15. package/dist/types/asset-allocation-algorithm.d.ts +0 -6
  16. package/dist/types/asset-allocation-algorithm.d.ts.map +1 -1
  17. package/dist/types/crypto.d.ts +2 -2
  18. package/dist/types/crypto.d.ts.map +1 -1
  19. package/dist/types/examples/asset-allocation-example.d.ts +6 -7
  20. package/dist/types/examples/asset-allocation-example.d.ts.map +1 -1
  21. package/dist/types/index.d.ts +37 -373
  22. package/dist/types/index.d.ts.map +1 -1
  23. package/dist/types/market-hours.d.ts.map +1 -1
  24. package/dist/types/market-time.d.ts +11 -73
  25. package/dist/types/market-time.d.ts.map +1 -1
  26. package/dist/types/metrics-calcs.d.ts.map +1 -1
  27. package/dist/types/misc-utils.d.ts +0 -3
  28. package/dist/types/misc-utils.d.ts.map +1 -1
  29. package/dist/types/performance-metrics.d.ts +5 -5
  30. package/dist/types/performance-metrics.d.ts.map +1 -1
  31. package/dist/types/polygon-indices.d.ts +2 -2
  32. package/dist/types/polygon-indices.d.ts.map +1 -1
  33. package/dist/types/polygon.d.ts.map +1 -1
  34. package/dist/types/price-utils.d.ts.map +1 -1
  35. package/dist/types/technical-analysis.d.ts.map +1 -1
  36. package/dist/types/trading-policy/defaults.d.ts +46 -0
  37. package/dist/types/trading-policy/defaults.d.ts.map +1 -0
  38. package/dist/types/trading-policy/index.d.ts +8 -0
  39. package/dist/types/trading-policy/index.d.ts.map +1 -0
  40. package/dist/types/types/adaptic-types.d.ts +1 -1
  41. package/dist/types/types/adaptic-types.d.ts.map +1 -1
  42. package/dist/types/types/alpaca-types.d.ts +17 -91
  43. package/dist/types/types/alpaca-types.d.ts.map +1 -1
  44. package/dist/types/types/logging-types.d.ts +1 -1
  45. package/dist/types/types/logging-types.d.ts.map +1 -1
  46. package/dist/types/types/metrics-types.d.ts +1 -1
  47. package/dist/types/types/metrics-types.d.ts.map +1 -1
  48. package/package.json +10 -25
  49. package/dist/types/__tests__/alpaca-functions.test.d.ts +0 -2
  50. package/dist/types/__tests__/alpaca-functions.test.d.ts.map +0 -1
  51. package/dist/types/__tests__/api-endpoints.test.d.ts +0 -2
  52. package/dist/types/__tests__/api-endpoints.test.d.ts.map +0 -1
  53. package/dist/types/__tests__/asset-allocation.test.d.ts +0 -2
  54. package/dist/types/__tests__/asset-allocation.test.d.ts.map +0 -1
  55. package/dist/types/__tests__/auth-validator.test.d.ts +0 -2
  56. package/dist/types/__tests__/auth-validator.test.d.ts.map +0 -1
  57. package/dist/types/__tests__/cache.test.d.ts +0 -2
  58. package/dist/types/__tests__/cache.test.d.ts.map +0 -1
  59. package/dist/types/__tests__/errors.test.d.ts +0 -2
  60. package/dist/types/__tests__/errors.test.d.ts.map +0 -1
  61. package/dist/types/__tests__/format-tools.test.d.ts +0 -2
  62. package/dist/types/__tests__/format-tools.test.d.ts.map +0 -1
  63. package/dist/types/__tests__/http-keep-alive.test.d.ts +0 -2
  64. package/dist/types/__tests__/http-keep-alive.test.d.ts.map +0 -1
  65. package/dist/types/__tests__/http-timeout.test.d.ts +0 -2
  66. package/dist/types/__tests__/http-timeout.test.d.ts.map +0 -1
  67. package/dist/types/__tests__/logger.test.d.ts +0 -2
  68. package/dist/types/__tests__/logger.test.d.ts.map +0 -1
  69. package/dist/types/__tests__/market-time.test.d.ts +0 -2
  70. package/dist/types/__tests__/market-time.test.d.ts.map +0 -1
  71. package/dist/types/__tests__/misc-utils.test.d.ts +0 -2
  72. package/dist/types/__tests__/misc-utils.test.d.ts.map +0 -1
  73. package/dist/types/__tests__/paginator.test.d.ts +0 -2
  74. package/dist/types/__tests__/paginator.test.d.ts.map +0 -1
  75. package/dist/types/__tests__/performance-metrics.test.d.ts +0 -2
  76. package/dist/types/__tests__/performance-metrics.test.d.ts.map +0 -1
  77. package/dist/types/__tests__/polygon.test.d.ts +0 -2
  78. package/dist/types/__tests__/polygon.test.d.ts.map +0 -1
  79. package/dist/types/__tests__/property-based-financial.test.d.ts +0 -2
  80. package/dist/types/__tests__/property-based-financial.test.d.ts.map +0 -1
  81. package/dist/types/__tests__/rate-limiter.test.d.ts +0 -2
  82. package/dist/types/__tests__/rate-limiter.test.d.ts.map +0 -1
  83. package/dist/types/__tests__/schema-validation.test.d.ts +0 -2
  84. package/dist/types/__tests__/schema-validation.test.d.ts.map +0 -1
  85. package/dist/types/__tests__/technical-analysis.test.d.ts +0 -2
  86. package/dist/types/__tests__/technical-analysis.test.d.ts.map +0 -1
  87. package/dist/types/__tests__/time-utils.test.d.ts +0 -2
  88. package/dist/types/__tests__/time-utils.test.d.ts.map +0 -1
  89. package/dist/types/alpaca/client.d.ts +0 -95
  90. package/dist/types/alpaca/client.d.ts.map +0 -1
  91. package/dist/types/alpaca/crypto/data.d.ts +0 -281
  92. package/dist/types/alpaca/crypto/data.d.ts.map +0 -1
  93. package/dist/types/alpaca/crypto/index.d.ts +0 -75
  94. package/dist/types/alpaca/crypto/index.d.ts.map +0 -1
  95. package/dist/types/alpaca/crypto/orders.d.ts +0 -221
  96. package/dist/types/alpaca/crypto/orders.d.ts.map +0 -1
  97. package/dist/types/alpaca/index.d.ts +0 -205
  98. package/dist/types/alpaca/index.d.ts.map +0 -1
  99. package/dist/types/alpaca/legacy/account.d.ts +0 -34
  100. package/dist/types/alpaca/legacy/account.d.ts.map +0 -1
  101. package/dist/types/alpaca/legacy/assets.d.ts +0 -13
  102. package/dist/types/alpaca/legacy/assets.d.ts.map +0 -1
  103. package/dist/types/alpaca/legacy/auth.d.ts +0 -18
  104. package/dist/types/alpaca/legacy/auth.d.ts.map +0 -1
  105. package/dist/types/alpaca/legacy/index.d.ts +0 -15
  106. package/dist/types/alpaca/legacy/index.d.ts.map +0 -1
  107. package/dist/types/alpaca/legacy/market-data.d.ts +0 -32
  108. package/dist/types/alpaca/legacy/market-data.d.ts.map +0 -1
  109. package/dist/types/alpaca/legacy/orders.d.ts +0 -84
  110. package/dist/types/alpaca/legacy/orders.d.ts.map +0 -1
  111. package/dist/types/alpaca/legacy/positions.d.ts +0 -66
  112. package/dist/types/alpaca/legacy/positions.d.ts.map +0 -1
  113. package/dist/types/alpaca/legacy/utils.d.ts +0 -18
  114. package/dist/types/alpaca/legacy/utils.d.ts.map +0 -1
  115. package/dist/types/alpaca/market-data/bars.d.ts +0 -142
  116. package/dist/types/alpaca/market-data/bars.d.ts.map +0 -1
  117. package/dist/types/alpaca/market-data/index.d.ts +0 -13
  118. package/dist/types/alpaca/market-data/index.d.ts.map +0 -1
  119. package/dist/types/alpaca/market-data/news.d.ts +0 -87
  120. package/dist/types/alpaca/market-data/news.d.ts.map +0 -1
  121. package/dist/types/alpaca/market-data/quotes.d.ts +0 -85
  122. package/dist/types/alpaca/market-data/quotes.d.ts.map +0 -1
  123. package/dist/types/alpaca/market-data/trades.d.ts +0 -98
  124. package/dist/types/alpaca/market-data/trades.d.ts.map +0 -1
  125. package/dist/types/alpaca/options/contracts.d.ts +0 -279
  126. package/dist/types/alpaca/options/contracts.d.ts.map +0 -1
  127. package/dist/types/alpaca/options/data.d.ts +0 -126
  128. package/dist/types/alpaca/options/data.d.ts.map +0 -1
  129. package/dist/types/alpaca/options/index.d.ts +0 -17
  130. package/dist/types/alpaca/options/index.d.ts.map +0 -1
  131. package/dist/types/alpaca/options/orders.d.ts +0 -366
  132. package/dist/types/alpaca/options/orders.d.ts.map +0 -1
  133. package/dist/types/alpaca/options/strategies.d.ts +0 -224
  134. package/dist/types/alpaca/options/strategies.d.ts.map +0 -1
  135. package/dist/types/alpaca/streams/base-stream.d.ts +0 -143
  136. package/dist/types/alpaca/streams/base-stream.d.ts.map +0 -1
  137. package/dist/types/alpaca/streams/crypto-stream.d.ts +0 -173
  138. package/dist/types/alpaca/streams/crypto-stream.d.ts.map +0 -1
  139. package/dist/types/alpaca/streams/index.d.ts +0 -54
  140. package/dist/types/alpaca/streams/index.d.ts.map +0 -1
  141. package/dist/types/alpaca/streams/option-stream.d.ts +0 -167
  142. package/dist/types/alpaca/streams/option-stream.d.ts.map +0 -1
  143. package/dist/types/alpaca/streams/stock-stream.d.ts +0 -176
  144. package/dist/types/alpaca/streams/stock-stream.d.ts.map +0 -1
  145. package/dist/types/alpaca/streams/stream-manager.d.ts +0 -277
  146. package/dist/types/alpaca/streams/stream-manager.d.ts.map +0 -1
  147. package/dist/types/alpaca/streams/trading-stream.d.ts +0 -186
  148. package/dist/types/alpaca/streams/trading-stream.d.ts.map +0 -1
  149. package/dist/types/alpaca/streams.d.ts +0 -88
  150. package/dist/types/alpaca/streams.d.ts.map +0 -1
  151. package/dist/types/alpaca/test-imports.d.ts +0 -7
  152. package/dist/types/alpaca/test-imports.d.ts.map +0 -1
  153. package/dist/types/alpaca/trading/account.d.ts +0 -198
  154. package/dist/types/alpaca/trading/account.d.ts.map +0 -1
  155. package/dist/types/alpaca/trading/bracket-orders.d.ts +0 -162
  156. package/dist/types/alpaca/trading/bracket-orders.d.ts.map +0 -1
  157. package/dist/types/alpaca/trading/clock.d.ts +0 -99
  158. package/dist/types/alpaca/trading/clock.d.ts.map +0 -1
  159. package/dist/types/alpaca/trading/index.d.ts +0 -15
  160. package/dist/types/alpaca/trading/index.d.ts.map +0 -1
  161. package/dist/types/alpaca/trading/oco-orders.d.ts +0 -203
  162. package/dist/types/alpaca/trading/oco-orders.d.ts.map +0 -1
  163. package/dist/types/alpaca/trading/order-utils.d.ts +0 -404
  164. package/dist/types/alpaca/trading/order-utils.d.ts.map +0 -1
  165. package/dist/types/alpaca/trading/orders.d.ts +0 -199
  166. package/dist/types/alpaca/trading/orders.d.ts.map +0 -1
  167. package/dist/types/alpaca/trading/oto-orders.d.ts +0 -282
  168. package/dist/types/alpaca/trading/oto-orders.d.ts.map +0 -1
  169. package/dist/types/alpaca/trading/positions.d.ts +0 -389
  170. package/dist/types/alpaca/trading/positions.d.ts.map +0 -1
  171. package/dist/types/alpaca/trading/smart-orders.d.ts +0 -301
  172. package/dist/types/alpaca/trading/smart-orders.d.ts.map +0 -1
  173. package/dist/types/alpaca/trading/trailing-stops.d.ts +0 -240
  174. package/dist/types/alpaca/trading/trailing-stops.d.ts.map +0 -1
  175. package/dist/types/config/api-endpoints.d.ts +0 -94
  176. package/dist/types/config/api-endpoints.d.ts.map +0 -1
  177. package/dist/types/errors/index.d.ts +0 -130
  178. package/dist/types/errors/index.d.ts.map +0 -1
  179. package/dist/types/examples/rate-limiter-example.d.ts +0 -7
  180. package/dist/types/examples/rate-limiter-example.d.ts.map +0 -1
  181. package/dist/types/http-timeout.d.ts +0 -37
  182. package/dist/types/http-timeout.d.ts.map +0 -1
  183. package/dist/types/logger.d.ts +0 -56
  184. package/dist/types/logger.d.ts.map +0 -1
  185. package/dist/types/rate-limiter.d.ts +0 -171
  186. package/dist/types/rate-limiter.d.ts.map +0 -1
  187. package/dist/types/schemas/alpaca-schemas.d.ts +0 -779
  188. package/dist/types/schemas/alpaca-schemas.d.ts.map +0 -1
  189. package/dist/types/schemas/alphavantage-schemas.d.ts +0 -255
  190. package/dist/types/schemas/alphavantage-schemas.d.ts.map +0 -1
  191. package/dist/types/schemas/index.d.ts +0 -21
  192. package/dist/types/schemas/index.d.ts.map +0 -1
  193. package/dist/types/schemas/polygon-schemas.d.ts +0 -551
  194. package/dist/types/schemas/polygon-schemas.d.ts.map +0 -1
  195. package/dist/types/schemas/validate-response.d.ts +0 -88
  196. package/dist/types/schemas/validate-response.d.ts.map +0 -1
  197. package/dist/types/utils/auth-validator.d.ts +0 -32
  198. package/dist/types/utils/auth-validator.d.ts.map +0 -1
  199. package/dist/types/utils/http-keep-alive.d.ts +0 -110
  200. package/dist/types/utils/http-keep-alive.d.ts.map +0 -1
  201. package/dist/types/utils/paginator.d.ts +0 -154
  202. package/dist/types/utils/paginator.d.ts.map +0 -1
  203. package/dist/types/utils/retry.d.ts +0 -78
  204. package/dist/types/utils/retry.d.ts.map +0 -1
package/dist/test.js CHANGED
@@ -620,80 +620,6 @@ function log$2(message, options = { source: "Server", type: "info" }) {
620
620
  displayManager.log(message, options);
621
621
  }
622
622
 
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
623
  // market-hours.ts
698
624
  const marketHolidays = {
699
625
  2024: {
@@ -733,18 +659,6 @@ const marketHolidays = {
733
659
  "Thanksgiving Day": { date: "2026-11-26" },
734
660
  "Christmas Day": { date: "2026-12-25" },
735
661
  },
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
- },
748
662
  };
749
663
  const marketEarlyCloses = {
750
664
  2024: {
@@ -807,14 +721,6 @@ const marketEarlyCloses = {
807
721
  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.",
808
722
  },
809
723
  },
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.",
816
- },
817
- },
818
724
  };
819
725
 
820
726
  // market-time.ts
@@ -879,25 +785,13 @@ class MarketTimeUtil {
879
785
  return formatInTimeZone(date, this.timezone, "yyyy-MM-dd'T'HH:mm:ssXXX");
880
786
  }
881
787
  }
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();
788
+ isWeekend(date) {
789
+ const day = date.getDay();
890
790
  return day === 0 || day === 6;
891
791
  }
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()];
792
+ isHoliday(date) {
793
+ const formattedDate = format(date, "yyyy-MM-dd");
794
+ const yearHolidays = marketHolidays[date.getFullYear()];
901
795
  for (const holiday in yearHolidays) {
902
796
  if (yearHolidays[holiday].date === formattedDate) {
903
797
  return true;
@@ -905,26 +799,19 @@ class MarketTimeUtil {
905
799
  }
906
800
  return false;
907
801
  }
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()];
802
+ isEarlyCloseDay(date) {
803
+ const formattedDate = format(date, "yyyy-MM-dd");
804
+ const yearEarlyCloses = marketEarlyCloses[date.getFullYear()];
917
805
  return yearEarlyCloses && yearEarlyCloses[formattedDate] !== undefined;
918
806
  }
919
807
  /**
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
808
+ * Get the early close time for a given date
809
+ * @param date - The date to get the early close time for
810
+ * @returns The early close time in minutes from midnight, or null if there is no early close
924
811
  */
925
- getEarlyCloseTimeZoned(nyDate) {
926
- const formattedDate = format(nyDate, "yyyy-MM-dd");
927
- const yearEarlyCloses = marketEarlyCloses[nyDate.getFullYear()];
812
+ getEarlyCloseTime(date) {
813
+ const formattedDate = format(date, "yyyy-MM-dd");
814
+ const yearEarlyCloses = marketEarlyCloses[date.getFullYear()];
928
815
  if (yearEarlyCloses && yearEarlyCloses[formattedDate]) {
929
816
  const [hours, minutes] = yearEarlyCloses[formattedDate].time
930
817
  .split(":")
@@ -934,69 +821,30 @@ class MarketTimeUtil {
934
821
  return null;
935
822
  }
936
823
  /**
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)
824
+ * Check if a given date is a market day
825
+ * @param date - The date to check
969
826
  * @returns true if the date is a market day, false otherwise
970
827
  */
971
828
  isMarketDay(date) {
972
- const nyDate = toZonedTime(date, this.timezone);
973
- return this.isMarketDayZoned(nyDate);
829
+ const isWeekendDay = this.isWeekend(date);
830
+ const isHolidayDay = this.isHoliday(date);
831
+ const returner = !isWeekendDay && !isHolidayDay;
832
+ return returner;
974
833
  }
975
834
  /**
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)
835
+ * Check if a given date is within market hours
836
+ * @param date - The date to check
979
837
  * @returns true if the date is within market hours, false otherwise
980
838
  */
981
839
  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)) {
840
+ // Check for holidays first
841
+ if (this.isHoliday(date)) {
994
842
  return false;
995
843
  }
996
- const timeInMinutes = nyDate.getHours() * 60 + nyDate.getMinutes();
844
+ const timeInMinutes = date.getHours() * 60 + date.getMinutes();
997
845
  // Check for early closure
998
- if (this.isEarlyCloseDayZoned(nyDate)) {
999
- const earlyCloseMinutes = this.getEarlyCloseTimeZoned(nyDate);
846
+ if (this.isEarlyCloseDay(date)) {
847
+ const earlyCloseMinutes = this.getEarlyCloseTime(date);
1000
848
  if (earlyCloseMinutes !== null && timeInMinutes > earlyCloseMinutes) {
1001
849
  return false;
1002
850
  }
@@ -1010,10 +858,8 @@ class MarketTimeUtil {
1010
858
  const extendedEndMinutes = MARKET_TIMES.EXTENDED.END.HOUR * 60 +
1011
859
  MARKET_TIMES.EXTENDED.END.MINUTE;
1012
860
  // 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();
861
+ const adjustedDate = timeInMinutes < extendedStartMinutes ? sub(date, { days: 1 }) : date;
862
+ const adjustedTimeInMinutes = adjustedDate.getHours() * 60 + adjustedDate.getMinutes();
1017
863
  returner =
1018
864
  adjustedTimeInMinutes >= extendedStartMinutes &&
1019
865
  adjustedTimeInMinutes <= extendedEndMinutes;
@@ -1036,13 +882,12 @@ class MarketTimeUtil {
1036
882
  return returner;
1037
883
  }
1038
884
  /**
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
885
+ * Check if a given date is before market hours
886
+ * @param date - The date to check
1042
887
  * @returns true if the date is before market hours, false otherwise
1043
888
  */
1044
- isBeforeMarketHoursZoned(nyDate) {
1045
- const timeInMinutes = nyDate.getHours() * 60 + nyDate.getMinutes();
889
+ isBeforeMarketHours(date) {
890
+ const timeInMinutes = date.getHours() * 60 + date.getMinutes();
1046
891
  const startMinutes = this.intradayReporting === "extended_hours"
1047
892
  ? MARKET_TIMES.EXTENDED.START.HOUR * 60 +
1048
893
  MARKET_TIMES.EXTENDED.START.MINUTE
@@ -1057,7 +902,7 @@ class MarketTimeUtil {
1057
902
  */
1058
903
  getLastTradingDate(currentDate = new Date()) {
1059
904
  const nowET = toZonedTime(currentDate, this.timezone);
1060
- const isMarketDayToday = this.isMarketDayZoned(nowET);
905
+ const isMarketDayToday = this.isMarketDay(nowET);
1061
906
  const currentMinutes = nowET.getHours() * 60 + nowET.getMinutes();
1062
907
  const marketOpenMinutes = MARKET_TIMES.REGULAR.START.HOUR * 60 + MARKET_TIMES.REGULAR.START.MINUTE;
1063
908
  if (isMarketDayToday && currentMinutes >= marketOpenMinutes) {
@@ -1067,7 +912,7 @@ class MarketTimeUtil {
1067
912
  else {
1068
913
  // Before market open, or not a market day, return previous trading day
1069
914
  let lastTradingDate = sub(nowET, { days: 1 });
1070
- while (!this.isMarketDayZoned(lastTradingDate)) {
915
+ while (!this.isMarketDay(lastTradingDate)) {
1071
916
  lastTradingDate = sub(lastTradingDate, { days: 1 });
1072
917
  }
1073
918
  return lastTradingDate;
@@ -1075,7 +920,7 @@ class MarketTimeUtil {
1075
920
  }
1076
921
  getLastMarketDay(date) {
1077
922
  let currentDate = sub(date, { days: 1 });
1078
- while (!this.isMarketDayZoned(currentDate)) {
923
+ while (!this.isMarketDay(currentDate)) {
1079
924
  currentDate = sub(currentDate, { days: 1 });
1080
925
  }
1081
926
  return currentDate;
@@ -1084,7 +929,7 @@ class MarketTimeUtil {
1084
929
  const nowET = toZonedTime(currentDate, this.timezone);
1085
930
  // If today is a market day and we're after extended hours close
1086
931
  // then return today since it's a completed trading day
1087
- if (this.isMarketDayZoned(nowET)) {
932
+ if (this.isMarketDay(nowET)) {
1088
933
  const timeInMinutes = nowET.getHours() * 60 + nowET.getMinutes();
1089
934
  const extendedEndMinutes = MARKET_TIMES.EXTENDED.END.HOUR * 60 + MARKET_TIMES.EXTENDED.END.MINUTE;
1090
935
  // Check if we're after market close (including extended hours)
@@ -1108,28 +953,13 @@ class MarketTimeUtil {
1108
953
  * @property {string} yyyymmdd - The date in YYYY-MM-DD format
1109
954
  * @property {string} dateISOString - Full ISO date string
1110
955
  */
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)) {
956
+ getNextMarketDay(date) {
957
+ let currentDate = add(date, { days: 1 });
958
+ while (!this.isMarketDay(currentDate)) {
1119
959
  currentDate = add(currentDate, { days: 1 });
1120
960
  }
1121
961
  return currentDate;
1122
962
  }
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
963
  getDayBoundaries(date) {
1134
964
  let start;
1135
965
  let end;
@@ -1162,9 +992,9 @@ class MarketTimeUtil {
1162
992
  seconds: 0,
1163
993
  milliseconds: 0,
1164
994
  });
1165
- // Check for early close (date is already zoned)
1166
- if (this.isEarlyCloseDayZoned(date)) {
1167
- const earlyCloseMinutes = this.getEarlyCloseTimeZoned(date);
995
+ // Check for early close
996
+ if (this.isEarlyCloseDay(date)) {
997
+ const earlyCloseMinutes = this.getEarlyCloseTime(date);
1168
998
  if (earlyCloseMinutes !== null) {
1169
999
  const earlyCloseHours = Math.floor(earlyCloseMinutes / 60);
1170
1000
  const earlyCloseMinutesRemainder = earlyCloseMinutes % 60;
@@ -1221,8 +1051,8 @@ class MarketTimeUtil {
1221
1051
  default:
1222
1052
  throw new Error(`Invalid period: ${period}`);
1223
1053
  }
1224
- while (!this.isMarketDayZoned(startDate)) {
1225
- startDate = this.getNextMarketDayZoned(startDate);
1054
+ while (!this.isMarketDay(startDate)) {
1055
+ startDate = this.getNextMarketDay(startDate);
1226
1056
  }
1227
1057
  return startDate;
1228
1058
  }
@@ -1237,9 +1067,9 @@ class MarketTimeUtil {
1237
1067
  const zonedEndDate = toZonedTime(end, this.timezone);
1238
1068
  let startDate;
1239
1069
  let endDate;
1240
- const isCurrentMarketDay = this.isMarketDayZoned(zonedEndDate);
1241
- const isWithinHours = this.isWithinMarketHoursZoned(zonedEndDate);
1242
- const isBeforeHours = this.isBeforeMarketHoursZoned(zonedEndDate);
1070
+ const isCurrentMarketDay = this.isMarketDay(zonedEndDate);
1071
+ const isWithinHours = this.isWithinMarketHours(zonedEndDate);
1072
+ const isBeforeHours = this.isBeforeMarketHours(zonedEndDate);
1243
1073
  // First determine the end date based on current market conditions
1244
1074
  if (isCurrentMarketDay) {
1245
1075
  if (isBeforeHours) {
@@ -1284,7 +1114,7 @@ class MarketTimeUtil {
1284
1114
  const { date = new Date() } = options;
1285
1115
  const zonedDate = toZonedTime(date, this.timezone);
1286
1116
  // Check if market is closed for the day
1287
- if (this.isWeekendZoned(zonedDate) || this.isHolidayZoned(zonedDate)) {
1117
+ if (this.isWeekend(zonedDate) || this.isHoliday(zonedDate)) {
1288
1118
  return {
1289
1119
  marketOpen: false,
1290
1120
  open: null,
@@ -1298,10 +1128,10 @@ class MarketTimeUtil {
1298
1128
  let regularCloseTime = MARKET_TIMES.REGULAR.END;
1299
1129
  const extendedOpenTime = MARKET_TIMES.EXTENDED.START;
1300
1130
  let extendedCloseTime = MARKET_TIMES.EXTENDED.END;
1301
- // Check for early close (zonedDate is already in market timezone)
1302
- const isEarlyClose = this.isEarlyCloseDayZoned(zonedDate);
1131
+ // Check for early close
1132
+ const isEarlyClose = this.isEarlyCloseDay(zonedDate);
1303
1133
  if (isEarlyClose) {
1304
- const earlyCloseMinutes = this.getEarlyCloseTimeZoned(zonedDate);
1134
+ const earlyCloseMinutes = this.getEarlyCloseTime(zonedDate);
1305
1135
  if (earlyCloseMinutes !== null) {
1306
1136
  // For regular hours, use the early close time
1307
1137
  regularCloseTime = {
@@ -6329,82 +6159,13 @@ function requireWebsocketServer () {
6329
6159
 
6330
6160
  requireWebsocketServer();
6331
6161
 
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" });
6162
+ const log$1 = (message, options = { type: 'info' }) => {
6163
+ log$2(message, { ...options, source: 'AlpacaMarketDataAPI' });
6403
6164
  };
6404
6165
  // Default settings for market data API
6405
- const DEFAULT_ADJUSTMENT = "all";
6406
- const DEFAULT_FEED = "sip";
6407
- const DEFAULT_CURRENCY = "USD";
6166
+ const DEFAULT_ADJUSTMENT = 'all';
6167
+ const DEFAULT_FEED = 'sip';
6168
+ const DEFAULT_CURRENCY = 'USD';
6408
6169
  /**
6409
6170
  * Singleton class for interacting with Alpaca Market Data API
6410
6171
  * Provides methods for fetching historical bars, latest bars, last trades, latest trades, latest quotes, and latest quote for a single symbol
@@ -6415,84 +6176,56 @@ class AlpacaMarketDataAPI extends EventEmitter {
6415
6176
  dataURL;
6416
6177
  apiURL;
6417
6178
  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
6179
+ stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/sip'; // production values
6180
+ optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options'; // production values
6181
+ cryptoStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/crypto/us'; // production values
6423
6182
  stockWs = null;
6424
6183
  optionWs = null;
6425
6184
  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");
6185
+ stockSubscriptions = { trades: [], quotes: [], bars: [] };
6186
+ optionSubscriptions = { trades: [], quotes: [], bars: [] };
6187
+ cryptoSubscriptions = { trades: [], quotes: [], bars: [] };
6188
+ setMode(mode = 'production') {
6189
+ if (mode === 'sandbox') { // sandbox mode
6190
+ this.stockStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v2/sip';
6191
+ this.optionStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v1beta3/options';
6192
+ this.cryptoStreamUrl = 'wss://stream.data.sandbox.alpaca.markets/v1beta3/crypto/us';
6447
6193
  }
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
6194
+ else if (mode === 'test') { // test mode, can only use ticker FAKEPACA
6195
+ this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/test';
6196
+ this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options'; // there's no test mode for options
6197
+ this.cryptoStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/crypto/us'; // there's no test mode for crypto
6453
6198
  }
6454
- else {
6455
- // production
6456
- this.stockStreamUrl = getStockStreamUrl("PRODUCTION");
6457
- this.optionStreamUrl = getOptionsStreamUrl("PRODUCTION");
6458
- this.cryptoStreamUrl = getCryptoStreamUrl("PRODUCTION");
6199
+ else { // production
6200
+ this.stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/sip';
6201
+ this.optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options';
6202
+ this.cryptoStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/crypto/us';
6459
6203
  }
6460
6204
  }
6461
6205
  getMode() {
6462
- if (this.stockStreamUrl.includes("sandbox")) {
6463
- return "sandbox";
6206
+ if (this.stockStreamUrl.includes('sandbox')) {
6207
+ return 'sandbox';
6464
6208
  }
6465
- else if (this.stockStreamUrl.includes("test")) {
6466
- return "test";
6209
+ else if (this.stockStreamUrl.includes('test')) {
6210
+ return 'test';
6467
6211
  }
6468
6212
  else {
6469
- return "production";
6213
+ return 'production';
6470
6214
  }
6471
6215
  }
6472
6216
  constructor() {
6473
6217
  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;
6218
+ this.dataURL = 'https://data.alpaca.markets/v2';
6486
6219
  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
6220
+ process.env.ALPACA_ACCOUNT_TYPE === 'PAPER'
6221
+ ? 'https://paper-api.alpaca.markets/v2'
6222
+ : 'https://api.alpaca.markets/v2'; // used by some, e.g. getAssets
6223
+ this.v1beta1url = 'https://data.alpaca.markets/v1beta1'; // used for options endpoints
6224
+ this.setMode('production'); // sets stockStreamUrl and optionStreamUrl
6492
6225
  this.headers = {
6493
- "APCA-API-KEY-ID": apiKey,
6494
- "APCA-API-SECRET-KEY": apiSecret,
6495
- "Content-Type": "application/json",
6226
+ 'APCA-API-KEY-ID': process.env.ALPACA_API_KEY,
6227
+ 'APCA-API-SECRET-KEY': process.env.ALPACA_SECRET_KEY,
6228
+ 'Content-Type': 'application/json',
6496
6229
  };
6497
6230
  }
6498
6231
  static getInstance() {
@@ -6509,75 +6242,56 @@ class AlpacaMarketDataAPI extends EventEmitter {
6509
6242
  }
6510
6243
  connect(streamType) {
6511
6244
  let url;
6512
- if (streamType === "stock") {
6245
+ if (streamType === 'stock') {
6513
6246
  url = this.stockStreamUrl;
6514
6247
  }
6515
- else if (streamType === "option") {
6248
+ else if (streamType === 'option') {
6516
6249
  url = this.optionStreamUrl;
6517
6250
  }
6518
6251
  else {
6519
6252
  url = this.cryptoStreamUrl;
6520
6253
  }
6521
6254
  const ws = new WebSocket(url);
6522
- if (streamType === "stock") {
6255
+ if (streamType === 'stock') {
6523
6256
  this.stockWs = ws;
6524
6257
  }
6525
- else if (streamType === "option") {
6258
+ else if (streamType === 'option') {
6526
6259
  this.optionWs = ws;
6527
6260
  }
6528
6261
  else {
6529
6262
  this.cryptoWs = ws;
6530
6263
  }
6531
- ws.on("open", () => {
6532
- log$1(`${streamType} stream connected`, { type: "info" });
6264
+ ws.on('open', () => {
6265
+ log$1(`${streamType} stream connected`, { type: 'info' });
6533
6266
  const authMessage = {
6534
- action: "auth",
6267
+ action: 'auth',
6535
6268
  key: process.env.ALPACA_API_KEY,
6536
6269
  secret: process.env.ALPACA_SECRET_KEY,
6537
6270
  };
6538
6271
  ws.send(JSON.stringify(authMessage));
6539
6272
  });
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
- }
6273
+ ws.on('message', (data) => {
6274
+ const messages = JSON.parse(data.toString());
6550
6275
  for (const message of messages) {
6551
- if (message.T === "success" && message.msg === "authenticated") {
6552
- log$1(`${streamType} stream authenticated`, { type: "info" });
6276
+ if (message.T === 'success' && message.msg === 'authenticated') {
6277
+ log$1(`${streamType} stream authenticated`, { type: 'info' });
6553
6278
  this.sendSubscription(streamType);
6554
6279
  }
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" });
6280
+ else if (message.T === 'error') {
6281
+ log$1(`${streamType} stream error: ${message.msg} (code: ${message.code})`, { type: 'error' });
6565
6282
  }
6566
6283
  else if (message.S) {
6567
6284
  super.emit(`${streamType}-${message.T}`, message);
6568
6285
  super.emit(`${streamType}-data`, message);
6569
6286
  }
6570
- else {
6571
- log$1(`${streamType} received unknown message type: ${JSON.stringify(message)}`, { type: "debug" });
6572
- }
6573
6287
  }
6574
6288
  });
6575
- ws.on("close", () => {
6576
- log$1(`${streamType} stream disconnected`, { type: "warn" });
6577
- if (streamType === "stock") {
6289
+ ws.on('close', () => {
6290
+ log$1(`${streamType} stream disconnected`, { type: 'warn' });
6291
+ if (streamType === 'stock') {
6578
6292
  this.stockWs = null;
6579
6293
  }
6580
- else if (streamType === "option") {
6294
+ else if (streamType === 'option') {
6581
6295
  this.optionWs = null;
6582
6296
  }
6583
6297
  else {
@@ -6585,18 +6299,18 @@ class AlpacaMarketDataAPI extends EventEmitter {
6585
6299
  }
6586
6300
  // Optional: implement reconnect logic
6587
6301
  });
6588
- ws.on("error", (error) => {
6589
- log$1(`${streamType} stream error: ${error.message}`, { type: "error" });
6302
+ ws.on('error', (error) => {
6303
+ log$1(`${streamType} stream error: ${error.message}`, { type: 'error' });
6590
6304
  });
6591
6305
  }
6592
6306
  sendSubscription(streamType) {
6593
6307
  let ws;
6594
6308
  let subscriptions;
6595
- if (streamType === "stock") {
6309
+ if (streamType === 'stock') {
6596
6310
  ws = this.stockWs;
6597
6311
  subscriptions = this.stockSubscriptions;
6598
6312
  }
6599
- else if (streamType === "option") {
6313
+ else if (streamType === 'option') {
6600
6314
  ws = this.optionWs;
6601
6315
  subscriptions = this.optionSubscriptions;
6602
6316
  }
@@ -6604,9 +6318,6 @@ class AlpacaMarketDataAPI extends EventEmitter {
6604
6318
  ws = this.cryptoWs;
6605
6319
  subscriptions = this.cryptoSubscriptions;
6606
6320
  }
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
- });
6610
6321
  if (ws && ws.readyState === WebSocket.OPEN) {
6611
6322
  const subMessagePayload = {};
6612
6323
  if (subscriptions.trades.length > 0) {
@@ -6620,40 +6331,26 @@ class AlpacaMarketDataAPI extends EventEmitter {
6620
6331
  }
6621
6332
  if (Object.keys(subMessagePayload).length > 0) {
6622
6333
  const subMessage = {
6623
- action: "subscribe",
6334
+ action: 'subscribe',
6624
6335
  ...subMessagePayload,
6625
6336
  };
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
- });
6337
+ ws.send(JSON.stringify(subMessage));
6636
6338
  }
6637
6339
  }
6638
- else {
6639
- log$1(`Cannot send ${streamType} subscription: WebSocket not ready`, {
6640
- type: "warn",
6641
- });
6642
- }
6643
6340
  }
6644
6341
  connectStockStream() {
6645
6342
  if (!this.stockWs) {
6646
- this.connect("stock");
6343
+ this.connect('stock');
6647
6344
  }
6648
6345
  }
6649
6346
  connectOptionStream() {
6650
6347
  if (!this.optionWs) {
6651
- this.connect("option");
6348
+ this.connect('option');
6652
6349
  }
6653
6350
  }
6654
6351
  connectCryptoStream() {
6655
6352
  if (!this.cryptoWs) {
6656
- this.connect("crypto");
6353
+ this.connect('crypto');
6657
6354
  }
6658
6355
  }
6659
6356
  disconnectStockStream() {
@@ -6677,22 +6374,22 @@ class AlpacaMarketDataAPI extends EventEmitter {
6677
6374
  * @returns True if the stream is connected
6678
6375
  */
6679
6376
  isStreamConnected(streamType) {
6680
- if (streamType === "stock") {
6681
- return (this.stockWs !== null && this.stockWs.readyState === WebSocket.OPEN);
6377
+ if (streamType === 'stock') {
6378
+ return this.stockWs !== null && this.stockWs.readyState === WebSocket.OPEN;
6682
6379
  }
6683
- else if (streamType === "option") {
6684
- return (this.optionWs !== null && this.optionWs.readyState === WebSocket.OPEN);
6380
+ else if (streamType === 'option') {
6381
+ return this.optionWs !== null && this.optionWs.readyState === WebSocket.OPEN;
6685
6382
  }
6686
6383
  else {
6687
- return (this.cryptoWs !== null && this.cryptoWs.readyState === WebSocket.OPEN);
6384
+ return this.cryptoWs !== null && this.cryptoWs.readyState === WebSocket.OPEN;
6688
6385
  }
6689
6386
  }
6690
6387
  subscribe(streamType, subscriptions) {
6691
6388
  let currentSubscriptions;
6692
- if (streamType === "stock") {
6389
+ if (streamType === 'stock') {
6693
6390
  currentSubscriptions = this.stockSubscriptions;
6694
6391
  }
6695
- else if (streamType === "option") {
6392
+ else if (streamType === 'option') {
6696
6393
  currentSubscriptions = this.optionSubscriptions;
6697
6394
  }
6698
6395
  else {
@@ -6700,19 +6397,17 @@ class AlpacaMarketDataAPI extends EventEmitter {
6700
6397
  }
6701
6398
  Object.entries(subscriptions).forEach(([key, value]) => {
6702
6399
  if (value) {
6703
- currentSubscriptions[key] = [
6704
- ...new Set([...(currentSubscriptions[key] || []), ...value]),
6705
- ];
6400
+ currentSubscriptions[key] = [...new Set([...(currentSubscriptions[key] || []), ...value])];
6706
6401
  }
6707
6402
  });
6708
6403
  this.sendSubscription(streamType);
6709
6404
  }
6710
6405
  unsubscribe(streamType, subscriptions) {
6711
6406
  let currentSubscriptions;
6712
- if (streamType === "stock") {
6407
+ if (streamType === 'stock') {
6713
6408
  currentSubscriptions = this.stockSubscriptions;
6714
6409
  }
6715
- else if (streamType === "option") {
6410
+ else if (streamType === 'option') {
6716
6411
  currentSubscriptions = this.optionSubscriptions;
6717
6412
  }
6718
6413
  else {
@@ -6720,18 +6415,18 @@ class AlpacaMarketDataAPI extends EventEmitter {
6720
6415
  }
6721
6416
  Object.entries(subscriptions).forEach(([key, value]) => {
6722
6417
  if (value) {
6723
- currentSubscriptions[key] = (currentSubscriptions[key] || []).filter((s) => !value.includes(s));
6418
+ currentSubscriptions[key] = (currentSubscriptions[key] || []).filter(s => !value.includes(s));
6724
6419
  }
6725
6420
  });
6726
6421
  const unsubMessage = {
6727
- action: "unsubscribe",
6422
+ action: 'unsubscribe',
6728
6423
  ...subscriptions,
6729
6424
  };
6730
6425
  let ws;
6731
- if (streamType === "stock") {
6426
+ if (streamType === 'stock') {
6732
6427
  ws = this.stockWs;
6733
6428
  }
6734
- else if (streamType === "option") {
6429
+ else if (streamType === 'option') {
6735
6430
  ws = this.optionWs;
6736
6431
  }
6737
6432
  else {
@@ -6741,20 +6436,16 @@ class AlpacaMarketDataAPI extends EventEmitter {
6741
6436
  ws.send(JSON.stringify(unsubMessage));
6742
6437
  }
6743
6438
  }
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;
6439
+ async makeRequest(endpoint, method = 'GET', params, baseUrlName = 'data') {
6440
+ const baseUrl = baseUrlName === 'data' ? this.dataURL : baseUrlName === 'api' ? this.apiURL : this.v1beta1url;
6750
6441
  const url = new URL(`${baseUrl}${endpoint}`);
6751
6442
  try {
6752
6443
  if (params) {
6753
6444
  Object.entries(params).forEach(([key, value]) => {
6754
6445
  if (Array.isArray(value)) {
6755
- url.searchParams.append(key, value.join(","));
6446
+ url.searchParams.append(key, value.join(','));
6756
6447
  }
6757
- else if (value !== undefined && value !== null) {
6448
+ else if (value !== undefined) {
6758
6449
  url.searchParams.append(key, value.toString());
6759
6450
  }
6760
6451
  });
@@ -6762,13 +6453,10 @@ class AlpacaMarketDataAPI extends EventEmitter {
6762
6453
  const response = await fetch(url.toString(), {
6763
6454
  method,
6764
6455
  headers: this.headers,
6765
- signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
6766
6456
  });
6767
6457
  if (!response.ok) {
6768
6458
  const errorText = await response.text();
6769
- log$1(`Market Data API error (${response.status}): ${errorText}`, {
6770
- type: "error",
6771
- });
6459
+ log$1(`Market Data API error (${response.status}): ${errorText}`, { type: 'error' });
6772
6460
  throw new Error(`Market Data API error (${response.status}): ${errorText}`);
6773
6461
  }
6774
6462
  const data = await response.json();
@@ -6776,9 +6464,9 @@ class AlpacaMarketDataAPI extends EventEmitter {
6776
6464
  }
6777
6465
  catch (err) {
6778
6466
  const error = err;
6779
- log$1(`Error in makeRequest: ${error.message}. Endpoint: ${endpoint}. Url: ${url.toString()}`, { type: "error" });
6467
+ log$1(`Error in makeRequest: ${error.message}. Endpoint: ${endpoint}. Url: ${url.toString()}`, { type: 'error' });
6780
6468
  if (error instanceof TypeError) {
6781
- log$1(`Network error details: ${error.stack}`, { type: "error" });
6469
+ log$1(`Network error details: ${error.stack}`, { type: 'error' });
6782
6470
  }
6783
6471
  throw error;
6784
6472
  }
@@ -6791,19 +6479,19 @@ class AlpacaMarketDataAPI extends EventEmitter {
6791
6479
  */
6792
6480
  async getHistoricalBars(params) {
6793
6481
  const symbols = params.symbols;
6794
- const symbolsStr = symbols.join(",");
6482
+ const symbolsStr = symbols.join(',');
6795
6483
  let allBars = {};
6796
6484
  let pageToken = null;
6797
6485
  let hasMorePages = true;
6798
6486
  let totalBarsCount = 0;
6799
6487
  let pageCount = 0;
6800
- let currency = "";
6488
+ let currency = '';
6801
6489
  // Initialize bar arrays for each symbol
6802
- symbols.forEach((symbol) => {
6490
+ symbols.forEach(symbol => {
6803
6491
  allBars[symbol] = [];
6804
6492
  });
6805
- log$1(`Starting historical bars fetch for ${symbolsStr} (${params.timeframe}, ${params.start || "no start"} to ${params.end || "no end"})`, {
6806
- type: "info",
6493
+ log$1(`Starting historical bars fetch for ${symbolsStr} (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`, {
6494
+ type: 'info'
6807
6495
  });
6808
6496
  while (hasMorePages) {
6809
6497
  pageCount++;
@@ -6813,11 +6501,9 @@ class AlpacaMarketDataAPI extends EventEmitter {
6813
6501
  feed: DEFAULT_FEED,
6814
6502
  ...(pageToken && { page_token: pageToken }),
6815
6503
  };
6816
- const response = await this.makeRequest("/stocks/bars", "GET", requestParams);
6504
+ const response = await this.makeRequest('/stocks/bars', 'GET', requestParams);
6817
6505
  if (!response.bars) {
6818
- log$1(`No bars data found in response for ${symbolsStr}`, {
6819
- type: "warn",
6820
- });
6506
+ log$1(`No bars data found in response for ${symbolsStr}`, { type: 'warn' });
6821
6507
  break;
6822
6508
  }
6823
6509
  // Track currency from first response
@@ -6833,7 +6519,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6833
6519
  allBars[symbol] = [...allBars[symbol], ...bars];
6834
6520
  pageBarsCount += bars.length;
6835
6521
  // Track date range for this page
6836
- bars.forEach((bar) => {
6522
+ bars.forEach(bar => {
6837
6523
  const barDate = new Date(bar.t);
6838
6524
  if (!earliestTimestamp || barDate < earliestTimestamp) {
6839
6525
  earliestTimestamp = barDate;
@@ -6849,23 +6535,21 @@ class AlpacaMarketDataAPI extends EventEmitter {
6849
6535
  hasMorePages = !!pageToken;
6850
6536
  // Enhanced logging with date range and progress info
6851
6537
  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",
6538
+ ? `${earliestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${latestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
6539
+ : 'unknown range';
6540
+ log$1(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbolsStr}, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {
6541
+ type: 'info'
6856
6542
  });
6857
6543
  // Prevent infinite loops
6858
6544
  if (pageCount > 1000) {
6859
- log$1(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: "warn" });
6545
+ log$1(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
6860
6546
  break;
6861
6547
  }
6862
6548
  }
6863
6549
  // Final summary
6864
- const symbolCounts = Object.entries(allBars)
6865
- .map(([symbol, bars]) => `${symbol}: ${bars.length}`)
6866
- .join(", ");
6550
+ const symbolCounts = Object.entries(allBars).map(([symbol, bars]) => `${symbol}: ${bars.length}`).join(', ');
6867
6551
  log$1(`Historical bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages (${symbolCounts})`, {
6868
- type: "info",
6552
+ type: 'info'
6869
6553
  });
6870
6554
  return {
6871
6555
  bars: allBars,
@@ -6881,7 +6565,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6881
6565
 
6882
6566
  */
6883
6567
  async getLatestBars(symbols, currency) {
6884
- return this.makeRequest("/stocks/bars/latest", "GET", {
6568
+ return this.makeRequest('/stocks/bars/latest', 'GET', {
6885
6569
  symbols,
6886
6570
  feed: DEFAULT_FEED,
6887
6571
  currency: currency || DEFAULT_CURRENCY,
@@ -6893,7 +6577,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6893
6577
  * @returns Last trade details including price, size, exchange, and conditions
6894
6578
  */
6895
6579
  async getLastTrade(symbol) {
6896
- return this.makeRequest(`/v1/last/stocks/${symbol}`, "GET");
6580
+ return this.makeRequest(`/v1/last/stocks/${symbol}`, 'GET');
6897
6581
  }
6898
6582
  /**
6899
6583
  * Get the most recent trades for requested symbols
@@ -6904,7 +6588,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6904
6588
 
6905
6589
  */
6906
6590
  async getLatestTrades(symbols, feed, currency) {
6907
- return this.makeRequest("/stocks/trades/latest", "GET", {
6591
+ return this.makeRequest('/stocks/trades/latest', 'GET', {
6908
6592
  symbols,
6909
6593
  feed: feed || DEFAULT_FEED,
6910
6594
  currency: currency || DEFAULT_CURRENCY,
@@ -6920,15 +6604,13 @@ class AlpacaMarketDataAPI extends EventEmitter {
6920
6604
  async getLatestQuotes(symbols, feed, currency) {
6921
6605
  // Return empty response if symbols array is empty to avoid API error
6922
6606
  if (!symbols || symbols.length === 0) {
6923
- log$1("No symbols provided to getLatestQuotes, returning empty response", {
6924
- type: "warn",
6925
- });
6607
+ log$1('No symbols provided to getLatestQuotes, returning empty response', { type: 'warn' });
6926
6608
  return {
6927
6609
  quotes: {},
6928
6610
  currency: currency || DEFAULT_CURRENCY,
6929
6611
  };
6930
6612
  }
6931
- return this.makeRequest("/stocks/quotes/latest", "GET", {
6613
+ return this.makeRequest('/stocks/quotes/latest', 'GET', {
6932
6614
  symbols,
6933
6615
  feed: feed || DEFAULT_FEED,
6934
6616
  currency: currency || DEFAULT_CURRENCY,
@@ -6942,7 +6624,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6942
6624
  * @returns Latest quote data with symbol and currency information
6943
6625
  */
6944
6626
  async getLatestQuote(symbol, feed, currency) {
6945
- return this.makeRequest(`/stocks/${symbol}/quotes/latest`, "GET", {
6627
+ return this.makeRequest(`/stocks/${symbol}/quotes/latest`, 'GET', {
6946
6628
  feed: feed || DEFAULT_FEED,
6947
6629
  currency,
6948
6630
  });
@@ -6958,16 +6640,13 @@ class AlpacaMarketDataAPI extends EventEmitter {
6958
6640
  const prevMarketDate = getLastFullTradingDate(date);
6959
6641
  const response = await this.getHistoricalBars({
6960
6642
  symbols: [symbol],
6961
- timeframe: "1Day",
6643
+ timeframe: '1Day',
6962
6644
  start: prevMarketDate.date.toISOString(),
6963
6645
  end: prevMarketDate.date.toISOString(),
6964
6646
  limit: 1,
6965
6647
  });
6966
6648
  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
- });
6649
+ log$1(`No previous close data available for ${symbol}`, { type: 'error', symbol });
6971
6650
  return null;
6972
6651
  }
6973
6652
  return response.bars[symbol][0];
@@ -6982,7 +6661,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6982
6661
  async getHourlyPrices(symbol, start, end) {
6983
6662
  const response = await this.getHistoricalBars({
6984
6663
  symbols: [symbol],
6985
- timeframe: "1Hour",
6664
+ timeframe: '1Hour',
6986
6665
  start: new Date(start).toISOString(),
6987
6666
  end: new Date(end).toISOString(),
6988
6667
  limit: 96, // Last 96 hours (4 days)
@@ -6999,7 +6678,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
6999
6678
  async getHalfHourlyPrices(symbol, start, end) {
7000
6679
  const response = await this.getHistoricalBars({
7001
6680
  symbols: [symbol],
7002
- timeframe: "30Min",
6681
+ timeframe: '30Min',
7003
6682
  start: new Date(start).toISOString(),
7004
6683
  end: new Date(end).toISOString(),
7005
6684
  limit: 16 * 2 * 4, // last 4 days, 16 hours per day, 2 bars per hour
@@ -7016,7 +6695,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7016
6695
  async getDailyPrices(symbol, start, end) {
7017
6696
  const response = await this.getHistoricalBars({
7018
6697
  symbols: [symbol],
7019
- timeframe: "1Day",
6698
+ timeframe: '1Day',
7020
6699
  start: new Date(start).toISOString(),
7021
6700
  end: new Date(end).toISOString(),
7022
6701
  limit: 100, // Last 100 days
@@ -7048,7 +6727,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7048
6727
  */
7049
6728
  static analyzeBars(bars) {
7050
6729
  if (!bars || bars.length === 0) {
7051
- return "No price data available";
6730
+ return 'No price data available';
7052
6731
  }
7053
6732
  const firstBar = bars[0];
7054
6733
  const lastBar = bars[bars.length - 1];
@@ -7073,7 +6752,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7073
6752
  */
7074
6753
  async getAssets(params) {
7075
6754
  // Endpoint: GET /v2/assets
7076
- return this.makeRequest("/assets", "GET", params, "api"); // use apiURL
6755
+ return this.makeRequest('/assets', 'GET', params, 'api'); // use apiURL
7077
6756
  }
7078
6757
  /**
7079
6758
  * Get a single asset by symbol or asset_id
@@ -7083,7 +6762,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7083
6762
  */
7084
6763
  async getAsset(symbolOrAssetId) {
7085
6764
  // Endpoint: GET /v2/assets/{symbol_or_asset_id}
7086
- return this.makeRequest(`/assets/${encodeURIComponent(symbolOrAssetId)}`, "GET", undefined, "api");
6765
+ return this.makeRequest(`/assets/${encodeURIComponent(symbolOrAssetId)}`, 'GET', undefined, 'api');
7087
6766
  }
7088
6767
  // ===== OPTIONS MARKET DATA METHODS =====
7089
6768
  /**
@@ -7095,7 +6774,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7095
6774
  */
7096
6775
  async getOptionsChain(params) {
7097
6776
  const { underlying_symbol, ...queryParams } = params;
7098
- return this.makeRequest(`/options/snapshots/${encodeURIComponent(underlying_symbol)}`, "GET", queryParams, "v1beta1");
6777
+ return this.makeRequest(`/options/snapshots/${encodeURIComponent(underlying_symbol)}`, 'GET', queryParams, 'v1beta1');
7099
6778
  }
7100
6779
  /**
7101
6780
  * Get the most recent trades for requested option contract symbols
@@ -7107,7 +6786,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7107
6786
  async getLatestOptionsTrades(params) {
7108
6787
  // Remove limit and page_token as they're not supported by this endpoint
7109
6788
  const { limit, page_token, ...requestParams } = params;
7110
- return this.makeRequest("/options/trades/latest", "GET", requestParams, "v1beta1");
6789
+ return this.makeRequest('/options/trades/latest', 'GET', requestParams, 'v1beta1');
7111
6790
  }
7112
6791
  /**
7113
6792
  * Get the most recent quotes for requested option contract symbols
@@ -7119,7 +6798,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7119
6798
  async getLatestOptionsQuotes(params) {
7120
6799
  // Remove limit and page_token as they're not supported by this endpoint
7121
6800
  const { limit, page_token, ...requestParams } = params;
7122
- return this.makeRequest("/options/quotes/latest", "GET", requestParams, "v1beta1");
6801
+ return this.makeRequest('/options/quotes/latest', 'GET', requestParams, 'v1beta1');
7123
6802
  }
7124
6803
  /**
7125
6804
  * Get historical OHLCV bars for option contract symbols
@@ -7131,18 +6810,18 @@ class AlpacaMarketDataAPI extends EventEmitter {
7131
6810
  */
7132
6811
  async getHistoricalOptionsBars(params) {
7133
6812
  const symbols = params.symbols;
7134
- const symbolsStr = symbols.join(",");
6813
+ const symbolsStr = symbols.join(',');
7135
6814
  let allBars = {};
7136
6815
  let pageToken = null;
7137
6816
  let hasMorePages = true;
7138
6817
  let totalBarsCount = 0;
7139
6818
  let pageCount = 0;
7140
6819
  // Initialize bar arrays for each symbol
7141
- symbols.forEach((symbol) => {
6820
+ symbols.forEach(symbol => {
7142
6821
  allBars[symbol] = [];
7143
6822
  });
7144
- log$1(`Starting historical options bars fetch for ${symbolsStr} (${params.timeframe}, ${params.start || "no start"} to ${params.end || "no end"})`, {
7145
- type: "info",
6823
+ log$1(`Starting historical options bars fetch for ${symbolsStr} (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`, {
6824
+ type: 'info'
7146
6825
  });
7147
6826
  while (hasMorePages) {
7148
6827
  pageCount++;
@@ -7150,11 +6829,9 @@ class AlpacaMarketDataAPI extends EventEmitter {
7150
6829
  ...params,
7151
6830
  ...(pageToken && { page_token: pageToken }),
7152
6831
  };
7153
- const response = await this.makeRequest("/options/bars", "GET", requestParams, "v1beta1");
6832
+ const response = await this.makeRequest('/options/bars', 'GET', requestParams, 'v1beta1');
7154
6833
  if (!response.bars) {
7155
- log$1(`No options bars data found in response for ${symbolsStr}`, {
7156
- type: "warn",
7157
- });
6834
+ log$1(`No options bars data found in response for ${symbolsStr}`, { type: 'warn' });
7158
6835
  break;
7159
6836
  }
7160
6837
  // Combine bars for each symbol
@@ -7166,7 +6843,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7166
6843
  allBars[symbol] = [...allBars[symbol], ...bars];
7167
6844
  pageBarsCount += bars.length;
7168
6845
  // Track date range for this page
7169
- bars.forEach((bar) => {
6846
+ bars.forEach(bar => {
7170
6847
  const barDate = new Date(bar.t);
7171
6848
  if (!earliestTimestamp || barDate < earliestTimestamp) {
7172
6849
  earliestTimestamp = barDate;
@@ -7182,23 +6859,21 @@ class AlpacaMarketDataAPI extends EventEmitter {
7182
6859
  hasMorePages = !!pageToken;
7183
6860
  // Enhanced logging with date range and progress info
7184
6861
  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",
6862
+ ? `${earliestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${latestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
6863
+ : 'unknown range';
6864
+ log$1(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} option bars (total: ${totalBarsCount.toLocaleString()}) for ${symbolsStr}, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {
6865
+ type: 'info'
7189
6866
  });
7190
6867
  // Prevent infinite loops
7191
6868
  if (pageCount > 1000) {
7192
- log$1(`Stopping options bars pagination after ${pageCount} pages to prevent infinite loop`, { type: "warn" });
6869
+ log$1(`Stopping options bars pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
7193
6870
  break;
7194
6871
  }
7195
6872
  }
7196
6873
  // Final summary
7197
- const symbolCounts = Object.entries(allBars)
7198
- .map(([symbol, bars]) => `${symbol}: ${bars.length}`)
7199
- .join(", ");
6874
+ const symbolCounts = Object.entries(allBars).map(([symbol, bars]) => `${symbol}: ${bars.length}`).join(', ');
7200
6875
  log$1(`Historical options bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages (${symbolCounts})`, {
7201
- type: "info",
6876
+ type: 'info'
7202
6877
  });
7203
6878
  return {
7204
6879
  bars: allBars,
@@ -7215,18 +6890,18 @@ class AlpacaMarketDataAPI extends EventEmitter {
7215
6890
  */
7216
6891
  async getHistoricalOptionsTrades(params) {
7217
6892
  const symbols = params.symbols;
7218
- const symbolsStr = symbols.join(",");
6893
+ const symbolsStr = symbols.join(',');
7219
6894
  let allTrades = {};
7220
6895
  let pageToken = null;
7221
6896
  let hasMorePages = true;
7222
6897
  let totalTradesCount = 0;
7223
6898
  let pageCount = 0;
7224
6899
  // Initialize trades arrays for each symbol
7225
- symbols.forEach((symbol) => {
6900
+ symbols.forEach(symbol => {
7226
6901
  allTrades[symbol] = [];
7227
6902
  });
7228
- log$1(`Starting historical options trades fetch for ${symbolsStr} (${params.start || "no start"} to ${params.end || "no end"})`, {
7229
- type: "info",
6903
+ log$1(`Starting historical options trades fetch for ${symbolsStr} (${params.start || 'no start'} to ${params.end || 'no end'})`, {
6904
+ type: 'info'
7230
6905
  });
7231
6906
  while (hasMorePages) {
7232
6907
  pageCount++;
@@ -7234,11 +6909,9 @@ class AlpacaMarketDataAPI extends EventEmitter {
7234
6909
  ...params,
7235
6910
  ...(pageToken && { page_token: pageToken }),
7236
6911
  };
7237
- const response = await this.makeRequest("/options/trades", "GET", requestParams, "v1beta1");
6912
+ const response = await this.makeRequest('/options/trades', 'GET', requestParams, 'v1beta1');
7238
6913
  if (!response.trades) {
7239
- log$1(`No options trades data found in response for ${symbolsStr}`, {
7240
- type: "warn",
7241
- });
6914
+ log$1(`No options trades data found in response for ${symbolsStr}`, { type: 'warn' });
7242
6915
  break;
7243
6916
  }
7244
6917
  // Combine trades for each symbol
@@ -7250,7 +6923,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7250
6923
  allTrades[symbol] = [...allTrades[symbol], ...trades];
7251
6924
  pageTradesCount += trades.length;
7252
6925
  // Track date range for this page
7253
- trades.forEach((trade) => {
6926
+ trades.forEach(trade => {
7254
6927
  const tradeDate = new Date(trade.t);
7255
6928
  if (!earliestTimestamp || tradeDate < earliestTimestamp) {
7256
6929
  earliestTimestamp = tradeDate;
@@ -7266,23 +6939,21 @@ class AlpacaMarketDataAPI extends EventEmitter {
7266
6939
  hasMorePages = !!pageToken;
7267
6940
  // Enhanced logging with date range and progress info
7268
6941
  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",
6942
+ ? `${earliestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${latestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
6943
+ : 'unknown range';
6944
+ log$1(`Page ${pageCount}: Fetched ${pageTradesCount.toLocaleString()} option trades (total: ${totalTradesCount.toLocaleString()}) for ${symbolsStr}, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {
6945
+ type: 'info'
7273
6946
  });
7274
6947
  // Prevent infinite loops
7275
6948
  if (pageCount > 1000) {
7276
- log$1(`Stopping options trades pagination after ${pageCount} pages to prevent infinite loop`, { type: "warn" });
6949
+ log$1(`Stopping options trades pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
7277
6950
  break;
7278
6951
  }
7279
6952
  }
7280
6953
  // Final summary
7281
- const symbolCounts = Object.entries(allTrades)
7282
- .map(([symbol, trades]) => `${symbol}: ${trades.length}`)
7283
- .join(", ");
6954
+ const symbolCounts = Object.entries(allTrades).map(([symbol, trades]) => `${symbol}: ${trades.length}`).join(', ');
7284
6955
  log$1(`Historical options trades fetch complete: ${totalTradesCount.toLocaleString()} total trades across ${pageCount} pages (${symbolCounts})`, {
7285
- type: "info",
6956
+ type: 'info'
7286
6957
  });
7287
6958
  return {
7288
6959
  trades: allTrades,
@@ -7300,7 +6971,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7300
6971
  async getOptionsSnapshot(params) {
7301
6972
  // Remove limit and page_token as they may not be supported by this endpoint
7302
6973
  const { limit, page_token, ...requestParams } = params;
7303
- return this.makeRequest("/options/snapshots", "GET", requestParams, "v1beta1");
6974
+ return this.makeRequest('/options/snapshots', 'GET', requestParams, 'v1beta1');
7304
6975
  }
7305
6976
  /**
7306
6977
  * Get condition codes for options trades or quotes
@@ -7311,7 +6982,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7311
6982
  * @see https://docs.alpaca.markets/reference/optionmetaconditions
7312
6983
  */
7313
6984
  async getOptionsConditionCodes(tickType) {
7314
- return this.makeRequest(`/options/meta/conditions/${tickType}`, "GET", undefined, "v1beta1");
6985
+ return this.makeRequest(`/options/meta/conditions/${tickType}`, 'GET', undefined, 'v1beta1');
7315
6986
  }
7316
6987
  /**
7317
6988
  * Get exchange codes for options
@@ -7321,7 +6992,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7321
6992
  * @see https://docs.alpaca.markets/reference/optionmetaexchanges
7322
6993
  */
7323
6994
  async getOptionsExchangeCodes() {
7324
- return this.makeRequest("/options/meta/exchanges", "GET", undefined, "v1beta1");
6995
+ return this.makeRequest('/options/meta/exchanges', 'GET', undefined, 'v1beta1');
7325
6996
  }
7326
6997
  /**
7327
6998
  * Analyzes an array of option bars and returns a summary string
@@ -7330,7 +7001,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7330
7001
  */
7331
7002
  static analyzeOptionBars(bars) {
7332
7003
  if (!bars || bars.length === 0) {
7333
- return "No option price data available";
7004
+ return 'No option price data available';
7334
7005
  }
7335
7006
  const firstBar = bars[0];
7336
7007
  const lastBar = bars[bars.length - 1];
@@ -7354,7 +7025,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7354
7025
  */
7355
7026
  static formatOptionGreeks(greeks) {
7356
7027
  if (!greeks) {
7357
- return "No greeks data available";
7028
+ return 'No greeks data available';
7358
7029
  }
7359
7030
  const parts = [];
7360
7031
  if (greeks.delta !== undefined)
@@ -7367,7 +7038,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7367
7038
  parts.push(`Vega: ${greeks.vega.toFixed(4)}`);
7368
7039
  if (greeks.rho !== undefined)
7369
7040
  parts.push(`Rho: ${greeks.rho.toFixed(4)}`);
7370
- return parts.length > 0 ? parts.join(", ") : "No greeks data available";
7041
+ return parts.length > 0 ? parts.join(', ') : 'No greeks data available';
7371
7042
  }
7372
7043
  /**
7373
7044
  * Interprets condition codes using the provided condition codes mapping
@@ -7377,14 +7048,12 @@ class AlpacaMarketDataAPI extends EventEmitter {
7377
7048
  */
7378
7049
  static interpretConditionCodes(conditionCodes, conditionCodesMap) {
7379
7050
  if (!conditionCodes || conditionCodes.length === 0) {
7380
- return "No conditions";
7051
+ return 'No conditions';
7381
7052
  }
7382
7053
  const descriptions = conditionCodes
7383
7054
  .map((code) => conditionCodesMap[code] || `Unknown (${code})`)
7384
7055
  .filter((desc) => desc !== undefined);
7385
- return descriptions.length > 0
7386
- ? descriptions.join(", ")
7387
- : "No condition descriptions available";
7056
+ return descriptions.length > 0 ? descriptions.join(', ') : 'No condition descriptions available';
7388
7057
  }
7389
7058
  /**
7390
7059
  * Gets the exchange name from exchange code using the provided exchange codes mapping
@@ -7393,7 +7062,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7393
7062
  * @returns Exchange name or formatted unknown exchange
7394
7063
  */
7395
7064
  static getExchangeName(exchangeCode, exchangeCodesMap) {
7396
- return (exchangeCodesMap[exchangeCode] || `Unknown Exchange (${exchangeCode})`);
7065
+ return exchangeCodesMap[exchangeCode] || `Unknown Exchange (${exchangeCode})`;
7397
7066
  }
7398
7067
  /**
7399
7068
  * Fetches news articles from Alpaca API for a symbol, paginating through all results.
@@ -7406,7 +7075,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7406
7075
  start: new Date(Date.now() - 24 * 60 * 60 * 1000),
7407
7076
  end: new Date(),
7408
7077
  limit: 10,
7409
- sort: "desc",
7078
+ sort: 'desc',
7410
7079
  include_content: true,
7411
7080
  };
7412
7081
  const mergedParams = { ...defaultParams, ...params };
@@ -7420,52 +7089,38 @@ class AlpacaMarketDataAPI extends EventEmitter {
7420
7089
  if (!content)
7421
7090
  return undefined;
7422
7091
  // Remove excessive whitespace, newlines, and trim
7423
- return content.replace(/\s+/g, " ").trim();
7092
+ return content.replace(/\s+/g, ' ').trim();
7424
7093
  }
7425
7094
  while (hasMorePages) {
7426
7095
  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
- }),
7096
+ ...(mergedParams.start && { start: new Date(mergedParams.start).toISOString() }),
7097
+ ...(mergedParams.end && { end: new Date(mergedParams.end).toISOString() }),
7433
7098
  ...(symbol && { symbols: symbol }),
7434
- ...(mergedParams.limit && {
7435
- limit: Math.min(50, maxLimit - fetchedCount).toString(),
7436
- }),
7099
+ ...(mergedParams.limit && { limit: Math.min(50, maxLimit - fetchedCount).toString() }),
7437
7100
  ...(mergedParams.sort && { sort: mergedParams.sort }),
7438
- ...(mergedParams.include_content !== undefined
7439
- ? { include_content: mergedParams.include_content.toString() }
7440
- : {}),
7101
+ ...(mergedParams.include_content !== undefined ? { include_content: mergedParams.include_content.toString() } : {}),
7441
7102
  ...(pageToken && { page_token: pageToken }),
7442
7103
  });
7443
7104
  const url = `${this.v1beta1url}/news?${queryParams}`;
7444
- log$1(`Fetching news from: ${url}`, { type: "debug", symbol });
7105
+ log$1(`Fetching news from: ${url}`, { type: 'debug', symbol });
7445
7106
  const response = await fetch(url, {
7446
- method: "GET",
7107
+ method: 'GET',
7447
7108
  headers: this.headers,
7448
7109
  });
7449
7110
  if (!response.ok) {
7450
7111
  const errorText = await response.text();
7451
- log$1(`Alpaca news API error (${response.status}): ${errorText}`, {
7452
- type: "error",
7453
- symbol,
7454
- });
7112
+ log$1(`Alpaca news API error (${response.status}): ${errorText}`, { type: 'error', symbol });
7455
7113
  throw new Error(`Alpaca news API error (${response.status}): ${errorText}`);
7456
7114
  }
7457
7115
  const data = await response.json();
7458
7116
  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
- });
7117
+ log$1(`No news data found in Alpaca response for ${symbol}`, { type: 'warn', symbol });
7463
7118
  break;
7464
7119
  }
7465
7120
  const transformedNews = data.news.map((article) => ({
7466
7121
  symbols: article.symbols,
7467
7122
  title: article.headline,
7468
- summary: cleanContent(article.summary) ?? "",
7123
+ summary: cleanContent(article.summary) ?? '',
7469
7124
  content: article.content ? cleanContent(article.content) : undefined,
7470
7125
  url: article.url,
7471
7126
  source: article.source,
@@ -7478,7 +7133,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
7478
7133
  fetchedCount = newsArticles.length;
7479
7134
  pageToken = data.next_page_token || null;
7480
7135
  hasMorePages = !!pageToken && (!maxLimit || fetchedCount < maxLimit);
7481
- log$1(`Fetched ${transformedNews.length} news articles (total: ${fetchedCount}) for ${symbol}. More pages: ${hasMorePages}`, { type: "debug", symbol });
7136
+ log$1(`Fetched ${transformedNews.length} news articles (total: ${fetchedCount}) for ${symbol}. More pages: ${hasMorePages}`, { type: 'debug', symbol });
7482
7137
  if (maxLimit && fetchedCount >= maxLimit) {
7483
7138
  newsArticles = newsArticles.slice(0, maxLimit);
7484
7139
  break;