hedgequantx 1.8.6 → 1.8.8

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": "1.8.6",
3
+ "version": "1.8.8",
4
4
  "description": "Prop Futures Algo Trading CLI - Connect to Topstep, Alpha Futures, and other prop firms",
5
5
  "main": "src/app.js",
6
6
  "bin": {
package/src/app.js CHANGED
@@ -170,7 +170,7 @@ const mainMenu = async () => {
170
170
 
171
171
  console.log(chalk.cyan('╚' + '═'.repeat(innerWidth) + '╝'));
172
172
 
173
- const input = await prompts.textInput('Select (1/2/3/X)');
173
+ const input = await prompts.textInput(chalk.cyan('Select (1/2/3/X)'));
174
174
 
175
175
  const actionMap = {
176
176
  '1': 'projectx',
@@ -91,7 +91,7 @@ const dashboardMenu = async (service) => {
91
91
  console.log(chalk.cyan('╚' + '═'.repeat(W) + '╝'));
92
92
 
93
93
  // Simple input - no duplicate menu
94
- const input = await prompts.textInput('Select (1/2/+/A/U/X)');
94
+ const input = await prompts.textInput(chalk.cyan('Select (1/2/+/A/U/X)'));
95
95
 
96
96
  const actionMap = {
97
97
  '1': 'accounts',
@@ -84,20 +84,15 @@ const copyTradingMenu = async () => {
84
84
  if (followerIdx === null || followerIdx === -1) return;
85
85
  const follower = allAccounts[followerIdx];
86
86
 
87
- // Step 3-4: Select Symbols
87
+ // Step 3: Select Trading Symbol
88
88
  console.log();
89
- console.log(chalk.cyan(' Step 3: Select Symbol for LEAD'));
90
- const leadSymbol = await selectSymbol(lead.service, 'Lead');
91
- if (!leadSymbol) return;
89
+ console.log(chalk.cyan(' Step 3: Select Trading Symbol'));
90
+ const symbol = await selectSymbol(lead.service, 'Trading');
91
+ if (!symbol) return;
92
92
 
93
+ // Step 4: Configure parameters
93
94
  console.log();
94
- console.log(chalk.cyan(' Step 4: Select Symbol for FOLLOWER'));
95
- const followerSymbol = await selectSymbol(follower.service, 'Follower');
96
- if (!followerSymbol) return;
97
-
98
- // Step 5: Configure parameters
99
- console.log();
100
- console.log(chalk.cyan(' Step 5: Configure Parameters'));
95
+ console.log(chalk.cyan(' Step 4: Configure Parameters'));
101
96
 
102
97
  const leadContracts = await prompts.numberInput('Lead contracts:', 1, 1, 10);
103
98
  if (leadContracts === null) return;
@@ -111,7 +106,7 @@ const copyTradingMenu = async () => {
111
106
  const maxRisk = await prompts.numberInput('Max risk ($):', 200, 1, 5000);
112
107
  if (maxRisk === null) return;
113
108
 
114
- // Step 6: Privacy
109
+ // Step 5: Privacy
115
110
  const showNames = await prompts.selectOption('Account names:', [
116
111
  { label: 'Hide account names', value: false },
117
112
  { label: 'Show account names', value: true }
@@ -121,8 +116,9 @@ const copyTradingMenu = async () => {
121
116
  // Confirm
122
117
  console.log();
123
118
  console.log(chalk.white(' Summary:'));
124
- console.log(chalk.gray(` Lead: ${lead.propfirm} -> ${leadSymbol.name} x${leadContracts}`));
125
- console.log(chalk.gray(` Follower: ${follower.propfirm} -> ${followerSymbol.name} x${followerContracts}`));
119
+ console.log(chalk.gray(` Symbol: ${symbol.name}`));
120
+ console.log(chalk.gray(` Lead: ${lead.propfirm} x${leadContracts}`));
121
+ console.log(chalk.gray(` Follower: ${follower.propfirm} x${followerContracts}`));
126
122
  console.log(chalk.gray(` Target: $${dailyTarget} | Risk: $${maxRisk}`));
127
123
  console.log();
128
124
 
@@ -131,8 +127,8 @@ const copyTradingMenu = async () => {
131
127
 
132
128
  // Launch
133
129
  await launchCopyTrading({
134
- lead: { ...lead, symbol: leadSymbol, contracts: leadContracts },
135
- follower: { ...follower, symbol: followerSymbol, contracts: followerContracts },
130
+ lead: { ...lead, symbol, contracts: leadContracts },
131
+ follower: { ...follower, symbol, contracts: followerContracts },
136
132
  dailyTarget, maxRisk, showNames
137
133
  });
138
134
  };
@@ -153,7 +149,12 @@ const getContractsFromAPI = async () => {
153
149
  if (projectxConn && typeof projectxConn.service.getContracts === 'function') {
154
150
  const result = await projectxConn.service.getContracts();
155
151
  if (result.success && result.contracts?.length > 0) {
156
- cachedContracts = result.contracts;
152
+ // Normalize contract structure - API returns { name: "ESH6", description: "E-mini S&P 500..." }
153
+ cachedContracts = result.contracts.map(c => ({
154
+ ...c,
155
+ symbol: c.name || c.symbol,
156
+ name: c.description || c.name || c.symbol
157
+ }));
157
158
  return cachedContracts;
158
159
  }
159
160
  }
@@ -166,6 +167,8 @@ const getContractsFromAPI = async () => {
166
167
  */
167
168
  const selectSymbol = async (service, label) => {
168
169
  try {
170
+ const spinner = ora({ text: 'Loading symbols...', color: 'yellow' }).start();
171
+
169
172
  // Always use contracts from ProjectX API for consistency
170
173
  let contracts = await getContractsFromAPI();
171
174
 
@@ -178,15 +181,18 @@ const selectSymbol = async (service, label) => {
178
181
  }
179
182
 
180
183
  if (!contracts || contracts.length === 0) {
181
- console.log(chalk.red(' No contracts available'));
184
+ spinner.fail('No contracts available');
182
185
  return null;
183
186
  }
184
187
 
188
+ spinner.succeed(`Found ${contracts.length} contracts`);
189
+
185
190
  const options = contracts.map(c => ({ label: c.name || c.symbol, value: c }));
186
191
  options.push({ label: '< Cancel', value: null });
187
192
 
188
193
  return await prompts.selectOption(`${label} Symbol:`, options);
189
194
  } catch (e) {
195
+ console.log(chalk.red(' Error loading contracts'));
190
196
  return null;
191
197
  }
192
198
  };
@@ -54,16 +54,21 @@ const passwordInput = async (message) => {
54
54
  };
55
55
 
56
56
  /**
57
- * Confirm Y/n
57
+ * Confirm - arrow keys selection
58
58
  */
59
59
  const confirmPrompt = async (message, defaultVal = true) => {
60
60
  prepareStdin();
61
+ const choices = defaultVal
62
+ ? [{ name: 'Yes', value: true }, { name: 'No', value: false }]
63
+ : [{ name: 'No', value: false }, { name: 'Yes', value: true }];
64
+
61
65
  const { value } = await inquirer.prompt([{
62
- type: 'confirm',
66
+ type: 'list',
63
67
  name: 'value',
64
68
  message,
65
- default: defaultVal,
66
- prefix: ''
69
+ choices,
70
+ prefix: '',
71
+ loop: false
67
72
  }]);
68
73
  return value;
69
74
  };