hedgequantx 2.6.146 → 2.6.148

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.146",
3
+ "version": "2.6.148",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -2009,33 +2009,94 @@ const launchMultiSymbolRithmic = async (service, account, contracts, config) =>
2009
2009
  }
2010
2010
 
2011
2011
  // ═══════════════════════════════════════════════════════════════════════════
2012
- // EMERGENCY STOP
2012
+ // EMERGENCY STOP - Force close ALL positions
2013
2013
  // ═══════════════════════════════════════════════════════════════════════════
2014
2014
  const emergencyStopAll = async () => {
2015
- ui.addLog('warning', '████ EMERGENCY STOP ████');
2015
+ ui.addLog('warning', '████ EMERGENCY STOP INITIATED ████');
2016
+ ui.render(stats);
2017
+
2018
+ const TIMEOUT_MS = 5000;
2019
+ const withTimeout = (promise, ms) => Promise.race([
2020
+ promise,
2021
+ new Promise((_, reject) => setTimeout(() => reject(new Error('TIMEOUT')), ms))
2022
+ ]);
2016
2023
 
2017
2024
  try {
2018
- // Use Rithmic emergencyStop to flatten all positions with timeout
2019
- const stopPromise = (async () => {
2025
+ // Step 1: Cancel all pending orders
2026
+ ui.addLog('info', 'Cancelling all orders...');
2027
+ ui.render(stats);
2028
+ try {
2029
+ if (service && typeof service.cancelAllOrders === 'function') {
2030
+ await withTimeout(service.cancelAllOrders(rithmicAccountId), TIMEOUT_MS);
2031
+ }
2032
+ } catch (e) {
2033
+ ui.addLog('warning', `Cancel orders: ${e.message}`);
2034
+ }
2035
+
2036
+ // Step 2: Force close each symbol's position via fastExit
2037
+ ui.addLog('info', 'Closing all positions...');
2038
+ ui.render(stats);
2039
+
2040
+ for (const [symbolName, symStats] of Object.entries(stats.symbolStats)) {
2041
+ // Get position from positionManager (more reliable than stats)
2042
+ const pm = positionManagers[symbolName];
2043
+ const pmPosition = pm?.currentPosition;
2044
+
2045
+ // Use PM position if available, otherwise fallback to stats
2046
+ let posQty = 0;
2047
+ let closeSide = 0;
2048
+
2049
+ if (pmPosition && pmPosition.size > 0) {
2050
+ posQty = pmPosition.size;
2051
+ closeSide = pmPosition.side === 0 ? 1 : 0; // Sell if long (0), Buy if short (1)
2052
+ } else if (symStats.position && symStats.position !== 0) {
2053
+ // Fallback: use stats but sanitize the value
2054
+ posQty = Math.min(Math.abs(Number(symStats.position) || 0), 10); // Max 10 contracts safety
2055
+ if (posQty === 0) posQty = 1; // Default to 1 if we think there's a position
2056
+ closeSide = symStats.position > 0 ? 1 : 0;
2057
+ }
2058
+
2059
+ if (posQty === 0) continue;
2060
+
2061
+ const sideStr = closeSide === 1 ? 'SELL' : 'BUY';
2062
+
2063
+ ui.addLog('info', `Closing [${symbolName}] ${sideStr} ${posQty}x...`);
2064
+ ui.render(stats);
2065
+
2066
+ try {
2067
+ // Try fastExit first (fastest)
2068
+ if (service && typeof service.fastExit === 'function') {
2069
+ const result = await withTimeout(service.fastExit({
2070
+ accountId: rithmicAccountId,
2071
+ symbol: symbolName,
2072
+ exchange: contractInfoMap[symbolName]?.exchange || 'CME',
2073
+ size: posQty,
2074
+ side: closeSide,
2075
+ }), TIMEOUT_MS);
2076
+
2077
+ if (result.success) {
2078
+ ui.addLog('success', `[${symbolName}] FLATTENED`);
2079
+ symStats.position = 0;
2080
+ } else {
2081
+ ui.addLog('error', `[${symbolName}] Exit failed: ${result.error}`);
2082
+ }
2083
+ }
2084
+ } catch (e) {
2085
+ ui.addLog('error', `[${symbolName}] Exit error: ${e.message}`);
2086
+ }
2087
+ }
2088
+
2089
+ // Step 3: Fallback - call service.emergencyStop for any remaining
2090
+ try {
2020
2091
  if (service && typeof service.emergencyStop === 'function') {
2021
- await service.emergencyStop(rithmicAccountId);
2022
- ui.addLog('info', 'Emergency stop executed - all positions flattened');
2023
- } else if (service && typeof service.flattenAll === 'function') {
2024
- await service.flattenAll(rithmicAccountId);
2025
- ui.addLog('info', 'Flatten all executed - all positions closed');
2026
- } else if (service && typeof service.cancelAllOrders === 'function') {
2027
- await service.cancelAllOrders(rithmicAccountId);
2028
- ui.addLog('info', 'All orders cancelled');
2092
+ await withTimeout(service.emergencyStop(rithmicAccountId), TIMEOUT_MS);
2029
2093
  }
2030
- })();
2094
+ } catch (e) {
2095
+ // Silent - already tried individual closes
2096
+ }
2031
2097
 
2032
- // Timeout after 3 seconds
2033
- const timeoutPromise = new Promise(resolve => setTimeout(() => {
2034
- ui.addLog('warning', 'Emergency stop timeout - proceeding to summary');
2035
- resolve();
2036
- }, 3000));
2098
+ ui.addLog('success', '████ EMERGENCY STOP COMPLETE ████');
2037
2099
 
2038
- await Promise.race([stopPromise, timeoutPromise]);
2039
2100
  } catch (e) {
2040
2101
  ui.addLog('error', `Emergency stop error: ${e.message}`);
2041
2102
  }