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