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
|
@@ -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
|
-
|
|
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 &&
|
|
124
|
+
if (sampleProducts.length < 5 && productCode) {
|
|
111
125
|
sampleProducts.push({
|
|
112
|
-
code:
|
|
113
|
-
exchange:
|
|
114
|
-
name:
|
|
126
|
+
code: productCode,
|
|
127
|
+
exchange: exchange,
|
|
128
|
+
name: productName?.substring(0, 30)
|
|
115
129
|
});
|
|
116
130
|
}
|
|
117
131
|
|
|
118
|
-
if (!
|
|
132
|
+
if (!productCode || !exchange) return;
|
|
119
133
|
|
|
120
134
|
const validExchanges = ['CME', 'CBOT', 'NYMEX', 'COMEX', 'NYBOT', 'CFE'];
|
|
121
|
-
if (!validExchanges.includes(
|
|
135
|
+
if (!validExchanges.includes(exchange)) return;
|
|
122
136
|
|
|
123
|
-
const name = (
|
|
137
|
+
const name = (productName || '').toLowerCase();
|
|
124
138
|
if (name.includes('option') || name.includes('swap') || name.includes('spread')) return;
|
|
125
139
|
|
|
126
|
-
const key = `${
|
|
140
|
+
const key = `${productCode}:${exchange}`;
|
|
127
141
|
if (!productsToCheck.has(key)) {
|
|
128
142
|
productsToCheck.set(key, {
|
|
129
|
-
productCode:
|
|
130
|
-
productName:
|
|
131
|
-
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
|
};
|