@discomedia/utils 1.0.52 → 1.0.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -11381,6 +11381,7 @@ function requireConstants () {
11381
11381
 
11382
11382
  constants = {
11383
11383
  BINARY_TYPES,
11384
+ CLOSE_TIMEOUT: 30000,
11384
11385
  EMPTY_BUFFER: Buffer.alloc(0),
11385
11386
  GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
11386
11387
  hasBlob,
@@ -14151,6 +14152,7 @@ function requireWebsocket () {
14151
14152
 
14152
14153
  const {
14153
14154
  BINARY_TYPES,
14155
+ CLOSE_TIMEOUT,
14154
14156
  EMPTY_BUFFER,
14155
14157
  GUID,
14156
14158
  kForOnEventAttribute,
@@ -14165,7 +14167,6 @@ function requireWebsocket () {
14165
14167
  const { format, parse } = requireExtension();
14166
14168
  const { toBuffer } = requireBufferUtil();
14167
14169
 
14168
- const closeTimeout = 30 * 1000;
14169
14170
  const kAborted = Symbol('kAborted');
14170
14171
  const protocolVersions = [8, 13];
14171
14172
  const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
@@ -14221,6 +14222,7 @@ function requireWebsocket () {
14221
14222
  initAsClient(this, address, protocols, options);
14222
14223
  } else {
14223
14224
  this._autoPong = options.autoPong;
14225
+ this._closeTimeout = options.closeTimeout;
14224
14226
  this._isServer = true;
14225
14227
  }
14226
14228
  }
@@ -14762,6 +14764,8 @@ function requireWebsocket () {
14762
14764
  * times in the same tick
14763
14765
  * @param {Boolean} [options.autoPong=true] Specifies whether or not to
14764
14766
  * automatically send a pong in response to a ping
14767
+ * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait
14768
+ * for the closing handshake to finish after `websocket.close()` is called
14765
14769
  * @param {Function} [options.finishRequest] A function which can be used to
14766
14770
  * customize the headers of each http request before it is sent
14767
14771
  * @param {Boolean} [options.followRedirects=false] Whether or not to follow
@@ -14788,6 +14792,7 @@ function requireWebsocket () {
14788
14792
  const opts = {
14789
14793
  allowSynchronousEvents: true,
14790
14794
  autoPong: true,
14795
+ closeTimeout: CLOSE_TIMEOUT,
14791
14796
  protocolVersion: protocolVersions[1],
14792
14797
  maxPayload: 100 * 1024 * 1024,
14793
14798
  skipUTF8Validation: false,
@@ -14806,6 +14811,7 @@ function requireWebsocket () {
14806
14811
  };
14807
14812
 
14808
14813
  websocket._autoPong = opts.autoPong;
14814
+ websocket._closeTimeout = opts.closeTimeout;
14809
14815
 
14810
14816
  if (!protocolVersions.includes(opts.protocolVersion)) {
14811
14817
  throw new RangeError(
@@ -15423,7 +15429,7 @@ function requireWebsocket () {
15423
15429
  function setCloseTimer(websocket) {
15424
15430
  websocket._closeTimer = setTimeout(
15425
15431
  websocket._socket.destroy.bind(websocket._socket),
15426
- closeTimeout
15432
+ websocket._closeTimeout
15427
15433
  );
15428
15434
  }
15429
15435
 
@@ -15441,23 +15447,23 @@ function requireWebsocket () {
15441
15447
 
15442
15448
  websocket._readyState = WebSocket.CLOSING;
15443
15449
 
15444
- let chunk;
15445
-
15446
15450
  //
15447
15451
  // The close frame might not have been received or the `'end'` event emitted,
15448
15452
  // for example, if the socket was destroyed due to an error. Ensure that the
15449
15453
  // `receiver` stream is closed after writing any remaining buffered data to
15450
15454
  // it. If the readable side of the socket is in flowing mode then there is no
15451
- // buffered data as everything has been already written and `readable.read()`
15452
- // will return `null`. If instead, the socket is paused, any possible buffered
15453
- // data will be read as a single chunk.
15455
+ // buffered data as everything has been already written. If instead, the
15456
+ // socket is paused, any possible buffered data will be read as a single
15457
+ // chunk.
15454
15458
  //
15455
15459
  if (
15456
15460
  !this._readableState.endEmitted &&
15457
15461
  !websocket._closeFrameReceived &&
15458
15462
  !websocket._receiver._writableState.errorEmitted &&
15459
- (chunk = websocket._socket.read()) !== null
15463
+ this._readableState.length !== 0
15460
15464
  ) {
15465
+ const chunk = this.read(this._readableState.length);
15466
+
15461
15467
  websocket._receiver.write(chunk);
15462
15468
  }
15463
15469
 
@@ -15789,7 +15795,7 @@ function requireWebsocketServer () {
15789
15795
  const PerMessageDeflate = requirePermessageDeflate();
15790
15796
  const subprotocol = requireSubprotocol();
15791
15797
  const WebSocket = requireWebsocket();
15792
- const { GUID, kWebSocket } = requireConstants();
15798
+ const { CLOSE_TIMEOUT, GUID, kWebSocket } = requireConstants();
15793
15799
 
15794
15800
  const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
15795
15801
 
@@ -15816,6 +15822,9 @@ function requireWebsocketServer () {
15816
15822
  * pending connections
15817
15823
  * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
15818
15824
  * track clients
15825
+ * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to
15826
+ * wait for the closing handshake to finish after `websocket.close()` is
15827
+ * called
15819
15828
  * @param {Function} [options.handleProtocols] A hook to handle protocols
15820
15829
  * @param {String} [options.host] The hostname where to bind the server
15821
15830
  * @param {Number} [options.maxPayload=104857600] The maximum allowed message
@@ -15845,6 +15854,7 @@ function requireWebsocketServer () {
15845
15854
  perMessageDeflate: false,
15846
15855
  handleProtocols: null,
15847
15856
  clientTracking: true,
15857
+ closeTimeout: CLOSE_TIMEOUT,
15848
15858
  verifyClient: null,
15849
15859
  noServer: false,
15850
15860
  backlog: null, // use default (511 as implemented in net.js)
@@ -18129,7 +18139,7 @@ class AlpacaTradingAPI {
18129
18139
  }
18130
18140
  handleTradeUpdate(data) {
18131
18141
  if (this.tradeUpdateCallback) {
18132
- this.log(`Trade update: ${data.event} to ${data.order.side} ${data.order.qty} shares, type ${data.order.type}`, {
18142
+ this.log(`Trade update: ${data.event} to ${data.order.side} ${data.order.qty} shares${data.event === 'partial_fill' ? ` (filled shares: ${data.order.filled_qty})` : ''}, type ${data.order.type}`, {
18133
18143
  symbol: data.order.symbol,
18134
18144
  type: 'debug',
18135
18145
  });
@@ -18247,7 +18257,9 @@ class AlpacaTradingAPI {
18247
18257
  try {
18248
18258
  this.ws.terminate();
18249
18259
  }
18250
- catch { /* no-op */ }
18260
+ catch {
18261
+ /* no-op */
18262
+ }
18251
18263
  }
18252
18264
  this.ws = null;
18253
18265
  }
@@ -18464,6 +18476,7 @@ class AlpacaTradingAPI {
18464
18476
  * @param qty (number) - the quantity of the order
18465
18477
  * @param side (string) - the side of the order
18466
18478
  * @param position_intent (string) - the position intent of the order. Important for knowing if a position needs a trailing stop.
18479
+ * @param client_order_id (string) - optional client order id
18467
18480
  */
18468
18481
  async createMarketOrder(symbol, qty, side, position_intent, client_order_id) {
18469
18482
  this.log(`Creating market order for ${symbol}: ${side} ${qty} shares (${position_intent})`, {
@@ -18489,6 +18502,86 @@ class AlpacaTradingAPI {
18489
18502
  throw error;
18490
18503
  }
18491
18504
  }
18505
+ /**
18506
+ * Create a Market on Open (MOO) order - executes in the opening auction
18507
+ *
18508
+ * IMPORTANT TIMING CONSTRAINTS:
18509
+ * - Valid submission window: After 7:00pm ET and before 9:28am ET
18510
+ * - Orders submitted between 9:28am and 7:00pm ET will be REJECTED
18511
+ * - Orders submitted after 7:00pm ET are queued for the next trading day's opening auction
18512
+ * - Example: An order at 8:00pm Monday will execute at Tuesday's market open (9:30am)
18513
+ *
18514
+ * @param symbol - The symbol of the order
18515
+ * @param qty - The quantity of shares
18516
+ * @param side - Buy or sell
18517
+ * @param position_intent - The position intent (buy_to_open, sell_to_close, etc.)
18518
+ * @param client_order_id - Optional client order id
18519
+ * @returns The created order
18520
+ */
18521
+ async createMOOOrder(symbol, qty, side, position_intent, client_order_id) {
18522
+ this.log(`Creating Market on Open order for ${symbol}: ${side} ${qty} shares (${position_intent})`, {
18523
+ symbol,
18524
+ });
18525
+ const body = {
18526
+ symbol,
18527
+ qty: Math.abs(qty).toString(),
18528
+ side,
18529
+ position_intent,
18530
+ type: 'market',
18531
+ time_in_force: 'opg',
18532
+ order_class: 'simple',
18533
+ };
18534
+ if (client_order_id !== undefined) {
18535
+ body.client_order_id = client_order_id;
18536
+ }
18537
+ try {
18538
+ return await this.makeRequest('/orders', 'POST', body);
18539
+ }
18540
+ catch (error) {
18541
+ this.log(`Error creating MOO order: ${error}`, { type: 'error' });
18542
+ throw error;
18543
+ }
18544
+ }
18545
+ /**
18546
+ * Create a Market on Close (MOC) order - executes in the closing auction
18547
+ *
18548
+ * IMPORTANT TIMING CONSTRAINTS:
18549
+ * - Valid submission window: After 7:00pm ET (previous day) and before 3:50pm ET (same day)
18550
+ * - Orders submitted between 3:50pm and 7:00pm ET will be REJECTED
18551
+ * - Orders submitted after 7:00pm ET are queued for the next trading day's closing auction
18552
+ * - Example: An order at 8:00pm Monday will execute at Tuesday's market close (4:00pm)
18553
+ *
18554
+ * @param symbol - The symbol of the order
18555
+ * @param qty - The quantity of shares
18556
+ * @param side - Buy or sell
18557
+ * @param position_intent - The position intent (buy_to_open, sell_to_close, etc.)
18558
+ * @param client_order_id - Optional client order id
18559
+ * @returns The created order
18560
+ */
18561
+ async createMOCOrder(symbol, qty, side, position_intent, client_order_id) {
18562
+ this.log(`Creating Market on Close order for ${symbol}: ${side} ${qty} shares (${position_intent})`, {
18563
+ symbol,
18564
+ });
18565
+ const body = {
18566
+ symbol,
18567
+ qty: Math.abs(qty).toString(),
18568
+ side,
18569
+ position_intent,
18570
+ type: 'market',
18571
+ time_in_force: 'cls',
18572
+ order_class: 'simple',
18573
+ };
18574
+ if (client_order_id !== undefined) {
18575
+ body.client_order_id = client_order_id;
18576
+ }
18577
+ try {
18578
+ return await this.makeRequest('/orders', 'POST', body);
18579
+ }
18580
+ catch (error) {
18581
+ this.log(`Error creating MOC order: ${error}`, { type: 'error' });
18582
+ throw error;
18583
+ }
18584
+ }
18492
18585
  /**
18493
18586
  * Get the current trail percent for a symbol, assuming that it has an open position and a trailing stop order to close it. Because this relies on an orders request for one symbol, you can't do it too often.
18494
18587
  * @param symbol (string) - the symbol of the order
@@ -18806,7 +18899,7 @@ class AlpacaTradingAPI {
18806
18899
  const hourlyParams = { timeframe: '1Min', period: '1D' };
18807
18900
  const [dailyHistory, hourlyHistory] = await Promise.all([
18808
18901
  this.getPortfolioHistory(dailyParams),
18809
- this.getPortfolioHistory(hourlyParams)
18902
+ this.getPortfolioHistory(hourlyParams),
18810
18903
  ]);
18811
18904
  // If no hourly history, return daily as-is
18812
18905
  if (!hourlyHistory.timestamp || hourlyHistory.timestamp.length === 0) {