hedgequantx 2.9.174 → 2.9.175

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "2.9.174",
3
+ "version": "2.9.175",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -5,7 +5,7 @@
5
5
  * NO FAKE DATA - Only real values from Rithmic API
6
6
  */
7
7
 
8
- const { decodeFrontMonthContract } = require('./protobuf');
8
+ const { proto, decodeFrontMonthContract } = require('./protobuf');
9
9
  const { TIMEOUTS, CACHE } = require('../../config/settings');
10
10
  const { logger } = require('../../utils/logger');
11
11
  const { getContractDescription, getTickSize } = require('../../config/constants');
@@ -104,31 +104,45 @@ const fetchAllFrontMonths = (service) => {
104
104
  if (msg.templateId !== 112) return;
105
105
  productMsgCount++;
106
106
 
107
- const decoded = decodeProductCodes(msg.data);
107
+ // Use official protobuf decoder instead of manual parsing
108
+ let decoded;
109
+ try {
110
+ decoded = proto.decode('ResponseProductCodes', msg.data);
111
+ } catch (e) {
112
+ // Log first decode error
113
+ if (sampleProducts.length === 0) {
114
+ brokerLog('Decode error', { error: e.message });
115
+ }
116
+ return;
117
+ }
118
+
119
+ const productCode = decoded.productCode;
120
+ const exchange = decoded.exchange;
121
+ const productName = decoded.productName;
108
122
 
109
123
  // Log first 5 decoded products
110
- if (sampleProducts.length < 5 && decoded.productCode) {
124
+ if (sampleProducts.length < 5 && productCode) {
111
125
  sampleProducts.push({
112
- code: decoded.productCode,
113
- exchange: decoded.exchange,
114
- name: decoded.productName?.substring(0, 30)
126
+ code: productCode,
127
+ exchange: exchange,
128
+ name: productName?.substring(0, 30)
115
129
  });
116
130
  }
117
131
 
118
- if (!decoded.productCode || !decoded.exchange) return;
132
+ if (!productCode || !exchange) return;
119
133
 
120
134
  const validExchanges = ['CME', 'CBOT', 'NYMEX', 'COMEX', 'NYBOT', 'CFE'];
121
- if (!validExchanges.includes(decoded.exchange)) return;
135
+ if (!validExchanges.includes(exchange)) return;
122
136
 
123
- const name = (decoded.productName || '').toLowerCase();
137
+ const name = (productName || '').toLowerCase();
124
138
  if (name.includes('option') || name.includes('swap') || name.includes('spread')) return;
125
139
 
126
- const key = `${decoded.productCode}:${decoded.exchange}`;
140
+ const key = `${productCode}:${exchange}`;
127
141
  if (!productsToCheck.has(key)) {
128
142
  productsToCheck.set(key, {
129
- productCode: decoded.productCode,
130
- productName: decoded.productName || decoded.productCode,
131
- exchange: decoded.exchange,
143
+ productCode: productCode,
144
+ productName: productName || productCode,
145
+ exchange: exchange,
132
146
  });
133
147
  }
134
148
  };
@@ -279,66 +293,8 @@ const fetchAllFrontMonths = (service) => {
279
293
  });
280
294
  };
281
295
 
282
- /**
283
- * Decode ProductCodes response
284
- * @param {Buffer} buffer - Protobuf buffer (with 4-byte length prefix)
285
- * @returns {Object} Decoded product data
286
- */
287
- const decodeProductCodes = (buffer) => {
288
- // Skip 4-byte length prefix
289
- const data = buffer.length > 4 ? buffer.slice(4) : buffer;
290
-
291
- const result = {};
292
- let offset = 0;
293
-
294
- const readVarint = (buf, off) => {
295
- let value = 0;
296
- let shift = 0;
297
- while (off < buf.length) {
298
- const byte = buf[off++];
299
- value |= (byte & 0x7F) << shift;
300
- if (!(byte & 0x80)) break;
301
- shift += 7;
302
- }
303
- return [value, off];
304
- };
305
-
306
- const readString = (buf, off) => {
307
- const [len, newOff] = readVarint(buf, off);
308
- return [buf.slice(newOff, newOff + len).toString('utf8'), newOff + len];
309
- };
310
-
311
- while (offset < data.length) {
312
- try {
313
- const [tag, tagOff] = readVarint(data, offset);
314
- const wireType = tag & 0x7;
315
- const fieldNumber = tag >>> 3;
316
- offset = tagOff;
317
-
318
- if (wireType === 0) {
319
- const [, newOff] = readVarint(data, offset);
320
- offset = newOff;
321
- } else if (wireType === 2) {
322
- const [val, newOff] = readString(data, offset);
323
- offset = newOff;
324
- // Field IDs from Rithmic API (response_product_codes.proto)
325
- if (fieldNumber === 110101) result.exchange = val; // exchange
326
- if (fieldNumber === 110102) result.productCode = val; // product_code (ES, MES, MNQ, etc.)
327
- if (fieldNumber === 110103) result.productName = val; // product_name
328
- } else {
329
- break;
330
- }
331
- } catch {
332
- break;
333
- }
334
- }
335
-
336
- return result;
337
- };
338
-
339
296
  module.exports = {
340
297
  getContracts,
341
298
  searchContracts,
342
299
  fetchAllFrontMonths,
343
- decodeProductCodes,
344
300
  };