hedgequantx 2.7.11 → 2.7.13
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/app.js +77 -11
- package/src/config/propfirms.js +16 -4
- package/src/menus/connect.js +2 -2
- package/src/pages/accounts.js +33 -6
- package/src/pages/stats/display.js +41 -28
- package/src/pages/stats/metrics.js +11 -3
- package/src/services/rithmic/accounts.js +120 -1
- package/src/services/rithmic/constants.js +4 -0
- package/src/services/rithmic/handlers.js +43 -0
- package/src/services/rithmic/index.js +27 -71
- package/src/services/rithmic/orders.js +97 -67
- package/src/services/rithmic/proto/request_account_rms_info.proto +20 -0
- package/src/services/rithmic/proto/response_account_rms_info.proto +61 -0
- package/src/services/rithmic/proto/response_show_order_history_summary.proto +5 -5
- package/src/services/rithmic/trades.js +334 -0
|
@@ -17,6 +17,7 @@ const {
|
|
|
17
17
|
getPositions,
|
|
18
18
|
} = require('./accounts');
|
|
19
19
|
const { placeOrder, cancelOrder, getOrders, getOrderHistory, getOrderHistoryDates, getTradeHistoryFull, closePosition } = require('./orders');
|
|
20
|
+
const { fillsToRoundTrips, calculateTradeStats } = require('./trades');
|
|
20
21
|
const { getContracts, searchContracts } = require('./contracts');
|
|
21
22
|
const { TIMEOUTS } = require('../../config/settings');
|
|
22
23
|
const { logger } = require('../../utils/logger');
|
|
@@ -242,53 +243,50 @@ class RithmicService extends EventEmitter {
|
|
|
242
243
|
async getUser() { return this.user; }
|
|
243
244
|
|
|
244
245
|
/**
|
|
245
|
-
* Get trade history from Rithmic API
|
|
246
|
+
* Get trade history from Rithmic API as round-trips
|
|
246
247
|
* @param {string} accountId - Optional account filter
|
|
247
248
|
* @param {number} days - Number of days to look back (default 30)
|
|
248
249
|
*/
|
|
249
250
|
async getTradeHistory(accountId, days = 30) {
|
|
250
|
-
// Fetch from API
|
|
251
|
+
// Fetch fills from API
|
|
251
252
|
const result = await getTradeHistoryFull(this, days);
|
|
252
253
|
|
|
253
254
|
if (!result.success) {
|
|
254
255
|
return { success: false, trades: [] };
|
|
255
256
|
}
|
|
256
257
|
|
|
257
|
-
let
|
|
258
|
+
let fills = result.trades || [];
|
|
258
259
|
|
|
259
260
|
// Filter by account if specified
|
|
260
261
|
if (accountId) {
|
|
261
|
-
|
|
262
|
+
fills = fills.filter(t => t.accountId === accountId);
|
|
262
263
|
}
|
|
263
264
|
|
|
264
|
-
//
|
|
265
|
-
|
|
266
|
-
...t,
|
|
267
|
-
timestamp: t.timestamp || this._parseDateTime(t.fillDate, t.fillTime),
|
|
268
|
-
}));
|
|
265
|
+
// Convert fills to round-trips with P&L
|
|
266
|
+
const roundTrips = fillsToRoundTrips(fills);
|
|
269
267
|
|
|
270
|
-
|
|
271
|
-
trades.sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));
|
|
272
|
-
|
|
273
|
-
return { success: true, trades };
|
|
268
|
+
return { success: true, trades: roundTrips };
|
|
274
269
|
}
|
|
275
270
|
|
|
276
271
|
/**
|
|
277
|
-
*
|
|
278
|
-
* @
|
|
272
|
+
* Get raw fills (not matched to round-trips)
|
|
273
|
+
* @param {string} accountId - Optional account filter
|
|
274
|
+
* @param {number} days - Number of days to look back (default 30)
|
|
279
275
|
*/
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
276
|
+
async getRawFills(accountId, days = 30) {
|
|
277
|
+
const result = await getTradeHistoryFull(this, days);
|
|
278
|
+
|
|
279
|
+
if (!result.success) {
|
|
280
|
+
return { success: false, fills: [] };
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
let fills = result.trades || [];
|
|
284
|
+
|
|
285
|
+
if (accountId) {
|
|
286
|
+
fills = fills.filter(t => t.accountId === accountId);
|
|
291
287
|
}
|
|
288
|
+
|
|
289
|
+
return { success: true, fills };
|
|
292
290
|
}
|
|
293
291
|
|
|
294
292
|
/**
|
|
@@ -297,54 +295,12 @@ class RithmicService extends EventEmitter {
|
|
|
297
295
|
async getLifetimeStats(accountId) {
|
|
298
296
|
const { trades } = await this.getTradeHistory(accountId, 365);
|
|
299
297
|
|
|
300
|
-
if (trades.length === 0) {
|
|
298
|
+
if (!trades || trades.length === 0) {
|
|
301
299
|
return { success: true, stats: null };
|
|
302
300
|
}
|
|
303
301
|
|
|
304
|
-
// Calculate stats from
|
|
305
|
-
|
|
306
|
-
let winningTrades = 0;
|
|
307
|
-
let losingTrades = 0;
|
|
308
|
-
let totalProfit = 0;
|
|
309
|
-
let totalLoss = 0;
|
|
310
|
-
let longTrades = 0;
|
|
311
|
-
let shortTrades = 0;
|
|
312
|
-
let totalVolume = 0;
|
|
313
|
-
|
|
314
|
-
// Group fills by basketId to calculate P&L per trade
|
|
315
|
-
const tradeGroups = new Map();
|
|
316
|
-
for (const trade of trades) {
|
|
317
|
-
const key = trade.basketId || trade.id;
|
|
318
|
-
if (!tradeGroups.has(key)) {
|
|
319
|
-
tradeGroups.set(key, []);
|
|
320
|
-
}
|
|
321
|
-
tradeGroups.get(key).push(trade);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
for (const [, fills] of tradeGroups) {
|
|
325
|
-
const firstFill = fills[0];
|
|
326
|
-
totalVolume += fills.reduce((sum, f) => sum + f.size, 0);
|
|
327
|
-
|
|
328
|
-
if (firstFill.side === 1) longTrades++;
|
|
329
|
-
else if (firstFill.side === 2) shortTrades++;
|
|
330
|
-
|
|
331
|
-
// P&L calculation requires entry/exit matching which needs position tracking
|
|
332
|
-
// For now, count trades
|
|
333
|
-
totalTrades = tradeGroups.size;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const stats = {
|
|
337
|
-
totalTrades,
|
|
338
|
-
winningTrades,
|
|
339
|
-
losingTrades,
|
|
340
|
-
winRate: totalTrades > 0 ? ((winningTrades / totalTrades) * 100).toFixed(2) : 0,
|
|
341
|
-
totalProfit,
|
|
342
|
-
totalLoss,
|
|
343
|
-
netPnL: totalProfit - totalLoss,
|
|
344
|
-
longTrades,
|
|
345
|
-
shortTrades,
|
|
346
|
-
totalVolume,
|
|
347
|
-
};
|
|
302
|
+
// Calculate stats from round-trips
|
|
303
|
+
const stats = calculateTradeStats(trades);
|
|
348
304
|
|
|
349
305
|
return { success: true, stats };
|
|
350
306
|
}
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
const { REQ } = require('./constants');
|
|
7
7
|
|
|
8
|
+
// Debug mode
|
|
9
|
+
const DEBUG = process.env.HQX_DEBUG === '1';
|
|
10
|
+
|
|
8
11
|
/**
|
|
9
12
|
* Place order via ORDER_PLANT
|
|
10
13
|
* @param {RithmicService} service - The Rithmic service instance
|
|
@@ -120,14 +123,17 @@ const getOrders = async (service) => {
|
|
|
120
123
|
|
|
121
124
|
/**
|
|
122
125
|
* Get available order history dates
|
|
126
|
+
* RequestShowOrderHistoryDates (318) does NOT require account_id
|
|
123
127
|
* @param {RithmicService} service - The Rithmic service instance
|
|
124
128
|
* @returns {Promise<{success: boolean, dates: string[]}>}
|
|
125
129
|
*/
|
|
126
130
|
const getOrderHistoryDates = async (service) => {
|
|
127
|
-
if (!service.orderConn || !service.loginInfo
|
|
131
|
+
if (!service.orderConn || !service.loginInfo) {
|
|
128
132
|
return { success: false, dates: [] };
|
|
129
133
|
}
|
|
130
134
|
|
|
135
|
+
const { proto } = require('./protobuf');
|
|
136
|
+
|
|
131
137
|
return new Promise((resolve) => {
|
|
132
138
|
const dates = [];
|
|
133
139
|
const timeout = setTimeout(() => {
|
|
@@ -136,19 +142,30 @@ const getOrderHistoryDates = async (service) => {
|
|
|
136
142
|
}, 5000);
|
|
137
143
|
|
|
138
144
|
const handler = (msg) => {
|
|
145
|
+
// msg contains { templateId, data }
|
|
139
146
|
if (msg.templateId === 319) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
147
|
+
try {
|
|
148
|
+
const res = proto.decode('ResponseShowOrderHistoryDates', msg.data);
|
|
149
|
+
DEBUG && console.log('[OrderHistory] 319 response:', JSON.stringify(res));
|
|
150
|
+
|
|
151
|
+
// Dates come as repeated string field
|
|
152
|
+
if (res.date) {
|
|
153
|
+
const dateList = Array.isArray(res.date) ? res.date : [res.date];
|
|
154
|
+
for (const d of dateList) {
|
|
155
|
+
if (d && !dates.includes(d)) {
|
|
156
|
+
dates.push(d);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
146
159
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
160
|
+
|
|
161
|
+
// Check for completion (rpCode = '0')
|
|
162
|
+
if (res.rpCode && res.rpCode.length > 0 && res.rpCode[0] === '0') {
|
|
163
|
+
clearTimeout(timeout);
|
|
164
|
+
service.orderConn.removeListener('message', handler);
|
|
165
|
+
resolve({ success: true, dates });
|
|
166
|
+
}
|
|
167
|
+
} catch (e) {
|
|
168
|
+
DEBUG && console.log('[OrderHistory] Error decoding 319:', e.message);
|
|
152
169
|
}
|
|
153
170
|
}
|
|
154
171
|
};
|
|
@@ -156,16 +173,12 @@ const getOrderHistoryDates = async (service) => {
|
|
|
156
173
|
service.orderConn.on('message', handler);
|
|
157
174
|
|
|
158
175
|
try {
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
ibId: acc.ibId || service.loginInfo.ibId,
|
|
166
|
-
accountId: acc.accountId,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
176
|
+
// Request 318 does NOT need account_id - just template_id and user_msg
|
|
177
|
+
service.orderConn.send('RequestShowOrderHistoryDates', {
|
|
178
|
+
templateId: REQ.SHOW_ORDER_HISTORY_DATES,
|
|
179
|
+
userMsg: ['HQX'],
|
|
180
|
+
});
|
|
181
|
+
DEBUG && console.log('[OrderHistory] Sent request 318 (ShowOrderHistoryDates)');
|
|
169
182
|
} catch (e) {
|
|
170
183
|
clearTimeout(timeout);
|
|
171
184
|
service.orderConn.removeListener('message', handler);
|
|
@@ -176,86 +189,103 @@ const getOrderHistoryDates = async (service) => {
|
|
|
176
189
|
|
|
177
190
|
/**
|
|
178
191
|
* Get order history for a specific date using show_order_history_summary
|
|
192
|
+
* RequestShowOrderHistorySummary (324) returns ExchangeOrderNotification (352) with is_snapshot=true
|
|
179
193
|
* @param {RithmicService} service - The Rithmic service instance
|
|
180
194
|
* @param {string} date - Date in YYYYMMDD format
|
|
181
195
|
* @returns {Promise<{success: boolean, orders: Array}>}
|
|
182
196
|
*/
|
|
183
197
|
const getOrderHistory = async (service, date) => {
|
|
184
|
-
if (!service.orderConn || !service.loginInfo) {
|
|
198
|
+
if (!service.orderConn || !service.loginInfo || service.accounts.length === 0) {
|
|
185
199
|
return { success: true, orders: [] };
|
|
186
200
|
}
|
|
187
201
|
|
|
202
|
+
const { proto } = require('./protobuf');
|
|
188
203
|
const dateStr = date || new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
189
204
|
|
|
190
205
|
return new Promise((resolve) => {
|
|
191
206
|
const orders = [];
|
|
192
|
-
let
|
|
207
|
+
let receivedCount = 0;
|
|
208
|
+
const expectedAccounts = service.accounts.length;
|
|
209
|
+
const requestId = `HQX-${Date.now()}`;
|
|
193
210
|
|
|
194
211
|
const timeout = setTimeout(() => {
|
|
195
|
-
service.removeListener('
|
|
212
|
+
service.orderConn.removeListener('message', handler);
|
|
213
|
+
DEBUG && console.log(`[OrderHistory] Timeout. Got ${orders.length} orders`);
|
|
196
214
|
resolve({ success: true, orders });
|
|
197
215
|
}, 10000);
|
|
198
216
|
|
|
199
|
-
const handler = (
|
|
200
|
-
// ExchangeOrderNotification with
|
|
201
|
-
if (
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
217
|
+
const handler = (msg) => {
|
|
218
|
+
// Response comes as template 352 (ExchangeOrderNotification) with is_snapshot=true
|
|
219
|
+
if (msg.templateId === 352) {
|
|
220
|
+
try {
|
|
221
|
+
const notification = proto.decode('ExchangeOrderNotification', msg.data);
|
|
222
|
+
|
|
223
|
+
// Only process snapshot data (historical orders)
|
|
224
|
+
if (notification.isSnapshot) {
|
|
225
|
+
DEBUG && console.log('[OrderHistory] 352 snapshot:', notification.symbol, notification.notifyType);
|
|
226
|
+
|
|
227
|
+
if (notification.symbol) {
|
|
228
|
+
orders.push({
|
|
229
|
+
id: notification.fillId || notification.basketId || `${Date.now()}-${orders.length}`,
|
|
230
|
+
accountId: notification.accountId,
|
|
231
|
+
symbol: notification.symbol,
|
|
232
|
+
exchange: notification.exchange || 'CME',
|
|
233
|
+
side: notification.transactionType, // 1=BUY, 2=SELL
|
|
234
|
+
quantity: parseInt(notification.quantity) || 0,
|
|
235
|
+
price: parseFloat(notification.price) || 0,
|
|
236
|
+
fillPrice: parseFloat(notification.fillPrice) || 0,
|
|
237
|
+
fillSize: parseInt(notification.fillSize) || 0,
|
|
238
|
+
fillTime: notification.fillTime,
|
|
239
|
+
fillDate: notification.fillDate,
|
|
240
|
+
avgFillPrice: parseFloat(notification.avgFillPrice) || 0,
|
|
241
|
+
totalFillSize: parseInt(notification.totalFillSize) || 0,
|
|
242
|
+
status: notification.status,
|
|
243
|
+
notifyType: notification.notifyType,
|
|
244
|
+
isSnapshot: true,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
} catch (e) {
|
|
249
|
+
DEBUG && console.log('[OrderHistory] Error decoding 352:', e.message);
|
|
250
|
+
}
|
|
222
251
|
}
|
|
223
252
|
|
|
224
|
-
//
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
253
|
+
// Template 325 signals completion of order history summary
|
|
254
|
+
if (msg.templateId === 325) {
|
|
255
|
+
try {
|
|
256
|
+
const res = proto.decode('ResponseShowOrderHistorySummary', msg.data);
|
|
257
|
+
DEBUG && console.log('[OrderHistory] 325 response:', JSON.stringify(res));
|
|
258
|
+
receivedCount++;
|
|
259
|
+
|
|
260
|
+
if (receivedCount >= expectedAccounts) {
|
|
261
|
+
clearTimeout(timeout);
|
|
262
|
+
service.orderConn.removeListener('message', handler);
|
|
263
|
+
resolve({ success: true, orders });
|
|
264
|
+
}
|
|
265
|
+
} catch (e) {
|
|
266
|
+
DEBUG && console.log('[OrderHistory] Error decoding 325:', e.message);
|
|
267
|
+
}
|
|
230
268
|
}
|
|
231
269
|
};
|
|
232
270
|
|
|
233
|
-
service.on('
|
|
271
|
+
service.orderConn.on('message', handler);
|
|
234
272
|
|
|
235
273
|
try {
|
|
236
|
-
//
|
|
274
|
+
// Send request 324 for each account
|
|
237
275
|
for (const acc of service.accounts) {
|
|
276
|
+
DEBUG && console.log(`[OrderHistory] Sending 324 for account ${acc.accountId}, date ${dateStr}`);
|
|
238
277
|
service.orderConn.send('RequestShowOrderHistorySummary', {
|
|
239
278
|
templateId: REQ.SHOW_ORDER_HISTORY,
|
|
240
|
-
userMsg: [
|
|
279
|
+
userMsg: [requestId],
|
|
241
280
|
fcmId: acc.fcmId || service.loginInfo.fcmId,
|
|
242
281
|
ibId: acc.ibId || service.loginInfo.ibId,
|
|
243
282
|
accountId: acc.accountId,
|
|
244
283
|
date: dateStr,
|
|
245
284
|
});
|
|
246
285
|
}
|
|
247
|
-
|
|
248
|
-
// Wait for responses
|
|
249
|
-
setTimeout(() => {
|
|
250
|
-
if (!receivedEnd) {
|
|
251
|
-
clearTimeout(timeout);
|
|
252
|
-
service.removeListener('exchangeNotification', handler);
|
|
253
|
-
resolve({ success: true, orders });
|
|
254
|
-
}
|
|
255
|
-
}, 5000);
|
|
256
286
|
} catch (e) {
|
|
257
287
|
clearTimeout(timeout);
|
|
258
|
-
service.removeListener('
|
|
288
|
+
service.orderConn.removeListener('message', handler);
|
|
259
289
|
resolve({ success: false, error: e.message, orders: [] });
|
|
260
290
|
}
|
|
261
291
|
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
package rti;
|
|
3
|
+
|
|
4
|
+
message RequestAccountRmsInfo
|
|
5
|
+
{
|
|
6
|
+
// PB_OFFSET = 100000, is the offset added for each MNM field id
|
|
7
|
+
|
|
8
|
+
enum UserType {
|
|
9
|
+
USER_TYPE_FCM = 1;
|
|
10
|
+
USER_TYPE_IB = 2;
|
|
11
|
+
USER_TYPE_TRADER = 3;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
required int32 template_id = 154467; // PB_OFFSET + MNM_TEMPLATE_ID
|
|
15
|
+
repeated string user_msg = 132760; // PB_OFFSET + MNM_USER_MSG
|
|
16
|
+
|
|
17
|
+
optional string fcm_id = 154013; // PB_OFFSET + MNM_FCM_ID
|
|
18
|
+
optional string ib_id = 154014; // PB_OFFSET + MNM_IB_ID
|
|
19
|
+
optional UserType user_type = 154036; // PB_OFFSET + MNM_USER_TYPE
|
|
20
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
|
|
2
|
+
package rti;
|
|
3
|
+
|
|
4
|
+
message ResponseAccountRmsInfo
|
|
5
|
+
{
|
|
6
|
+
// PB_OFFSET = 100000, is the offset added for each MNM field id
|
|
7
|
+
|
|
8
|
+
// below enum is just for reference only, not used in this message
|
|
9
|
+
enum PresenceBits {
|
|
10
|
+
BUY_LIMIT = 1;
|
|
11
|
+
SELL_LIMIT = 2;
|
|
12
|
+
LOSS_LIMIT = 4;
|
|
13
|
+
MAX_ORDER_QUANTITY = 8;
|
|
14
|
+
MIN_ACCOUNT_BALANCE = 16;
|
|
15
|
+
MIN_MARGIN_BALANCE = 32;
|
|
16
|
+
ALGORITHM = 64;
|
|
17
|
+
STATUS = 128;
|
|
18
|
+
CURRENCY = 256;
|
|
19
|
+
DEFAULT_COMMISSION = 512;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
enum AutoLiquidateFlag {
|
|
23
|
+
ENABLED = 1;
|
|
24
|
+
DISABLED = 2;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
required int32 template_id = 154467; // PB_OFFSET + MNM_TEMPLATE_ID
|
|
29
|
+
repeated string user_msg = 132760; // PB_OFFSET + MNM_USER_MSG
|
|
30
|
+
repeated string rq_handler_rp_code = 132764; // PB_OFFSET + MNM_REQUEST_HANDLER_RESPONSE_CODE
|
|
31
|
+
repeated string rp_code = 132766; // PB_OFFSET + MNM_RESPONSE_CODE
|
|
32
|
+
|
|
33
|
+
optional uint32 presence_bits = 153622; // PB_OFFSET + MNM_FIELD_PRESENCE_BITS
|
|
34
|
+
|
|
35
|
+
optional string fcm_id = 154013; // PB_OFFSET + MNM_FCM_ID
|
|
36
|
+
optional string ib_id = 154014; // PB_OFFSET + MNM_IB_ID
|
|
37
|
+
optional string account_id = 154008; // PB_OFFSET + MNM_ACCOUNT_ID
|
|
38
|
+
|
|
39
|
+
optional string currency = 154383; // PB_OFFSET + MNM_ACCOUNT_CURRENCY
|
|
40
|
+
optional string status = 154003; // PB_OFFSET + MNM_ACCOUNT_STATUS
|
|
41
|
+
optional string algorithm = 150142; // PB_OFFSET + MNM_ALGORITHM
|
|
42
|
+
|
|
43
|
+
optional string auto_liquidate_criteria = 131036; // PB_OFFSET + MNM_ACCOUNT_AUTO_LIQUIDATE_CRITERIA
|
|
44
|
+
|
|
45
|
+
optional AutoLiquidateFlag auto_liquidate = 131035; // PB_OFFSET + MNM_ACCOUNT_AUTO_LIQUIDATE
|
|
46
|
+
optional AutoLiquidateFlag disable_on_auto_liquidate = 131038; // PB_OFFSET + MNM_DISABLE_ON_AUTO_LIQUIDATE_FLAG
|
|
47
|
+
|
|
48
|
+
optional double auto_liquidate_threshold = 131037; // PB_OFFSET + MNM_ACCOUNT_AUTO_LIQUIDATE_THRESHOLD
|
|
49
|
+
optional double auto_liquidate_max_min_account_balance = 131039; // PB_OFFSET + MNM_AUTO_LIQ_MAX_MIN_ACCOUNT_BALANCE
|
|
50
|
+
|
|
51
|
+
optional double loss_limit = 154019; // PB_OFFSET + MNM_LOSS_LIMIT
|
|
52
|
+
optional double min_account_balance = 156968; // PB_OFFSET + MNM_MINIMUM_ACCOUNT_BALANCE
|
|
53
|
+
optional double min_margin_balance = 156976; // PB_OFFSET + MNM_MIN_MARGIN_BALANCE
|
|
54
|
+
optional double default_commission = 153368; // PB_OFFSET + MNM_DEFAULT_COMMISSION
|
|
55
|
+
|
|
56
|
+
optional int32 buy_limit = 154009; // PB_OFFSET + MNM_BUY_LIMIT
|
|
57
|
+
optional int32 max_order_quantity = 110105; // PB_OFFSET + MNM_MAX_LIMIT_QUAN
|
|
58
|
+
optional int32 sell_limit = 154035; // PB_OFFSET + MNM_SELL_LIMIT
|
|
59
|
+
|
|
60
|
+
optional bool check_min_account_balance = 156972; // PB_OFFSET + MNM_CHECK_MIN_ACCT_BALANCE
|
|
61
|
+
}
|
|
@@ -3,9 +3,9 @@ package rti;
|
|
|
3
3
|
|
|
4
4
|
message ResponseShowOrderHistorySummary
|
|
5
5
|
{
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
repeated string
|
|
10
|
-
|
|
6
|
+
// Field IDs from rundef/async_rithmic (verified Jan 2026)
|
|
7
|
+
// Same field IDs as other messages (PB_OFFSET = 100000)
|
|
8
|
+
optional int32 template_id = 154467;
|
|
9
|
+
repeated string user_msg = 132760;
|
|
10
|
+
repeated string rp_code = 132766;
|
|
11
11
|
}
|