hedgequantx 2.9.87 → 2.9.89
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
|
@@ -647,8 +647,16 @@ var require_core = __commonJS({
|
|
|
647
647
|
}
|
|
648
648
|
if (sweep && sweep.isValid) {
|
|
649
649
|
if (Date.now() - this.lastSignalTime < this.config.execution.cooldownMs) {
|
|
650
|
+
this.emit("log", {
|
|
651
|
+
type: "debug",
|
|
652
|
+
message: `[2B] COOLDOWN - waiting ${Math.ceil((this.config.execution.cooldownMs - (Date.now() - this.lastSignalTime)) / 1e3)}s`
|
|
653
|
+
});
|
|
650
654
|
return null;
|
|
651
655
|
}
|
|
656
|
+
this.emit("log", {
|
|
657
|
+
type: "debug",
|
|
658
|
+
message: `[2B] GENERATING SIGNAL from ${sweep.sweepType} sweep...`
|
|
659
|
+
});
|
|
652
660
|
const signal = generateSignal({
|
|
653
661
|
contractId,
|
|
654
662
|
currentBar: bar,
|
|
@@ -728,6 +736,47 @@ var require_core = __commonJS({
|
|
|
728
736
|
message: `[HQX-2B] Reset state for ${contractId}`
|
|
729
737
|
});
|
|
730
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
|
+
}
|
|
731
780
|
};
|
|
732
781
|
module2.exports = { HQX2BLiquiditySweep: HQX2BLiquiditySweep2 };
|
|
733
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,21 @@ 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 instant strategy warmup
|
|
415
|
+
ui.addLog('system', 'Loading historical data...');
|
|
416
|
+
try {
|
|
417
|
+
const historicalBars = await marketFeed.getHistoricalBars(symbolCode, contract.exchange || 'CME', 30);
|
|
418
|
+
if (historicalBars && historicalBars.length > 0 && strategy.preloadBars) {
|
|
419
|
+
strategy.preloadBars(contractId, historicalBars);
|
|
420
|
+
ui.addLog('system', `Loaded ${historicalBars.length} historical bars - strategy ready!`);
|
|
421
|
+
} else {
|
|
422
|
+
ui.addLog('system', 'No historical bars available - collecting live data...');
|
|
423
|
+
}
|
|
424
|
+
} catch (histErr) {
|
|
425
|
+
ui.addLog('debug', `Historical data unavailable: ${histErr.message}`);
|
|
426
|
+
ui.addLog('system', 'Collecting live data...');
|
|
427
|
+
}
|
|
413
428
|
} catch (e) {
|
|
414
429
|
ui.addLog('error', `Failed to connect: ${e.message}`);
|
|
415
430
|
}
|
|
@@ -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',
|