Core Features: - True 24/7 automation runs without browser dependency - Server-side process in Docker container - Auto-executes paper trades with ≥60% confidence - Integrates with existing AI learning system - Safe paper trading mode only (zero real money risk) - working-24x7.js: Main automation process (currently running) - check-automation.js: Status monitoring and health checks - app/api/safe-paper-trading/create-trade/route.js: Paper trade API - app/api/automation-24x7/route.js: Automation control API - Fixed continuous learning state persistence issues - Added force enable function for debugging: window.forceEnableLearning() - Enhanced state restoration logic with immediate and delayed checks - Auto-execute toggle now properly unlocks when continuous learning active - System running successfully (PID: 3922502) - Already executed first automated paper trade (80% confidence SELL) - Scheduled to run every 60 minutes automatically - Logs all activity for monitoring and debugging ical Implementation: - Uses curl for HTTP requests (no fetch dependencies) - Background process with proper signal handling - Comprehensive error handling and logging - Integration with existing analysis pipeline - Maintains compatibility with browser-based safe paper trading This completes the 24/7 automation requirement - system now runs continuously in Docker container without requiring browser tabs to remain open.
264 lines
7.8 KiB
JavaScript
264 lines
7.8 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* 24/7 Server-Side Automation with AI Learning
|
|
* Runs continuously in Docker container without browser dependency
|
|
*/
|
|
|
|
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
|
|
class Server24x7Automation {
|
|
constructor() {
|
|
this.isRunning = false;
|
|
this.config = {
|
|
mode: 'SIMULATION', // Safe paper trading
|
|
symbol: 'SOLUSD',
|
|
timeframe: '60', // 1 hour
|
|
intervalMinutes: 60, // Run every 60 minutes
|
|
autoExecuteThreshold: 60, // Execute trades with ≥60% confidence
|
|
maxDailyTrades: 10,
|
|
tradingAmount: 100,
|
|
learningEnabled: true
|
|
};
|
|
this.stats = {
|
|
startTime: null,
|
|
totalCycles: 0,
|
|
totalTrades: 0,
|
|
successfulTrades: 0,
|
|
lastAnalysis: null,
|
|
lastTrade: null
|
|
};
|
|
this.intervalId = null;
|
|
}
|
|
|
|
async log(message) {
|
|
const timestamp = new Date().toISOString();
|
|
const logEntry = `[${timestamp}] ${message}`;
|
|
console.log(logEntry);
|
|
|
|
// Also save to log file
|
|
try {
|
|
await fs.appendFile('/tmp/24x7-automation.log', logEntry + '\n');
|
|
} catch (error) {
|
|
// Ignore file errors
|
|
}
|
|
}
|
|
|
|
async start() {
|
|
if (this.isRunning) {
|
|
await this.log('⚠️ Automation already running');
|
|
return { success: false, message: 'Already running' };
|
|
}
|
|
|
|
await this.log('🚀 Starting 24/7 Server Automation...');
|
|
await this.log(`📊 Config: ${this.config.symbol} ${this.config.timeframe}m, every ${this.config.intervalMinutes} minutes`);
|
|
await this.log(`🎯 Auto-execute threshold: ≥${this.config.autoExecuteThreshold}% confidence`);
|
|
|
|
this.isRunning = true;
|
|
this.stats.startTime = new Date();
|
|
|
|
// Run first cycle immediately
|
|
await this.runAnalysisCycle();
|
|
|
|
// Schedule recurring cycles
|
|
this.intervalId = setInterval(async () => {
|
|
try {
|
|
await this.runAnalysisCycle();
|
|
} catch (error) {
|
|
await this.log(`❌ Cycle error: ${error.message}`);
|
|
}
|
|
}, this.config.intervalMinutes * 60 * 1000);
|
|
|
|
await this.log('✅ 24/7 Automation started successfully');
|
|
return { success: true, message: '24/7 automation started' };
|
|
}
|
|
|
|
async stop() {
|
|
if (!this.isRunning) {
|
|
await this.log('⚠️ Automation not running');
|
|
return { success: false, message: 'Not running' };
|
|
}
|
|
|
|
this.isRunning = false;
|
|
if (this.intervalId) {
|
|
clearInterval(this.intervalId);
|
|
this.intervalId = null;
|
|
}
|
|
|
|
await this.log('🛑 24/7 Automation stopped');
|
|
return { success: true, message: 'Automation stopped' };
|
|
}
|
|
|
|
async runAnalysisCycle() {
|
|
this.stats.totalCycles++;
|
|
await this.log(`🔄 Starting analysis cycle #${this.stats.totalCycles}`);
|
|
|
|
try {
|
|
// 1. Get AI analysis
|
|
const analysis = await this.getAIAnalysis();
|
|
if (!analysis) {
|
|
await this.log('❌ Failed to get AI analysis');
|
|
return;
|
|
}
|
|
|
|
this.stats.lastAnalysis = new Date();
|
|
await this.log(`📊 Analysis: ${analysis.recommendation} (${analysis.confidence}% confidence)`);
|
|
|
|
// 2. Check if we should auto-execute
|
|
if (analysis.confidence >= this.config.autoExecuteThreshold) {
|
|
await this.log(`🎯 Confidence ${analysis.confidence}% ≥ threshold ${this.config.autoExecuteThreshold}% - executing trade`);
|
|
|
|
const tradeResult = await this.executeAutoTrade(analysis);
|
|
if (tradeResult.success) {
|
|
this.stats.totalTrades++;
|
|
this.stats.lastTrade = new Date();
|
|
await this.log(`✅ Auto-trade executed: ${tradeResult.message}`);
|
|
} else {
|
|
await this.log(`❌ Auto-trade failed: ${tradeResult.message}`);
|
|
}
|
|
} else {
|
|
await this.log(`⏸️ Confidence ${analysis.confidence}% < threshold ${this.config.autoExecuteThreshold}% - no trade`);
|
|
}
|
|
|
|
} catch (error) {
|
|
await this.log(`❌ Analysis cycle error: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
async getAIAnalysis() {
|
|
try {
|
|
// Call the same API that the browser version uses
|
|
const response = await fetch(`http://localhost:9001/api/ai-analysis/latest?symbol=${this.config.symbol}&timeframe=${this.config.timeframe}`);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`API responded with ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success && data.data && data.data.analysis) {
|
|
return {
|
|
recommendation: data.data.analysis.recommendation,
|
|
confidence: data.data.analysis.confidence,
|
|
reasoning: data.data.analysis.reasoning,
|
|
entry: data.data.analysis.entry,
|
|
stopLoss: data.data.analysis.stopLoss,
|
|
takeProfit: data.data.analysis.takeProfit
|
|
};
|
|
}
|
|
|
|
return null;
|
|
} catch (error) {
|
|
await this.log(`❌ AI Analysis API error: ${error.message}`);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async executeAutoTrade(analysis) {
|
|
try {
|
|
// Create paper trade using the same API
|
|
const tradeData = {
|
|
symbol: this.config.symbol,
|
|
side: analysis.recommendation, // BUY or SELL
|
|
amount: this.config.tradingAmount,
|
|
entry: analysis.entry,
|
|
stopLoss: analysis.stopLoss,
|
|
takeProfit: analysis.takeProfit,
|
|
confidence: analysis.confidence,
|
|
reasoning: analysis.reasoning,
|
|
source: '24x7_automation'
|
|
};
|
|
|
|
const response = await fetch('http://localhost:9001/api/safe-paper-trading/create-trade', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(tradeData)
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Trade API responded with ${response.status}`);
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
this.stats.successfulTrades++;
|
|
return { success: true, message: `Paper trade created: ${result.trade.id}` };
|
|
} else {
|
|
return { success: false, message: result.message || 'Trade creation failed' };
|
|
}
|
|
|
|
} catch (error) {
|
|
return { success: false, message: error.message };
|
|
}
|
|
}
|
|
|
|
getStatus() {
|
|
const uptime = this.stats.startTime ? Math.floor((Date.now() - this.stats.startTime.getTime()) / 1000) : 0;
|
|
const successRate = this.stats.totalTrades > 0 ? Math.round((this.stats.successfulTrades / this.stats.totalTrades) * 100) : 0;
|
|
|
|
return {
|
|
isRunning: this.isRunning,
|
|
config: this.config,
|
|
stats: {
|
|
...this.stats,
|
|
uptime: `${Math.floor(uptime / 3600)}h ${Math.floor((uptime % 3600) / 60)}m`,
|
|
successRate: `${successRate}%`,
|
|
nextCycle: this.intervalId ? new Date(Date.now() + (this.config.intervalMinutes * 60 * 1000)) : null
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
// Create singleton instance
|
|
const automation24x7 = new Server24x7Automation();
|
|
|
|
// Export for API use
|
|
if (typeof module !== 'undefined') {
|
|
module.exports = { automation24x7 };
|
|
}
|
|
|
|
// CLI interface
|
|
if (require.main === module) {
|
|
const command = process.argv[2];
|
|
|
|
switch (command) {
|
|
case 'start':
|
|
automation24x7.start().then(result => {
|
|
console.log(result);
|
|
if (!result.success) process.exit(1);
|
|
});
|
|
break;
|
|
|
|
case 'stop':
|
|
automation24x7.stop().then(result => {
|
|
console.log(result);
|
|
process.exit(0);
|
|
});
|
|
break;
|
|
|
|
case 'status':
|
|
console.log(JSON.stringify(automation24x7.getStatus(), null, 2));
|
|
break;
|
|
|
|
default:
|
|
console.log(`
|
|
🤖 24/7 Server Automation
|
|
|
|
Usage:
|
|
node start-24-7-automation.js start # Start automation
|
|
node start-24-7-automation.js stop # Stop automation
|
|
node start-24-7-automation.js status # Check status
|
|
|
|
Features:
|
|
✅ Runs without browser dependency
|
|
✅ Safe paper trading mode
|
|
✅ AI analysis every 60 minutes
|
|
✅ Auto-execute trades ≥60% confidence
|
|
✅ Integrates with existing learning system
|
|
✅ Logs all activity
|
|
`);
|
|
}
|
|
}
|