hedgequantx 2.6.83 → 2.6.85
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 +147 -16
package/package.json
CHANGED
|
@@ -986,17 +986,163 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
986
986
|
const pnlInterval = setInterval(() => { if (running) pollPnL(); }, 10000);
|
|
987
987
|
pollPnL(); // Initial poll
|
|
988
988
|
|
|
989
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
990
|
+
// ULTRA SOLID EMERGENCY STOP FUNCTION
|
|
991
|
+
// Called when X is pressed - MUST cancel all orders and flatten positions
|
|
992
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
993
|
+
const emergencyStopAll = async () => {
|
|
994
|
+
const accountId = account.rithmicAccountId || account.accountId;
|
|
995
|
+
const MAX_RETRIES = 3;
|
|
996
|
+
const TIMEOUT_MS = 5000;
|
|
997
|
+
|
|
998
|
+
ui.addLog('warning', '████ EMERGENCY STOP INITIATED ████');
|
|
999
|
+
ui.render(stats);
|
|
1000
|
+
|
|
1001
|
+
// Helper: run with timeout
|
|
1002
|
+
const withTimeout = (promise, ms) => Promise.race([
|
|
1003
|
+
promise,
|
|
1004
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('TIMEOUT')), ms))
|
|
1005
|
+
]);
|
|
1006
|
+
|
|
1007
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1008
|
+
// STEP 1: CANCEL ALL ORDERS (with retries)
|
|
1009
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1010
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
1011
|
+
try {
|
|
1012
|
+
ui.addLog('info', `[${attempt}/${MAX_RETRIES}] Cancelling all orders...`);
|
|
1013
|
+
ui.render(stats);
|
|
1014
|
+
|
|
1015
|
+
if (typeof service.cancelAllOrders === 'function') {
|
|
1016
|
+
await withTimeout(service.cancelAllOrders(accountId), TIMEOUT_MS);
|
|
1017
|
+
ui.addLog('success', 'All orders cancelled');
|
|
1018
|
+
ui.render(stats);
|
|
1019
|
+
break;
|
|
1020
|
+
} else {
|
|
1021
|
+
ui.addLog('info', 'No cancelAllOrders function - skipping');
|
|
1022
|
+
break;
|
|
1023
|
+
}
|
|
1024
|
+
} catch (e) {
|
|
1025
|
+
ui.addLog('error', `Cancel orders attempt ${attempt} failed: ${e.message}`);
|
|
1026
|
+
ui.render(stats);
|
|
1027
|
+
if (attempt === MAX_RETRIES) {
|
|
1028
|
+
ui.addLog('error', 'FAILED TO CANCEL ORDERS AFTER 3 ATTEMPTS');
|
|
1029
|
+
}
|
|
1030
|
+
await new Promise(r => setTimeout(r, 500)); // Wait before retry
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1035
|
+
// STEP 2: FLATTEN POSITION (with retries)
|
|
1036
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1037
|
+
const posQty = Math.abs(currentPosition || stats.position || 0);
|
|
1038
|
+
|
|
1039
|
+
if (posQty > 0) {
|
|
1040
|
+
const closeSide = (currentPosition || stats.position) > 0 ? 1 : 0;
|
|
1041
|
+
const sideStr = closeSide === 1 ? 'SELL' : 'BUY';
|
|
1042
|
+
|
|
1043
|
+
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
1044
|
+
try {
|
|
1045
|
+
ui.addLog('info', `[${attempt}/${MAX_RETRIES}] Flattening ${posQty}x position (${sideStr})...`);
|
|
1046
|
+
ui.render(stats);
|
|
1047
|
+
|
|
1048
|
+
// Method 1: Rithmic emergencyStop (best)
|
|
1049
|
+
if (typeof service.emergencyStop === 'function') {
|
|
1050
|
+
const result = await withTimeout(service.emergencyStop(accountId), TIMEOUT_MS);
|
|
1051
|
+
if (result.success) {
|
|
1052
|
+
ui.addLog('success', 'Position FLATTENED (Rithmic emergency stop)');
|
|
1053
|
+
ui.render(stats);
|
|
1054
|
+
break;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
// Method 2: Market order to close
|
|
1059
|
+
if (typeof service.placeOrder === 'function') {
|
|
1060
|
+
await withTimeout(service.placeOrder({
|
|
1061
|
+
accountId: account.accountId,
|
|
1062
|
+
contractId: contractId,
|
|
1063
|
+
type: 2, // Market order
|
|
1064
|
+
side: closeSide,
|
|
1065
|
+
size: posQty
|
|
1066
|
+
}), TIMEOUT_MS);
|
|
1067
|
+
ui.addLog('success', `Position FLATTENED (market ${sideStr} ${posQty}x)`);
|
|
1068
|
+
ui.render(stats);
|
|
1069
|
+
break;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
// Method 3: Rithmic fastExit
|
|
1073
|
+
if (typeof service.fastExit === 'function') {
|
|
1074
|
+
await withTimeout(service.fastExit({
|
|
1075
|
+
accountId: accountId,
|
|
1076
|
+
symbol: symbolName,
|
|
1077
|
+
exchange: contract.exchange || 'CME',
|
|
1078
|
+
size: posQty,
|
|
1079
|
+
side: closeSide
|
|
1080
|
+
}), TIMEOUT_MS);
|
|
1081
|
+
ui.addLog('success', `Position FLATTENED (fast exit ${sideStr} ${posQty}x)`);
|
|
1082
|
+
ui.render(stats);
|
|
1083
|
+
break;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
} catch (e) {
|
|
1087
|
+
ui.addLog('error', `Flatten attempt ${attempt} failed: ${e.message}`);
|
|
1088
|
+
ui.render(stats);
|
|
1089
|
+
if (attempt === MAX_RETRIES) {
|
|
1090
|
+
ui.addLog('error', '████ FAILED TO FLATTEN - CHECK MANUALLY! ████');
|
|
1091
|
+
}
|
|
1092
|
+
await new Promise(r => setTimeout(r, 500));
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
} else {
|
|
1096
|
+
ui.addLog('success', 'No position to flatten - clean exit');
|
|
1097
|
+
ui.render(stats);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1101
|
+
// STEP 3: VERIFY (optional - check position is actually flat)
|
|
1102
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1103
|
+
try {
|
|
1104
|
+
if (typeof service.getPositions === 'function') {
|
|
1105
|
+
const posResult = await withTimeout(service.getPositions(account.accountId), 3000);
|
|
1106
|
+
if (posResult.success && posResult.positions) {
|
|
1107
|
+
const stillOpen = posResult.positions.find(p => {
|
|
1108
|
+
const sym = p.contractId || p.symbol || '';
|
|
1109
|
+
return (sym.includes(symbolName) || sym.includes(contractId)) && p.quantity !== 0;
|
|
1110
|
+
});
|
|
1111
|
+
if (stillOpen) {
|
|
1112
|
+
ui.addLog('error', `████ POSITION STILL OPEN: ${stillOpen.quantity}x ████`);
|
|
1113
|
+
ui.addLog('error', 'CLOSE MANUALLY IN R TRADER!');
|
|
1114
|
+
} else {
|
|
1115
|
+
ui.addLog('success', 'VERIFIED: Position is flat');
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
} catch (e) {
|
|
1120
|
+
// Verification failed, but main stop was attempted
|
|
1121
|
+
ui.addLog('warning', 'Could not verify position - check manually');
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
ui.addLog('info', '════════════════════════════════════');
|
|
1125
|
+
ui.render(stats);
|
|
1126
|
+
};
|
|
1127
|
+
|
|
989
1128
|
// Keyboard handler
|
|
1129
|
+
let emergencyStopInProgress = false;
|
|
1130
|
+
|
|
990
1131
|
const setupKeyHandler = () => {
|
|
991
1132
|
if (!process.stdin.isTTY) return;
|
|
992
1133
|
readline.emitKeypressEvents(process.stdin);
|
|
993
1134
|
process.stdin.setRawMode(true);
|
|
994
1135
|
process.stdin.resume();
|
|
995
1136
|
|
|
996
|
-
const onKey = (str, key) => {
|
|
1137
|
+
const onKey = async (str, key) => {
|
|
997
1138
|
if (key && (key.name === 'x' || key.name === 'X' || (key.ctrl && key.name === 'c'))) {
|
|
1139
|
+
if (emergencyStopInProgress) return; // Prevent double-trigger
|
|
1140
|
+
emergencyStopInProgress = true;
|
|
998
1141
|
running = false;
|
|
999
1142
|
stopReason = 'manual';
|
|
1143
|
+
|
|
1144
|
+
// Run emergency stop IMMEDIATELY on keypress (don't wait for main loop)
|
|
1145
|
+
await emergencyStopAll();
|
|
1000
1146
|
}
|
|
1001
1147
|
};
|
|
1002
1148
|
process.stdin.on('keypress', onKey);
|
|
@@ -1022,21 +1168,6 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
1022
1168
|
clearInterval(refreshInterval);
|
|
1023
1169
|
clearInterval(pnlInterval);
|
|
1024
1170
|
|
|
1025
|
-
// EMERGENCY STOP: Cancel all orders and flatten all positions
|
|
1026
|
-
if (useFastPath && service && account.rithmicAccountId) {
|
|
1027
|
-
try {
|
|
1028
|
-
ui.addLog('warning', 'EMERGENCY STOP - Cancelling orders & flattening positions...');
|
|
1029
|
-
const stopResult = await service.emergencyStop(account.rithmicAccountId);
|
|
1030
|
-
if (stopResult.success) {
|
|
1031
|
-
ui.addLog('success', 'All orders cancelled, positions flattened');
|
|
1032
|
-
} else {
|
|
1033
|
-
ui.addLog('error', 'Emergency stop partial - check positions manually');
|
|
1034
|
-
}
|
|
1035
|
-
} catch (e) {
|
|
1036
|
-
ui.addLog('error', `Emergency stop failed: ${e.message}`);
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
1171
|
// Stop Position Manager (fast path)
|
|
1041
1172
|
if (positionManager) {
|
|
1042
1173
|
positionManager.stop();
|