diff --git a/lib/position-aware-automation.js b/lib/position-aware-automation.js index eef209b..b146c08 100644 --- a/lib/position-aware-automation.js +++ b/lib/position-aware-automation.js @@ -235,14 +235,248 @@ class PositionAwareAutomation { console.log(`πŸ’° Current PnL: $${positionData.position.unrealizedPnl}`); console.log(`🎯 Distance to SL: ${positionData.stopLossProximity.distancePercent}%`); - // Here you would run your analysis to decide: - // 1. Close position early - // 2. Move stop loss - // 3. Double down - // 4. Do nothing + try { + // Run AI analysis to determine market reversal potential + const analysis = await this.runAIAnalysisForDCA(positionData); + + if (analysis && analysis.recommendation === 'DCA_DOUBLE_DOWN') { + console.log('🎯 AI DECISION: Market showing reversal signs - DOUBLING DOWN'); + console.log(`πŸ“ˆ Confidence: ${analysis.confidence}%`); + console.log(`πŸ’° DCA Amount: ${analysis.dcaAmount} SOL`); + console.log(`🎯 New Average: $${analysis.newAveragePrice}`); + + // Execute DCA trade + await this.executeDCATradeAction(analysis, positionData); + + } else if (analysis && analysis.recommendation === 'CLOSE_EARLY') { + console.log('πŸ›‘ AI DECISION: No reversal signs - CLOSING EARLY to minimize loss'); + console.log(`πŸ“‰ Confidence: ${analysis.confidence}%`); + + // Execute early close + await this.executeEarlyCloseAction(positionData); + + } else { + console.log('⏸️ AI DECISION: HOLD position - unclear signals'); + console.log('⏰ Will re-analyze in 30 seconds'); + } + + } catch (error) { + console.error('❌ Emergency analysis failed:', error); + console.log('⏰ Next check in 30 seconds due to high risk'); + } + } + + async runAIAnalysisForDCA(positionData) { + console.log('🧠 Running AI DCA Analysis...'); - console.log('πŸ€– ANALYSIS DECISION: [Would run AI analysis here]'); - console.log('⏰ Next check in 30 seconds due to high risk'); + try { + // Get fresh market analysis + const response = await fetch('http://localhost:3000/api/analysis-optimized', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + symbol: positionData.position.symbol.replace('-PERP', 'USD'), + timeframes: ['5', '15', '1h'], + layouts: ['ai'], + analyze: true, + dcaMode: true, // Special DCA analysis mode + currentPosition: positionData.position + }) + }); + + if (!response.ok) { + throw new Error(`Analysis failed: ${response.status}`); + } + + const analysisData = await response.json(); + const analysis = analysisData.analysis; + + if (!analysis) { + console.log('❌ No analysis returned'); + return null; + } + + // Determine DCA strategy based on AI analysis + const dcaDecision = this.evaluateDCAOpportunity(analysis, positionData); + + return dcaDecision; + + } catch (error) { + console.error('❌ AI DCA analysis failed:', error); + return null; + } + } + + evaluateDCAOpportunity(analysis, positionData) { + const currentPrice = positionData.position.currentPrice; + const entryPrice = positionData.position.entryPrice; + const unrealizedPnl = positionData.position.unrealizedPnl; + const confidence = analysis.confidence || 0; + + // Calculate price movement from entry + const priceMovement = ((currentPrice - entryPrice) / entryPrice) * 100; + const isLongPosition = positionData.position.side === 'long'; + + console.log(`πŸ“Š DCA Evaluation:`); + console.log(` Price Movement: ${priceMovement.toFixed(2)}%`); + console.log(` AI Confidence: ${confidence}%`); + console.log(` Analysis: ${analysis.recommendation}`); + + // DCA Logic for LONG positions + if (isLongPosition) { + // Price has dropped significantly (good DCA opportunity) + const hasDropped = priceMovement < -2; // 2%+ drop + const aiSaysBuy = analysis.recommendation?.toLowerCase().includes('buy'); + const highConfidence = confidence > 75; + const oversoldSignals = analysis.technicalIndicators?.rsi < 35; // Oversold + + if (hasDropped && aiSaysBuy && highConfidence) { + const dcaAmount = this.calculateDCAAmount(positionData); + const newAveragePrice = this.calculateNewAveragePrice( + positionData.position.size, + entryPrice, + dcaAmount, + currentPrice + ); + + return { + recommendation: 'DCA_DOUBLE_DOWN', + confidence: confidence, + dcaAmount: dcaAmount, + newAveragePrice: newAveragePrice, + reasoning: `AI detects reversal: ${analysis.reasoning || 'Strong buy signal'}` + }; + } + } + + // DCA Logic for SHORT positions + if (!isLongPosition) { + // Price has risen significantly (good DCA opportunity for shorts) + const hasRisen = priceMovement > 2; // 2%+ rise + const aiSaysSell = analysis.recommendation?.toLowerCase().includes('sell'); + const highConfidence = confidence > 75; + const overboughtSignals = analysis.technicalIndicators?.rsi > 65; // Overbought + + if (hasRisen && aiSaysSell && highConfidence) { + const dcaAmount = this.calculateDCAAmount(positionData); + const newAveragePrice = this.calculateNewAveragePrice( + positionData.position.size, + entryPrice, + dcaAmount, + currentPrice + ); + + return { + recommendation: 'DCA_DOUBLE_DOWN', + confidence: confidence, + dcaAmount: dcaAmount, + newAveragePrice: newAveragePrice, + reasoning: `AI detects short opportunity: ${analysis.reasoning || 'Strong sell signal'}` + }; + } + } + + // If no DCA opportunity but low confidence, suggest early close + if (confidence < 40 && Math.abs(unrealizedPnl) > 20) { + return { + recommendation: 'CLOSE_EARLY', + confidence: 100 - confidence, // Inverse confidence for closing + reasoning: 'Low AI confidence + significant loss suggests early exit' + }; + } + + return { + recommendation: 'HOLD', + confidence: confidence, + reasoning: 'No clear DCA or exit signals' + }; + } + + calculateDCAAmount(positionData) { + // Calculate safe DCA amount (max 50% of current position) + const currentSize = positionData.position.size; + const maxDCASize = currentSize * 0.5; // Max 50% of current position + + // Could also factor in available balance, but for now use conservative 50% + return Math.min(maxDCASize, 2.0); // Cap at 2 SOL for safety + } + + calculateNewAveragePrice(currentSize, currentEntryPrice, dcaAmount, dcaPrice) { + const totalValue = (currentSize * currentEntryPrice) + (dcaAmount * dcaPrice); + const totalSize = currentSize + dcaAmount; + return totalValue / totalSize; + } + + async executeDCATradeAction(analysis, positionData) { + console.log('🎯 EXECUTING DCA TRADE...'); + + try { + const tradeParams = { + symbol: positionData.position.symbol, + side: positionData.position.side === 'long' ? 'BUY' : 'SELL', + amount: analysis.dcaAmount, + orderType: 'MARKET', + leverage: 10, // Use moderate leverage for DCA + stopLoss: 1.0, + takeProfit: 3.0, + isExecution: true, + dcaMode: true, + analysis: analysis + }; + + const response = await fetch('http://localhost:3000/api/trading/execute', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(tradeParams) + }); + + const result = await response.json(); + + if (result.success) { + console.log('βœ… DCA TRADE EXECUTED SUCCESSFULLY!'); + console.log(`πŸ’° Added ${analysis.dcaAmount} SOL to position`); + console.log(`πŸ“Š New Average Price: $${analysis.newAveragePrice.toFixed(4)}`); + } else { + console.error('❌ DCA trade failed:', result.error); + } + + } catch (error) { + console.error('❌ Error executing DCA trade:', error); + } + } + + async executeEarlyCloseAction(positionData) { + console.log('πŸ›‘ EXECUTING EARLY CLOSE...'); + + try { + const closeParams = { + symbol: positionData.position.symbol, + side: positionData.position.side === 'long' ? 'SELL' : 'BUY', + amount: positionData.position.size, + orderType: 'MARKET', + isExecution: true, + earlyClose: true, + reason: 'Emergency early close due to low AI confidence' + }; + + const response = await fetch('http://localhost:3000/api/trading/execute', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(closeParams) + }); + + const result = await response.json(); + + if (result.success) { + console.log('βœ… POSITION CLOSED EARLY'); + console.log(`πŸ’° Final P&L: ${positionData.position.unrealizedPnl >= 0 ? '+' : ''}$${positionData.position.unrealizedPnl.toFixed(2)}`); + } else { + console.error('❌ Early close failed:', result.error); + } + + } catch (error) { + console.error('❌ Error executing early close:', error); + } } async stop() { diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index 74467d5..1f48770 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 629bfaa..fe2f0a6 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -8,7 +8,7 @@ datasource db { } model ai_learning_data { - id String @id + id String @id @default(cuid()) userId String sessionId String? tradeId String? @@ -24,7 +24,7 @@ model ai_learning_data { screenshot String? feedbackData Json? createdAt DateTime @default(now()) - updatedAt DateTime + updatedAt DateTime @updatedAt users users @relation(fields: [userId], references: [id], onDelete: Cascade) } @@ -36,7 +36,7 @@ model api_keys { encryptedKey String isActive Boolean @default(true) createdAt DateTime @default(now()) - updatedAt DateTime + updatedAt DateTime @updatedAt users users @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([userId, provider, keyName]) @@ -66,7 +66,7 @@ model automation_sessions { errorCount Int @default(0) lastError String? createdAt DateTime @default(now()) - updatedAt DateTime + updatedAt DateTime @updatedAt lastAnalysisData Json? users users @relation(fields: [userId], references: [id], onDelete: Cascade) @@ -120,7 +120,7 @@ model trades { executionTime DateTime? learningData Json? createdAt DateTime @default(now()) - updatedAt DateTime + updatedAt DateTime @updatedAt executedAt DateTime? closedAt DateTime? users users @relation(fields: [userId], references: [id], onDelete: Cascade) @@ -150,7 +150,7 @@ model trading_journals { marketCondition String? sessionId String? createdAt DateTime @default(now()) - updatedAt DateTime + updatedAt DateTime @updatedAt users users @relation(fields: [userId], references: [id], onDelete: Cascade) } @@ -171,7 +171,7 @@ model user_settings { stopLossPercent Float @default(2.0) takeProfitPercent Float @default(6.0) createdAt DateTime @default(now()) - updatedAt DateTime + updatedAt DateTime @updatedAt users users @relation(fields: [userId], references: [id], onDelete: Cascade) } @@ -180,7 +180,7 @@ model users { email String @unique name String? createdAt DateTime @default(now()) - updatedAt DateTime + updatedAt DateTime @updatedAt ai_learning_data ai_learning_data[] api_keys api_keys[] automation_sessions automation_sessions[] diff --git a/start-automation-safe.js b/start-automation-safe.js new file mode 100755 index 0000000..757f6ea --- /dev/null +++ b/start-automation-safe.js @@ -0,0 +1,87 @@ +#!/usr/bin/env node + +/** + * Safe automation starter - checks position status before starting + */ + +const axios = require('axios'); + +const BASE_URL = 'http://localhost:9001'; + +async function startAutomationSafely() { + console.log('πŸš€ Starting Position-Aware Automation Safely...\n'); + + try { + // 1. Check current positions first + console.log('1. Checking current positions...'); + const positionsResponse = await axios.get(`${BASE_URL}/api/drift/positions`); + const positions = positionsResponse.data.positions || []; + + console.log(`πŸ“Š Found ${positions.length} open position(s)`); + if (positions.length > 0) { + positions.forEach((pos, idx) => { + console.log(` ${idx + 1}. ${pos.symbol} ${pos.side.toUpperCase()} ${pos.size} SOL`); + console.log(` Entry: $${pos.entryPrice.toFixed(4)}, Current: $${pos.markPrice.toFixed(4)}`); + console.log(` P&L: ${pos.unrealizedPnl >= 0 ? '+' : ''}$${pos.unrealizedPnl.toFixed(2)}`); + }); + } + console.log(''); + + // 2. Start automation with position-aware configuration + console.log('2. Starting position-aware automation...'); + const automationConfig = { + symbol: 'SOLUSD', + mode: 'LIVE', // Set to LIVE for real trading + selectedTimeframes: ['5', '15'], // Scalping timeframes + enableTrading: true, // Enable real trades + tradingAmount: 100, // Position size in USD + maxLeverage: 10, // Maximum leverage + riskPercentage: 2, // 2% risk per trade + maxDailyTrades: 5, // Maximum 5 trades per day + stopLoss: 1.0, // 1% stop loss + takeProfit: 2.0, // 2% take profit + dexProvider: 'DRIFT' + }; + + const automationResponse = await axios.post(`${BASE_URL}/api/automation/start`, automationConfig); + + if (automationResponse.data.success) { + console.log('βœ… Automation started successfully!'); + console.log(`πŸ“Š Mode: ${automationConfig.mode}`); + console.log(`πŸ’° Trading: ${automationConfig.enableTrading ? 'ENABLED' : 'SIMULATION ONLY'}`); + console.log(`🎯 Symbol: ${automationConfig.symbol}`); + console.log(`⏱️ Timeframes: ${automationConfig.selectedTimeframes.join(', ')}`); + + if (positions.length > 0) { + console.log('\n🎯 INTELLIGENT BEHAVIOR:'); + console.log(' βœ… Will monitor existing position for stop loss proximity'); + console.log(' βœ… Will switch to DCA/doubling down if price approaches SL'); + console.log(' βœ… Will scan for new opportunities only after position closes'); + } else { + console.log('\n🎯 SCANNING MODE:'); + console.log(' βœ… Will scan for new entry opportunities'); + console.log(' βœ… Will execute trades based on AI analysis'); + } + + } else { + console.error('❌ Failed to start automation:', automationResponse.data.error); + } + + // 3. Check final status + console.log('\n3. Checking automation status...'); + const statusResponse = await axios.get(`${BASE_URL}/api/automation/status`); + console.log(`πŸ“Š Status: ${JSON.stringify(statusResponse.data, null, 2)}`); + + } catch (error) { + console.error('❌ Error starting automation:', error.response?.data || error.message); + } +} + +// Run the automation starter +startAutomationSafely() + .then(() => { + console.log('\nβœ… Automation startup completed'); + }) + .catch((error) => { + console.error('❌ Startup failed:', error); + });