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 +1 -1
- package/src/pages/algo/one-account.js +80 -19
package/package.json
CHANGED
|
@@ -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
|
-
//
|
|
2019
|
-
|
|
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
|
-
|
|
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
|
}
|