hedgequantx 2.9.88 → 2.9.90
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/m/hqx-2b.js
CHANGED
|
@@ -736,6 +736,47 @@ var require_core = __commonJS({
|
|
|
736
736
|
message: `[HQX-2B] Reset state for ${contractId}`
|
|
737
737
|
});
|
|
738
738
|
}
|
|
739
|
+
/**
|
|
740
|
+
* Preload historical bars to warm up the strategy
|
|
741
|
+
* @param {string} contractId - Contract ID
|
|
742
|
+
* @param {Array} bars - Array of bars {timestamp, open, high, low, close, volume}
|
|
743
|
+
*/
|
|
744
|
+
preloadBars(contractId, bars) {
|
|
745
|
+
if (!bars || bars.length === 0) {
|
|
746
|
+
this.emit("log", {
|
|
747
|
+
type: "debug",
|
|
748
|
+
message: `[HQX-2B] No historical bars to preload`
|
|
749
|
+
});
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
if (!this.barHistory.has(contractId)) {
|
|
753
|
+
this.initialize(contractId);
|
|
754
|
+
}
|
|
755
|
+
const sortedBars = [...bars].sort((a, b) => a.timestamp - b.timestamp);
|
|
756
|
+
this.emit("log", {
|
|
757
|
+
type: "info",
|
|
758
|
+
message: `[HQX-2B] Preloading ${sortedBars.length} historical bars...`
|
|
759
|
+
});
|
|
760
|
+
let signalCount = 0;
|
|
761
|
+
for (const bar of sortedBars) {
|
|
762
|
+
const signal = this.processBar(contractId, bar);
|
|
763
|
+
if (signal) signalCount++;
|
|
764
|
+
}
|
|
765
|
+
const history = this.barHistory.get(contractId) || [];
|
|
766
|
+
const swings = this.swingPoints.get(contractId) || [];
|
|
767
|
+
const zones = this.liquidityZones.get(contractId) || [];
|
|
768
|
+
this.emit("log", {
|
|
769
|
+
type: "info",
|
|
770
|
+
message: `[HQX-2B] Preload complete: ${history.length} bars, ${swings.length} swings, ${zones.length} zones`
|
|
771
|
+
});
|
|
772
|
+
if (signalCount > 0) {
|
|
773
|
+
this.emit("log", {
|
|
774
|
+
type: "debug",
|
|
775
|
+
message: `[HQX-2B] ${signalCount} historical signals detected (ignored)`
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
this.lastSignalTime = 0;
|
|
779
|
+
}
|
|
739
780
|
};
|
|
740
781
|
module2.exports = { HQX2BLiquiditySweep: HQX2BLiquiditySweep2 };
|
|
741
782
|
}
|
package/package.json
CHANGED
package/src/lib/data.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
const EventEmitter = require('events');
|
|
17
17
|
const { RithmicConnection } = require('../services/rithmic/connection');
|
|
18
18
|
const { proto } = require('../services/rithmic/protobuf');
|
|
19
|
-
const { REQ, RES, STREAM, RITHMIC_ENDPOINTS, RITHMIC_SYSTEMS } = require('../services/rithmic/constants');
|
|
19
|
+
const { REQ, RES, STREAM, RITHMIC_ENDPOINTS, RITHMIC_SYSTEMS, INFRA_TYPE } = require('../services/rithmic/constants');
|
|
20
20
|
|
|
21
21
|
// =============================================================================
|
|
22
22
|
// MARKET DATA FEED CLASS (Rithmic TICKER_PLANT)
|
|
@@ -170,6 +170,99 @@ class MarketDataFeed extends EventEmitter {
|
|
|
170
170
|
this.emit('disconnected');
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Get historical bars from HISTORY_PLANT
|
|
175
|
+
* @param {string} symbol - Symbol (e.g., 'MNQH5')
|
|
176
|
+
* @param {string} exchange - Exchange (default: 'CME')
|
|
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}
|
|
179
|
+
*/
|
|
180
|
+
async getHistoricalBars(symbol, exchange = 'CME', barCount = 30) {
|
|
181
|
+
if (!this.credentials) {
|
|
182
|
+
throw new Error('Not connected - call connect() first');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Create a separate connection to HISTORY_PLANT
|
|
186
|
+
const historyConn = new RithmicConnection();
|
|
187
|
+
const historyConfig = {
|
|
188
|
+
...this.config,
|
|
189
|
+
infraType: INFRA_TYPE.HISTORY_PLANT,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
await historyConn.connect(historyConfig);
|
|
194
|
+
|
|
195
|
+
return new Promise((resolve, reject) => {
|
|
196
|
+
const bars = [];
|
|
197
|
+
const timeout = setTimeout(() => {
|
|
198
|
+
historyConn.disconnect();
|
|
199
|
+
if (bars.length > 0) {
|
|
200
|
+
resolve(bars);
|
|
201
|
+
} else {
|
|
202
|
+
reject(new Error('History request timeout'));
|
|
203
|
+
}
|
|
204
|
+
}, 10000);
|
|
205
|
+
|
|
206
|
+
// Listen for bar data
|
|
207
|
+
historyConn.on('message', (msg) => {
|
|
208
|
+
if (msg.templateId === RES.TICK_BAR_REPLAY) {
|
|
209
|
+
try {
|
|
210
|
+
const data = proto.decode('ResponseTickBarReplay', msg.data);
|
|
211
|
+
const barObj = data.toJSON ? data.toJSON() : data;
|
|
212
|
+
|
|
213
|
+
if (barObj.openPrice !== undefined) {
|
|
214
|
+
bars.push({
|
|
215
|
+
timestamp: barObj.dataBarSsboe ? barObj.dataBarSsboe[0] * 1000 : Date.now(),
|
|
216
|
+
open: Number(barObj.openPrice),
|
|
217
|
+
high: Number(barObj.highPrice),
|
|
218
|
+
low: Number(barObj.lowPrice),
|
|
219
|
+
close: Number(barObj.closePrice),
|
|
220
|
+
volume: Number(barObj.volume) || 0,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Check if this is the last bar (rpCode contains "end" or empty)
|
|
225
|
+
if (barObj.rpCode && barObj.rpCode.includes('0')) {
|
|
226
|
+
clearTimeout(timeout);
|
|
227
|
+
historyConn.disconnect();
|
|
228
|
+
resolve(bars);
|
|
229
|
+
}
|
|
230
|
+
} catch (e) {
|
|
231
|
+
this.emit('debug', `History decode error: ${e.message}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Login to HISTORY_PLANT
|
|
237
|
+
historyConn.once('loggedIn', () => {
|
|
238
|
+
// Request tick bar replay (1-minute bars)
|
|
239
|
+
historyConn.send('RequestTickBarReplay', {
|
|
240
|
+
templateId: REQ.TICK_BAR_REPLAY,
|
|
241
|
+
symbol: symbol,
|
|
242
|
+
exchange: exchange,
|
|
243
|
+
barType: 1, // TICK_BAR
|
|
244
|
+
barSubType: 1, // REGULAR
|
|
245
|
+
barTypeSpecifier: '1', // 1-minute
|
|
246
|
+
userMaxCount: barCount,
|
|
247
|
+
direction: 2, // LAST (most recent)
|
|
248
|
+
timeOrder: 2, // BACKWARDS
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
historyConn.once('loginFailed', (data) => {
|
|
253
|
+
clearTimeout(timeout);
|
|
254
|
+
historyConn.disconnect();
|
|
255
|
+
reject(new Error(`HISTORY_PLANT login failed: ${data.message}`));
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
historyConn.login('HISTORY_PLANT');
|
|
259
|
+
});
|
|
260
|
+
} catch (e) {
|
|
261
|
+
historyConn.disconnect();
|
|
262
|
+
throw e;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
173
266
|
/**
|
|
174
267
|
* Handle incoming messages from TICKER_PLANT
|
|
175
268
|
*/
|
|
@@ -410,6 +410,23 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
410
410
|
}
|
|
411
411
|
await marketFeed.connect(rithmicCredentials);
|
|
412
412
|
await marketFeed.subscribe(symbolCode, contract.exchange || 'CME');
|
|
413
|
+
|
|
414
|
+
// Preload historical bars for HQX-2B strategy only (bar-based strategy)
|
|
415
|
+
if (strategyId === 'hqx-2b' && strategy.preloadBars) {
|
|
416
|
+
ui.addLog('system', 'Loading historical bars...');
|
|
417
|
+
try {
|
|
418
|
+
const historicalBars = await marketFeed.getHistoricalBars(symbolCode, contract.exchange || 'CME', 30);
|
|
419
|
+
if (historicalBars && historicalBars.length > 0) {
|
|
420
|
+
strategy.preloadBars(contractId, historicalBars);
|
|
421
|
+
ui.addLog('system', `Loaded ${historicalBars.length} bars - strategy ready!`);
|
|
422
|
+
} else {
|
|
423
|
+
ui.addLog('system', 'No historical bars - collecting live data...');
|
|
424
|
+
}
|
|
425
|
+
} catch (histErr) {
|
|
426
|
+
ui.addLog('debug', `Historical data unavailable: ${histErr.message}`);
|
|
427
|
+
ui.addLog('system', 'Collecting live data...');
|
|
428
|
+
}
|
|
429
|
+
}
|
|
413
430
|
} catch (e) {
|
|
414
431
|
ui.addLog('error', `Failed to connect: ${e.message}`);
|
|
415
432
|
}
|
|
@@ -60,6 +60,7 @@ const REQ = {
|
|
|
60
60
|
MARKET_DATA: 100,
|
|
61
61
|
PRODUCT_CODES: 111,
|
|
62
62
|
FRONT_MONTH_CONTRACT: 113,
|
|
63
|
+
TICK_BAR_REPLAY: 200, // History plant - request bar data
|
|
63
64
|
LOGIN_INFO: 300,
|
|
64
65
|
ACCOUNT_LIST: 302,
|
|
65
66
|
ACCOUNT_RMS: 304,
|
|
@@ -88,6 +89,7 @@ const RES = {
|
|
|
88
89
|
MARKET_DATA: 101,
|
|
89
90
|
PRODUCT_CODES: 112,
|
|
90
91
|
FRONT_MONTH_CONTRACT: 114,
|
|
92
|
+
TICK_BAR_REPLAY: 201, // History plant - bar data response
|
|
91
93
|
LOGIN_INFO: 301,
|
|
92
94
|
ACCOUNT_LIST: 303,
|
|
93
95
|
ACCOUNT_RMS: 305,
|
|
@@ -134,6 +136,8 @@ const PROTO_FILES = [
|
|
|
134
136
|
'response_login_info.proto',
|
|
135
137
|
'request_account_list.proto',
|
|
136
138
|
'response_account_list.proto',
|
|
139
|
+
'request_tick_bar_replay.proto',
|
|
140
|
+
'response_tick_bar_replay.proto',
|
|
137
141
|
'request_trade_routes.proto',
|
|
138
142
|
'response_trade_routes.proto',
|
|
139
143
|
'request_subscribe_for_order_updates.proto',
|