feat: implement 24/7 server-side automation with AI learning integration

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.
This commit is contained in:
mindesbunister
2025-08-05 23:41:29 +02:00
parent d7de856ce0
commit 532c5c888e
10 changed files with 1166 additions and 89 deletions

View File

@@ -0,0 +1,76 @@
import { NextResponse } from 'next/server'
// Import the 24/7 automation service
let automation24x7
try {
const automationModule = require('../../../../start-24-7-automation.js')
automation24x7 = automationModule.automation24x7
} catch (error) {
console.error('❌ Could not load 24/7 automation service:', error.message)
}
export async function POST(request) {
try {
if (!automation24x7) {
return NextResponse.json({
success: false,
message: '24/7 automation service not available'
}, { status: 500 })
}
const { action, config } = await request.json()
if (action === 'start') {
// Update config if provided
if (config) {
Object.assign(automation24x7.config, config)
}
const result = await automation24x7.start()
return NextResponse.json(result)
} else if (action === 'stop') {
const result = await automation24x7.stop()
return NextResponse.json(result)
} else {
return NextResponse.json({
success: false,
message: 'Invalid action. Use "start" or "stop"'
}, { status: 400 })
}
} catch (error) {
console.error('❌ 24/7 automation control error:', error)
return NextResponse.json({
success: false,
message: 'Failed to control automation',
error: error.message
}, { status: 500 })
}
}
export async function GET(request) {
try {
if (!automation24x7) {
return NextResponse.json({
success: false,
message: '24/7 automation service not available'
}, { status: 500 })
}
const status = automation24x7.getStatus()
return NextResponse.json({
success: true,
automation: status
})
} catch (error) {
console.error('❌ 24/7 automation status error:', error)
return NextResponse.json({
success: false,
message: 'Failed to get automation status',
error: error.message
}, { status: 500 })
}
}

View File

@@ -0,0 +1,111 @@
import { NextResponse } from 'next/server'
// Simple in-memory storage for paper trades (in production, use database)
let paperTrades = []
let tradeIdCounter = 1
export async function POST(request) {
try {
const tradeData = await request.json()
// Validate required fields
const required = ['symbol', 'side', 'amount', 'entry', 'confidence']
for (const field of required) {
if (!tradeData[field]) {
return NextResponse.json({
success: false,
message: `Missing required field: ${field}`
}, { status: 400 })
}
}
// Create paper trade
const trade = {
id: `PAPER_${Date.now()}_${tradeIdCounter++}`,
symbol: tradeData.symbol,
side: tradeData.side,
amount: tradeData.amount,
entry: tradeData.entry,
stopLoss: tradeData.stopLoss,
takeProfit: tradeData.takeProfit,
confidence: tradeData.confidence,
reasoning: tradeData.reasoning,
source: tradeData.source || 'manual',
status: 'OPEN',
createdAt: new Date().toISOString(),
pnl: 0,
fees: 0
}
// Store trade
paperTrades.push(trade)
console.log(`📄 Paper trade created: ${trade.id} - ${trade.side} ${trade.symbol} at $${trade.entry} (${trade.confidence}% confidence)`)
// Log to AI learning system if available
try {
const learningData = {
id: `decision_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
symbol: trade.symbol,
timeframe: '60',
side: trade.side,
confidence: trade.confidence,
entry: trade.entry,
stopLoss: trade.stopLoss,
takeProfit: trade.takeProfit,
reasoning: trade.reasoning,
source: 'paper_trade_automation',
createdAt: new Date().toISOString()
}
// Store in learning system (try to call learning API)
fetch('http://localhost:9001/api/ai-learning/record-decision', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(learningData)
}).catch(error => {
console.log('⚠️ Could not log to learning system:', error.message)
})
} catch (error) {
console.log('⚠️ Learning system integration error:', error.message)
}
return NextResponse.json({
success: true,
message: 'Paper trade created successfully',
trade: trade
})
} catch (error) {
console.error('❌ Create paper trade error:', error)
return NextResponse.json({
success: false,
message: 'Failed to create paper trade',
error: error.message
}, { status: 500 })
}
}
export async function GET(request) {
try {
// Return all paper trades
return NextResponse.json({
success: true,
trades: paperTrades,
summary: {
total: paperTrades.length,
open: paperTrades.filter(t => t.status === 'OPEN').length,
closed: paperTrades.filter(t => t.status === 'CLOSED').length,
totalPnL: paperTrades.reduce((sum, t) => sum + (t.pnl || 0), 0)
}
})
} catch (error) {
console.error('❌ Get paper trades error:', error)
return NextResponse.json({
success: false,
message: 'Failed to get paper trades',
error: error.message
}, { status: 500 })
}
}

View File

@@ -147,18 +147,42 @@ export default function SafePaperTradingPage() {
if (savedContinuousLearning === 'true') { if (savedContinuousLearning === 'true') {
console.log('🔄 Restoring continuous learning state...') console.log('🔄 Restoring continuous learning state...')
setContinuousLearning(true) setContinuousLearning(true)
// Force restart continuous learning immediately
setTimeout(() => { setTimeout(() => {
console.log('🎓 Starting continuous learning from restored state') console.log('🎓 Starting continuous learning from restored state')
startContinuousLearning() startContinuousLearning()
}, 2000) }, 1000) // Reduced delay
} else {
console.log('💡 No continuous learning state found - user needs to start manually')
} }
} catch (error) { } catch (error) {
console.error('⚠️ Error checking continuous learning state:', error) console.error('⚠️ Error checking continuous learning state:', error)
} }
} }
// Check state after a short delay to ensure everything is loaded // Force enable learning for testing - DEBUG FUNCTION
setTimeout(checkContinuousLearningState, 1000) const forceEnableLearning = () => {
console.log('🔧 FORCE ENABLING CONTINUOUS LEARNING...')
localStorage.setItem('safePaperTrading_continuousLearning', 'true')
setContinuousLearning(true)
setTimeout(() => {
console.log('🎓 Force starting continuous learning')
startContinuousLearning()
}, 500)
console.log('✅ Continuous learning forcefully enabled')
}
// Check state immediately
checkContinuousLearningState()
// Expose force enable function to browser console for debugging
if (typeof window !== 'undefined') {
window.forceEnableLearning = forceEnableLearning
console.log('🔧 Debug function exposed: window.forceEnableLearning()')
}
// Also check after a short delay to ensure everything is loaded
setTimeout(checkContinuousLearningState, 2000)
}, []) }, [])
// Persist analysis data whenever it changes // Persist analysis data whenever it changes
@@ -810,51 +834,6 @@ export default function SafePaperTradingPage() {
</div> </div>
</div> </div>
{/* AI LEARNING SETUP NOTICE */}
{!continuousLearning || !autoExecuteTrades ? (
<div className="bg-blue-900/30 border border-blue-600 rounded-lg p-4">
<h3 className="text-blue-400 font-bold text-lg mb-2">🤖 Enable AI Learning from Virtual Trading</h3>
<div className="text-sm text-blue-300 mb-3">
<strong>Current Issue:</strong> AI is analyzing but not learning from outcomes because virtual trading is not enabled.
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="bg-blue-800/30 rounded p-3">
<h4 className="text-blue-300 font-medium mb-1">Step 1: Enable Continuous Learning</h4>
<p className="text-xs text-blue-200">
{continuousLearning ? '✅ Enabled' : '❌ Click "🎓 Start Learning" button below'}
</p>
</div>
<div className="bg-blue-800/30 rounded p-3">
<h4 className="text-blue-300 font-medium mb-1">Step 2: Enable Auto-Execute</h4>
<p className="text-xs text-blue-200">
{autoExecuteTrades ? '✅ Enabled' : continuousLearning ? '❌ Enable "Auto-Execute Trades" below' : '⏸️ Waiting for Step 1'}
</p>
</div>
</div>
<div className="mt-3 text-xs text-blue-300 bg-blue-800/20 px-3 py-2 rounded">
<strong>Result:</strong> AI will automatically execute virtual trades track outcomes learn patterns improve over time
</div>
</div>
) : (
<div className="bg-green-900/30 border border-green-600 rounded-lg p-4">
<h3 className="text-green-400 font-bold text-lg mb-2"> AI Learning System Active</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-sm">
<div className="text-green-300">
<span className="font-medium">🎓 Continuous Learning:</span> ON
</div>
<div className="text-green-300">
<span className="font-medium">🤖 Auto-Execute:</span> ON
</div>
<div className="text-green-300">
<span className="font-medium">📈 Virtual Trading:</span> Active
</div>
</div>
<div className="mt-2 text-xs text-green-300">
🧠 AI will automatically execute virtual trades based on analysis and learn from outcomes to improve performance
</div>
</div>
)}
{/* Header with Balance */} {/* Header with Balance */}
<div className="bg-gray-800/50 rounded-lg p-6 border border-gray-700"> <div className="bg-gray-800/50 rounded-lg p-6 border border-gray-700">
<div className="flex items-center justify-between mb-4"> <div className="flex items-center justify-between mb-4">
@@ -995,51 +974,34 @@ export default function SafePaperTradingPage() {
</button> </button>
</div> </div>
{/* Auto-Execute Toggle - Show always, but disabled until continuous learning is active */} {/* Auto-Execute Toggle - Only show when continuous learning is active */}
{continuousLearning && (
<div className="mt-4 p-3 bg-gray-800 rounded-lg border border-gray-700"> <div className="mt-4 p-3 bg-gray-800 rounded-lg border border-gray-700">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex flex-col"> <div className="flex flex-col">
<span className="text-sm font-medium text-gray-300">Auto-Execute Trades</span> <span className="text-sm font-medium text-gray-300">Auto-Execute Trades</span>
<span className="text-xs text-gray-400"> <span className="text-xs text-gray-400">Automatically execute paper trades based on AI recommendations (60% confidence)</span>
{continuousLearning
? "Automatically execute paper trades based on AI recommendations (≥60% confidence)"
: "⚠️ Enable Continuous Learning first to activate auto-execute virtual trading"
}
</span>
</div> </div>
<button <button
onClick={() => { onClick={() => setAutoExecuteTrades(!autoExecuteTrades)}
if (!continuousLearning) {
alert('Please enable Continuous Learning first to activate auto-execute virtual trading!')
return
}
setAutoExecuteTrades(!autoExecuteTrades)
}}
disabled={!continuousLearning}
className={`ml-4 px-4 py-2 rounded-lg font-medium transition-all duration-200 ${ className={`ml-4 px-4 py-2 rounded-lg font-medium transition-all duration-200 ${
!continuousLearning autoExecuteTrades
? 'bg-gray-500 text-gray-400 cursor-not-allowed opacity-50'
: autoExecuteTrades
? 'bg-green-600 hover:bg-green-700 text-white' ? 'bg-green-600 hover:bg-green-700 text-white'
: 'bg-gray-600 hover:bg-gray-700 text-white' : 'bg-gray-600 hover:bg-gray-700 text-white'
}`} }`}
> >
{!continuousLearning ? '🔒 Locked' : autoExecuteTrades ? '🤖 ON' : '📄 Manual'} {autoExecuteTrades ? '🤖 ON' : '📄 Manual'}
</button> </button>
</div> </div>
{autoExecuteTrades && continuousLearning && ( {autoExecuteTrades && (
<div className="mt-2 text-xs text-yellow-400"> <div className="mt-2 text-xs text-yellow-400">
Paper trades will be executed automatically when AI recommends BUY/SELL with 60% confidence Paper trades will be executed automatically when AI recommends BUY/SELL with 60% confidence
</div> </div>
)} )}
{!continuousLearning && (
<div className="mt-2 text-xs text-blue-400 bg-blue-900/20 px-2 py-1 rounded">
💡 <strong>For AI Learning:</strong> Enable "Continuous Learning" + "Auto-Execute" so the AI can learn from virtual trade outcomes
</div> </div>
)} )}
</div> </div>
</div> </div>
</div>
{/* Multi-Timeframe Selection */} {/* Multi-Timeframe Selection */}
<div className="mb-6"> <div className="mb-6">

271
automation-daemon.js Normal file
View File

@@ -0,0 +1,271 @@
#!/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 };

90
check-automation.js Normal file
View File

@@ -0,0 +1,90 @@
#!/usr/bin/env node
// Quick automation status checker
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
async function checkStatus() {
console.log('🤖 24/7 AUTOMATION STATUS CHECK\n');
try {
// Check if process is running
const { stdout } = await execAsync('ps aux | grep "working-24x7" | grep -v grep');
if (stdout.trim()) {
console.log('✅ AUTOMATION STATUS: RUNNING');
console.log(`📊 Process: ${stdout.trim().split(/\s+/).slice(0, 11).join(' ')}`);
} else {
console.log('❌ AUTOMATION STATUS: NOT RUNNING');
return;
}
} catch (error) {
console.log('❌ AUTOMATION STATUS: NOT RUNNING');
return;
}
try {
// Check recent logs
const { stdout: logs } = await execAsync('tail -5 nohup.out');
console.log('\n📝 RECENT LOGS:');
console.log(logs);
} catch (error) {
console.log('\n⚠ No logs available');
}
try {
// Check current analysis
const { stdout } = await execAsync('curl -s "http://localhost:9001/api/ai-analysis/latest?symbol=SOLUSD&timeframe=60"');
const data = JSON.parse(stdout);
if (data.success && data.data && data.data.analysis) {
const analysis = data.data.analysis;
console.log('\n📊 CURRENT ANALYSIS:');
console.log(` Signal: ${analysis.recommendation}`);
console.log(` Confidence: ${analysis.confidence}%`);
console.log(` Entry: $${analysis.entry}`);
console.log(` Status: ${analysis.confidence >= 60 ? '🎯 WILL AUTO-EXECUTE' : '⏸️ Below threshold'}`);
} else {
console.log('\n❌ No analysis data available');
}
} catch (error) {
console.log('\n❌ Analysis check failed:', error.message);
}
try {
// Check recent paper trades
const { stdout } = await execAsync('curl -s "http://localhost:9001/api/safe-paper-trading/create-trade"');
const data = JSON.parse(stdout);
if (data.success && data.trades) {
console.log('\n📄 PAPER TRADES:');
console.log(` Total: ${data.summary.total}`);
console.log(` Open: ${data.summary.open}`);
console.log(` Closed: ${data.summary.closed}`);
console.log(` P&L: $${data.summary.totalPnL}`);
// Show recent trades
const recentTrades = data.trades.slice(-3);
if (recentTrades.length > 0) {
console.log('\n📈 RECENT TRADES:');
recentTrades.forEach(trade => {
console.log(` ${trade.id}: ${trade.side} ${trade.symbol} @ $${trade.entry} (${trade.confidence}%)`);
});
}
}
} catch (error) {
console.log('\n⚠ Could not check paper trades');
}
console.log('\n🎯 AUTOMATION CONFIGURATION:');
console.log(' Symbol: SOLUSD');
console.log(' Timeframe: 1 hour');
console.log(' Interval: Every 60 minutes');
console.log(' Auto-execute: ≥60% confidence');
console.log(' Mode: Safe paper trading only');
console.log('\n✨ System is running 24/7 in your Docker container!');
}
checkStatus();

View File

@@ -0,0 +1,26 @@
#!/usr/bin/env node
// Quick script to enable continuous learning via browser console
console.log(`
🔧 ENABLE CONTINUOUS LEARNING MANUALLY
1. Open http://localhost:9001/safe-paper-trading in your browser
2. Open Developer Tools (F12)
3. Go to Console tab
4. Run this command:
window.forceEnableLearning()
5. Refresh the page - you should see:
- Button says "🛑 Stop Learning" (instead of Start)
- Auto-execute toggle becomes available: "🔒 Locked" → "🤖 OFF"
6. Click the auto-execute toggle to enable it: "🤖 OFF" → "🤖 ON"
7. Now when you get strong signals (≥60% confidence), it will auto-create paper trades!
Alternative: You can also run this in console:
localStorage.setItem('safePaperTrading_continuousLearning', 'true')
location.reload()
`);

7
nohup.out Normal file
View File

@@ -0,0 +1,7 @@
[2025-08-05T21:34:07.846Z] 🚀 24/7 AUTOMATION STARTED
[2025-08-05T21:34:07.848Z] 📊 SOLUSD every 60m, threshold ≥60%
[2025-08-05T21:34:07.848Z] 🔄 Analysis cycle #1
[2025-08-05T21:34:52.488Z] 📊 SELL (80% confidence)
[2025-08-05T21:34:52.489Z] 🎯 AUTO-EXECUTING: 80% ≥ 60%
[2025-08-05T21:34:52.961Z] ✅ TRADE CREATED: PAPER_1754429692956_1
[2025-08-05T21:34:53.032Z] ⏰ Next cycle: 12:34:52 AM

169
simple-24x7-automation.js Normal file
View File

@@ -0,0 +1,169 @@
#!/usr/bin/env node
/**
* Simple 24/7 Automation Service
* Direct execution without complex daemon management
*/
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
const fs = require('fs').promises;
class SimpleAutomation {
constructor() {
this.isRunning = false;
this.config = {
symbol: 'SOLUSD',
timeframe: '60',
intervalMinutes: 60,
autoExecuteThreshold: 60
};
this.stats = {
startTime: new Date(),
totalCycles: 0,
totalTrades: 0
};
}
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/automation-simple.log', logEntry + '\n');
} catch (error) {
// Ignore file errors
}
}
async start() {
if (this.isRunning) {
await this.log('⚠️ Already running');
return;
}
this.isRunning = true;
await this.log('🚀 Starting Simple 24/7 Automation...');
await this.log(`📊 Config: ${this.config.symbol} ${this.config.timeframe}m, every ${this.config.intervalMinutes} minutes`);
// Run first cycle immediately
await this.runCycle();
// Schedule recurring cycles
setInterval(async () => {
try {
await this.runCycle();
} catch (error) {
await this.log(`❌ Cycle error: ${error.message}`);
}
}, this.config.intervalMinutes * 60 * 1000);
await this.log('✅ 24/7 Automation running');
}
async runCycle() {
this.stats.totalCycles++;
await this.log(`🔄 Analysis cycle #${this.stats.totalCycles}`);
try {
// Get analysis using curl
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) {
const analysis = data.data.analysis;
await this.log(`📊 Analysis: ${analysis.recommendation} (${analysis.confidence}% confidence)`);
// Check if we should execute trade
if (analysis.confidence >= this.config.autoExecuteThreshold) {
await this.log(`🎯 Executing trade: confidence ${analysis.confidence}% ≥ ${this.config.autoExecuteThreshold}%`);
await this.executeTrade(analysis);
} else {
await this.log(`⏸️ No trade: confidence ${analysis.confidence}% < ${this.config.autoExecuteThreshold}%`);
}
} else {
await this.log('❌ No analysis data received');
}
} catch (error) {
await this.log(`❌ Cycle error: ${error.message}`);
}
}
async executeTrade(analysis) {
try {
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: 'simple_24x7'
};
// Use curl to create paper trade
const curlData = JSON.stringify(tradeData).replace(/'/g, "'\\''");
const { stdout } = await execAsync(`curl -s -X POST http://localhost:9001/api/safe-paper-trading/create-trade -H "Content-Type: application/json" -d '${curlData}'`);
const result = JSON.parse(stdout);
if (result.success) {
this.stats.totalTrades++;
await this.log(`✅ Paper trade created: ${result.trade.id}`);
} else {
await this.log(`❌ Trade failed: ${result.message}`);
}
} catch (error) {
await this.log(`❌ Trade execution error: ${error.message}`);
}
}
getStatus() {
const uptime = Math.floor((Date.now() - this.stats.startTime.getTime()) / 1000);
return {
isRunning: this.isRunning,
config: this.config,
stats: {
...this.stats,
uptime: `${Math.floor(uptime / 3600)}h ${Math.floor((uptime % 3600) / 60)}m`,
nextCycle: new Date(Date.now() + (this.config.intervalMinutes * 60 * 1000))
}
};
}
}
// Start automation
const automation = new SimpleAutomation();
// Handle graceful shutdown
process.on('SIGTERM', async () => {
await automation.log('🛑 Received SIGTERM, shutting down...');
process.exit(0);
});
process.on('SIGINT', async () => {
await automation.log('🛑 Received SIGINT, shutting down...');
process.exit(0);
});
// Start the automation
automation.start().catch(async (error) => {
await automation.log(`❌ Startup error: ${error.message}`);
process.exit(1);
});
// Keep process alive
console.log('🤖 Simple 24/7 Automation Service');
console.log('✅ Running in background - press Ctrl+C to stop');
console.log('📝 Logs: /tmp/automation-simple.log');
// Prevent the process from exiting
process.stdin.resume();

263
start-24-7-automation.js Normal file
View File

@@ -0,0 +1,263 @@
#!/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
`);
}
}

102
working-24x7.js Normal file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env node
/**
* Working 24/7 Automation - No stdin issues
*/
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
const fs = require('fs').promises;
class WorkingAutomation {
constructor() {
this.config = {
symbol: 'SOLUSD',
timeframe: '60',
intervalMinutes: 60,
autoExecuteThreshold: 60
};
this.stats = {
startTime: new Date(),
totalCycles: 0,
totalTrades: 0
};
}
async log(message) {
const timestamp = new Date().toISOString();
const logEntry = `[${timestamp}] ${message}`;
console.log(logEntry);
}
async runCycle() {
this.stats.totalCycles++;
await this.log(`🔄 Analysis cycle #${this.stats.totalCycles}`);
try {
// Get current analysis
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) {
const analysis = data.data.analysis;
await this.log(`📊 ${analysis.recommendation} (${analysis.confidence}% confidence)`);
if (analysis.confidence >= this.config.autoExecuteThreshold) {
await this.log(`🎯 AUTO-EXECUTING: ${analysis.confidence}% ≥ ${this.config.autoExecuteThreshold}%`);
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: 'automation_24x7'
};
// Create paper trade
const curlData = JSON.stringify(tradeData).replace(/"/g, '\\"');
const { stdout: tradeResult } = await execAsync(`curl -s -X POST http://localhost:9001/api/safe-paper-trading/create-trade -H "Content-Type: application/json" -d "${curlData}"`);
const result = JSON.parse(tradeResult);
if (result.success) {
this.stats.totalTrades++;
await this.log(`✅ TRADE CREATED: ${result.trade.id}`);
} else {
await this.log(`❌ TRADE FAILED: ${result.message}`);
}
} else {
await this.log(`⏸️ NO TRADE: ${analysis.confidence}% < ${this.config.autoExecuteThreshold}%`);
}
} else {
await this.log('❌ No analysis data available');
}
} catch (error) {
await this.log(`❌ Cycle error: ${error.message}`);
}
}
async start() {
await this.log('🚀 24/7 AUTOMATION STARTED');
await this.log(`📊 ${this.config.symbol} every ${this.config.intervalMinutes}m, threshold ≥${this.config.autoExecuteThreshold}%`);
// Run first cycle
await this.runCycle();
// Schedule recurring cycles
setInterval(() => this.runCycle().catch(console.error), this.config.intervalMinutes * 60 * 1000);
await this.log(`⏰ Next cycle: ${new Date(Date.now() + this.config.intervalMinutes * 60 * 1000).toLocaleTimeString()}`);
}
}
// Create and start automation
const automation = new WorkingAutomation();
automation.start();