hedgequantx 2.9.91 → 2.9.93
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/dist/lib/data.jsc
CHANGED
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/src/lib/data.js
CHANGED
|
@@ -171,11 +171,11 @@ class MarketDataFeed extends EventEmitter {
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
/**
|
|
174
|
-
* Get historical bars from HISTORY_PLANT
|
|
175
|
-
* @param {string} symbol - Symbol (e.g., '
|
|
174
|
+
* Get historical tick bars from HISTORY_PLANT
|
|
175
|
+
* @param {string} symbol - Symbol (e.g., 'MNQH6')
|
|
176
176
|
* @param {string} exchange - Exchange (default: 'CME')
|
|
177
177
|
* @param {number} barCount - Number of bars to fetch (default: 30)
|
|
178
|
-
* @returns {Promise<Array>} Array of bar objects {timestamp, open, high, low, close, volume}
|
|
178
|
+
* @returns {Promise<Array>} Array of tick bar objects {timestamp, open, high, low, close, volume}
|
|
179
179
|
*/
|
|
180
180
|
async getHistoricalBars(symbol, exchange = 'CME', barCount = 30) {
|
|
181
181
|
if (!this.credentials) {
|
|
@@ -194,36 +194,48 @@ class MarketDataFeed extends EventEmitter {
|
|
|
194
194
|
|
|
195
195
|
return new Promise((resolve, reject) => {
|
|
196
196
|
const bars = [];
|
|
197
|
+
let isComplete = false;
|
|
198
|
+
|
|
197
199
|
const timeout = setTimeout(() => {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
if (!isComplete) {
|
|
201
|
+
historyConn.disconnect();
|
|
202
|
+
// Return what we have even on timeout
|
|
200
203
|
resolve(bars);
|
|
201
|
-
} else {
|
|
202
|
-
reject(new Error('History request timeout'));
|
|
203
204
|
}
|
|
204
|
-
},
|
|
205
|
+
}, 15000);
|
|
205
206
|
|
|
206
|
-
// Listen for bar data
|
|
207
|
+
// Listen for bar data (template 207)
|
|
207
208
|
historyConn.on('message', (msg) => {
|
|
208
209
|
if (msg.templateId === RES.TICK_BAR_REPLAY) {
|
|
209
210
|
try {
|
|
210
211
|
const data = proto.decode('ResponseTickBarReplay', msg.data);
|
|
211
212
|
const barObj = data.toJSON ? data.toJSON() : data;
|
|
212
213
|
|
|
213
|
-
|
|
214
|
+
// Check for error response
|
|
215
|
+
if (barObj.rpCode && barObj.rpCode[0] !== '0') {
|
|
216
|
+
clearTimeout(timeout);
|
|
217
|
+
isComplete = true;
|
|
218
|
+
historyConn.disconnect();
|
|
219
|
+
reject(new Error(`History request failed: ${barObj.rpCode.join(' - ')}`));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Add bar if it has price data (OHLCV format)
|
|
224
|
+
if (barObj.closePrice !== undefined) {
|
|
214
225
|
bars.push({
|
|
215
|
-
timestamp: barObj.
|
|
216
|
-
open: Number(barObj.openPrice),
|
|
217
|
-
high: Number(barObj.highPrice),
|
|
218
|
-
low: Number(barObj.lowPrice),
|
|
226
|
+
timestamp: barObj.ssboe ? barObj.ssboe * 1000 : Date.now(),
|
|
227
|
+
open: Number(barObj.openPrice) || Number(barObj.closePrice),
|
|
228
|
+
high: Number(barObj.highPrice) || Number(barObj.closePrice),
|
|
229
|
+
low: Number(barObj.lowPrice) || Number(barObj.closePrice),
|
|
219
230
|
close: Number(barObj.closePrice),
|
|
220
|
-
volume: Number(barObj.volume) ||
|
|
231
|
+
volume: Number(barObj.volume) || 1,
|
|
221
232
|
});
|
|
222
233
|
}
|
|
223
234
|
|
|
224
|
-
// Check if this is the
|
|
225
|
-
if (barObj.rpCode && barObj.rpCode
|
|
235
|
+
// Check if this is the final response (rpCode = ['0'])
|
|
236
|
+
if (barObj.rpCode && barObj.rpCode[0] === '0' && barObj.closePrice === undefined) {
|
|
226
237
|
clearTimeout(timeout);
|
|
238
|
+
isComplete = true;
|
|
227
239
|
historyConn.disconnect();
|
|
228
240
|
resolve(bars);
|
|
229
241
|
}
|
|
@@ -235,17 +247,25 @@ class MarketDataFeed extends EventEmitter {
|
|
|
235
247
|
|
|
236
248
|
// Login to HISTORY_PLANT
|
|
237
249
|
historyConn.once('loggedIn', () => {
|
|
238
|
-
// Request tick bar replay
|
|
250
|
+
// Request tick bar replay - limited count, most recent bars
|
|
251
|
+
// startIndex/finishIndex are required, but userMaxCount + direction=LAST
|
|
252
|
+
// will return only the most recent barCount bars
|
|
253
|
+
const now = Math.floor(Date.now() / 1000);
|
|
254
|
+
const startTime = now - (24 * 60 * 60); // 24 hours ago (wide range)
|
|
255
|
+
|
|
239
256
|
historyConn.send('RequestTickBarReplay', {
|
|
240
|
-
templateId: REQ.TICK_BAR_REPLAY,
|
|
257
|
+
templateId: REQ.TICK_BAR_REPLAY, // 206
|
|
258
|
+
userMsg: ['hqx-history'],
|
|
241
259
|
symbol: symbol,
|
|
242
260
|
exchange: exchange,
|
|
243
|
-
barType: 1,
|
|
244
|
-
barSubType: 1,
|
|
245
|
-
barTypeSpecifier: '1',
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
261
|
+
barType: 1, // TICK_BAR
|
|
262
|
+
barSubType: 1, // REGULAR
|
|
263
|
+
barTypeSpecifier: '1', // 1 tick per bar
|
|
264
|
+
startIndex: startTime, // Required by Rithmic
|
|
265
|
+
finishIndex: now, // Required by Rithmic
|
|
266
|
+
userMaxCount: barCount, // Limit to barCount bars
|
|
267
|
+
direction: 2, // LAST (most recent bars first)
|
|
268
|
+
timeOrder: 1, // FORWARDS (return in chronological order)
|
|
249
269
|
});
|
|
250
270
|
});
|
|
251
271
|
|
|
@@ -413,6 +413,7 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
413
413
|
|
|
414
414
|
// Preload historical bars for HQX-2B strategy only (bar-based strategy)
|
|
415
415
|
// Note: HISTORY_PLANT may not be available on all accounts (e.g., paper trading)
|
|
416
|
+
ui.addLog('debug', `Strategy: ${strategyId}, preloadBars: ${typeof strategy.preloadBars}`);
|
|
416
417
|
if (strategyId === 'hqx-2b' && strategy.preloadBars) {
|
|
417
418
|
try {
|
|
418
419
|
ui.addLog('system', 'Loading historical bars...');
|
|
@@ -425,7 +426,7 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
425
426
|
}
|
|
426
427
|
} catch (histErr) {
|
|
427
428
|
// HISTORY_PLANT not available (common on paper accounts)
|
|
428
|
-
ui.addLog('system',
|
|
429
|
+
ui.addLog('system', `Historical data error: ${histErr.message}`);
|
|
429
430
|
}
|
|
430
431
|
}
|
|
431
432
|
} catch (e) {
|
|
@@ -60,7 +60,7 @@ const REQ = {
|
|
|
60
60
|
MARKET_DATA: 100,
|
|
61
61
|
PRODUCT_CODES: 111,
|
|
62
62
|
FRONT_MONTH_CONTRACT: 113,
|
|
63
|
-
TICK_BAR_REPLAY:
|
|
63
|
+
TICK_BAR_REPLAY: 206, // History plant - request tick bar replay
|
|
64
64
|
LOGIN_INFO: 300,
|
|
65
65
|
ACCOUNT_LIST: 302,
|
|
66
66
|
ACCOUNT_RMS: 304,
|
|
@@ -89,7 +89,7 @@ const RES = {
|
|
|
89
89
|
MARKET_DATA: 101,
|
|
90
90
|
PRODUCT_CODES: 112,
|
|
91
91
|
FRONT_MONTH_CONTRACT: 114,
|
|
92
|
-
TICK_BAR_REPLAY:
|
|
92
|
+
TICK_BAR_REPLAY: 207, // History plant - tick bar replay response
|
|
93
93
|
LOGIN_INFO: 301,
|
|
94
94
|
ACCOUNT_LIST: 303,
|
|
95
95
|
ACCOUNT_RMS: 305,
|
|
@@ -42,7 +42,7 @@ const PROPFIRM_CONFIGS = {
|
|
|
42
42
|
lucidtrading: { name: 'Lucid Trading', systemName: RITHMIC_SYSTEMS.LUCID_TRADING, gateway: RITHMIC_ENDPOINTS.CHICAGO },
|
|
43
43
|
thrivetrading: { name: 'Thrive Trading', systemName: RITHMIC_SYSTEMS.THRIVE_TRADING, gateway: RITHMIC_ENDPOINTS.CHICAGO },
|
|
44
44
|
legendstrading: { name: 'Legends Trading', systemName: RITHMIC_SYSTEMS.LEGENDS_TRADING, gateway: RITHMIC_ENDPOINTS.CHICAGO },
|
|
45
|
-
// Rithmic Paper Trading - uses CHICAGO endpoint
|
|
45
|
+
// Rithmic Paper Trading - uses CHICAGO endpoint
|
|
46
46
|
rithmic_paper: { name: 'Rithmic Paper Trading', systemName: RITHMIC_SYSTEMS.PAPER, gateway: RITHMIC_ENDPOINTS.CHICAGO },
|
|
47
47
|
};
|
|
48
48
|
|