hedgequantx 2.6.62 → 2.6.64

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "2.6.62",
3
+ "version": "2.6.64",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -961,6 +961,21 @@ const launchAlgo = async (service, account, contract, config) => {
961
961
  clearInterval(refreshInterval);
962
962
  clearInterval(pnlInterval);
963
963
 
964
+ // EMERGENCY STOP: Cancel all orders and flatten all positions
965
+ if (useFastPath && service && account.rithmicAccountId) {
966
+ try {
967
+ ui.addLog('warning', 'EMERGENCY STOP - Cancelling orders & flattening positions...');
968
+ const stopResult = await service.emergencyStop(account.rithmicAccountId);
969
+ if (stopResult.success) {
970
+ ui.addLog('success', 'All orders cancelled, positions flattened');
971
+ } else {
972
+ ui.addLog('error', 'Emergency stop partial - check positions manually');
973
+ }
974
+ } catch (e) {
975
+ ui.addLog('error', `Emergency stop failed: ${e.message}`);
976
+ }
977
+ }
978
+
964
979
  // Stop Position Manager (fast path)
965
980
  if (positionManager) {
966
981
  positionManager.stop();
@@ -39,28 +39,28 @@ const LOG_COLORS = {
39
39
  analysis: chalk.magenta
40
40
  };
41
41
 
42
- // Log type icons - UPPERCASE BOLD HF style
42
+ // Log type icons - Unicode icons with colors
43
43
  const LOG_ICONS = {
44
- fill_buy: 'BUY ',
45
- fill_sell: 'SELL ',
46
- fill_win: 'WIN ',
47
- fill_loss: 'LOSS ',
48
- win: 'WIN ',
49
- loss: 'LOSS ',
50
- be: 'BE ',
51
- entry: 'ENTRY ',
52
- filled: 'FILL ',
53
- connected: 'CONN ',
54
- ready: 'READY ',
55
- error: 'ERR ',
56
- reject: 'REJ ',
57
- info: 'INFO ',
58
- system: 'SYS ',
59
- signal: 'SIG ',
60
- trade: 'TRADE ',
61
- success: 'OK ',
62
- warning: 'WARN ',
63
- analysis: 'ANLYS '
44
+ fill_buy: 'BUY ',
45
+ fill_sell: 'SELL ',
46
+ fill_win: 'WIN ',
47
+ fill_loss: 'LOSS ',
48
+ win: 'WIN ',
49
+ loss: 'LOSS ',
50
+ be: 'BE ',
51
+ entry: 'ENTRY',
52
+ filled: 'FILL ',
53
+ connected: 'CONN ',
54
+ ready: 'READY',
55
+ error: 'ERR ',
56
+ reject: 'REJ ',
57
+ info: 'INFO ',
58
+ system: 'SYS ',
59
+ signal: 'SIG ',
60
+ trade: 'TRADE',
61
+ success: 'OK ',
62
+ warning: 'WARN ',
63
+ analysis: 'ANLYS'
64
64
  };
65
65
 
66
66
  /**
@@ -17,7 +17,7 @@ const {
17
17
  getPositions,
18
18
  hashAccountId,
19
19
  } = require('./accounts');
20
- const { placeOrder, cancelOrder, getOrders, getOrderHistory, closePosition, fastEntry, fastExit } = require('./orders');
20
+ const { placeOrder, cancelOrder, cancelAllOrders, getOrders, getOrderHistory, closePosition, flattenAll, emergencyStop, fastEntry, fastExit } = require('./orders');
21
21
  const { decodeFrontMonthContract } = require('./protobuf');
22
22
  const { TIMEOUTS, CACHE } = require('../../config/settings');
23
23
  const { logger } = require('../../utils/logger');
@@ -472,7 +472,10 @@ class RithmicService extends EventEmitter {
472
472
  async getOrderHistory(date) { return getOrderHistory(this, date); }
473
473
  async placeOrder(orderData) { return placeOrder(this, orderData); }
474
474
  async cancelOrder(orderId) { return cancelOrder(this, orderId); }
475
+ async cancelAllOrders(accountId) { return cancelAllOrders(this, accountId); }
475
476
  async closePosition(accountId, symbol) { return closePosition(this, accountId, symbol); }
477
+ async flattenAll(accountId) { return flattenAll(this, accountId); }
478
+ async emergencyStop(accountId) { return emergencyStop(this, accountId); }
476
479
 
477
480
  // ==================== FAST SCALPING (Ultra-Low Latency) ====================
478
481
 
@@ -16,6 +16,9 @@ const { REQ } = require('./constants');
16
16
  const { proto } = require('./protobuf');
17
17
  const { LatencyTracker } = require('./handlers');
18
18
  const { performance } = require('perf_hooks');
19
+ const { logger } = require('../../utils/logger');
20
+
21
+ const log = logger.scope('RithmicOrders');
19
22
 
20
23
  // Debug mode - use no-op function when disabled for zero overhead
21
24
  const DEBUG = process.env.HQX_DEBUG === '1';
@@ -447,12 +450,98 @@ const closePosition = async (service, accountId, symbol) => {
447
450
  });
448
451
  };
449
452
 
453
+ /**
454
+ * Cancel all open orders for an account
455
+ * @param {RithmicService} service - The Rithmic service instance
456
+ * @param {string} accountId - Account ID
457
+ */
458
+ const cancelAllOrders = async (service, accountId) => {
459
+ if (!service.orderConn || !service.loginInfo) {
460
+ return { success: false, error: 'Not connected' };
461
+ }
462
+
463
+ try {
464
+ // Use RequestCancelAllOrders template
465
+ service.orderConn.send('RequestCancelAllOrders', {
466
+ templateId: 346, // CANCEL_ALL_ORDERS
467
+ userMsg: ['HQX-STOP'],
468
+ fcmId: service.loginInfo.fcmId,
469
+ ibId: service.loginInfo.ibId,
470
+ accountId: accountId,
471
+ });
472
+
473
+ log.info('Cancel all orders sent', { accountId });
474
+ return { success: true };
475
+ } catch (error) {
476
+ log.error('Cancel all orders failed', { error: error.message });
477
+ return { success: false, error: error.message };
478
+ }
479
+ };
480
+
481
+ /**
482
+ * Flatten all positions for an account (close all positions)
483
+ * @param {RithmicService} service - The Rithmic service instance
484
+ * @param {string} accountId - Account ID
485
+ */
486
+ const flattenAll = async (service, accountId) => {
487
+ const results = [];
488
+ const positions = Array.from(service.positions.values());
489
+ const accountPositions = positions.filter(p => p.accountId === accountId && p.quantity !== 0);
490
+
491
+ log.info('Flattening all positions', { accountId, count: accountPositions.length });
492
+
493
+ for (const position of accountPositions) {
494
+ try {
495
+ const result = await placeOrder(service, {
496
+ accountId,
497
+ symbol: position.symbol,
498
+ exchange: position.exchange,
499
+ size: Math.abs(position.quantity),
500
+ side: position.quantity > 0 ? 1 : 0, // Sell if long, Buy if short
501
+ type: 2, // Market
502
+ });
503
+ results.push({ symbol: position.symbol, ...result });
504
+ } catch (error) {
505
+ results.push({ symbol: position.symbol, success: false, error: error.message });
506
+ }
507
+ }
508
+
509
+ return { success: true, results };
510
+ };
511
+
512
+ /**
513
+ * Emergency stop - Cancel all orders and flatten all positions
514
+ * @param {RithmicService} service - The Rithmic service instance
515
+ * @param {string} accountId - Account ID
516
+ */
517
+ const emergencyStop = async (service, accountId) => {
518
+ log.warn('EMERGENCY STOP initiated', { accountId });
519
+
520
+ // 1. Cancel all orders first
521
+ const cancelResult = await cancelAllOrders(service, accountId);
522
+
523
+ // 2. Wait a moment for cancellations to process
524
+ await new Promise(r => setTimeout(r, 500));
525
+
526
+ // 3. Flatten all positions
527
+ const flattenResult = await flattenAll(service, accountId);
528
+
529
+ return {
530
+ success: cancelResult.success && flattenResult.success,
531
+ cancelled: cancelResult,
532
+ flattened: flattenResult,
533
+ };
534
+ };
535
+
450
536
  module.exports = {
451
537
  placeOrder,
452
538
  cancelOrder,
539
+ cancelAllOrders,
453
540
  getOrders,
454
541
  getOrderHistory,
455
542
  closePosition,
543
+ flattenAll,
544
+ emergencyStop,
456
545
  // Fast scalping - ultra-low latency
457
546
  fastEntry,
458
547
  fastExit,