hedgequantx 2.6.161 → 2.6.163
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/menus/ai-agent-connect.js +181 -0
- package/src/menus/ai-agent-models.js +219 -0
- package/src/menus/ai-agent-oauth.js +292 -0
- package/src/menus/ai-agent-ui.js +141 -0
- package/src/menus/ai-agent.js +88 -1489
- package/src/pages/algo/copy-engine.js +449 -0
- package/src/pages/algo/copy-trading.js +11 -543
- package/src/pages/algo/smart-logs-data.js +218 -0
- package/src/pages/algo/smart-logs.js +9 -214
- package/src/pages/algo/ui-constants.js +144 -0
- package/src/pages/algo/ui-summary.js +184 -0
- package/src/pages/algo/ui.js +42 -526
- package/src/pages/stats-calculations.js +191 -0
- package/src/pages/stats-ui.js +381 -0
- package/src/pages/stats.js +14 -507
- package/src/services/ai/client-analysis.js +194 -0
- package/src/services/ai/client-models.js +333 -0
- package/src/services/ai/client.js +6 -489
- package/src/services/ai/index.js +2 -257
- package/src/services/ai/providers/direct-providers.js +323 -0
- package/src/services/ai/providers/index.js +8 -472
- package/src/services/ai/providers/other-providers.js +104 -0
- package/src/services/ai/proxy-install.js +249 -0
- package/src/services/ai/proxy-manager.js +29 -411
- package/src/services/ai/proxy-remote.js +161 -0
- package/src/services/ai/supervisor-optimize.js +215 -0
- package/src/services/ai/supervisor-sync.js +178 -0
- package/src/services/ai/supervisor.js +50 -515
- package/src/services/ai/validation.js +250 -0
- package/src/services/hqx-server-events.js +110 -0
- package/src/services/hqx-server-handlers.js +217 -0
- package/src/services/hqx-server-latency.js +136 -0
- package/src/services/hqx-server.js +51 -403
- package/src/services/position-constants.js +28 -0
- package/src/services/position-exit-logic.js +174 -0
- package/src/services/position-manager.js +90 -629
- package/src/services/position-momentum.js +206 -0
- package/src/services/projectx/accounts.js +142 -0
- package/src/services/projectx/index.js +40 -289
- package/src/services/projectx/trading.js +180 -0
- package/src/services/rithmic/contracts.js +218 -0
- package/src/services/rithmic/handlers.js +2 -208
- package/src/services/rithmic/index.js +28 -712
- package/src/services/rithmic/latency-tracker.js +182 -0
- package/src/services/rithmic/market-data-decoders.js +229 -0
- package/src/services/rithmic/market-data.js +1 -278
- package/src/services/rithmic/orders-fast.js +246 -0
- package/src/services/rithmic/orders.js +1 -251
- package/src/services/rithmic/proto-decoders.js +403 -0
- package/src/services/rithmic/protobuf.js +7 -443
- package/src/services/rithmic/specs.js +146 -0
- package/src/services/rithmic/trade-history.js +254 -0
- package/src/services/strategy/hft-signal-calc.js +147 -0
- package/src/services/strategy/hft-tick.js +33 -133
- package/src/services/tradovate/index.js +6 -119
- package/src/services/tradovate/orders.js +145 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rithmic Fast Orders Module
|
|
3
|
+
* @module services/rithmic/orders-fast
|
|
4
|
+
*
|
|
5
|
+
* Ultra-low latency order entry/exit for scalping
|
|
6
|
+
* Target: < 5ms local processing (network latency separate)
|
|
7
|
+
*
|
|
8
|
+
* OPTIMIZATIONS:
|
|
9
|
+
* - Pre-allocated order template objects
|
|
10
|
+
* - Fast orderTag generation (no Date.now in hot path)
|
|
11
|
+
* - Direct proto encoding with cached types
|
|
12
|
+
* - Minimal object creation
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { REQ } = require('./constants');
|
|
16
|
+
const { proto } = require('./protobuf');
|
|
17
|
+
const { LatencyTracker } = require('./latency-tracker');
|
|
18
|
+
const { performance } = require('perf_hooks');
|
|
19
|
+
|
|
20
|
+
// Debug mode - use no-op function when disabled for zero overhead
|
|
21
|
+
const DEBUG = process.env.HQX_DEBUG === '1';
|
|
22
|
+
const debug = DEBUG ? (...args) => console.log('[Rithmic:Orders]', ...args) : () => {};
|
|
23
|
+
|
|
24
|
+
// ==================== FAST ORDER TAG ====================
|
|
25
|
+
// Pre-generate prefix once at module load (not per-order)
|
|
26
|
+
const ORDER_TAG_PREFIX = `HQX${process.pid}-`;
|
|
27
|
+
let orderIdCounter = 0;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Ultra-fast order tag generation
|
|
31
|
+
* Avoids Date.now() and string interpolation in hot path
|
|
32
|
+
* @returns {string}
|
|
33
|
+
*/
|
|
34
|
+
const generateOrderTag = () => ORDER_TAG_PREFIX + (++orderIdCounter);
|
|
35
|
+
|
|
36
|
+
// ==================== PRE-ALLOCATED ORDER TEMPLATES ====================
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Order object pool for zero-allocation hot path
|
|
40
|
+
*/
|
|
41
|
+
const OrderPool = {
|
|
42
|
+
// Pre-allocated order template
|
|
43
|
+
_template: {
|
|
44
|
+
templateId: REQ.NEW_ORDER,
|
|
45
|
+
userMsg: [''],
|
|
46
|
+
userTag: '',
|
|
47
|
+
fcmId: '',
|
|
48
|
+
ibId: '',
|
|
49
|
+
accountId: '',
|
|
50
|
+
symbol: '',
|
|
51
|
+
exchange: 'CME',
|
|
52
|
+
quantity: 0,
|
|
53
|
+
transactionType: 1,
|
|
54
|
+
duration: 1,
|
|
55
|
+
priceType: 2, // priceType 2 = MARKET order
|
|
56
|
+
manualOrAuto: 2,
|
|
57
|
+
tradeRoute: '',
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get order object with values filled in
|
|
62
|
+
* @param {string} orderTag
|
|
63
|
+
* @param {Object} loginInfo - { fcmId, ibId }
|
|
64
|
+
* @param {Object} orderData - { accountId, symbol, exchange, size, side, tradeRoute }
|
|
65
|
+
*/
|
|
66
|
+
fill(orderTag, loginInfo, orderData) {
|
|
67
|
+
const o = this._template;
|
|
68
|
+
o.userMsg[0] = orderTag;
|
|
69
|
+
o.userTag = orderTag;
|
|
70
|
+
o.fcmId = loginInfo.fcmId;
|
|
71
|
+
o.ibId = loginInfo.ibId;
|
|
72
|
+
o.accountId = orderData.accountId;
|
|
73
|
+
o.symbol = orderData.symbol;
|
|
74
|
+
o.exchange = orderData.exchange || 'CME';
|
|
75
|
+
o.quantity = orderData.size;
|
|
76
|
+
o.transactionType = orderData.side === 0 ? 1 : 2;
|
|
77
|
+
o.tradeRoute = orderData.tradeRoute || '';
|
|
78
|
+
return o;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get effective login info for account
|
|
84
|
+
* @param {RithmicService} service
|
|
85
|
+
* @param {string} accountId
|
|
86
|
+
* @returns {{ fcmId: string, ibId: string }}
|
|
87
|
+
*/
|
|
88
|
+
function getEffectiveLoginInfo(service, accountId) {
|
|
89
|
+
const account = service.accounts?.find(a =>
|
|
90
|
+
a.accountId === accountId || a.rithmicAccountId === accountId
|
|
91
|
+
);
|
|
92
|
+
return {
|
|
93
|
+
fcmId: account?.fcmId || service.loginInfo.fcmId,
|
|
94
|
+
ibId: account?.ibId || service.loginInfo.ibId,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Send order buffer via optimized path
|
|
100
|
+
* @param {Object} conn - Order connection
|
|
101
|
+
* @param {Buffer} buffer
|
|
102
|
+
*/
|
|
103
|
+
function sendOrderBuffer(conn, buffer) {
|
|
104
|
+
const sent = conn.ultraSend
|
|
105
|
+
? conn.ultraSend(buffer)
|
|
106
|
+
: (conn.fastSend(buffer), true);
|
|
107
|
+
|
|
108
|
+
if (!sent) {
|
|
109
|
+
conn.fastSend(buffer);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Ultra-fast market order entry - HOT PATH
|
|
115
|
+
* NO SL/TP, NO await confirmation, fire-and-forget
|
|
116
|
+
*
|
|
117
|
+
* @param {RithmicService} service
|
|
118
|
+
* @param {Object} orderData - { accountId, symbol, exchange, size, side }
|
|
119
|
+
* @returns {{ success: boolean, orderTag: string, entryTime: number, latencyMs: number }}
|
|
120
|
+
*/
|
|
121
|
+
const fastEntry = (service, orderData) => {
|
|
122
|
+
const startTime = performance.now();
|
|
123
|
+
const orderTag = generateOrderTag();
|
|
124
|
+
const entryTime = Date.now();
|
|
125
|
+
|
|
126
|
+
if (!service.orderConn?.isConnected || !service.loginInfo) {
|
|
127
|
+
return {
|
|
128
|
+
success: false,
|
|
129
|
+
error: 'Not connected',
|
|
130
|
+
orderTag,
|
|
131
|
+
entryTime,
|
|
132
|
+
latencyMs: performance.now() - startTime,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const effectiveLoginInfo = getEffectiveLoginInfo(service, orderData.accountId);
|
|
138
|
+
|
|
139
|
+
const exchange = orderData.exchange || 'CME';
|
|
140
|
+
const tradeRoute = service.getTradeRoute?.(exchange);
|
|
141
|
+
if (!tradeRoute) {
|
|
142
|
+
return {
|
|
143
|
+
success: false,
|
|
144
|
+
error: `No trade route for exchange ${exchange}`,
|
|
145
|
+
orderTag,
|
|
146
|
+
entryTime,
|
|
147
|
+
latencyMs: performance.now() - startTime,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const orderWithRoute = { ...orderData, tradeRoute };
|
|
152
|
+
const order = OrderPool.fill(orderTag, effectiveLoginInfo, orderWithRoute);
|
|
153
|
+
|
|
154
|
+
debug('ORDER Sending:', orderTag, orderData.side === 0 ? 'BUY' : 'SELL', orderData.size, 'x', orderData.symbol);
|
|
155
|
+
|
|
156
|
+
const buffer = proto.fastEncode('RequestNewOrder', order);
|
|
157
|
+
sendOrderBuffer(service.orderConn, buffer);
|
|
158
|
+
|
|
159
|
+
debug('ORDER Sent to Rithmic:', orderTag, 'buffer:', buffer.length, 'bytes');
|
|
160
|
+
|
|
161
|
+
LatencyTracker.recordEntry(orderTag, entryTime);
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
success: true,
|
|
165
|
+
orderTag,
|
|
166
|
+
entryTime,
|
|
167
|
+
latencyMs: performance.now() - startTime,
|
|
168
|
+
};
|
|
169
|
+
} catch (error) {
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
error: error.message,
|
|
173
|
+
orderTag,
|
|
174
|
+
entryTime,
|
|
175
|
+
latencyMs: performance.now() - startTime,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Ultra-fast market exit - for position closing
|
|
182
|
+
*
|
|
183
|
+
* @param {RithmicService} service
|
|
184
|
+
* @param {Object} orderData - { accountId, symbol, exchange, size, side }
|
|
185
|
+
* @returns {{ success: boolean, orderTag: string, exitTime: number, latencyMs: number }}
|
|
186
|
+
*/
|
|
187
|
+
const fastExit = (service, orderData) => {
|
|
188
|
+
const startTime = performance.now();
|
|
189
|
+
const orderTag = generateOrderTag();
|
|
190
|
+
const exitTime = Date.now();
|
|
191
|
+
|
|
192
|
+
if (!service.orderConn?.isConnected || !service.loginInfo) {
|
|
193
|
+
return {
|
|
194
|
+
success: false,
|
|
195
|
+
error: 'Not connected',
|
|
196
|
+
orderTag,
|
|
197
|
+
exitTime,
|
|
198
|
+
latencyMs: performance.now() - startTime,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const effectiveLoginInfo = getEffectiveLoginInfo(service, orderData.accountId);
|
|
204
|
+
|
|
205
|
+
const exchange = orderData.exchange || 'CME';
|
|
206
|
+
const tradeRoute = service.getTradeRoute?.(exchange);
|
|
207
|
+
if (!tradeRoute) {
|
|
208
|
+
return {
|
|
209
|
+
success: false,
|
|
210
|
+
error: `No trade route for exchange ${exchange}`,
|
|
211
|
+
orderTag,
|
|
212
|
+
exitTime,
|
|
213
|
+
latencyMs: performance.now() - startTime,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const orderWithRoute = { ...orderData, tradeRoute };
|
|
218
|
+
const order = OrderPool.fill(orderTag, effectiveLoginInfo, orderWithRoute);
|
|
219
|
+
|
|
220
|
+
const buffer = proto.fastEncode('RequestNewOrder', order);
|
|
221
|
+
sendOrderBuffer(service.orderConn, buffer);
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
success: true,
|
|
225
|
+
orderTag,
|
|
226
|
+
exitTime,
|
|
227
|
+
latencyMs: performance.now() - startTime,
|
|
228
|
+
};
|
|
229
|
+
} catch (error) {
|
|
230
|
+
return {
|
|
231
|
+
success: false,
|
|
232
|
+
error: error.message,
|
|
233
|
+
orderTag,
|
|
234
|
+
exitTime,
|
|
235
|
+
latencyMs: performance.now() - startTime,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
module.exports = {
|
|
241
|
+
generateOrderTag,
|
|
242
|
+
OrderPool,
|
|
243
|
+
getEffectiveLoginInfo,
|
|
244
|
+
fastEntry,
|
|
245
|
+
fastExit,
|
|
246
|
+
};
|
|
@@ -1,264 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Rithmic Orders Module
|
|
3
3
|
* Order placement, cancellation, and history
|
|
4
|
-
*
|
|
5
|
-
* FAST SCALPING: fastEntry() and fastExit() for ultra-low latency execution
|
|
6
|
-
* Target: < 5ms local processing (network latency separate)
|
|
7
|
-
*
|
|
8
|
-
* OPTIMIZATIONS:
|
|
9
|
-
* - Pre-allocated order template objects
|
|
10
|
-
* - Fast orderTag generation (no Date.now in hot path)
|
|
11
|
-
* - Direct proto encoding with cached types
|
|
12
|
-
* - Minimal object creation
|
|
13
4
|
*/
|
|
14
5
|
|
|
15
6
|
const { REQ } = require('./constants');
|
|
16
|
-
const { proto } = require('./protobuf');
|
|
17
|
-
const { LatencyTracker } = require('./handlers');
|
|
18
|
-
const { performance } = require('perf_hooks');
|
|
19
7
|
const { logger } = require('../../utils/logger');
|
|
8
|
+
const { fastEntry, fastExit, getEffectiveLoginInfo } = require('./orders-fast');
|
|
20
9
|
|
|
21
10
|
const log = logger.scope('RithmicOrders');
|
|
22
11
|
|
|
23
|
-
// Debug mode - use no-op function when disabled for zero overhead
|
|
24
|
-
const DEBUG = process.env.HQX_DEBUG === '1';
|
|
25
|
-
const debug = DEBUG ? (...args) => console.log('[Rithmic:Orders]', ...args) : () => {};
|
|
26
|
-
|
|
27
|
-
// ==================== FAST ORDER TAG ====================
|
|
28
|
-
// Pre-generate prefix once at module load (not per-order)
|
|
29
|
-
const ORDER_TAG_PREFIX = `HQX${process.pid}-`;
|
|
30
|
-
let orderIdCounter = 0;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Ultra-fast order tag generation
|
|
34
|
-
* Avoids Date.now() and string interpolation in hot path
|
|
35
|
-
* @returns {string}
|
|
36
|
-
*/
|
|
37
|
-
const generateOrderTag = () => ORDER_TAG_PREFIX + (++orderIdCounter);
|
|
38
|
-
|
|
39
|
-
// ==================== PRE-ALLOCATED ORDER TEMPLATES ====================
|
|
40
|
-
// Reusable order object to minimize GC pressure
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Order object pool for zero-allocation hot path
|
|
44
|
-
*/
|
|
45
|
-
const OrderPool = {
|
|
46
|
-
// Pre-allocated order template
|
|
47
|
-
_template: {
|
|
48
|
-
templateId: REQ.NEW_ORDER,
|
|
49
|
-
userMsg: [''],
|
|
50
|
-
userTag: '', // Our order tag - returned in RithmicOrderNotification
|
|
51
|
-
fcmId: '',
|
|
52
|
-
ibId: '',
|
|
53
|
-
accountId: '',
|
|
54
|
-
symbol: '',
|
|
55
|
-
exchange: 'CME',
|
|
56
|
-
quantity: 0,
|
|
57
|
-
transactionType: 1,
|
|
58
|
-
duration: 1,
|
|
59
|
-
priceType: 2, // priceType 2 = MARKET order
|
|
60
|
-
manualOrAuto: 2,
|
|
61
|
-
tradeRoute: '', // Required by Rithmic API - fetched from RequestTradeRoutes
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Get order object with values filled in
|
|
66
|
-
* Reuses same object to avoid allocation
|
|
67
|
-
* @param {string} orderTag - Unique order tag
|
|
68
|
-
* @param {Object} loginInfo - { fcmId, ibId }
|
|
69
|
-
* @param {Object} orderData - { accountId, symbol, exchange, size, side, tradeRoute }
|
|
70
|
-
*/
|
|
71
|
-
fill(orderTag, loginInfo, orderData) {
|
|
72
|
-
const o = this._template;
|
|
73
|
-
o.userMsg[0] = orderTag;
|
|
74
|
-
o.userTag = orderTag; // Set userTag for notification tracking
|
|
75
|
-
o.fcmId = loginInfo.fcmId;
|
|
76
|
-
o.ibId = loginInfo.ibId;
|
|
77
|
-
o.accountId = orderData.accountId;
|
|
78
|
-
o.symbol = orderData.symbol;
|
|
79
|
-
o.exchange = orderData.exchange || 'CME';
|
|
80
|
-
o.quantity = orderData.size;
|
|
81
|
-
o.transactionType = orderData.side === 0 ? 1 : 2;
|
|
82
|
-
o.tradeRoute = orderData.tradeRoute || ''; // From API via service.getTradeRoute()
|
|
83
|
-
return o;
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Ultra-fast market order entry - HOT PATH
|
|
89
|
-
* NO SL/TP, NO await confirmation, fire-and-forget
|
|
90
|
-
* Target latency: < 5ms local processing
|
|
91
|
-
*
|
|
92
|
-
* OPTIMIZATIONS:
|
|
93
|
-
* - Reuses pre-allocated order object
|
|
94
|
-
* - Fast orderTag (no Date.now)
|
|
95
|
-
* - Uses fastEncode for cached protobuf type
|
|
96
|
-
* - Minimal branching
|
|
97
|
-
*
|
|
98
|
-
* @param {RithmicService} service - The Rithmic service instance
|
|
99
|
-
* @param {Object} orderData - { accountId, symbol, exchange, size, side }
|
|
100
|
-
* @returns {{ success: boolean, orderTag: string, entryTime: number, latencyMs: number }}
|
|
101
|
-
*/
|
|
102
|
-
const fastEntry = (service, orderData) => {
|
|
103
|
-
const startTime = performance.now();
|
|
104
|
-
const orderTag = generateOrderTag();
|
|
105
|
-
const entryTime = Date.now();
|
|
106
|
-
|
|
107
|
-
// Fast connection check
|
|
108
|
-
if (!service.orderConn?.isConnected || !service.loginInfo) {
|
|
109
|
-
return {
|
|
110
|
-
success: false,
|
|
111
|
-
error: 'Not connected',
|
|
112
|
-
orderTag,
|
|
113
|
-
entryTime,
|
|
114
|
-
latencyMs: performance.now() - startTime,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
// FIXED: Use account-specific fcmId/ibId if available (some prop firms have different IDs per account)
|
|
120
|
-
const account = service.accounts?.find(a =>
|
|
121
|
-
a.accountId === orderData.accountId || a.rithmicAccountId === orderData.accountId
|
|
122
|
-
);
|
|
123
|
-
const effectiveLoginInfo = {
|
|
124
|
-
fcmId: account?.fcmId || service.loginInfo.fcmId,
|
|
125
|
-
ibId: account?.ibId || service.loginInfo.ibId,
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
// Get trade route from API (required by Rithmic)
|
|
129
|
-
const exchange = orderData.exchange || 'CME';
|
|
130
|
-
const tradeRoute = service.getTradeRoute?.(exchange);
|
|
131
|
-
if (!tradeRoute) {
|
|
132
|
-
return {
|
|
133
|
-
success: false,
|
|
134
|
-
error: `No trade route for exchange ${exchange}`,
|
|
135
|
-
orderTag,
|
|
136
|
-
entryTime,
|
|
137
|
-
latencyMs: performance.now() - startTime,
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// OPTIMIZED: Use pre-allocated order object
|
|
142
|
-
const orderWithRoute = { ...orderData, tradeRoute };
|
|
143
|
-
const order = OrderPool.fill(orderTag, effectiveLoginInfo, orderWithRoute);
|
|
144
|
-
|
|
145
|
-
// Debug only - UI handles display via events
|
|
146
|
-
debug('ORDER Sending:', orderTag, orderData.side === 0 ? 'BUY' : 'SELL', orderData.size, 'x', orderData.symbol, 'acct:', orderData.accountId, 'route:', tradeRoute);
|
|
147
|
-
|
|
148
|
-
// OPTIMIZED: Use fastEncode with cached type
|
|
149
|
-
const buffer = proto.fastEncode('RequestNewOrder', order);
|
|
150
|
-
|
|
151
|
-
// ULTRA-OPTIMIZED: Try direct socket write first, fallback to fastSend
|
|
152
|
-
const sent = service.orderConn.ultraSend
|
|
153
|
-
? service.orderConn.ultraSend(buffer)
|
|
154
|
-
: (service.orderConn.fastSend(buffer), true);
|
|
155
|
-
|
|
156
|
-
if (!sent) {
|
|
157
|
-
service.orderConn.fastSend(buffer);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
debug('ORDER Sent to Rithmic:', orderTag, 'buffer:', buffer.length, 'bytes');
|
|
161
|
-
|
|
162
|
-
// Track for round-trip latency measurement
|
|
163
|
-
LatencyTracker.recordEntry(orderTag, entryTime);
|
|
164
|
-
|
|
165
|
-
return {
|
|
166
|
-
success: true,
|
|
167
|
-
orderTag,
|
|
168
|
-
entryTime,
|
|
169
|
-
latencyMs: performance.now() - startTime,
|
|
170
|
-
};
|
|
171
|
-
} catch (error) {
|
|
172
|
-
return {
|
|
173
|
-
success: false,
|
|
174
|
-
error: error.message,
|
|
175
|
-
orderTag,
|
|
176
|
-
entryTime,
|
|
177
|
-
latencyMs: performance.now() - startTime,
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Ultra-fast market exit - for position closing
|
|
184
|
-
* Fire-and-forget like fastEntry
|
|
185
|
-
* Same optimizations as fastEntry
|
|
186
|
-
*
|
|
187
|
-
* @param {RithmicService} service - The Rithmic service instance
|
|
188
|
-
* @param {Object} orderData - { accountId, symbol, exchange, size, side }
|
|
189
|
-
* @returns {{ success: boolean, orderTag: string, exitTime: number, latencyMs: number }}
|
|
190
|
-
*/
|
|
191
|
-
const fastExit = (service, orderData) => {
|
|
192
|
-
const startTime = performance.now();
|
|
193
|
-
const orderTag = generateOrderTag();
|
|
194
|
-
const exitTime = Date.now();
|
|
195
|
-
|
|
196
|
-
if (!service.orderConn?.isConnected || !service.loginInfo) {
|
|
197
|
-
return {
|
|
198
|
-
success: false,
|
|
199
|
-
error: 'Not connected',
|
|
200
|
-
orderTag,
|
|
201
|
-
exitTime,
|
|
202
|
-
latencyMs: performance.now() - startTime,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
try {
|
|
207
|
-
// FIXED: Use account-specific fcmId/ibId if available
|
|
208
|
-
const account = service.accounts?.find(a =>
|
|
209
|
-
a.accountId === orderData.accountId || a.rithmicAccountId === orderData.accountId
|
|
210
|
-
);
|
|
211
|
-
const effectiveLoginInfo = {
|
|
212
|
-
fcmId: account?.fcmId || service.loginInfo.fcmId,
|
|
213
|
-
ibId: account?.ibId || service.loginInfo.ibId,
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
// Get trade route from API (required by Rithmic)
|
|
217
|
-
const exchange = orderData.exchange || 'CME';
|
|
218
|
-
const tradeRoute = service.getTradeRoute?.(exchange);
|
|
219
|
-
if (!tradeRoute) {
|
|
220
|
-
return {
|
|
221
|
-
success: false,
|
|
222
|
-
error: `No trade route for exchange ${exchange}`,
|
|
223
|
-
orderTag,
|
|
224
|
-
exitTime,
|
|
225
|
-
latencyMs: performance.now() - startTime,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// OPTIMIZED: Use pre-allocated order object
|
|
230
|
-
const orderWithRoute = { ...orderData, tradeRoute };
|
|
231
|
-
const order = OrderPool.fill(orderTag, effectiveLoginInfo, orderWithRoute);
|
|
232
|
-
|
|
233
|
-
// OPTIMIZED: Use fastEncode with cached type
|
|
234
|
-
const buffer = proto.fastEncode('RequestNewOrder', order);
|
|
235
|
-
|
|
236
|
-
// ULTRA-OPTIMIZED: Try direct socket write first, fallback to fastSend
|
|
237
|
-
const sent = service.orderConn.ultraSend
|
|
238
|
-
? service.orderConn.ultraSend(buffer)
|
|
239
|
-
: (service.orderConn.fastSend(buffer), true);
|
|
240
|
-
|
|
241
|
-
if (!sent) {
|
|
242
|
-
service.orderConn.fastSend(buffer);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return {
|
|
246
|
-
success: true,
|
|
247
|
-
orderTag,
|
|
248
|
-
exitTime,
|
|
249
|
-
latencyMs: performance.now() - startTime,
|
|
250
|
-
};
|
|
251
|
-
} catch (error) {
|
|
252
|
-
return {
|
|
253
|
-
success: false,
|
|
254
|
-
error: error.message,
|
|
255
|
-
orderTag,
|
|
256
|
-
exitTime,
|
|
257
|
-
latencyMs: performance.now() - startTime,
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
};
|
|
261
|
-
|
|
262
12
|
/**
|
|
263
13
|
* Place order via ORDER_PLANT
|
|
264
14
|
* @param {RithmicService} service - The Rithmic service instance
|