#!/usr/bin/env node /** * Robust 24/7 Trading Automation * Handles API timeouts and network issues gracefully */ class RobustAutomation { constructor() { this.config = { symbol: 'SOLUSD', timeframe: '60', intervalMinutes: 60, autoExecuteThreshold: 60, apiHost: '192.168.0.1:9001', requestTimeout: 30000 // 30 seconds }; this.cycleCount = 0; this.stats = { startTime: new Date(), totalCycles: 0, totalTrades: 0, successfulCycles: 0, failedCycles: 0, lastSignal: null, lastTrade: null }; } async log(message) { const timestamp = new Date().toISOString(); console.log(`[${timestamp}] ${message}`); } async makeRequest(url, options = {}) { try { // Add timeout to all requests const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.config.requestTimeout); const response = await fetch(url, { ...options, signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return await response.json(); } catch (error) { if (error.name === 'AbortError') { await this.log(`⏱️ Request timeout: ${url}`); } else { await this.log(`❌ Request failed: ${error.message}`); } return null; } } async runAnalysisCycle() { this.stats.totalCycles++; await this.log(`πŸ”„ Analysis cycle #${this.stats.totalCycles}`); try { // Get current technical analysis with timeout await this.log(`πŸ“‘ Fetching analysis from API...`); const data = await this.makeRequest(`http://${this.config.apiHost}/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}`); if (data && data.success && data.data && data.data.analysis) { const analysis = data.data.analysis; this.stats.lastSignal = { time: new Date(), recommendation: analysis.recommendation, confidence: analysis.confidence }; await this.log(`πŸ“Š Signal: ${analysis.recommendation} (${analysis.confidence}% confidence)`); // Execute trade if confidence is high enough if (analysis.confidence >= this.config.autoExecuteThreshold && (analysis.recommendation === 'BUY' || analysis.recommendation === 'SELL')) { await this.log(`πŸš€ Executing ${analysis.recommendation} trade with ${analysis.confidence}% confidence`); const trade = await this.executeTrade(analysis); if (trade && trade.success) { this.stats.totalTrades++; this.stats.lastTrade = { time: new Date(), type: analysis.recommendation, confidence: analysis.confidence, price: trade.trade?.entry || analysis.entry?.price || 'unknown' }; await this.log(`βœ… Trade executed successfully: ${analysis.recommendation} at ${trade.trade?.entry || analysis.entry?.price || 'unknown'}`); } else { await this.log(`❌ Trade execution failed`); } } else { await this.log(`⏸️ Confidence ${analysis.confidence}% below threshold ${this.config.autoExecuteThreshold}% - holding`); } this.stats.successfulCycles++; } else { await this.log(`❌ No valid analysis data received`); this.stats.failedCycles++; } } catch (error) { await this.log(`❌ Cycle error: ${error.message}`); this.stats.failedCycles++; } // Print stats every cycle await this.printStats(); // Schedule next cycle const nextCycle = new Date(Date.now() + this.config.intervalMinutes * 60 * 1000); await this.log(`⏰ Next cycle: ${nextCycle.toLocaleTimeString()}`); await this.log(`πŸ”„ Scheduling next cycle in ${this.config.intervalMinutes} minutes...`); setTimeout(() => this.runAnalysisCycle(), this.config.intervalMinutes * 60 * 1000); } async executeTrade(analysis) { try { await this.log(`πŸ’± Preparing trade data...`); const tradeData = { symbol: this.config.symbol, side: analysis.recommendation, amount: 100, // $100 paper trade entry: analysis.entry?.price || 150, // Use analysis entry price or fallback confidence: analysis.confidence, reasoning: analysis.reasoning || 'Automated trade from analysis', source: 'robust_automation_24x7' }; await this.log(`πŸ“€ Sending trade request...`); const result = await this.makeRequest(`http://${this.config.apiHost}/api/safe-paper-trading/create-trade`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(tradeData) }); return result; } catch (error) { await this.log(`❌ Trade execution error: ${error.message}`); return null; } } async printStats() { const uptime = Math.floor((Date.now() - this.stats.startTime) / 1000 / 60); // minutes const successRate = this.stats.totalCycles > 0 ? Math.round((this.stats.successfulCycles / this.stats.totalCycles) * 100) : 0; await this.log(`πŸ“ˆ Stats: ${this.stats.totalCycles} cycles (${successRate}% success), ${this.stats.totalTrades} trades, ${uptime}m uptime`); if (this.stats.lastSignal) { const signalAge = Math.floor((Date.now() - this.stats.lastSignal.time) / 1000 / 60); await this.log(`🎯 Last signal: ${this.stats.lastSignal.recommendation} (${this.stats.lastSignal.confidence}%) ${signalAge}m ago`); } if (this.stats.lastTrade) { const tradeAge = Math.floor((Date.now() - this.stats.lastTrade.time) / 1000 / 60); await this.log(`πŸ’° Last trade: ${this.stats.lastTrade.type} at ${this.stats.lastTrade.price} ${tradeAge}m ago`); } } async start() { await this.log('πŸš€ Robust 24/7 Trading Automation Started'); await this.log(`πŸ“Š Config: ${this.config.symbol} every ${this.config.intervalMinutes}m, threshold: ${this.config.autoExecuteThreshold}%`); await this.log(`🌐 API Host: ${this.config.apiHost}, Timeout: ${this.config.requestTimeout}ms`); // Start first cycle await this.runAnalysisCycle(); } } // Start the automation const automation = new RobustAutomation(); automation.start().catch(error => { console.error('πŸ’₯ Automation failed to start:', error); process.exit(1); });