hedgequantx 2.6.160 → 2.6.162

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 (45) hide show
  1. package/package.json +1 -1
  2. package/src/menus/ai-agent-connect.js +181 -0
  3. package/src/menus/ai-agent-models.js +219 -0
  4. package/src/menus/ai-agent-oauth.js +292 -0
  5. package/src/menus/ai-agent-ui.js +141 -0
  6. package/src/menus/ai-agent.js +88 -1489
  7. package/src/pages/algo/copy-engine.js +449 -0
  8. package/src/pages/algo/copy-trading.js +11 -543
  9. package/src/pages/algo/smart-logs-data.js +218 -0
  10. package/src/pages/algo/smart-logs.js +9 -214
  11. package/src/pages/algo/ui-constants.js +144 -0
  12. package/src/pages/algo/ui-summary.js +184 -0
  13. package/src/pages/algo/ui.js +42 -526
  14. package/src/pages/stats-calculations.js +191 -0
  15. package/src/pages/stats-ui.js +381 -0
  16. package/src/pages/stats.js +14 -507
  17. package/src/services/ai/client-analysis.js +194 -0
  18. package/src/services/ai/client-models.js +333 -0
  19. package/src/services/ai/client.js +6 -489
  20. package/src/services/ai/index.js +2 -257
  21. package/src/services/ai/proxy-install.js +249 -0
  22. package/src/services/ai/proxy-manager.js +29 -411
  23. package/src/services/ai/proxy-remote.js +161 -0
  24. package/src/services/ai/strategy-supervisor.js +10 -765
  25. package/src/services/ai/supervisor-data.js +195 -0
  26. package/src/services/ai/supervisor-optimize.js +215 -0
  27. package/src/services/ai/supervisor-sync.js +178 -0
  28. package/src/services/ai/supervisor-utils.js +158 -0
  29. package/src/services/ai/supervisor.js +50 -515
  30. package/src/services/ai/validation.js +250 -0
  31. package/src/services/hqx-server-events.js +110 -0
  32. package/src/services/hqx-server-handlers.js +217 -0
  33. package/src/services/hqx-server-latency.js +136 -0
  34. package/src/services/hqx-server.js +51 -403
  35. package/src/services/position-constants.js +28 -0
  36. package/src/services/position-manager.js +105 -554
  37. package/src/services/position-momentum.js +206 -0
  38. package/src/services/projectx/accounts.js +142 -0
  39. package/src/services/projectx/index.js +40 -289
  40. package/src/services/projectx/trading.js +180 -0
  41. package/src/services/rithmic/handlers.js +2 -208
  42. package/src/services/rithmic/index.js +32 -542
  43. package/src/services/rithmic/latency-tracker.js +182 -0
  44. package/src/services/rithmic/specs.js +146 -0
  45. package/src/services/rithmic/trade-history.js +254 -0
@@ -12,6 +12,8 @@
12
12
  const https = require('https');
13
13
  const http = require('http');
14
14
  const { getProvider } = require('./providers');
15
+ const { analyzeTrading: analyzeTradingImpl, analyzePerformance: analyzePerformanceImpl, getMarketAdvice: getMarketAdviceImpl } = require('./client-analysis');
16
+ const { fetchAnthropicModels, fetchAnthropicModelsOAuth, fetchGeminiModels, fetchOpenAIModels, fetchModelsWithOAuth, fetchModelsViaProxy } = require('./client-models');
15
17
 
16
18
  /**
17
19
  * Make HTTP request to AI provider
@@ -317,495 +319,10 @@ const callAI = async (agent, prompt, systemPrompt = '', options = {}) => {
317
319
  }
318
320
  };
319
321
 
320
- /**
321
- * Analyze trading data with AI
322
- * @param {Object} agent - AI agent
323
- * @param {Object} data - Trading data from APIs
324
- * @returns {Promise<Object|null>} Analysis result or null
325
- */
326
- const analyzeTrading = async (agent, data) => {
327
- if (!agent || !data) return null;
328
-
329
- const systemPrompt = `You are a professional trading analyst for prop firm futures trading.
330
- Analyze the provided real-time trading data and provide actionable insights.
331
- Be concise. Focus on risk management and optimization.
332
- Respond in JSON format with: { "action": "HOLD|REDUCE_SIZE|PAUSE|CONTINUE", "confidence": 0-100, "reason": "brief reason" }`;
333
-
334
- const prompt = `Current trading session data:
335
- - Account Balance: ${data.account?.balance ?? 'N/A'}
336
- - Today P&L: ${data.account?.profitAndLoss ?? 'N/A'}
337
- - Open Positions: ${data.positions?.length ?? 0}
338
- - Open Orders: ${data.orders?.length ?? 0}
339
- - Today Trades: ${data.trades?.length ?? 0}
340
-
341
- ${data.positions?.length > 0 ? `Positions: ${JSON.stringify(data.positions.map(p => ({
342
- symbol: p.symbol || p.contractId,
343
- qty: p.quantity,
344
- pnl: p.profitAndLoss
345
- })))}` : ''}
346
-
347
- Analyze and provide recommendation.`;
348
-
349
- try {
350
- const response = await callAI(agent, prompt, systemPrompt);
351
- if (!response) return null;
352
-
353
- // Try to parse JSON from response
354
- const jsonMatch = response.match(/\{[\s\S]*\}/);
355
- if (jsonMatch) {
356
- return JSON.parse(jsonMatch[0]);
357
- }
358
-
359
- return null;
360
- } catch (error) {
361
- return null;
362
- }
363
- };
364
-
365
- /**
366
- * Analyze strategy performance and suggest optimizations
367
- * Called periodically to help the strategy improve
368
- *
369
- * @param {Object} agent - AI agent
370
- * @param {Object} performanceData - Strategy performance data
371
- * @returns {Promise<Object|null>} Optimization suggestions
372
- */
373
- const analyzePerformance = async (agent, performanceData) => {
374
- if (!agent || !performanceData) return null;
375
-
376
- const systemPrompt = `You are an AI supervisor for HQX Ultra Scalping, a professional prop firm futures trading strategy.
377
-
378
- The strategy uses advanced mathematical models:
379
- - Order flow analysis (delta, cumulative delta, absorption)
380
- - Market microstructure (bid/ask imbalance, volume profile)
381
- - Statistical edge detection (z-score, standard deviation bands)
382
- - Dynamic risk management (Kelly criterion, volatility-adjusted sizing)
383
-
384
- Your job is to analyze performance data and suggest parameter optimizations.
385
- Be precise and actionable. Focus on improving win rate, reducing drawdown, and optimizing risk/reward.
386
-
387
- Respond ONLY in valid JSON format:
388
- {
389
- "assessment": "brief performance assessment",
390
- "winRateAnalysis": "analysis of win/loss patterns",
391
- "riskAnalysis": "analysis of risk management",
392
- "optimizations": [
393
- { "param": "parameter_name", "current": "current_value", "suggested": "new_value", "reason": "why" }
394
- ],
395
- "marketCondition": "trending|ranging|volatile|calm",
396
- "confidence": 0-100
397
- }`;
398
-
399
- const prompt = `STRATEGY PERFORMANCE DATA - ANALYZE AND OPTIMIZE
400
-
401
- Session Stats:
402
- - Trades: ${performanceData.trades || 0}
403
- - Wins: ${performanceData.wins || 0}
404
- - Losses: ${performanceData.losses || 0}
405
- - Win Rate: ${performanceData.winRate ? (performanceData.winRate * 100).toFixed(1) + '%' : 'N/A'}
406
- - Total P&L: $${performanceData.pnl?.toFixed(2) || '0.00'}
407
- - Avg Win: $${performanceData.avgWin?.toFixed(2) || 'N/A'}
408
- - Avg Loss: $${performanceData.avgLoss?.toFixed(2) || 'N/A'}
409
- - Largest Win: $${performanceData.largestWin?.toFixed(2) || 'N/A'}
410
- - Largest Loss: $${performanceData.largestLoss?.toFixed(2) || 'N/A'}
411
- - Max Drawdown: $${performanceData.maxDrawdown?.toFixed(2) || 'N/A'}
412
- - Profit Factor: ${performanceData.profitFactor?.toFixed(2) || 'N/A'}
413
-
414
- Current Parameters:
415
- - Position Size: ${performanceData.positionSize || 'N/A'} contracts
416
- - Daily Target: $${performanceData.dailyTarget || 'N/A'}
417
- - Max Risk: $${performanceData.maxRisk || 'N/A'}
418
- - Symbol: ${performanceData.symbol || 'N/A'}
419
-
420
- Recent Trades:
421
- ${performanceData.recentTrades?.map(t =>
422
- `- ${t.side} ${t.qty}x @ ${t.price} → P&L: $${t.pnl?.toFixed(2) || 'N/A'}`
423
- ).join('\n') || 'No recent trades'}
424
-
425
- Market Context:
426
- - Volatility: ${performanceData.volatility || 'N/A'}
427
- - Trend: ${performanceData.trend || 'N/A'}
428
- - Session: ${performanceData.session || 'N/A'}
429
-
430
- Analyze and suggest optimizations to improve performance.`;
431
-
432
- try {
433
- const response = await callAI(agent, prompt, systemPrompt);
434
- if (!response) return null;
435
-
436
- // Parse JSON from response
437
- const jsonMatch = response.match(/\{[\s\S]*\}/);
438
- if (jsonMatch) {
439
- return JSON.parse(jsonMatch[0]);
440
- }
441
-
442
- return null;
443
- } catch (error) {
444
- return null;
445
- }
446
- };
447
-
448
- /**
449
- * Get real-time trading advice based on current market conditions
450
- *
451
- * @param {Object} agent - AI agent
452
- * @param {Object} marketData - Current market data
453
- * @returns {Promise<Object|null>} Trading advice
454
- */
455
- const getMarketAdvice = async (agent, marketData) => {
456
- if (!agent || !marketData) return null;
457
-
458
- const systemPrompt = `You are an AI supervisor for HQX Ultra Scalping futures strategy.
459
- Analyze real-time market data and provide actionable advice.
460
- Be concise and precise. The strategy will use your recommendations.
461
-
462
- Respond ONLY in valid JSON:
463
- {
464
- "action": "AGGRESSIVE|NORMAL|CAUTIOUS|PAUSE",
465
- "sizeMultiplier": 0.5-1.5,
466
- "reason": "brief reason",
467
- "confidence": 0-100
468
- }`;
469
-
470
- const prompt = `REAL-TIME MARKET ANALYSIS
471
-
472
- Current Price: ${marketData.price || 'N/A'}
473
- Bid: ${marketData.bid || 'N/A'} | Ask: ${marketData.ask || 'N/A'}
474
- Spread: ${marketData.spread || 'N/A'}
475
- Volume: ${marketData.volume || 'N/A'}
476
- Delta: ${marketData.delta || 'N/A'}
477
- Volatility: ${marketData.volatility || 'N/A'}
478
-
479
- Recent Price Action:
480
- - High: ${marketData.high || 'N/A'}
481
- - Low: ${marketData.low || 'N/A'}
482
- - Range: ${marketData.range || 'N/A'}
483
-
484
- Current Position: ${marketData.position || 'FLAT'}
485
- Session P&L: $${marketData.pnl?.toFixed(2) || '0.00'}
486
-
487
- What should the strategy do?`;
488
-
489
- try {
490
- const response = await callAI(agent, prompt, systemPrompt);
491
- if (!response) return null;
492
-
493
- const jsonMatch = response.match(/\{[\s\S]*\}/);
494
- if (jsonMatch) {
495
- return JSON.parse(jsonMatch[0]);
496
- }
497
-
498
- return null;
499
- } catch (error) {
500
- return null;
501
- }
502
- };
503
-
504
- /**
505
- * Fetch available models from Anthropic API (API Key auth)
506
- * @param {string} apiKey - API key
507
- * @returns {Promise<Array|null>} Array of model IDs or null on error
508
- *
509
- * Data source: https://api.anthropic.com/v1/models (GET)
510
- */
511
- const fetchAnthropicModels = async (apiKey) => {
512
- if (!apiKey) return null;
513
-
514
- const url = 'https://api.anthropic.com/v1/models';
515
-
516
- const headers = {
517
- 'x-api-key': apiKey,
518
- 'anthropic-version': '2023-06-01'
519
- };
520
-
521
- try {
522
- const response = await makeRequest(url, { method: 'GET', headers, timeout: 10000 });
523
- if (response.data && Array.isArray(response.data)) {
524
- return response.data.map(m => m.id).filter(Boolean);
525
- }
526
- return null;
527
- } catch (error) {
528
- return null;
529
- }
530
- };
531
-
532
- /**
533
- * Fetch available models from Anthropic API (OAuth auth)
534
- *
535
- * @param {string} accessToken - OAuth access token
536
- * @returns {Promise<Object>} { models: Array, error: string|null }
537
- *
538
- * Data source: https://api.anthropic.com/v1/models (GET with Bearer token)
539
- * NO HARDCODED FALLBACK - models must come from API only
540
- */
541
- const fetchAnthropicModelsOAuth = async (accessToken) => {
542
- if (!accessToken) return { models: null, error: 'No access token provided' };
543
-
544
- const modelsUrl = 'https://api.anthropic.com/v1/models';
545
-
546
- const headers = {
547
- 'Authorization': `Bearer ${accessToken}`,
548
- 'anthropic-version': '2023-06-01',
549
- 'anthropic-beta': 'oauth-2025-04-20'
550
- };
551
-
552
- try {
553
- const response = await makeRequest(modelsUrl, { method: 'GET', headers, timeout: 15000 });
554
- if (response.data && Array.isArray(response.data)) {
555
- const models = response.data.map(m => m.id).filter(Boolean);
556
- if (models.length > 0) return { models, error: null };
557
- }
558
- return { models: null, error: 'API returned empty or invalid response' };
559
- } catch (error) {
560
- return { models: null, error: error.message };
561
- }
562
- };
563
-
564
- /**
565
- * Fetch available models from Google Gemini API
566
- * @param {string} apiKey - API key
567
- * @returns {Promise<Array|null>} Array of model IDs or null on error
568
- *
569
- * Data source: https://generativelanguage.googleapis.com/v1/models (GET)
570
- */
571
- const fetchGeminiModels = async (apiKey) => {
572
- if (!apiKey) return null;
573
-
574
- const url = `https://generativelanguage.googleapis.com/v1/models?key=${apiKey}`;
575
-
576
- try {
577
- const response = await makeRequest(url, { method: 'GET', timeout: 10000 });
578
- if (response.models && Array.isArray(response.models)) {
579
- // Filter only generative models and extract the model name
580
- return response.models
581
- .filter(m => m.supportedGenerationMethods?.includes('generateContent'))
582
- .map(m => m.name.replace('models/', ''))
583
- .filter(Boolean);
584
- }
585
- return null;
586
- } catch (error) {
587
- return null;
588
- }
589
- };
590
-
591
- /**
592
- * Fetch available models from OpenAI-compatible API
593
- * @param {string} endpoint - API endpoint
594
- * @param {string} apiKey - API key
595
- * @returns {Promise<Array|null>} Array of model IDs or null on error
596
- *
597
- * Data source: {endpoint}/models (GET)
598
- */
599
- /**
600
- * Fetch available models from OpenAI-compatible API
601
- * @param {string} endpoint - API endpoint base URL
602
- * @param {string} apiKey - API key or OAuth token
603
- * @returns {Promise<Array|null>} Array of model IDs from API, null if unavailable
604
- *
605
- * Data source: {endpoint}/models (GET)
606
- */
607
- const fetchOpenAIModels = async (endpoint, apiKey) => {
608
- if (!endpoint) return null;
609
-
610
- const url = `${endpoint}/models`;
611
-
612
- const headers = {
613
- 'Content-Type': 'application/json'
614
- };
615
-
616
- if (apiKey) {
617
- headers['Authorization'] = `Bearer ${apiKey}`;
618
- }
619
-
620
- try {
621
- const response = await makeRequest(url, { method: 'GET', headers, timeout: 10000 });
622
- if (response.data && Array.isArray(response.data)) {
623
- // Return models from API - filter to chat models only
624
- const chatModels = response.data
625
- .map(m => m.id)
626
- .filter(id => id && (
627
- id.includes('gpt') ||
628
- id.includes('o1') ||
629
- id.includes('o3') ||
630
- id.includes('claude') ||
631
- id.includes('gemini')
632
- ))
633
- .filter(id =>
634
- !id.includes('embedding') &&
635
- !id.includes('whisper') &&
636
- !id.includes('tts') &&
637
- !id.includes('dall-e')
638
- );
639
-
640
- return chatModels.length > 0 ? chatModels : null;
641
- }
642
- return null;
643
- } catch (error) {
644
- return null;
645
- }
646
- };
647
-
648
- /**
649
- * Fetch available models for OAuth-authenticated providers
650
- * Uses multiple API endpoints to discover available models
651
- *
652
- * @param {string} providerId - Provider ID (anthropic, openai, gemini, etc.)
653
- * @param {string} accessToken - OAuth access token
654
- * @returns {Promise<Array|null>} Array of model IDs from API, null if unavailable
655
- *
656
- * Data sources:
657
- * - OpenAI: https://api.openai.com/v1/models (GET)
658
- * - Anthropic: https://api.anthropic.com/v1/models (GET)
659
- * - Gemini: https://generativelanguage.googleapis.com/v1/models (GET)
660
- */
661
- const fetchModelsWithOAuth = async (providerId, accessToken) => {
662
- if (!accessToken) return null;
663
-
664
- try {
665
- switch (providerId) {
666
- case 'anthropic':
667
- return await fetchAnthropicModelsOAuth(accessToken);
668
-
669
- case 'openai': {
670
- // Try OpenAI /v1/models endpoint with OAuth token
671
- // NO HARDCODED FALLBACK - models must come from API only
672
- const openaiModels = await fetchOpenAIModels('https://api.openai.com/v1', accessToken);
673
- if (openaiModels && openaiModels.length > 0) {
674
- return openaiModels;
675
- }
676
-
677
- // Try alternative: ChatGPT backend API (for Plus/Pro plans)
678
- try {
679
- const chatgptUrl = 'https://chatgpt.com/backend-api/models';
680
- const chatgptHeaders = {
681
- 'Authorization': `Bearer ${accessToken}`,
682
- 'Content-Type': 'application/json'
683
- };
684
- const chatgptResponse = await makeRequest(chatgptUrl, {
685
- method: 'GET',
686
- headers: chatgptHeaders,
687
- timeout: 10000
688
- });
689
- if (chatgptResponse.models && Array.isArray(chatgptResponse.models)) {
690
- return chatgptResponse.models
691
- .map(m => m.slug || m.id || m.name)
692
- .filter(Boolean);
693
- }
694
- } catch (e) {
695
- if (process.env.HQX_DEBUG) {
696
- console.error('[DEBUG] ChatGPT backend error:', e.message);
697
- }
698
- }
699
-
700
- return null;
701
- }
702
-
703
- case 'gemini': {
704
- // Gemini OAuth - fetch from Generative Language API
705
- // NO HARDCODED FALLBACK - models must come from API only
706
- try {
707
- const geminiUrl = 'https://generativelanguage.googleapis.com/v1/models';
708
- const geminiHeaders = {
709
- 'Authorization': `Bearer ${accessToken}`
710
- };
711
- const geminiResponse = await makeRequest(geminiUrl, {
712
- method: 'GET',
713
- headers: geminiHeaders,
714
- timeout: 15000
715
- });
716
- if (geminiResponse.models && Array.isArray(geminiResponse.models)) {
717
- const models = geminiResponse.models
718
- .filter(m => m.supportedGenerationMethods?.includes('generateContent'))
719
- .map(m => m.name.replace('models/', ''))
720
- .filter(Boolean);
721
- if (models.length > 0) return models;
722
- }
723
- } catch (e) {
724
- if (process.env.HQX_DEBUG) {
725
- console.error('[DEBUG] Gemini models API error:', e.message);
726
- }
727
- }
728
-
729
- return null;
730
- }
731
-
732
- case 'qwen': {
733
- // Qwen - try to fetch models from Alibaba Cloud API
734
- try {
735
- const qwenUrl = 'https://dashscope.aliyuncs.com/api/v1/models';
736
- const qwenHeaders = {
737
- 'Authorization': `Bearer ${accessToken}`,
738
- 'Content-Type': 'application/json'
739
- };
740
- const qwenResponse = await makeRequest(qwenUrl, {
741
- method: 'GET',
742
- headers: qwenHeaders,
743
- timeout: 10000
744
- });
745
- if (qwenResponse.data && Array.isArray(qwenResponse.data)) {
746
- return qwenResponse.data
747
- .map(m => m.id || m.model_id)
748
- .filter(Boolean);
749
- }
750
- } catch (e) {
751
- // Qwen API may not support model listing
752
- }
753
- return null;
754
- }
755
-
756
- case 'iflow': {
757
- // iFlow - fetch models from iFlow API
758
- try {
759
- const iflowUrl = 'https://apis.iflow.cn/v1/models';
760
- const iflowHeaders = {
761
- 'Authorization': `Bearer ${accessToken}`,
762
- 'Content-Type': 'application/json'
763
- };
764
- const iflowResponse = await makeRequest(iflowUrl, {
765
- method: 'GET',
766
- headers: iflowHeaders,
767
- timeout: 10000
768
- });
769
- if (iflowResponse.data && Array.isArray(iflowResponse.data)) {
770
- return iflowResponse.data
771
- .map(m => m.id)
772
- .filter(Boolean);
773
- }
774
- } catch (e) {
775
- // iFlow API may not support model listing
776
- }
777
- return null;
778
- }
779
-
780
- default:
781
- return null;
782
- }
783
- } catch (error) {
784
- return null;
785
- }
786
- };
787
-
788
- /**
789
- * Fetch models via local CLIProxyAPI proxy
790
- * @returns {Promise<Array|null>} Array of model IDs or null
791
- */
792
- const fetchModelsViaProxy = async (proxyPort = 8317) => {
793
- const url = `http://127.0.0.1:${proxyPort}/v1/models`;
794
-
795
- const headers = {
796
- 'Authorization': 'Bearer hqx-local-key'
797
- };
798
-
799
- try {
800
- const response = await makeRequest(url, { method: 'GET', headers, timeout: 10000 });
801
- if (response.data && Array.isArray(response.data)) {
802
- return response.data.map(m => m.id || m).filter(Boolean);
803
- }
804
- return null;
805
- } catch (error) {
806
- return null;
807
- }
808
- };
322
+ // Wrapper functions for analysis (pass callAI to implementation)
323
+ const analyzeTrading = (agent, data) => analyzeTradingImpl(callAI, agent, data);
324
+ const analyzePerformance = (agent, performanceData) => analyzePerformanceImpl(callAI, agent, performanceData);
325
+ const getMarketAdvice = (agent, marketData) => getMarketAdviceImpl(callAI, agent, marketData);
809
326
 
810
327
  module.exports = {
811
328
  callAI,