hedgequantx 1.2.33 → 1.2.35

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.
Files changed (48) hide show
  1. package/package.json +2 -1
  2. package/src/app.js +121 -9
  3. package/src/services/rithmic/connection.js +203 -0
  4. package/src/services/rithmic/constants.js +156 -0
  5. package/src/services/rithmic/index.js +487 -0
  6. package/src/services/rithmic/proto/account_pnl_position_update.proto +59 -0
  7. package/src/services/rithmic/proto/base.proto +7 -0
  8. package/src/services/rithmic/proto/best_bid_offer.proto +39 -0
  9. package/src/services/rithmic/proto/exchange_order_notification.proto +140 -0
  10. package/src/services/rithmic/proto/instrument_pnl_position_update.proto +50 -0
  11. package/src/services/rithmic/proto/last_trade.proto +53 -0
  12. package/src/services/rithmic/proto/request_account_list.proto +20 -0
  13. package/src/services/rithmic/proto/request_cancel_all_orders.proto +15 -0
  14. package/src/services/rithmic/proto/request_heartbeat.proto +13 -0
  15. package/src/services/rithmic/proto/request_login.proto +28 -0
  16. package/src/services/rithmic/proto/request_login_info.proto +10 -0
  17. package/src/services/rithmic/proto/request_logout.proto +10 -0
  18. package/src/services/rithmic/proto/request_market_data_update.proto +42 -0
  19. package/src/services/rithmic/proto/request_new_order.proto +84 -0
  20. package/src/services/rithmic/proto/request_pnl_position_snapshot.proto +14 -0
  21. package/src/services/rithmic/proto/request_pnl_position_updates.proto +20 -0
  22. package/src/services/rithmic/proto/request_rithmic_system_info.proto +8 -0
  23. package/src/services/rithmic/proto/request_show_order_history.proto +16 -0
  24. package/src/services/rithmic/proto/request_show_order_history_dates.proto +10 -0
  25. package/src/services/rithmic/proto/request_show_order_history_summary.proto +14 -0
  26. package/src/services/rithmic/proto/request_show_orders.proto +14 -0
  27. package/src/services/rithmic/proto/request_subscribe_for_order_updates.proto +14 -0
  28. package/src/services/rithmic/proto/request_tick_bar_replay.proto +48 -0
  29. package/src/services/rithmic/proto/request_trade_routes.proto +11 -0
  30. package/src/services/rithmic/proto/response_account_list.proto +18 -0
  31. package/src/services/rithmic/proto/response_heartbeat.proto +14 -0
  32. package/src/services/rithmic/proto/response_login.proto +18 -0
  33. package/src/services/rithmic/proto/response_login_info.proto +24 -0
  34. package/src/services/rithmic/proto/response_logout.proto +11 -0
  35. package/src/services/rithmic/proto/response_market_data_update.proto +9 -0
  36. package/src/services/rithmic/proto/response_new_order.proto +18 -0
  37. package/src/services/rithmic/proto/response_pnl_position_snapshot.proto +11 -0
  38. package/src/services/rithmic/proto/response_pnl_position_updates.proto +11 -0
  39. package/src/services/rithmic/proto/response_rithmic_system_info.proto +12 -0
  40. package/src/services/rithmic/proto/response_show_order_history.proto +11 -0
  41. package/src/services/rithmic/proto/response_show_order_history_dates.proto +13 -0
  42. package/src/services/rithmic/proto/response_show_order_history_summary.proto +11 -0
  43. package/src/services/rithmic/proto/response_show_orders.proto +11 -0
  44. package/src/services/rithmic/proto/response_subscribe_for_order_updates.proto +11 -0
  45. package/src/services/rithmic/proto/response_tick_bar_replay.proto +40 -0
  46. package/src/services/rithmic/proto/response_trade_routes.proto +19 -0
  47. package/src/services/rithmic/proto/rithmic_order_notification.proto +124 -0
  48. package/src/services/rithmic/protobuf.js +259 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "1.2.33",
3
+ "version": "1.2.35",
4
4
  "description": "Prop Futures Algo Trading CLI - Connect to Topstep, Alpha Futures, and other prop firms",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -47,6 +47,7 @@
47
47
  "figlet": "^1.7.0",
48
48
  "inquirer": "^7.3.3",
49
49
  "ora": "^5.4.1",
50
+ "protobufjs": "^8.0.0",
50
51
  "ws": "^8.18.3"
51
52
  }
52
53
  }
package/src/app.js CHANGED
@@ -11,7 +11,8 @@ const { execSync } = require('child_process');
11
11
  const path = require('path');
12
12
 
13
13
  const { ProjectXService, connections } = require('./services');
14
- const { PROPFIRM_CHOICES, getPropFirmsByPlatform } = require('./config');
14
+ const { RithmicService } = require('./services/rithmic');
15
+ const { PROPFIRM_CHOICES, getPropFirmsByPlatform, getPropFirm } = require('./config');
15
16
  const { getDevice, getSeparator, printLogo, getLogoWidth, drawBoxHeader, drawBoxFooter, centerText, createBoxMenu } = require('./ui');
16
17
  const { validateUsername, validatePassword, maskSensitive } = require('./security');
17
18
 
@@ -22,6 +23,7 @@ const { algoTradingMenu } = require('./pages/algo');
22
23
 
23
24
  // Current service reference
24
25
  let currentService = null;
26
+ let currentPlatform = null; // 'projectx' or 'rithmic'
25
27
 
26
28
  /**
27
29
  * Displays the application banner with stats if connected
@@ -193,17 +195,20 @@ const projectXMenu = async () => {
193
195
  console.log(chalk.cyan('║') + chalk.white.bold(centerText('SELECT PROPFIRM', innerWidth)) + chalk.cyan('║'));
194
196
  console.log(chalk.cyan('║') + ' '.repeat(innerWidth) + chalk.cyan('║'));
195
197
 
196
- // Display in 3 columns
198
+ // Display in 3 columns with fixed width alignment
197
199
  const rows = Math.ceil(numbered.length / numCols);
200
+ const maxNum = numbered.length;
201
+ const numWidth = maxNum >= 10 ? 4 : 3; // [XX] or [X]
202
+
198
203
  for (let row = 0; row < rows; row++) {
199
204
  let line = '';
200
205
  for (let col = 0; col < numCols; col++) {
201
206
  const idx = row + col * rows;
202
207
  if (idx < numbered.length) {
203
208
  const item = numbered[idx];
204
- const text = `[${item.num}] ${item.name}`;
205
- const coloredText = chalk.cyan(`[${item.num}]`) + ' ' + chalk.white(item.name);
206
- const textLen = text.length;
209
+ const numStr = item.num.toString().padStart(2, ' ');
210
+ const coloredText = chalk.cyan(`[${numStr}]`) + ' ' + chalk.white(item.name);
211
+ const textLen = 4 + 1 + item.name.length; // [XX] + space + name
207
212
  const padding = colWidth - textLen - 2;
208
213
  line += ' ' + coloredText + ' '.repeat(Math.max(0, padding));
209
214
  } else {
@@ -254,6 +259,107 @@ const projectXMenu = async () => {
254
259
  await service.getUser();
255
260
  connections.add('projectx', service, service.propfirm.name);
256
261
  currentService = service;
262
+ currentPlatform = 'projectx';
263
+ spinner.succeed(`Connected to ${service.propfirm.name}`);
264
+ return service;
265
+ } else {
266
+ spinner.fail(result.error || 'Authentication failed');
267
+ return null;
268
+ }
269
+ } catch (error) {
270
+ spinner.fail(error.message);
271
+ return null;
272
+ }
273
+ };
274
+
275
+ /**
276
+ * Rithmic platform connection menu
277
+ */
278
+ const rithmicMenu = async () => {
279
+ const propfirms = getPropFirmsByPlatform('Rithmic');
280
+ const boxWidth = getLogoWidth();
281
+ const innerWidth = boxWidth - 2;
282
+ const numCols = 3;
283
+ const colWidth = Math.floor(innerWidth / numCols);
284
+
285
+ // Build numbered list
286
+ const numbered = propfirms.map((pf, i) => ({
287
+ num: i + 1,
288
+ key: pf.key,
289
+ name: pf.displayName,
290
+ systemName: pf.rithmicSystem
291
+ }));
292
+
293
+ // PropFirm selection box
294
+ console.log();
295
+ console.log(chalk.cyan('╔' + '═'.repeat(innerWidth) + '╗'));
296
+ console.log(chalk.cyan('║') + chalk.white.bold(centerText('SELECT PROPFIRM (RITHMIC)', innerWidth)) + chalk.cyan('║'));
297
+ console.log(chalk.cyan('║') + ' '.repeat(innerWidth) + chalk.cyan('║'));
298
+
299
+ // Display in 3 columns with fixed width alignment
300
+ const rows = Math.ceil(numbered.length / numCols);
301
+
302
+ for (let row = 0; row < rows; row++) {
303
+ let line = '';
304
+ for (let col = 0; col < numCols; col++) {
305
+ const idx = row + col * rows;
306
+ if (idx < numbered.length) {
307
+ const item = numbered[idx];
308
+ const numStr = item.num.toString().padStart(2, ' ');
309
+ const coloredText = chalk.cyan(`[${numStr}]`) + ' ' + chalk.white(item.name);
310
+ const textLen = 4 + 1 + item.name.length;
311
+ const padding = colWidth - textLen - 2;
312
+ line += ' ' + coloredText + ' '.repeat(Math.max(0, padding));
313
+ } else {
314
+ line += ' '.repeat(colWidth);
315
+ }
316
+ }
317
+ const lineLen = line.replace(/\x1b\[[0-9;]*m/g, '').length;
318
+ const adjust = innerWidth - lineLen;
319
+ console.log(chalk.cyan('║') + line + ' '.repeat(Math.max(0, adjust)) + chalk.cyan('║'));
320
+ }
321
+
322
+ console.log(chalk.cyan('║') + ' '.repeat(innerWidth) + chalk.cyan('║'));
323
+ const backText = ' ' + chalk.red('[X] Back');
324
+ const backLen = '[X] Back'.length + 2;
325
+ console.log(chalk.cyan('║') + backText + ' '.repeat(innerWidth - backLen) + chalk.cyan('║'));
326
+ console.log(chalk.cyan('╚' + '═'.repeat(innerWidth) + '╝'));
327
+ console.log();
328
+
329
+ const validInputs = numbered.map(n => n.num.toString());
330
+ validInputs.push('x', 'X');
331
+
332
+ const { action } = await inquirer.prompt([
333
+ {
334
+ type: 'input',
335
+ name: 'action',
336
+ message: chalk.cyan(`Enter choice (1-${numbered.length}/X):`),
337
+ validate: (input) => {
338
+ if (validInputs.includes(input)) return true;
339
+ return `Please enter 1-${numbered.length} or X`;
340
+ }
341
+ }
342
+ ]);
343
+
344
+ if (action.toLowerCase() === 'x') return null;
345
+
346
+ const selectedIdx = parseInt(action) - 1;
347
+ const selectedPropfirm = numbered[selectedIdx];
348
+
349
+ const credentials = await loginPrompt(selectedPropfirm.name);
350
+ const spinner = ora('Connecting to Rithmic...').start();
351
+
352
+ try {
353
+ const service = new RithmicService(selectedPropfirm.key);
354
+ const result = await service.login(credentials.username, credentials.password);
355
+
356
+ if (result.success) {
357
+ spinner.text = 'Fetching accounts...';
358
+ await service.getTradingAccounts();
359
+
360
+ connections.add('rithmic', service, service.propfirm.name);
361
+ currentService = service;
362
+ currentPlatform = 'rithmic';
257
363
  spinner.succeed(`Connected to ${service.propfirm.name}`);
258
364
  return service;
259
365
  } else {
@@ -291,7 +397,7 @@ const mainMenu = async () => {
291
397
  console.log(chalk.cyan('║') + leftText + ' '.repeat(Math.max(0, leftPad)) + rightText + ' '.repeat(Math.max(0, rightPad)) + chalk.cyan('║'));
292
398
  };
293
399
 
294
- menuRow(chalk.cyan('[1] ProjectX'), chalk.gray('[2] Rithmic (Coming Soon)'));
400
+ menuRow(chalk.cyan('[1] ProjectX'), chalk.cyan('[2] Rithmic'));
295
401
  menuRow(chalk.gray('[3] Tradovate (Coming Soon)'), chalk.red('[X] Exit'));
296
402
 
297
403
  console.log(chalk.cyan('╚' + '═'.repeat(innerWidth) + '╝'));
@@ -301,11 +407,11 @@ const mainMenu = async () => {
301
407
  {
302
408
  type: 'input',
303
409
  name: 'action',
304
- message: chalk.cyan('Enter choice (1/X):'),
410
+ message: chalk.cyan('Enter choice (1/2/X):'),
305
411
  validate: (input) => {
306
- const valid = ['1', 'x', 'X'];
412
+ const valid = ['1', '2', 'x', 'X'];
307
413
  if (valid.includes(input)) return true;
308
- return 'Please enter 1 or X';
414
+ return 'Please enter 1, 2 or X';
309
415
  }
310
416
  }
311
417
  ]);
@@ -313,6 +419,7 @@ const mainMenu = async () => {
313
419
  // Map input to action
314
420
  const actionMap = {
315
421
  '1': 'projectx',
422
+ '2': 'rithmic',
316
423
  'x': 'exit',
317
424
  'X': 'exit'
318
425
  };
@@ -509,6 +616,11 @@ const run = async () => {
509
616
  const service = await projectXMenu();
510
617
  if (service) currentService = service;
511
618
  }
619
+
620
+ if (choice === 'rithmic') {
621
+ const service = await rithmicMenu();
622
+ if (service) currentService = service;
623
+ }
512
624
  } else {
513
625
  const action = await dashboardMenu(currentService);
514
626
 
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Rithmic Connection Manager
3
+ * Handles WebSocket connection and heartbeat
4
+ */
5
+
6
+ const WebSocket = require('ws');
7
+ const EventEmitter = require('events');
8
+ const { proto } = require('./protobuf');
9
+ const { REQ, RES, INFRA_TYPE } = require('./constants');
10
+
11
+ class RithmicConnection extends EventEmitter {
12
+ constructor() {
13
+ super();
14
+ this.ws = null;
15
+ this.config = null;
16
+ this.state = 'DISCONNECTED';
17
+ this.heartbeatTimer = null;
18
+ }
19
+
20
+ get isConnected() {
21
+ return this.ws?.readyState === WebSocket.OPEN;
22
+ }
23
+
24
+ get connectionState() {
25
+ return this.state;
26
+ }
27
+
28
+ /**
29
+ * Connect to Rithmic server
30
+ */
31
+ async connect(config) {
32
+ this.config = config;
33
+ this.state = 'CONNECTING';
34
+
35
+ await proto.load();
36
+
37
+ return new Promise((resolve, reject) => {
38
+ this.ws = new WebSocket(config.uri, { rejectUnauthorized: false });
39
+
40
+ this.ws.on('open', () => {
41
+ this.state = 'CONNECTED';
42
+ this.emit('connected');
43
+ resolve(true);
44
+ });
45
+
46
+ this.ws.on('message', (data) => {
47
+ this.handleMessage(data);
48
+ });
49
+
50
+ this.ws.on('error', (err) => {
51
+ this.state = 'ERROR';
52
+ this.emit('error', err);
53
+ reject(err);
54
+ });
55
+
56
+ this.ws.on('close', (code, reason) => {
57
+ this.state = 'DISCONNECTED';
58
+ this.stopHeartbeat();
59
+ this.emit('disconnected', { code, reason: reason?.toString() });
60
+ });
61
+
62
+ // Timeout
63
+ setTimeout(() => {
64
+ if (this.state === 'CONNECTING') {
65
+ reject(new Error('Connection timeout'));
66
+ }
67
+ }, 15000);
68
+ });
69
+ }
70
+
71
+ /**
72
+ * Disconnect
73
+ */
74
+ async disconnect() {
75
+ this.stopHeartbeat();
76
+ if (this.ws?.readyState === WebSocket.OPEN) {
77
+ this.send('RequestLogout', { templateId: REQ.LOGOUT, userMsg: ['HQX'] });
78
+ this.ws.close(1000, 'bye');
79
+ }
80
+ this.ws = null;
81
+ this.state = 'DISCONNECTED';
82
+ }
83
+
84
+ /**
85
+ * Send a protobuf message
86
+ */
87
+ send(typeName, data) {
88
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
89
+ throw new Error('Not connected');
90
+ }
91
+ const buffer = proto.encode(typeName, data);
92
+ this.ws.send(buffer);
93
+ }
94
+
95
+ /**
96
+ * Login to system
97
+ */
98
+ login(infraType = 'ORDER_PLANT') {
99
+ if (!this.config) throw new Error('No config');
100
+
101
+ this.send('RequestLogin', {
102
+ templateId: REQ.LOGIN,
103
+ templateVersion: '3.9',
104
+ userMsg: ['HQX'],
105
+ user: this.config.userId,
106
+ password: this.config.password,
107
+ appName: this.config.appName || 'HQX-CLI',
108
+ appVersion: this.config.appVersion || '1.0.0',
109
+ systemName: this.config.systemName,
110
+ infraType: INFRA_TYPE[infraType],
111
+ });
112
+ }
113
+
114
+ /**
115
+ * List available systems
116
+ */
117
+ listSystems() {
118
+ this.send('RequestRithmicSystemInfo', {
119
+ templateId: REQ.SYSTEM_INFO,
120
+ userMsg: ['HQX'],
121
+ });
122
+ }
123
+
124
+ /**
125
+ * Handle incoming message
126
+ */
127
+ handleMessage(data) {
128
+ const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
129
+ const templateId = proto.getTemplateId(buffer);
130
+
131
+ switch (templateId) {
132
+ case RES.LOGIN:
133
+ this.onLoginResponse(buffer);
134
+ break;
135
+
136
+ case RES.HEARTBEAT:
137
+ // OK
138
+ break;
139
+
140
+ case RES.SYSTEM_INFO:
141
+ this.onSystemInfo(buffer);
142
+ break;
143
+
144
+ default:
145
+ // Forward to listeners
146
+ this.emit('message', { templateId, data: buffer });
147
+ }
148
+ }
149
+
150
+ onLoginResponse(data) {
151
+ try {
152
+ const res = proto.decode('ResponseLogin', data);
153
+
154
+ if (res.rpCode?.[0] === '0') {
155
+ this.state = 'LOGGED_IN';
156
+ this.startHeartbeat(res.heartbeatInterval || 60);
157
+ this.emit('loggedIn', {
158
+ fcmId: res.fcmId,
159
+ ibId: res.ibId,
160
+ heartbeatInterval: res.heartbeatInterval,
161
+ });
162
+ } else {
163
+ const errorCode = res.rpCode?.[0] || 'UNKNOWN';
164
+ const errorMsg = res.rpCode?.[1] || 'Login failed';
165
+ this.emit('loginFailed', { code: errorCode, message: errorMsg });
166
+ }
167
+ } catch (e) {
168
+ this.emit('loginFailed', { code: 'DECODE_ERROR', message: e.message });
169
+ }
170
+ }
171
+
172
+ onSystemInfo(data) {
173
+ try {
174
+ const res = proto.decode('ResponseRithmicSystemInfo', data);
175
+
176
+ if (res.rpCode?.[0] === '0') {
177
+ this.emit('systems', res.systemName || []);
178
+ }
179
+ } catch (e) {
180
+ // Ignore
181
+ }
182
+ }
183
+
184
+ startHeartbeat(intervalSec) {
185
+ this.stopHeartbeat();
186
+ this.heartbeatTimer = setInterval(() => {
187
+ try {
188
+ this.send('RequestHeartbeat', { templateId: REQ.HEARTBEAT });
189
+ } catch (e) {
190
+ // Ignore
191
+ }
192
+ }, (intervalSec - 5) * 1000);
193
+ }
194
+
195
+ stopHeartbeat() {
196
+ if (this.heartbeatTimer) {
197
+ clearInterval(this.heartbeatTimer);
198
+ this.heartbeatTimer = null;
199
+ }
200
+ }
201
+ }
202
+
203
+ module.exports = { RithmicConnection };
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Rithmic Constants
3
+ */
4
+
5
+ // Endpoints
6
+ const RITHMIC_ENDPOINTS = {
7
+ TEST: 'wss://rituz00100.rithmic.com:443',
8
+ PAPER: 'wss://ritpa11120.11.rithmic.com:443',
9
+ LIVE: 'wss://ritpz01000.01.rithmic.com:443',
10
+ };
11
+
12
+ // System names for PropFirms
13
+ const RITHMIC_SYSTEMS = {
14
+ TEST: 'Rithmic Test',
15
+ PAPER: 'Rithmic Paper Trading',
16
+ APEX: 'Apex',
17
+ TOPSTEP: 'TopstepTrader',
18
+ MES_CAPITAL: 'MES Capital',
19
+ BULENOX: 'Bulenox',
20
+ TRADEFUNDRR: 'TradeFundrr',
21
+ THE_TRADING_PIT: 'TheTradingPit',
22
+ FUNDED_FUTURES_NETWORK: 'FundedFuturesNetwork',
23
+ PROPSHOP_TRADER: 'PropShopTrader',
24
+ FOUR_PROP_TRADER: '4PropTrader',
25
+ DAY_TRADERS: 'DayTraders.com',
26
+ TEN_X_FUTURES: '10XFutures',
27
+ LUCID_TRADING: 'LucidTrading',
28
+ THRIVE_TRADING: 'ThriveTrading',
29
+ LEGENDS_TRADING: 'LegendsTrading',
30
+ EARN_2_TRADE: 'Earn2Trade',
31
+ };
32
+
33
+ // Infrastructure types
34
+ const INFRA_TYPE = {
35
+ TICKER_PLANT: 1,
36
+ ORDER_PLANT: 2,
37
+ HISTORY_PLANT: 3,
38
+ PNL_PLANT: 4,
39
+ REPOSITORY_PLANT: 5,
40
+ };
41
+
42
+ // Request template IDs
43
+ const REQ = {
44
+ LOGIN: 10,
45
+ LOGOUT: 12,
46
+ SYSTEM_INFO: 16,
47
+ HEARTBEAT: 18,
48
+ MARKET_DATA: 100,
49
+ LOGIN_INFO: 300,
50
+ ACCOUNT_LIST: 302,
51
+ ACCOUNT_RMS: 304,
52
+ PRODUCT_RMS: 306,
53
+ ORDER_UPDATES: 308,
54
+ TRADE_ROUTES: 310,
55
+ NEW_ORDER: 312,
56
+ MODIFY_ORDER: 314,
57
+ CANCEL_ORDER: 316,
58
+ SHOW_ORDER_HISTORY_DATES: 318,
59
+ SHOW_ORDERS: 320,
60
+ SHOW_ORDER_HISTORY: 324,
61
+ BRACKET_ORDER: 330,
62
+ CANCEL_ALL_ORDERS: 346,
63
+ EXIT_POSITION: 3504,
64
+ PNL_POSITION_SNAPSHOT: 400,
65
+ PNL_POSITION_UPDATES: 402,
66
+ };
67
+
68
+ // Response template IDs
69
+ const RES = {
70
+ LOGIN: 11,
71
+ LOGOUT: 13,
72
+ SYSTEM_INFO: 17,
73
+ HEARTBEAT: 19,
74
+ MARKET_DATA: 101,
75
+ LOGIN_INFO: 301,
76
+ ACCOUNT_LIST: 303,
77
+ ACCOUNT_RMS: 305,
78
+ PRODUCT_RMS: 307,
79
+ ORDER_UPDATES: 309,
80
+ TRADE_ROUTES: 311,
81
+ NEW_ORDER: 313,
82
+ MODIFY_ORDER: 315,
83
+ CANCEL_ORDER: 317,
84
+ SHOW_ORDER_HISTORY_DATES: 319,
85
+ SHOW_ORDERS: 321,
86
+ SHOW_ORDER_HISTORY: 325,
87
+ BRACKET_ORDER: 331,
88
+ CANCEL_ALL_ORDERS: 347,
89
+ EXIT_POSITION: 3505,
90
+ PNL_POSITION_SNAPSHOT: 401,
91
+ PNL_POSITION_UPDATES: 403,
92
+ };
93
+
94
+ // Streaming template IDs
95
+ const STREAM = {
96
+ LAST_TRADE: 150,
97
+ BBO: 151,
98
+ TRADE_ROUTE_UPDATE: 350,
99
+ ORDER_NOTIFICATION: 351,
100
+ EXCHANGE_NOTIFICATION: 352,
101
+ BRACKET_UPDATE: 353,
102
+ INSTRUMENT_PNL_UPDATE: 450,
103
+ ACCOUNT_PNL_UPDATE: 451,
104
+ };
105
+
106
+ // Proto files to load
107
+ const PROTO_FILES = [
108
+ 'base.proto',
109
+ 'request_heartbeat.proto',
110
+ 'response_heartbeat.proto',
111
+ 'request_rithmic_system_info.proto',
112
+ 'response_rithmic_system_info.proto',
113
+ 'request_login.proto',
114
+ 'response_login.proto',
115
+ 'request_logout.proto',
116
+ 'response_logout.proto',
117
+ 'request_login_info.proto',
118
+ 'response_login_info.proto',
119
+ 'request_account_list.proto',
120
+ 'response_account_list.proto',
121
+ 'request_trade_routes.proto',
122
+ 'response_trade_routes.proto',
123
+ 'request_subscribe_for_order_updates.proto',
124
+ 'response_subscribe_for_order_updates.proto',
125
+ 'request_new_order.proto',
126
+ 'response_new_order.proto',
127
+ 'request_cancel_all_orders.proto',
128
+ 'rithmic_order_notification.proto',
129
+ 'exchange_order_notification.proto',
130
+ 'request_show_orders.proto',
131
+ 'response_show_orders.proto',
132
+ 'request_show_order_history.proto',
133
+ 'response_show_order_history.proto',
134
+ 'request_show_order_history_dates.proto',
135
+ 'response_show_order_history_dates.proto',
136
+ 'request_market_data_update.proto',
137
+ 'response_market_data_update.proto',
138
+ 'last_trade.proto',
139
+ 'best_bid_offer.proto',
140
+ 'request_pnl_position_snapshot.proto',
141
+ 'response_pnl_position_snapshot.proto',
142
+ 'request_pnl_position_updates.proto',
143
+ 'response_pnl_position_updates.proto',
144
+ 'account_pnl_position_update.proto',
145
+ 'instrument_pnl_position_update.proto',
146
+ ];
147
+
148
+ module.exports = {
149
+ RITHMIC_ENDPOINTS,
150
+ RITHMIC_SYSTEMS,
151
+ INFRA_TYPE,
152
+ REQ,
153
+ RES,
154
+ STREAM,
155
+ PROTO_FILES,
156
+ };