FRONTEND PRESET CORRECTIONS: - Scalp Trading: 5m, 15m, 30m (was 5m, 15m) → 3 timeframes - Day Trading: 1h, 2h (was 1h, 4h) → 2 timeframes - Swing Trading: 4h, 1D (correct) → 2 timeframes UPDATED FILES: - lib/superior-screenshot-service.ts → Correct timeframe definitions - lib/auto-trading-service.ts → TRADING_CONFIGS match frontend - app/api/superior-screenshot/route.js → API presets corrected - Verification and test scripts updated PERFORMANCE ESTIMATES: - Scalp (3 timeframes): ~90s → ~30-40s parallel - Day Trading (2 timeframes): ~60s → ~20-30s parallel - Swing Trading (2 timeframes): ~60s → ~20-30s parallel - Extended (9 timeframes): ~270s → ~70-100s parallel System now matches frontend UI exactly with superior parallel capture!
307 lines
11 KiB
TypeScript
307 lines
11 KiB
TypeScript
import { superiorScreenshotService } from './superior-screenshot-service'
|
|
import { aiAnalysisService } from './ai-analysis'
|
|
import { automatedCleanupService } from './automated-cleanup-service'
|
|
import aggressiveCleanup from './aggressive-cleanup'
|
|
|
|
export interface TradingConfig {
|
|
symbol: string
|
|
timeframes: string[]
|
|
layouts: string[]
|
|
intervalMs: number // How often to run analysis
|
|
maxCycles?: number // Optional limit for testing
|
|
}
|
|
|
|
export class AutoTradingService {
|
|
private isRunning = false
|
|
private currentCycle = 0
|
|
private config: TradingConfig | null = null
|
|
|
|
async start(config: TradingConfig) {
|
|
if (this.isRunning) {
|
|
console.log('⚠️ Trading service already running')
|
|
return
|
|
}
|
|
|
|
this.isRunning = true
|
|
this.config = config
|
|
this.currentCycle = 0
|
|
|
|
console.log('🚀 Starting automated trading service with robust cleanup...')
|
|
console.log('🔧 Config:', config)
|
|
|
|
// Start background cleanup service
|
|
automatedCleanupService.start(30000) // Every 30 seconds
|
|
|
|
// Start aggressive cleanup system
|
|
aggressiveCleanup.startPeriodicCleanup()
|
|
|
|
try {
|
|
while (this.isRunning && (!config.maxCycles || this.currentCycle < config.maxCycles)) {
|
|
this.currentCycle++
|
|
console.log(`\n🔄 === TRADING CYCLE ${this.currentCycle} ===`)
|
|
|
|
await this.runTradingCycle(config)
|
|
|
|
if (this.isRunning) {
|
|
console.log(`⏳ Waiting ${config.intervalMs/1000} seconds until next cycle...`)
|
|
await new Promise(resolve => setTimeout(resolve, config.intervalMs))
|
|
}
|
|
}
|
|
|
|
if (config.maxCycles && this.currentCycle >= config.maxCycles) {
|
|
console.log(`✅ Completed ${this.currentCycle} cycles (reached max limit)`)
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('❌ Trading service error:', error)
|
|
} finally {
|
|
await this.stop()
|
|
}
|
|
}
|
|
|
|
async stop() {
|
|
console.log('🛑 Stopping automated trading service...')
|
|
this.isRunning = false
|
|
|
|
// Stop cleanup services
|
|
automatedCleanupService.stop()
|
|
aggressiveCleanup.stop()
|
|
|
|
// Force cleanup all browser sessions
|
|
try {
|
|
await superiorScreenshotService.cleanup()
|
|
await aggressiveCleanup.forceCleanup()
|
|
console.log('✅ Trading service stopped and cleaned up')
|
|
} catch (cleanupError) {
|
|
console.error('❌ Error during final cleanup:', cleanupError)
|
|
}
|
|
}
|
|
|
|
private async runTradingCycle(config: TradingConfig): Promise<void> {
|
|
console.log(`🔄 Running trading cycle ${this.currentCycle}...`)
|
|
|
|
try {
|
|
console.log(`\n📊 Processing ${config.symbol} with ${config.timeframes.length} timeframes...`)
|
|
|
|
// Determine trading strategy based on timeframes for intelligent parallel capture
|
|
const timeframeSet = new Set(config.timeframes)
|
|
let preset: 'scalp' | 'day-trading' | 'swing-trading' | 'custom' = 'custom'
|
|
|
|
// Detect strategy based on timeframe patterns
|
|
if (timeframeSet.has('5') && timeframeSet.has('15') && timeframeSet.has('30') && config.timeframes.length === 3) {
|
|
preset = 'scalp'
|
|
console.log('🎯 Detected: SCALP trading strategy (5m, 15m, 30m)')
|
|
} else if (timeframeSet.has('60') && timeframeSet.has('120') && config.timeframes.length === 2) {
|
|
preset = 'day-trading'
|
|
console.log('🎯 Detected: DAY TRADING strategy (1h, 2h)')
|
|
} else if (timeframeSet.has('240') && timeframeSet.has('1D') && config.timeframes.length === 2) {
|
|
preset = 'swing-trading'
|
|
console.log('🎯 Detected: SWING TRADING strategy (4h, 1d)')
|
|
} else {
|
|
preset = 'custom'
|
|
console.log('🎯 Using: CUSTOM timeframe configuration')
|
|
}
|
|
|
|
// Capture screenshots using superior parallel technique
|
|
let screenshots: any[] = []
|
|
let allResults: any[] = []
|
|
|
|
if (preset === 'custom') {
|
|
// Custom timeframes - use parallel capture with custom preset
|
|
console.log('🚀 Using superior parallel capture with custom timeframes...')
|
|
allResults = await superiorScreenshotService.captureParallel({
|
|
symbol: config.symbol,
|
|
preset: 'custom',
|
|
timeframes: config.timeframes,
|
|
layouts: config.layouts,
|
|
analyze: false
|
|
})
|
|
} else {
|
|
// Standard preset - use optimized preset method
|
|
console.log(`🚀 Using superior parallel capture with ${preset} preset...`)
|
|
allResults = await superiorScreenshotService.captureParallel({
|
|
symbol: config.symbol,
|
|
preset: preset,
|
|
layouts: config.layouts,
|
|
analyze: false
|
|
})
|
|
}
|
|
|
|
// Extract successful screenshots for analysis
|
|
screenshots = allResults
|
|
.filter(result => result.success && result.screenshots)
|
|
.flatMap(result => result.screenshots || [])
|
|
|
|
if (screenshots.length > 0) {
|
|
console.log(`✅ Superior parallel capture completed: ${screenshots.length} screenshots`)
|
|
|
|
// Process results by timeframe for detailed analysis
|
|
for (const result of allResults) {
|
|
if (!result.success) {
|
|
console.error(`❌ Failed to capture ${result.timeframeName}: ${result.error}`)
|
|
continue
|
|
}
|
|
|
|
if (!result.screenshots || result.screenshots.length === 0) {
|
|
console.warn(`⚠️ No screenshots for ${result.timeframeName}`)
|
|
continue
|
|
}
|
|
|
|
try {
|
|
console.log(`\n🤖 Analyzing ${result.timeframeName} (${result.screenshots.length} screenshots)...`)
|
|
|
|
let analysis = null
|
|
if (result.screenshots.length === 1) {
|
|
analysis = await aiAnalysisService.analyzeScreenshot(result.screenshots[0])
|
|
} else if (result.screenshots.length > 1) {
|
|
analysis = await aiAnalysisService.analyzeMultipleScreenshots(result.screenshots)
|
|
}
|
|
|
|
if (analysis) {
|
|
console.log(`✅ Analysis completed for ${result.timeframeName}`)
|
|
console.log(`📈 Sentiment: ${analysis.marketSentiment || 'Unknown'}`)
|
|
console.log(`🎯 Recommendation: ${analysis.recommendation}, Confidence: ${analysis.confidence}%`)
|
|
|
|
// Process trading logic based on analysis
|
|
await this.processAnalysisForTrading(analysis, config.symbol, result.timeframeName)
|
|
} else {
|
|
console.warn(`⚠️ No analysis returned for ${result.timeframeName}`)
|
|
}
|
|
} catch (analysisError) {
|
|
console.error(`❌ Analysis failed for ${result.timeframeName}:`, analysisError)
|
|
}
|
|
}
|
|
} else {
|
|
console.error(`❌ No screenshots captured using superior parallel technique`)
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error(`❌ Error in trading cycle:`, error)
|
|
}
|
|
|
|
console.log(`✅ Trading cycle ${this.currentCycle} completed`)
|
|
|
|
// Run post-cycle cleanup to ensure no browser processes are left running
|
|
try {
|
|
await aggressiveCleanup.runPostAnalysisCleanup()
|
|
} catch (cleanupError) {
|
|
console.error('❌ Error in post-cycle cleanup:', cleanupError)
|
|
}
|
|
}
|
|
|
|
private async processAnalysisForTrading(analysis: any, symbol: string, timeframe: string): Promise<void> {
|
|
try {
|
|
console.log(`🎯 Processing trading analysis for ${symbol} ${timeframe}...`)
|
|
|
|
// Extract key trading signals from analysis
|
|
const sentiment = analysis.marketSentiment
|
|
const confidence = analysis.confidence || 0
|
|
const recommendation = analysis.recommendation
|
|
|
|
console.log(`📊 Sentiment: ${sentiment}, Recommendation: ${recommendation}, Confidence: ${confidence}%`)
|
|
|
|
if (analysis.keyLevels) {
|
|
console.log(`📈 Support levels: ${analysis.keyLevels.support.join(', ')}`)
|
|
console.log(`📉 Resistance levels: ${analysis.keyLevels.resistance.join(', ')}`)
|
|
}
|
|
|
|
// Trading decision logic
|
|
if (confidence >= 70) {
|
|
if (sentiment === 'BULLISH' && recommendation === 'BUY') {
|
|
console.log('🟢 HIGH CONFIDENCE BULLISH - Consider long position')
|
|
// await this.executeLongTrade(symbol, timeframe, analysis)
|
|
} else if (sentiment === 'BEARISH' && recommendation === 'SELL') {
|
|
console.log('🔴 HIGH CONFIDENCE BEARISH - Consider short position')
|
|
// await this.executeShortTrade(symbol, timeframe, analysis)
|
|
}
|
|
} else if (confidence >= 50) {
|
|
console.log('🟡 MODERATE CONFIDENCE - Monitor for confirmation')
|
|
} else {
|
|
console.log('⚪ LOW CONFIDENCE - Hold current positions')
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('❌ Error processing trading analysis:', error)
|
|
}
|
|
}
|
|
|
|
// Example trading execution methods (implement with your preferred exchange)
|
|
private async executeLongTrade(symbol: string, timeframe: string, analysis: any): Promise<void> {
|
|
console.log(`🟢 Executing LONG trade for ${symbol} based on ${timeframe} analysis`)
|
|
// Implement actual trading logic here
|
|
// This could use Drift Protocol, Jupiter DEX, or other trading interfaces
|
|
}
|
|
|
|
private async executeShortTrade(symbol: string, timeframe: string, analysis: any): Promise<void> {
|
|
console.log(`🔴 Executing SHORT trade for ${symbol} based on ${timeframe} analysis`)
|
|
// Implement actual trading logic here
|
|
}
|
|
|
|
// Status methods
|
|
getStatus() {
|
|
return {
|
|
isRunning: this.isRunning,
|
|
currentCycle: this.currentCycle,
|
|
config: this.config
|
|
}
|
|
}
|
|
|
|
getCurrentCycle(): number {
|
|
return this.currentCycle
|
|
}
|
|
|
|
isServiceRunning(): boolean {
|
|
return this.isRunning
|
|
}
|
|
}
|
|
|
|
// Example usage configurations
|
|
export const TRADING_CONFIGS = {
|
|
// Scalping configuration - frequent analysis of short timeframes
|
|
scalping: {
|
|
symbol: 'SOLUSD',
|
|
timeframes: ['5m', '15m', '30m'], // Updated to match frontend: 5m, 15m, 30m
|
|
layouts: ['ai', 'diy'],
|
|
intervalMs: 5 * 60 * 1000, // Every 5 minutes
|
|
maxCycles: 100 // Limit for testing
|
|
},
|
|
|
|
// Day trading configuration - moderate frequency on intraday timeframes
|
|
dayTrading: {
|
|
symbol: 'SOLUSD',
|
|
timeframes: ['1h', '2h'], // Updated to match frontend: 1h, 2h
|
|
layouts: ['ai', 'diy'],
|
|
intervalMs: 30 * 60 * 1000, // Every 30 minutes
|
|
maxCycles: 50 // Limit for testing
|
|
},
|
|
|
|
// Swing trading configuration - less frequent analysis of longer timeframes
|
|
swingTrading: {
|
|
symbol: 'SOLUSD',
|
|
timeframes: ['4h', '1d'], // Matches frontend: 4h, 1d
|
|
layouts: ['ai', 'diy'],
|
|
intervalMs: 2 * 60 * 60 * 1000, // Every 2 hours
|
|
maxCycles: 24 // Limit for testing
|
|
}
|
|
}
|
|
|
|
// Singleton instance
|
|
export const autoTradingService = new AutoTradingService()
|
|
|
|
// Example startup function
|
|
export async function startTradingBot(configName: keyof typeof TRADING_CONFIGS = 'dayTrading') {
|
|
const config = TRADING_CONFIGS[configName]
|
|
if (!config) {
|
|
throw new Error(`Unknown trading configuration: ${configName}`)
|
|
}
|
|
|
|
console.log(`🚀 Starting trading bot with ${configName} configuration`)
|
|
await autoTradingService.start(config)
|
|
}
|
|
|
|
// Graceful shutdown
|
|
export async function stopTradingBot() {
|
|
console.log('🛑 Stopping trading bot...')
|
|
await autoTradingService.stop()
|
|
}
|