hedgequantx 2.9.34 → 2.9.36

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.34",
3
+ "version": "2.9.36",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -39,7 +39,10 @@ const copyTradingMenu = async () => {
39
39
  return;
40
40
  }
41
41
 
42
- const activeAccounts = allAccounts.filter(acc => acc.status === 0);
42
+ // Filter active accounts: status === 0 (ProjectX) OR status === 'active' (Rithmic) OR no status
43
+ const activeAccounts = allAccounts.filter(acc =>
44
+ acc.status === 0 || acc.status === 'active' || acc.status === undefined || acc.status === null
45
+ );
43
46
 
44
47
  if (activeAccounts.length < 2) {
45
48
  spinner.fail(`Need at least 2 active accounts (found: ${activeAccounts.length})`);
@@ -46,7 +46,10 @@ const customStrategyMenu = async (service) => {
46
46
 
47
47
  if (!allAccounts?.length) { spinner.fail('No accounts found'); await prompts.waitForEnter(); return; }
48
48
 
49
- const activeAccounts = allAccounts.filter(acc => acc.status === 0);
49
+ // Filter active accounts: status === 0 (ProjectX) OR status === 'active' (Rithmic) OR no status
50
+ const activeAccounts = allAccounts.filter(acc =>
51
+ acc.status === 0 || acc.status === 'active' || acc.status === undefined || acc.status === null
52
+ );
50
53
  if (!activeAccounts.length) { spinner.fail('No active accounts'); await prompts.waitForEnter(); return; }
51
54
 
52
55
  spinner.succeed(`Found ${activeAccounts.length} active account(s)`);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * One Account Mode - HQX Ultra Scalping
2
+ * One Account Mode - Trading with Strategy Selection
3
3
  * Supports multi-agent AI supervision
4
4
  */
5
5
 
@@ -12,6 +12,7 @@ const { checkMarketHours } = require('../../services/rithmic/market');
12
12
  const { executeAlgo } = require('./algo-executor');
13
13
  const { getActiveAgentCount, getSupervisionConfig, getActiveAgents } = require('../ai-agents');
14
14
  const { runPreflightCheck, formatPreflightResults, getPreflightSummary } = require('../../services/ai-supervision');
15
+ const { getAvailableStrategies } = require('../../lib/m');
15
16
 
16
17
 
17
18
 
@@ -40,7 +41,10 @@ const oneAccountMenu = async (service) => {
40
41
  return;
41
42
  }
42
43
 
43
- const activeAccounts = allAccounts.filter(acc => acc.status === 0);
44
+ // Filter active accounts: status === 0 (ProjectX) OR status === 'active' (Rithmic) OR no status
45
+ const activeAccounts = allAccounts.filter(acc =>
46
+ acc.status === 0 || acc.status === 'active' || acc.status === undefined || acc.status === null
47
+ );
44
48
 
45
49
  if (!activeAccounts.length) {
46
50
  spinner.fail('No active accounts');
@@ -74,8 +78,12 @@ const oneAccountMenu = async (service) => {
74
78
  const contract = await selectSymbol(accountService, selectedAccount);
75
79
  if (!contract) return;
76
80
 
81
+ // Select strategy
82
+ const strategy = await selectStrategy();
83
+ if (!strategy) return;
84
+
77
85
  // Configure algo
78
- const config = await configureAlgo(selectedAccount, contract);
86
+ const config = await configureAlgo(selectedAccount, contract, strategy);
79
87
  if (!config) return;
80
88
 
81
89
  // Check for AI Supervision
@@ -126,6 +134,7 @@ const oneAccountMenu = async (service) => {
126
134
  account: selectedAccount,
127
135
  contract,
128
136
  config,
137
+ strategy,
129
138
  options: { supervisionConfig }
130
139
  });
131
140
  };
@@ -179,12 +188,42 @@ const selectSymbol = async (service, account) => {
179
188
  return contract === 'back' || contract === null ? null : contract;
180
189
  };
181
190
 
191
+ /**
192
+ * Select trading strategy
193
+ */
194
+ const selectStrategy = async () => {
195
+ console.log();
196
+ console.log(chalk.cyan(' Select Strategy'));
197
+ console.log();
198
+
199
+ const strategies = getAvailableStrategies();
200
+
201
+ const options = strategies.map(s => ({
202
+ label: `${s.name} (${s.backtest.winRate} WR, R:R ${s.params.riskReward})`,
203
+ value: s
204
+ }));
205
+ options.push({ label: chalk.gray('< Back'), value: 'back' });
206
+
207
+ // Show strategy details
208
+ for (const s of strategies) {
209
+ console.log(chalk.white(` ${s.name}`));
210
+ console.log(chalk.gray(` ${s.description}`));
211
+ console.log(chalk.gray(` Backtest: ${s.backtest.pnl} | ${s.backtest.winRate} WR | ${s.backtest.trades} trades`));
212
+ console.log(chalk.gray(` Stop: ${s.params.stopTicks} ticks | Target: ${s.params.targetTicks} ticks | R:R ${s.params.riskReward}`));
213
+ console.log();
214
+ }
215
+
216
+ const selected = await prompts.selectOption(chalk.yellow('Select Strategy:'), options);
217
+ return selected === 'back' || selected === null ? null : selected;
218
+ };
219
+
182
220
  /**
183
221
  * Configure algo
184
222
  */
185
- const configureAlgo = async (account, contract) => {
223
+ const configureAlgo = async (account, contract, strategy) => {
186
224
  console.log();
187
225
  console.log(chalk.cyan(' Configure Algo Parameters'));
226
+ console.log(chalk.gray(` Strategy: ${strategy.name}`));
188
227
  console.log();
189
228
 
190
229
  const contracts = await prompts.numberInput('Number of contracts:', 1, 1, 10);
@@ -176,10 +176,13 @@ const fetchAllFrontMonths = (service) => {
176
176
 
177
177
  /**
178
178
  * Decode ProductCodes response
179
- * @param {Buffer} buffer - Protobuf buffer
179
+ * @param {Buffer} buffer - Protobuf buffer (with 4-byte length prefix)
180
180
  * @returns {Object} Decoded product data
181
181
  */
182
182
  const decodeProductCodes = (buffer) => {
183
+ // Skip 4-byte length prefix
184
+ const data = buffer.length > 4 ? buffer.slice(4) : buffer;
185
+
183
186
  const result = {};
184
187
  let offset = 0;
185
188
 
@@ -200,18 +203,18 @@ const decodeProductCodes = (buffer) => {
200
203
  return [buf.slice(newOff, newOff + len).toString('utf8'), newOff + len];
201
204
  };
202
205
 
203
- while (offset < buffer.length) {
206
+ while (offset < data.length) {
204
207
  try {
205
- const [tag, tagOff] = readVarint(buffer, offset);
208
+ const [tag, tagOff] = readVarint(data, offset);
206
209
  const wireType = tag & 0x7;
207
210
  const fieldNumber = tag >>> 3;
208
211
  offset = tagOff;
209
212
 
210
213
  if (wireType === 0) {
211
- const [, newOff] = readVarint(buffer, offset);
214
+ const [, newOff] = readVarint(data, offset);
212
215
  offset = newOff;
213
216
  } else if (wireType === 2) {
214
- const [val, newOff] = readString(buffer, offset);
217
+ const [val, newOff] = readString(data, offset);
215
218
  offset = newOff;
216
219
  if (fieldNumber === 110101) result.exchange = val;
217
220
  if (fieldNumber === 100749) result.productCode = val;
@@ -459,44 +459,48 @@ function decodeProductCodes(buffer) {
459
459
 
460
460
  /**
461
461
  * Decode ResponseFrontMonthContract (template 114) - current tradeable contract
462
+ * Skips 4-byte length prefix if present
462
463
  */
463
464
  function decodeFrontMonthContract(buffer) {
465
+ // Skip 4-byte length prefix
466
+ const data = buffer.length > 4 ? buffer.slice(4) : buffer;
467
+
464
468
  const result = { rpCode: [] };
465
469
  let offset = 0;
466
470
 
467
- while (offset < buffer.length) {
471
+ while (offset < data.length) {
468
472
  try {
469
- const [tag, tagOffset] = readVarint(buffer, offset);
473
+ const [tag, tagOffset] = readVarint(data, offset);
470
474
  const wireType = tag & 0x7;
471
475
  const fieldNumber = tag >>> 3;
472
476
  offset = tagOffset;
473
477
 
474
478
  switch (fieldNumber) {
475
479
  case SYMBOL_FIELDS.TEMPLATE_ID:
476
- [result.templateId, offset] = readVarint(buffer, offset);
480
+ [result.templateId, offset] = readVarint(data, offset);
477
481
  break;
478
482
  case SYMBOL_FIELDS.RP_CODE:
479
483
  let rpCode;
480
- [rpCode, offset] = readLengthDelimited(buffer, offset);
484
+ [rpCode, offset] = readLengthDelimited(data, offset);
481
485
  result.rpCode.push(rpCode);
482
486
  break;
483
487
  case SYMBOL_FIELDS.SYMBOL:
484
- [result.symbol, offset] = readLengthDelimited(buffer, offset);
488
+ [result.symbol, offset] = readLengthDelimited(data, offset);
485
489
  break;
486
490
  case SYMBOL_FIELDS.EXCHANGE:
487
- [result.exchange, offset] = readLengthDelimited(buffer, offset);
491
+ [result.exchange, offset] = readLengthDelimited(data, offset);
488
492
  break;
489
493
  case SYMBOL_FIELDS.TRADING_SYMBOL:
490
- [result.tradingSymbol, offset] = readLengthDelimited(buffer, offset);
494
+ [result.tradingSymbol, offset] = readLengthDelimited(data, offset);
491
495
  break;
492
496
  case SYMBOL_FIELDS.DESCRIPTION:
493
- [result.description, offset] = readLengthDelimited(buffer, offset);
497
+ [result.description, offset] = readLengthDelimited(data, offset);
494
498
  break;
495
499
  case SYMBOL_FIELDS.USER_MSG:
496
- [result.userMsg, offset] = readLengthDelimited(buffer, offset);
500
+ [result.userMsg, offset] = readLengthDelimited(data, offset);
497
501
  break;
498
502
  default:
499
- offset = skipField(buffer, offset, wireType);
503
+ offset = skipField(data, offset, wireType);
500
504
  }
501
505
  } catch (error) {
502
506
  break;