#!/usr/bin/env node /** * Simple 24/7 Background Automation Daemon * Runs as a background process in Docker container */ const { spawn } = require('child_process'); const fs = require('fs').promises; const path = require('path'); class BackgroundAutomation { constructor() { this.logFile = '/tmp/automation-24x7.log'; this.pidFile = '/tmp/automation-24x7.pid'; this.config = { symbol: 'SOLUSD', timeframe: '60', intervalMinutes: 60, autoExecuteThreshold: 60 }; } async log(message) { const timestamp = new Date().toISOString(); const logEntry = `[${timestamp}] ${message}\n`; console.log(logEntry.trim()); try { await fs.appendFile(this.logFile, logEntry); } catch (error) { // Ignore file errors } } async isRunning() { try { const pidData = await fs.readFile(this.pidFile, 'utf8'); const pid = parseInt(pidData.trim()); // Check if process exists try { process.kill(pid, 0); // Signal 0 checks if process exists return { running: true, pid }; } catch (error) { // Process doesn't exist await fs.unlink(this.pidFile).catch(() => {}); return { running: false, pid: null }; } } catch (error) { return { running: false, pid: null }; } } async start() { const status = await this.isRunning(); if (status.running) { await this.log(`⚠️ Automation already running (PID: ${status.pid})`); return { success: false, message: 'Already running', pid: status.pid }; } await this.log('πŸš€ Starting 24/7 Background Automation...'); // Start the main automation loop this.startAutomationLoop(); await this.log(`βœ… Automation started (PID: ${process.pid})`); return { success: true, message: 'Started', pid: process.pid }; } async startAutomationLoop() { // Save PID await fs.writeFile(this.pidFile, process.pid.toString()); // Handle cleanup on exit process.on('SIGTERM', () => this.cleanup()); process.on('SIGINT', () => this.cleanup()); process.on('exit', () => this.cleanup()); let cycleCount = 0; // Main automation loop const runCycle = async () => { try { cycleCount++; await this.log(`πŸ”„ Starting analysis cycle #${cycleCount}`); // Get analysis const analysis = await this.getAnalysis(); if (analysis && analysis.confidence >= this.config.autoExecuteThreshold) { await this.log(`🎯 Executing trade: ${analysis.recommendation} (${analysis.confidence}% confidence)`); await this.createPaperTrade(analysis); } else if (analysis) { await this.log(`⏸️ No trade: ${analysis.recommendation} (${analysis.confidence}% confidence < ${this.config.autoExecuteThreshold}% threshold)`); } } catch (error) { await this.log(`❌ Cycle error: ${error.message}`); } }; // Run first cycle immediately await runCycle(); // Schedule recurring cycles setInterval(runCycle, this.config.intervalMinutes * 60 * 1000); await this.log(`⏰ Scheduled to run every ${this.config.intervalMinutes} minutes`); } async getAnalysis() { try { // Use curl to avoid fetch dependencies const { exec } = require('child_process'); const { promisify } = require('util'); const execAsync = promisify(exec); const { stdout } = await execAsync(`curl -s "http://localhost:9001/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}"`); const data = JSON.parse(stdout); if (data.success && data.data && data.data.analysis) { return data.data.analysis; } return null; } catch (error) { await this.log(`❌ Analysis error: ${error.message}`); return null; } } async createPaperTrade(analysis) { try { // Use curl to avoid fetch dependencies const { exec } = require('child_process'); const { promisify } = require('util'); const execAsync = promisify(exec); const tradeData = { symbol: this.config.symbol, side: analysis.recommendation, amount: 100, entry: analysis.entry, stopLoss: analysis.stopLoss, takeProfit: analysis.takeProfit, confidence: analysis.confidence, reasoning: analysis.reasoning, source: '24x7_daemon' }; const curlCommand = `curl -s -X POST http://localhost:9001/api/safe-paper-trading/create-trade \ -H "Content-Type: application/json" \ -d '${JSON.stringify(tradeData)}'`; const { stdout } = await execAsync(curlCommand); const result = JSON.parse(stdout); if (result.success) { await this.log(`βœ… Paper trade created: ${result.trade.id}`); } else { await this.log(`❌ Trade creation failed: ${result.message}`); } } catch (error) { await this.log(`❌ Trade creation error: ${error.message}`); } } async stop() { const status = await this.isRunning(); if (!status.running) { await this.log('⚠️ Automation not running'); return { success: false, message: 'Not running' }; } try { process.kill(status.pid, 'SIGTERM'); await fs.unlink(this.pidFile).catch(() => {}); await this.log(`πŸ›‘ Automation stopped (PID: ${status.pid})`); return { success: true, message: 'Stopped', pid: status.pid }; } catch (error) { await this.log(`❌ Stop error: ${error.message}`); return { success: false, message: error.message }; } } async cleanup() { try { await fs.unlink(this.pidFile).catch(() => {}); await this.log('🧹 Cleanup completed'); } catch (error) { // Ignore cleanup errors } } async getStatus() { const status = await this.isRunning(); let logs = ''; try { const logData = await fs.readFile(this.logFile, 'utf8'); logs = logData.split('\n').slice(-10).join('\n'); // Last 10 lines } catch (error) { logs = 'No logs available'; } return { running: status.running, pid: status.pid, config: this.config, recentLogs: logs }; } } // Create instance const daemon = new BackgroundAutomation(); // CLI interface if (require.main === module) { const command = process.argv[2]; switch (command) { case 'start': daemon.start().then(result => { console.log(JSON.stringify(result, null, 2)); if (result.success) { // Keep process alive process.stdin.resume(); } else { process.exit(1); } }); break; case 'stop': daemon.stop().then(result => { console.log(JSON.stringify(result, null, 2)); process.exit(0); }); break; case 'status': daemon.getStatus().then(status => { console.log(JSON.stringify(status, null, 2)); process.exit(0); }); break; default: console.log(` πŸ€– 24/7 Background Automation Daemon Usage: node automation-daemon.js start # Start in background node automation-daemon.js stop # Stop daemon node automation-daemon.js status # Check status Features: βœ… True background process βœ… Survives browser close βœ… Auto-executes trades β‰₯60% confidence βœ… Logs all activity βœ… Safe paper trading only `); } } // Export for API use module.exports = { daemon };