hedgequantx 1.2.113 → 1.2.115

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/pages/algo.js +57 -64
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "1.2.113",
3
+ "version": "1.2.115",
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/pages/algo.js CHANGED
@@ -178,29 +178,31 @@ const selectSymbolMenu = async (service, account) => {
178
178
  const result = await service.searchContracts(search, false);
179
179
  if (result.success && result.contracts && result.contracts.length > 0) {
180
180
  for (const contract of result.contracts) {
181
- // Only add contracts that have valid data
182
- if (contract.id || contract.contractId || contract.name) {
183
- const contractId = contract.id || contract.contractId;
184
- const existing = availableSymbols.find(s => s.id === contractId);
185
- if (!existing) {
186
- // Extract symbol from name if not provided (e.g., "NQH6" from "CON.F.US.ENQ.H26")
187
- let symbolCode = contract.symbol || search;
188
- if (contract.name && contract.name.includes(' ')) {
189
- // Try to extract from name like "E-mini NASDAQ-100 Mar 2026"
190
- symbolCode = search;
191
- }
192
-
193
- availableSymbols.push({
194
- id: contractId,
195
- name: contract.name || contract.symbol || search,
196
- symbol: symbolCode,
197
- tickSize: contract.tickSize,
198
- tickValue: contract.tickValue,
199
- exchange: contract.exchange || 'CME',
200
- activeContract: contract.activeContract || false
201
- });
202
- }
203
- }
181
+ // ProjectX API returns:
182
+ // id: "CON.F.US.ENQ.H26" (contract ID)
183
+ // name: "NQH6" (short symbol with month/year)
184
+ // description: "E-mini NASDAQ-100: March 2026"
185
+
186
+ const contractId = contract.id || contract.contractId;
187
+ if (!contractId) continue;
188
+
189
+ const existing = availableSymbols.find(s => s.id === contractId);
190
+ if (existing) continue;
191
+
192
+ // Use 'name' field which contains the symbol code like "NQH6", "ESH6", "MNQH6"
193
+ const symbolCode = contract.name || contract.symbol || '';
194
+ if (!symbolCode) continue;
195
+
196
+ availableSymbols.push({
197
+ id: contractId,
198
+ name: symbolCode,
199
+ symbol: symbolCode,
200
+ description: contract.description || '',
201
+ tickSize: contract.tickSize,
202
+ tickValue: contract.tickValue,
203
+ exchange: contract.exchange || 'CME',
204
+ activeContract: contract.activeContract || false
205
+ });
204
206
  }
205
207
  }
206
208
  }
@@ -208,22 +210,6 @@ const selectSymbolMenu = async (service, account) => {
208
210
  // Fallback to static list
209
211
  }
210
212
 
211
- // Add micro contracts if not found from API
212
- const microContracts = [
213
- { symbol: 'MNQ', name: 'Micro E-mini NASDAQ-100' },
214
- { symbol: 'MES', name: 'Micro E-mini S&P 500' },
215
- { symbol: 'MYM', name: 'Micro E-mini Dow Jones' },
216
- { symbol: 'M2K', name: 'Micro E-mini Russell 2000' },
217
- { symbol: 'MCL', name: 'Micro Crude Oil' },
218
- { symbol: 'MGC', name: 'Micro Gold' }
219
- ];
220
-
221
- // Get current month code for front month
222
- const now = new Date();
223
- const monthCodes = ['F', 'G', 'H', 'J', 'K', 'M', 'N', 'Q', 'U', 'V', 'X', 'Z'];
224
- const currentMonthCode = monthCodes[now.getMonth()];
225
- const yearCode = (now.getFullYear() % 100).toString();
226
-
227
213
  for (const micro of microContracts) {
228
214
  const hasMicro = availableSymbols.some(s =>
229
215
  (s.symbol && s.symbol.toUpperCase().startsWith(micro.symbol)) ||
@@ -294,42 +280,49 @@ const selectSymbolMenu = async (service, account) => {
294
280
  'ZW': 'Wheat'
295
281
  };
296
282
 
297
- // Format symbols for display - deduplicate by base symbol + month
298
- const seenSymbols = new Set();
283
+ // Format symbols for display - show ALL contracts from API
284
+ const seenIds = new Set();
299
285
  const symbolChoices = [];
300
286
 
301
- for (const symbol of availableSymbols) {
302
- const symbolCode = symbol.symbol || symbol.id || '';
287
+ for (const contract of availableSymbols) {
288
+ // Skip duplicates by contract ID
289
+ const contractId = contract.id || '';
290
+ if (seenIds.has(contractId)) continue;
291
+ seenIds.add(contractId);
303
292
 
304
- // Extract base symbol (e.g., NQ from NQH6) and month code
305
- const baseMatch = symbolCode.match(/^([A-Z0-9]{1,4})([FGHJKMNQUVXZ])(\d{1,2})$/i);
306
- let baseSymbol = symbolCode;
307
- let monthYear = '';
293
+ // Get the symbol code - API returns 'name' field with code like "NQH6"
294
+ const symbolCode = contract.name || contract.symbol || '';
295
+ if (!symbolCode) continue;
308
296
 
309
- if (baseMatch) {
310
- baseSymbol = baseMatch[1];
311
- const monthCodes = { F: 'Jan', G: 'Feb', H: 'Mar', J: 'Apr', K: 'May', M: 'Jun', N: 'Jul', Q: 'Aug', U: 'Sep', V: 'Oct', X: 'Nov', Z: 'Dec' };
312
- const monthCode = baseMatch[2].toUpperCase();
313
- const year = baseMatch[3].length === 1 ? '2' + baseMatch[3] : baseMatch[3];
314
- monthYear = (monthCodes[monthCode] || monthCode) + year;
297
+ // Get description from API or our mapping
298
+ let description = '';
299
+ if (contract.description) {
300
+ // API format: "E-mini NASDAQ-100: March 2026" -> extract instrument name
301
+ description = contract.description.split(':')[0].trim();
315
302
  }
316
303
 
317
- // Create unique key to deduplicate
318
- const uniqueKey = `${baseSymbol}-${monthYear}`;
319
- if (seenSymbols.has(uniqueKey)) continue;
320
- seenSymbols.add(uniqueKey);
321
-
322
- // Get descriptive name from mapping
323
- const description = symbolDescriptions[baseSymbol] || symbol.name || baseSymbol;
304
+ // Fallback to our symbol descriptions
305
+ if (!description) {
306
+ // Extract base symbol (NQ from NQH6)
307
+ const baseMatch = symbolCode.match(/^([A-Z0-9]{1,4})[FGHJKMNQUVXZ]\d{1,2}$/i);
308
+ const baseSymbol = baseMatch ? baseMatch[1] : symbolCode;
309
+ description = symbolDescriptions[baseSymbol] || symbolCode;
310
+ }
324
311
 
325
- // Format: "NQ.Mar26 E-mini NASDAQ-100"
326
- const symbolDisplay = monthYear ? `${baseSymbol}.${monthYear}` : baseSymbol;
312
+ // Format: "NQH6 E-mini NASDAQ-100"
327
313
  symbolChoices.push({
328
- name: chalk.yellow(symbolDisplay.padEnd(12)) + chalk.white(description),
329
- value: symbol
314
+ name: chalk.yellow(symbolCode.padEnd(12)) + chalk.white(description),
315
+ value: contract
330
316
  });
331
317
  }
332
318
 
319
+ // Sort by symbol code for better organization
320
+ symbolChoices.sort((a, b) => {
321
+ const aCode = a.value.name || a.value.symbol || '';
322
+ const bCode = b.value.name || b.value.symbol || '';
323
+ return aCode.localeCompare(bCode);
324
+ });
325
+
333
326
  symbolChoices.push(new inquirer.Separator());
334
327
  symbolChoices.push({ name: chalk.yellow('< Back'), value: 'back' });
335
328