Files
trading_bot_v3/lib/safe-parallel-automation.ts.broken
mindesbunister 0e3baa139f Fix automation system and AI learning integration
Fixed automation v2 start button (relative API URLs)
 Fixed batch analysis API endpoint in simple-automation
 Fixed AI learning storage with correct userId
 Implemented comprehensive learning data storage
 Fixed parallel analysis system working correctly

- Changed frontend API calls from localhost:9001 to relative URLs
- Updated simple-automation to use localhost:3000 for batch analysis
- Fixed learning integration with 'default-user' instead of 'system'
- AI learning now stores analysis results with confidence/recommendations
- Batch analysis working: 35s completion, 85% confidence, learning stored
- True parallel screenshot system operational (6 screenshots when multi-timeframe)
- Automation start/stop functionality fully working
2025-07-24 22:56:16 +02:00

327 lines
11 KiB
Plaintext

class SafeParallelAutomation {
private isRunning = false
private config: any = null
private intervalId: NodeJS.Timeout | null = null
private lastAnalysisTime = 0
// SAFE PARAMETERS - Respect timeframe strategy
private readonly MIN_ANALYSIS_INTERVAL = 10 * 60 * 1000 // 10 minutes minimum
private readonly MAX_TRADES_PER_HOUR = 2
private readonly ANALYSIS_COOLDOWN = 5 * 60 * 1000 // 5 minutes
private stats = {
totalTrades: 0,
successfulTrades: 0,
winRate: 0,
totalPnL: 0,
errorCount: 0,
lastAnalysis: null as string | null,
nextScheduled: null as string | null,
nextAnalysisIn: 0,
analysisInterval: 0,
currentCycle: 0,
lastError: null as string | null,
strategyType: 'General'
}
async startSafeAutomation(config: any): Promise<{ success: boolean, message?: string }> {
try {
if (this.isRunning) {
return { success: false, message: 'Safe automation already running' }
}
// SAFETY CHECK: Rate limiting
const now = Date.now()
if (now - this.lastAnalysisTime < this.ANALYSIS_COOLDOWN) {
const remaining = Math.ceil((this.ANALYSIS_COOLDOWN - (now - this.lastAnalysisTime)) / 1000)
return {
success: false,
message: 'Safety cooldown: Wait ' + remaining + ' seconds'
}
}
// SAFETY CHECK: Validate timeframes
if (!config.timeframes || config.timeframes.length === 0) {
return { success: false, message: 'At least one timeframe required' }
}
this.config = config
this.isRunning = true
this.lastAnalysisTime = now
this.stats.currentCycle = 0
this.stats.strategyType = config.strategyType || 'General'
console.log('SAFE PARALLEL: Starting for ' + config.symbol)
console.log('STRATEGY: ' + this.stats.strategyType)
console.log('TIMEFRAMES: [' + config.timeframes.join(', ') + ']')
console.log('SAFETY: Max ' + this.MAX_TRADES_PER_HOUR + ' trades/hour')
// Start with strategy-appropriate interval
this.startSafeAnalysisCycle()
return { success: true, message: 'Safe parallel automation started' }
} catch (error) {
console.error('Failed to start safe automation:', error)
return { success: false, message: 'Failed to start automation' }
}
}
private startSafeAnalysisCycle(): void {
// Get strategy-appropriate interval but enforce minimum safety
const strategyInterval = this.getStrategyInterval(this.config.timeframes, this.config.strategyType)
const safeInterval = Math.max(this.MIN_ANALYSIS_INTERVAL, strategyInterval)
console.log('STRATEGY INTERVAL: ' + (strategyInterval / 1000 / 60) + ' minutes')
console.log('SAFE INTERVAL: ' + (safeInterval / 1000 / 60) + ' minutes (enforced minimum)')
this.stats.analysisInterval = safeInterval
this.stats.nextScheduled = new Date(Date.now() + safeInterval).toISOString()
this.stats.nextAnalysisIn = safeInterval
// Set safe interval
this.intervalId = setInterval(async () => {
if (this.isRunning && this.config) {
await this.runSafeAnalysisCycle()
}
}, safeInterval)
// First cycle after delay
setTimeout(() => {
if (this.isRunning && this.config) {
this.runSafeAnalysisCycle()
}
}, 30000)
}
private async runSafeAnalysisCycle(): Promise<void> {
try {
console.log('\nSAFE CYCLE ' + (this.stats.currentCycle + 1) + ': ' + this.config.symbol)
console.log('STRATEGY: ' + this.stats.strategyType)
// SAFETY CHECK
const canTrade = await this.canExecuteTrade()
if (!canTrade.allowed) {
console.log('SAFETY BLOCK: ' + canTrade.reason)
this.updateNextAnalysisTime()
return
}
// PARALLEL ANALYSIS using enhanced screenshot API
console.log('PARALLEL: Analyzing ' + this.config.timeframes.length + ' timeframes...')
const analysisResult = await this.performParallelAnalysis()
if (!analysisResult || !analysisResult.analysis) {
console.log('Analysis failed, skipping')
return
}
this.stats.lastAnalysis = new Date().toISOString()
console.log('ANALYSIS: ' + analysisResult.analysis.recommendation)
// CONTROLLED TRADING with strategy-specific logic
if (this.shouldExecuteTrade(analysisResult.analysis)) {
console.log('EXECUTING: Trade criteria met for ' + this.stats.strategyType)
const tradeResult = await this.executeSafeTrade(analysisResult.analysis)
if (tradeResult?.success) {
this.stats.totalTrades++
this.stats.successfulTrades++
this.stats.winRate = (this.stats.successfulTrades / this.stats.totalTrades) * 100
console.log('TRADE: Executed successfully')
}
} else {
console.log('SIGNAL: Criteria not met for ' + this.stats.strategyType)
}
this.stats.currentCycle++
} catch (error) {
console.error('Error in safe cycle:', error)
this.stats.errorCount++
this.stats.lastError = error instanceof Error ? error.message : 'Unknown error'
} finally {
await this.guaranteedCleanup()
this.updateNextAnalysisTime()
}
}
private async performParallelAnalysis(): Promise<any> {
try {
// Use the enhanced screenshot API endpoint with all selected timeframes
const response = await fetch('http://localhost:3000/api/enhanced-screenshot', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
symbol: this.config.symbol,
timeframes: this.config.timeframes,
layouts: ['ai', 'diy'],
analyze: true
})
})
throw new Error('API response: ' + response.status)
}
const result = await response.json()
if (result.analysis) {
console.log('PARALLEL: Confidence ' + result.analysis.confidence + '%')
return result
}
return null
} catch (error) {
console.error('Error in parallel analysis:', error)
throw error
}
}
private shouldExecuteTrade(analysis: any): boolean {
const recommendation = analysis.recommendation.toLowerCase()
const confidence = analysis.confidence || 0
// Strategy-specific confidence requirements
let minConfidence = 75 // Default
if (this.stats.strategyType === 'Scalping') {
minConfidence = 80 // Higher confidence for scalping
} else if (this.stats.strategyType === 'Day Trading') {
minConfidence = 75 // Standard confidence
} else if (this.stats.strategyType === 'Swing Trading') {
minConfidence = 70 // Slightly lower for swing (longer timeframes)
}
const isHighConfidence = confidence >= minConfidence
const isClearDirection = recommendation.includes('buy') || recommendation.includes('sell')
console.log('SIGNAL: ' + recommendation + ' (' + confidence + '%) - Required: ' + minConfidence + '%')
return isHighConfidence && isClearDirection
}
private getStrategyInterval(timeframes: string[], strategyType: string): number {
// Strategy-based intervals (but minimum will be enforced)
if (strategyType === 'Scalping') {
console.log('SCALPING: Using 2-minute analysis cycle')
return 2 * 60 * 1000 // 2 minutes for scalping (will be enforced to 10 min minimum)
}
if (strategyType === 'Day Trading') {
console.log('DAY TRADING: Using 5-minute analysis cycle')
return 5 * 60 * 1000 // 5 minutes for day trading (will be enforced to 10 min minimum)
}
if (strategyType === 'Swing Trading') {
console.log('SWING TRADING: Using 15-minute analysis cycle')
return 15 * 60 * 1000 // 15 minutes for swing trading
}
// Fallback based on shortest timeframe
const shortest = Math.min(...timeframes.map(tf => {
if (tf === 'D') return 1440
return parseInt(tf) || 60
}))
if (shortest <= 5) return 2 * 60 * 1000 // 2 min for very short
if (shortest <= 15) return 5 * 60 * 1000 // 5 min for short
if (shortest <= 60) return 10 * 60 * 1000 // 10 min for medium
return 15 * 60 * 1000 // 15 min for long
}
private async executeSafeTrade(analysis: any): Promise<any> {
try {
console.log('SAFE TRADE: Executing...')
// Use drift trading API endpoint
const response = await fetch('http://localhost:3000/api/trading', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
mode: this.config.mode,
symbol: this.config.symbol,
amount: this.config.tradingAmount,
leverage: this.config.leverage,
stopLoss: this.config.stopLoss,
takeProfit: this.config.takeProfit,
analysis: analysis,
strategy: this.stats.strategyType
})
})
const result = await response.json()
return result
} catch (error) {
console.error('Error executing trade:', error)
return { success: false, error: error.message }
}
}
private async canExecuteTrade(): Promise<{ allowed: boolean, reason?: string }> {
const now = Date.now()
if (now - this.lastAnalysisTime < this.ANALYSIS_COOLDOWN) {
const remaining = Math.ceil((this.ANALYSIS_COOLDOWN - (now - this.lastAnalysisTime)) / 1000 / 60)
return { allowed: false, reason: 'Cooldown: ' + remaining + 'min' }
}
if (this.stats.totalTrades >= this.MAX_TRADES_PER_HOUR) {
return { allowed: false, reason: 'Hour limit: ' + this.stats.totalTrades + '/' + this.MAX_TRADES_PER_HOUR }
}
return { allowed: true }
}
private async guaranteedCleanup(): Promise<void> {
try {
const { execSync } = require('child_process')
execSync('pkill -f "chrome|chromium" 2>/dev/null || true')
console.log('CLEANUP: Completed')
} catch (error) {
console.error('CLEANUP: Failed', error)
}
}
private updateNextAnalysisTime(): void {
const nextTime = Date.now() + this.stats.analysisInterval
this.stats.nextScheduled = new Date(nextTime).toISOString()
this.stats.nextAnalysisIn = this.stats.analysisInterval
}
async stopSafeAutomation(): Promise<{ success: boolean, message?: string }> {
try {
this.isRunning = false
if (this.intervalId) {
clearInterval(this.intervalId)
this.intervalId = null
}
await this.guaranteedCleanup()
this.config = null
this.stats.nextAnalysisIn = 0
this.stats.nextScheduled = null
console.log('SAFE: Automation stopped')
return { success: true, message: 'Safe automation stopped' }
} catch (error) {
return { success: false, message: 'Stop failed' }
}
}
getStatus() {
return {
isActive: this.isRunning,
mode: this.config?.mode || 'SIMULATION',
symbol: this.config?.symbol || 'SOLUSD',
timeframes: this.config?.timeframes || ['1h'],
automationType: 'SAFE_PARALLEL',
strategy: this.stats.strategyType,
...this.stats
}
}
}
export const safeParallelAutomation = new SafeParallelAutomation()