hedgequantx 2.6.163 → 2.7.0
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/README.md +15 -88
- package/bin/cli.js +0 -11
- package/dist/lib/api.jsc +0 -0
- package/dist/lib/api2.jsc +0 -0
- package/dist/lib/core.jsc +0 -0
- package/dist/lib/core2.jsc +0 -0
- package/dist/lib/data.js +1 -1
- package/dist/lib/data.jsc +0 -0
- package/dist/lib/data2.jsc +0 -0
- package/dist/lib/decoder.jsc +0 -0
- package/dist/lib/m/mod1.jsc +0 -0
- package/dist/lib/m/mod2.jsc +0 -0
- package/dist/lib/n/r1.jsc +0 -0
- package/dist/lib/n/r2.jsc +0 -0
- package/dist/lib/n/r3.jsc +0 -0
- package/dist/lib/n/r4.jsc +0 -0
- package/dist/lib/n/r5.jsc +0 -0
- package/dist/lib/n/r6.jsc +0 -0
- package/dist/lib/n/r7.jsc +0 -0
- package/dist/lib/o/util1.jsc +0 -0
- package/dist/lib/o/util2.jsc +0 -0
- package/package.json +6 -3
- package/src/app.js +40 -162
- package/src/config/constants.js +31 -33
- package/src/config/propfirms.js +13 -217
- package/src/config/settings.js +0 -43
- package/src/lib/api.js +198 -0
- package/src/lib/api2.js +353 -0
- package/src/lib/core.js +539 -0
- package/src/lib/core2.js +341 -0
- package/src/lib/data.js +555 -0
- package/src/lib/data2.js +492 -0
- package/src/lib/decoder.js +599 -0
- package/src/lib/m/s1.js +804 -0
- package/src/lib/m/s2.js +34 -0
- package/src/lib/n/r1.js +454 -0
- package/src/lib/n/r2.js +514 -0
- package/src/lib/n/r3.js +631 -0
- package/src/lib/n/r4.js +401 -0
- package/src/lib/n/r5.js +335 -0
- package/src/lib/n/r6.js +425 -0
- package/src/lib/n/r7.js +530 -0
- package/src/lib/o/l1.js +44 -0
- package/src/lib/o/l2.js +427 -0
- package/src/lib/python-bridge.js +206 -0
- package/src/menus/connect.js +14 -176
- package/src/menus/dashboard.js +65 -110
- package/src/pages/accounts.js +18 -18
- package/src/pages/algo/copy-trading.js +210 -240
- package/src/pages/algo/index.js +41 -104
- package/src/pages/algo/one-account.js +386 -33
- package/src/pages/algo/ui.js +312 -151
- package/src/pages/orders.js +3 -3
- package/src/pages/positions.js +3 -3
- package/src/pages/stats/chart.js +74 -0
- package/src/pages/stats/display.js +228 -0
- package/src/pages/stats/index.js +236 -0
- package/src/pages/stats/metrics.js +213 -0
- package/src/pages/user.js +6 -6
- package/src/services/hqx-server/constants.js +55 -0
- package/src/services/hqx-server/index.js +401 -0
- package/src/services/hqx-server/latency.js +81 -0
- package/src/services/index.js +12 -3
- package/src/services/rithmic/accounts.js +7 -32
- package/src/services/rithmic/connection.js +1 -204
- package/src/services/rithmic/contracts.js +116 -99
- package/src/services/rithmic/handlers.js +21 -196
- package/src/services/rithmic/index.js +63 -120
- package/src/services/rithmic/market.js +31 -0
- package/src/services/rithmic/orders.js +5 -111
- package/src/services/rithmic/protobuf.js +384 -138
- package/src/services/session.js +22 -173
- package/src/ui/box.js +10 -18
- package/src/ui/index.js +1 -3
- package/src/ui/menu.js +1 -1
- package/src/utils/prompts.js +2 -2
- package/dist/lib/m/s1.js +0 -1
- package/src/menus/ai-agent-connect.js +0 -181
- package/src/menus/ai-agent-models.js +0 -219
- package/src/menus/ai-agent-oauth.js +0 -292
- package/src/menus/ai-agent-ui.js +0 -141
- package/src/menus/ai-agent.js +0 -484
- package/src/pages/algo/algo-config.js +0 -195
- package/src/pages/algo/algo-multi.js +0 -801
- package/src/pages/algo/algo-utils.js +0 -58
- package/src/pages/algo/copy-engine.js +0 -449
- package/src/pages/algo/custom-strategy.js +0 -459
- package/src/pages/algo/logger.js +0 -245
- package/src/pages/algo/smart-logs-data.js +0 -218
- package/src/pages/algo/smart-logs.js +0 -387
- package/src/pages/algo/ui-constants.js +0 -144
- package/src/pages/algo/ui-summary.js +0 -184
- package/src/pages/stats-calculations.js +0 -191
- package/src/pages/stats-ui.js +0 -381
- package/src/pages/stats.js +0 -339
- package/src/services/ai/client-analysis.js +0 -194
- package/src/services/ai/client-models.js +0 -333
- package/src/services/ai/client.js +0 -343
- package/src/services/ai/index.js +0 -384
- package/src/services/ai/oauth-anthropic.js +0 -265
- package/src/services/ai/oauth-gemini.js +0 -223
- package/src/services/ai/oauth-iflow.js +0 -269
- package/src/services/ai/oauth-openai.js +0 -233
- package/src/services/ai/oauth-qwen.js +0 -279
- package/src/services/ai/providers/direct-providers.js +0 -323
- package/src/services/ai/providers/index.js +0 -62
- package/src/services/ai/providers/other-providers.js +0 -104
- package/src/services/ai/proxy-install.js +0 -249
- package/src/services/ai/proxy-manager.js +0 -494
- package/src/services/ai/proxy-remote.js +0 -161
- package/src/services/ai/strategy-supervisor.js +0 -1312
- package/src/services/ai/supervisor-data.js +0 -195
- package/src/services/ai/supervisor-optimize.js +0 -215
- package/src/services/ai/supervisor-sync.js +0 -178
- package/src/services/ai/supervisor-utils.js +0 -158
- package/src/services/ai/supervisor.js +0 -484
- package/src/services/ai/validation.js +0 -250
- package/src/services/hqx-server-events.js +0 -110
- package/src/services/hqx-server-handlers.js +0 -217
- package/src/services/hqx-server-latency.js +0 -136
- package/src/services/hqx-server.js +0 -403
- package/src/services/position-constants.js +0 -28
- package/src/services/position-exit-logic.js +0 -174
- package/src/services/position-manager.js +0 -438
- package/src/services/position-momentum.js +0 -206
- package/src/services/projectx/accounts.js +0 -142
- package/src/services/projectx/index.js +0 -443
- package/src/services/projectx/market.js +0 -172
- package/src/services/projectx/stats.js +0 -110
- package/src/services/projectx/trading.js +0 -180
- package/src/services/rithmic/latency-tracker.js +0 -182
- package/src/services/rithmic/market-data-decoders.js +0 -229
- package/src/services/rithmic/market-data.js +0 -272
- package/src/services/rithmic/orders-fast.js +0 -246
- package/src/services/rithmic/proto-decoders.js +0 -403
- package/src/services/rithmic/specs.js +0 -146
- package/src/services/rithmic/trade-history.js +0 -254
- package/src/services/session-history.js +0 -475
- package/src/services/strategy/hft-signal-calc.js +0 -147
- package/src/services/strategy/hft-tick.js +0 -407
- package/src/services/strategy/recovery-math.js +0 -402
- package/src/services/tradovate/constants.js +0 -109
- package/src/services/tradovate/index.js +0 -392
- package/src/services/tradovate/market.js +0 -47
- package/src/services/tradovate/orders.js +0 -145
- package/src/services/tradovate/websocket.js +0 -97
|
@@ -1,246 +0,0 @@
|
|
|
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,403 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rithmic Protobuf Manual Decoders
|
|
3
|
-
* @module services/rithmic/proto-decoders
|
|
4
|
-
*
|
|
5
|
-
* Hand-optimized decoders for Rithmic's large field ID messages.
|
|
6
|
-
* Faster than generic protobuf parsing for hot path.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// PnL field IDs (Rithmic uses very large field IDs)
|
|
10
|
-
const PNL_FIELDS = {
|
|
11
|
-
TEMPLATE_ID: 154467,
|
|
12
|
-
IS_SNAPSHOT: 110121,
|
|
13
|
-
FCM_ID: 154013,
|
|
14
|
-
IB_ID: 154014,
|
|
15
|
-
ACCOUNT_ID: 154008,
|
|
16
|
-
ACCOUNT_BALANCE: 156970,
|
|
17
|
-
CASH_ON_HAND: 156971,
|
|
18
|
-
MARGIN_BALANCE: 156977,
|
|
19
|
-
MIN_ACCOUNT_BALANCE: 156968,
|
|
20
|
-
OPEN_POSITION_PNL: 156961,
|
|
21
|
-
CLOSED_POSITION_PNL: 156963,
|
|
22
|
-
DAY_PNL: 157956,
|
|
23
|
-
DAY_OPEN_PNL: 157954,
|
|
24
|
-
DAY_CLOSED_PNL: 157955,
|
|
25
|
-
AVAILABLE_BUYING_POWER: 157015,
|
|
26
|
-
SSBOE: 150100,
|
|
27
|
-
USECS: 150101,
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// Symbol/Contract field IDs
|
|
31
|
-
const SYMBOL_FIELDS = {
|
|
32
|
-
TEMPLATE_ID: 154467,
|
|
33
|
-
RP_CODE: 132766,
|
|
34
|
-
EXCHANGE: 110101,
|
|
35
|
-
PRODUCT_CODE: 110102,
|
|
36
|
-
PRODUCT_NAME: 110103,
|
|
37
|
-
SYMBOL: 110100,
|
|
38
|
-
TRADING_SYMBOL: 157095,
|
|
39
|
-
DESCRIPTION: 110114,
|
|
40
|
-
USER_MSG: 132760,
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// Instrument PnL Position Update field IDs
|
|
44
|
-
const INSTRUMENT_PNL_FIELDS = {
|
|
45
|
-
TEMPLATE_ID: 154467,
|
|
46
|
-
IS_SNAPSHOT: 110121,
|
|
47
|
-
FCM_ID: 154013,
|
|
48
|
-
IB_ID: 154014,
|
|
49
|
-
ACCOUNT_ID: 154008,
|
|
50
|
-
SYMBOL: 110100,
|
|
51
|
-
EXCHANGE: 110101,
|
|
52
|
-
PRODUCT_CODE: 100749,
|
|
53
|
-
INSTRUMENT_TYPE: 110116,
|
|
54
|
-
FILL_BUY_QTY: 154041,
|
|
55
|
-
FILL_SELL_QTY: 154042,
|
|
56
|
-
ORDER_BUY_QTY: 154037,
|
|
57
|
-
ORDER_SELL_QTY: 154038,
|
|
58
|
-
BUY_QTY: 154260,
|
|
59
|
-
SELL_QTY: 154261,
|
|
60
|
-
AVG_OPEN_FILL_PRICE: 154434,
|
|
61
|
-
DAY_OPEN_PNL: 157954,
|
|
62
|
-
DAY_CLOSED_PNL: 157955,
|
|
63
|
-
DAY_PNL: 157956,
|
|
64
|
-
OPEN_POSITION_PNL: 156961,
|
|
65
|
-
OPEN_POSITION_QUANTITY: 156962,
|
|
66
|
-
CLOSED_POSITION_PNL: 156963,
|
|
67
|
-
CLOSED_POSITION_QUANTITY: 156964,
|
|
68
|
-
NET_QUANTITY: 156967,
|
|
69
|
-
SSBOE: 150100,
|
|
70
|
-
USECS: 150101,
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
/** Read a varint from buffer */
|
|
74
|
-
function readVarint(buffer, offset) {
|
|
75
|
-
let result = BigInt(0);
|
|
76
|
-
let shift = BigInt(0);
|
|
77
|
-
let pos = offset;
|
|
78
|
-
|
|
79
|
-
while (pos < buffer.length) {
|
|
80
|
-
const byte = buffer[pos++];
|
|
81
|
-
result |= BigInt(byte & 0x7f) << shift;
|
|
82
|
-
if ((byte & 0x80) === 0) {
|
|
83
|
-
return [Number(result), pos];
|
|
84
|
-
}
|
|
85
|
-
shift += BigInt(7);
|
|
86
|
-
if (shift > BigInt(63)) throw new Error('Varint too large');
|
|
87
|
-
}
|
|
88
|
-
throw new Error('Incomplete varint');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** Read a length-delimited field (string/bytes) */
|
|
92
|
-
function readLengthDelimited(buffer, offset) {
|
|
93
|
-
const [length, newOffset] = readVarint(buffer, offset);
|
|
94
|
-
const value = buffer.slice(newOffset, newOffset + length).toString('utf8');
|
|
95
|
-
return [value, newOffset + length];
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** Skip a field based on wire type */
|
|
99
|
-
function skipField(buffer, offset, wireType) {
|
|
100
|
-
switch (wireType) {
|
|
101
|
-
case 0:
|
|
102
|
-
const [, newOffset] = readVarint(buffer, offset);
|
|
103
|
-
return newOffset;
|
|
104
|
-
case 1:
|
|
105
|
-
return offset + 8;
|
|
106
|
-
case 2:
|
|
107
|
-
const [length, lenOffset] = readVarint(buffer, offset);
|
|
108
|
-
return lenOffset + length;
|
|
109
|
-
case 5:
|
|
110
|
-
return offset + 4;
|
|
111
|
-
default:
|
|
112
|
-
throw new Error(`Unknown wire type: ${wireType}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** Manually decode AccountPnL from raw bytes */
|
|
117
|
-
function decodeAccountPnL(buffer) {
|
|
118
|
-
const result = {};
|
|
119
|
-
let offset = 0;
|
|
120
|
-
|
|
121
|
-
while (offset < buffer.length) {
|
|
122
|
-
try {
|
|
123
|
-
const [tag, tagOffset] = readVarint(buffer, offset);
|
|
124
|
-
const wireType = tag & 0x7;
|
|
125
|
-
const fieldNumber = tag >>> 3;
|
|
126
|
-
offset = tagOffset;
|
|
127
|
-
|
|
128
|
-
switch (fieldNumber) {
|
|
129
|
-
case PNL_FIELDS.TEMPLATE_ID:
|
|
130
|
-
[result.templateId, offset] = readVarint(buffer, offset);
|
|
131
|
-
break;
|
|
132
|
-
case PNL_FIELDS.IS_SNAPSHOT:
|
|
133
|
-
const [isSnap, snapOffset] = readVarint(buffer, offset);
|
|
134
|
-
result.isSnapshot = isSnap !== 0;
|
|
135
|
-
offset = snapOffset;
|
|
136
|
-
break;
|
|
137
|
-
case PNL_FIELDS.FCM_ID:
|
|
138
|
-
[result.fcmId, offset] = readLengthDelimited(buffer, offset);
|
|
139
|
-
break;
|
|
140
|
-
case PNL_FIELDS.IB_ID:
|
|
141
|
-
[result.ibId, offset] = readLengthDelimited(buffer, offset);
|
|
142
|
-
break;
|
|
143
|
-
case PNL_FIELDS.ACCOUNT_ID:
|
|
144
|
-
[result.accountId, offset] = readLengthDelimited(buffer, offset);
|
|
145
|
-
break;
|
|
146
|
-
case PNL_FIELDS.ACCOUNT_BALANCE:
|
|
147
|
-
[result.accountBalance, offset] = readLengthDelimited(buffer, offset);
|
|
148
|
-
break;
|
|
149
|
-
case PNL_FIELDS.CASH_ON_HAND:
|
|
150
|
-
[result.cashOnHand, offset] = readLengthDelimited(buffer, offset);
|
|
151
|
-
break;
|
|
152
|
-
case PNL_FIELDS.MARGIN_BALANCE:
|
|
153
|
-
[result.marginBalance, offset] = readLengthDelimited(buffer, offset);
|
|
154
|
-
break;
|
|
155
|
-
case PNL_FIELDS.MIN_ACCOUNT_BALANCE:
|
|
156
|
-
[result.minAccountBalance, offset] = readLengthDelimited(buffer, offset);
|
|
157
|
-
break;
|
|
158
|
-
case PNL_FIELDS.OPEN_POSITION_PNL:
|
|
159
|
-
[result.openPositionPnl, offset] = readLengthDelimited(buffer, offset);
|
|
160
|
-
break;
|
|
161
|
-
case PNL_FIELDS.CLOSED_POSITION_PNL:
|
|
162
|
-
[result.closedPositionPnl, offset] = readLengthDelimited(buffer, offset);
|
|
163
|
-
break;
|
|
164
|
-
case PNL_FIELDS.DAY_PNL:
|
|
165
|
-
[result.dayPnl, offset] = readLengthDelimited(buffer, offset);
|
|
166
|
-
break;
|
|
167
|
-
case PNL_FIELDS.DAY_OPEN_PNL:
|
|
168
|
-
[result.dayOpenPnl, offset] = readLengthDelimited(buffer, offset);
|
|
169
|
-
break;
|
|
170
|
-
case PNL_FIELDS.DAY_CLOSED_PNL:
|
|
171
|
-
[result.dayClosedPnl, offset] = readLengthDelimited(buffer, offset);
|
|
172
|
-
break;
|
|
173
|
-
case PNL_FIELDS.AVAILABLE_BUYING_POWER:
|
|
174
|
-
[result.availableBuyingPower, offset] = readLengthDelimited(buffer, offset);
|
|
175
|
-
break;
|
|
176
|
-
case PNL_FIELDS.SSBOE:
|
|
177
|
-
[result.ssboe, offset] = readVarint(buffer, offset);
|
|
178
|
-
break;
|
|
179
|
-
case PNL_FIELDS.USECS:
|
|
180
|
-
[result.usecs, offset] = readVarint(buffer, offset);
|
|
181
|
-
break;
|
|
182
|
-
default:
|
|
183
|
-
offset = skipField(buffer, offset, wireType);
|
|
184
|
-
}
|
|
185
|
-
} catch (error) {
|
|
186
|
-
break;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return result;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/** Manually decode InstrumentPnLPositionUpdate from raw bytes */
|
|
193
|
-
function decodeInstrumentPnL(buffer) {
|
|
194
|
-
const result = {};
|
|
195
|
-
let offset = 0;
|
|
196
|
-
|
|
197
|
-
while (offset < buffer.length) {
|
|
198
|
-
try {
|
|
199
|
-
const [tag, tagOffset] = readVarint(buffer, offset);
|
|
200
|
-
const wireType = tag & 0x7;
|
|
201
|
-
const fieldNumber = tag >>> 3;
|
|
202
|
-
offset = tagOffset;
|
|
203
|
-
|
|
204
|
-
switch (fieldNumber) {
|
|
205
|
-
case INSTRUMENT_PNL_FIELDS.TEMPLATE_ID:
|
|
206
|
-
[result.templateId, offset] = readVarint(buffer, offset);
|
|
207
|
-
break;
|
|
208
|
-
case INSTRUMENT_PNL_FIELDS.IS_SNAPSHOT:
|
|
209
|
-
const [isSnap, snapOffset] = readVarint(buffer, offset);
|
|
210
|
-
result.isSnapshot = isSnap !== 0;
|
|
211
|
-
offset = snapOffset;
|
|
212
|
-
break;
|
|
213
|
-
case INSTRUMENT_PNL_FIELDS.FCM_ID:
|
|
214
|
-
[result.fcmId, offset] = readLengthDelimited(buffer, offset);
|
|
215
|
-
break;
|
|
216
|
-
case INSTRUMENT_PNL_FIELDS.IB_ID:
|
|
217
|
-
[result.ibId, offset] = readLengthDelimited(buffer, offset);
|
|
218
|
-
break;
|
|
219
|
-
case INSTRUMENT_PNL_FIELDS.ACCOUNT_ID:
|
|
220
|
-
[result.accountId, offset] = readLengthDelimited(buffer, offset);
|
|
221
|
-
break;
|
|
222
|
-
case INSTRUMENT_PNL_FIELDS.SYMBOL:
|
|
223
|
-
[result.symbol, offset] = readLengthDelimited(buffer, offset);
|
|
224
|
-
break;
|
|
225
|
-
case INSTRUMENT_PNL_FIELDS.EXCHANGE:
|
|
226
|
-
[result.exchange, offset] = readLengthDelimited(buffer, offset);
|
|
227
|
-
break;
|
|
228
|
-
case INSTRUMENT_PNL_FIELDS.PRODUCT_CODE:
|
|
229
|
-
[result.productCode, offset] = readLengthDelimited(buffer, offset);
|
|
230
|
-
break;
|
|
231
|
-
case INSTRUMENT_PNL_FIELDS.BUY_QTY:
|
|
232
|
-
[result.buyQty, offset] = readVarint(buffer, offset);
|
|
233
|
-
break;
|
|
234
|
-
case INSTRUMENT_PNL_FIELDS.SELL_QTY:
|
|
235
|
-
[result.sellQty, offset] = readVarint(buffer, offset);
|
|
236
|
-
break;
|
|
237
|
-
case INSTRUMENT_PNL_FIELDS.FILL_BUY_QTY:
|
|
238
|
-
[result.fillBuyQty, offset] = readVarint(buffer, offset);
|
|
239
|
-
break;
|
|
240
|
-
case INSTRUMENT_PNL_FIELDS.FILL_SELL_QTY:
|
|
241
|
-
[result.fillSellQty, offset] = readVarint(buffer, offset);
|
|
242
|
-
break;
|
|
243
|
-
case INSTRUMENT_PNL_FIELDS.NET_QUANTITY:
|
|
244
|
-
[result.netQuantity, offset] = readVarint(buffer, offset);
|
|
245
|
-
break;
|
|
246
|
-
case INSTRUMENT_PNL_FIELDS.OPEN_POSITION_QUANTITY:
|
|
247
|
-
[result.openPositionQuantity, offset] = readVarint(buffer, offset);
|
|
248
|
-
break;
|
|
249
|
-
case INSTRUMENT_PNL_FIELDS.AVG_OPEN_FILL_PRICE:
|
|
250
|
-
if (wireType === 1) {
|
|
251
|
-
result.avgOpenFillPrice = buffer.readDoubleLE(offset);
|
|
252
|
-
offset += 8;
|
|
253
|
-
} else {
|
|
254
|
-
offset = skipField(buffer, offset, wireType);
|
|
255
|
-
}
|
|
256
|
-
break;
|
|
257
|
-
case INSTRUMENT_PNL_FIELDS.OPEN_POSITION_PNL:
|
|
258
|
-
[result.openPositionPnl, offset] = readLengthDelimited(buffer, offset);
|
|
259
|
-
break;
|
|
260
|
-
case INSTRUMENT_PNL_FIELDS.CLOSED_POSITION_PNL:
|
|
261
|
-
[result.closedPositionPnl, offset] = readLengthDelimited(buffer, offset);
|
|
262
|
-
break;
|
|
263
|
-
case INSTRUMENT_PNL_FIELDS.DAY_PNL:
|
|
264
|
-
if (wireType === 1) {
|
|
265
|
-
result.dayPnl = buffer.readDoubleLE(offset);
|
|
266
|
-
offset += 8;
|
|
267
|
-
} else {
|
|
268
|
-
[result.dayPnl, offset] = readLengthDelimited(buffer, offset);
|
|
269
|
-
}
|
|
270
|
-
break;
|
|
271
|
-
case INSTRUMENT_PNL_FIELDS.DAY_OPEN_PNL:
|
|
272
|
-
if (wireType === 1) {
|
|
273
|
-
result.dayOpenPnl = buffer.readDoubleLE(offset);
|
|
274
|
-
offset += 8;
|
|
275
|
-
} else {
|
|
276
|
-
[result.dayOpenPnl, offset] = readLengthDelimited(buffer, offset);
|
|
277
|
-
}
|
|
278
|
-
break;
|
|
279
|
-
case INSTRUMENT_PNL_FIELDS.DAY_CLOSED_PNL:
|
|
280
|
-
if (wireType === 1) {
|
|
281
|
-
result.dayClosedPnl = buffer.readDoubleLE(offset);
|
|
282
|
-
offset += 8;
|
|
283
|
-
} else {
|
|
284
|
-
[result.dayClosedPnl, offset] = readLengthDelimited(buffer, offset);
|
|
285
|
-
}
|
|
286
|
-
break;
|
|
287
|
-
case INSTRUMENT_PNL_FIELDS.SSBOE:
|
|
288
|
-
[result.ssboe, offset] = readVarint(buffer, offset);
|
|
289
|
-
break;
|
|
290
|
-
case INSTRUMENT_PNL_FIELDS.USECS:
|
|
291
|
-
[result.usecs, offset] = readVarint(buffer, offset);
|
|
292
|
-
break;
|
|
293
|
-
default:
|
|
294
|
-
offset = skipField(buffer, offset, wireType);
|
|
295
|
-
}
|
|
296
|
-
} catch (error) {
|
|
297
|
-
break;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
return result;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/** Decode ResponseProductCodes (template 112) */
|
|
304
|
-
function decodeProductCodes(buffer) {
|
|
305
|
-
const result = { rpCode: [] };
|
|
306
|
-
let offset = 0;
|
|
307
|
-
|
|
308
|
-
while (offset < buffer.length) {
|
|
309
|
-
try {
|
|
310
|
-
const [tag, tagOffset] = readVarint(buffer, offset);
|
|
311
|
-
const wireType = tag & 0x7;
|
|
312
|
-
const fieldNumber = tag >>> 3;
|
|
313
|
-
offset = tagOffset;
|
|
314
|
-
|
|
315
|
-
switch (fieldNumber) {
|
|
316
|
-
case SYMBOL_FIELDS.TEMPLATE_ID:
|
|
317
|
-
[result.templateId, offset] = readVarint(buffer, offset);
|
|
318
|
-
break;
|
|
319
|
-
case SYMBOL_FIELDS.RP_CODE:
|
|
320
|
-
let rpCode;
|
|
321
|
-
[rpCode, offset] = readLengthDelimited(buffer, offset);
|
|
322
|
-
result.rpCode.push(rpCode);
|
|
323
|
-
break;
|
|
324
|
-
case SYMBOL_FIELDS.EXCHANGE:
|
|
325
|
-
[result.exchange, offset] = readLengthDelimited(buffer, offset);
|
|
326
|
-
break;
|
|
327
|
-
case SYMBOL_FIELDS.PRODUCT_CODE:
|
|
328
|
-
[result.productCode, offset] = readLengthDelimited(buffer, offset);
|
|
329
|
-
break;
|
|
330
|
-
case SYMBOL_FIELDS.PRODUCT_NAME:
|
|
331
|
-
[result.productName, offset] = readLengthDelimited(buffer, offset);
|
|
332
|
-
break;
|
|
333
|
-
case SYMBOL_FIELDS.USER_MSG:
|
|
334
|
-
[result.userMsg, offset] = readLengthDelimited(buffer, offset);
|
|
335
|
-
break;
|
|
336
|
-
default:
|
|
337
|
-
offset = skipField(buffer, offset, wireType);
|
|
338
|
-
}
|
|
339
|
-
} catch (error) {
|
|
340
|
-
break;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
return result;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/** Decode ResponseFrontMonthContract (template 114) */
|
|
347
|
-
function decodeFrontMonthContract(buffer) {
|
|
348
|
-
const result = { rpCode: [] };
|
|
349
|
-
let offset = 0;
|
|
350
|
-
|
|
351
|
-
while (offset < buffer.length) {
|
|
352
|
-
try {
|
|
353
|
-
const [tag, tagOffset] = readVarint(buffer, offset);
|
|
354
|
-
const wireType = tag & 0x7;
|
|
355
|
-
const fieldNumber = tag >>> 3;
|
|
356
|
-
offset = tagOffset;
|
|
357
|
-
|
|
358
|
-
switch (fieldNumber) {
|
|
359
|
-
case SYMBOL_FIELDS.TEMPLATE_ID:
|
|
360
|
-
[result.templateId, offset] = readVarint(buffer, offset);
|
|
361
|
-
break;
|
|
362
|
-
case SYMBOL_FIELDS.RP_CODE:
|
|
363
|
-
let rpCode;
|
|
364
|
-
[rpCode, offset] = readLengthDelimited(buffer, offset);
|
|
365
|
-
result.rpCode.push(rpCode);
|
|
366
|
-
break;
|
|
367
|
-
case SYMBOL_FIELDS.SYMBOL:
|
|
368
|
-
[result.symbol, offset] = readLengthDelimited(buffer, offset);
|
|
369
|
-
break;
|
|
370
|
-
case SYMBOL_FIELDS.EXCHANGE:
|
|
371
|
-
[result.exchange, offset] = readLengthDelimited(buffer, offset);
|
|
372
|
-
break;
|
|
373
|
-
case SYMBOL_FIELDS.TRADING_SYMBOL:
|
|
374
|
-
[result.tradingSymbol, offset] = readLengthDelimited(buffer, offset);
|
|
375
|
-
break;
|
|
376
|
-
case SYMBOL_FIELDS.DESCRIPTION:
|
|
377
|
-
[result.description, offset] = readLengthDelimited(buffer, offset);
|
|
378
|
-
break;
|
|
379
|
-
case SYMBOL_FIELDS.USER_MSG:
|
|
380
|
-
[result.userMsg, offset] = readLengthDelimited(buffer, offset);
|
|
381
|
-
break;
|
|
382
|
-
default:
|
|
383
|
-
offset = skipField(buffer, offset, wireType);
|
|
384
|
-
}
|
|
385
|
-
} catch (error) {
|
|
386
|
-
break;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
return result;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
module.exports = {
|
|
393
|
-
PNL_FIELDS,
|
|
394
|
-
SYMBOL_FIELDS,
|
|
395
|
-
INSTRUMENT_PNL_FIELDS,
|
|
396
|
-
readVarint,
|
|
397
|
-
readLengthDelimited,
|
|
398
|
-
skipField,
|
|
399
|
-
decodeAccountPnL,
|
|
400
|
-
decodeInstrumentPnL,
|
|
401
|
-
decodeProductCodes,
|
|
402
|
-
decodeFrontMonthContract,
|
|
403
|
-
};
|