diff --git a/lib/notifications/telegram.ts b/lib/notifications/telegram.ts index 46c59af..81672c4 100644 --- a/lib/notifications/telegram.ts +++ b/lib/notifications/telegram.ts @@ -173,3 +173,37 @@ async function sendWithdrawalNotification(options: TelegramWithdrawalOptions): P console.error('❌ Error sending Telegram notification:', error) } } + +/** + * Send a generic text message to Telegram + * Used for alerts, revenge blocks, system notifications + */ +export async function sendTelegramMessage(message: string): Promise { + try { + const token = process.env.TELEGRAM_BOT_TOKEN + const chatId = process.env.TELEGRAM_CHAT_ID + + if (!token || !chatId) { + console.log('⚠️ Telegram credentials not configured, skipping notification') + return + } + + const url = `https://api.telegram.org/bot${token}/sendMessage` + const response = await fetch(url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + chat_id: chatId, + text: message, + parse_mode: 'HTML' + }) + }) + + if (!response.ok) { + const errorData = await response.json() + console.error('❌ Telegram notification failed:', errorData) + } + } catch (error) { + console.error('❌ Error sending Telegram notification:', error) + } +} diff --git a/lib/trading/stop-hunt-tracker.ts b/lib/trading/stop-hunt-tracker.ts index 1ac1653..bf6c943 100644 --- a/lib/trading/stop-hunt-tracker.ts +++ b/lib/trading/stop-hunt-tracker.ts @@ -358,6 +358,51 @@ export class StopHuntTracker { console.log(` Original loss: $${stopHunt.stopLossAmount.toFixed(2)}`) console.log(` Revenge size: 1.2x (getting our money back!)`) + // CRITICAL: Validate current ADX from 1-minute data cache + // Block revenge if trend has weakened (ADX < 20) + const { getMarketDataCache } = await import('../trading/market-data-cache') + const cache = getMarketDataCache() + const cachedData = cache.get(stopHunt.symbol) + + if (cachedData && cachedData.adx !== undefined) { + const currentADX = cachedData.adx + const dataAge = Date.now() - cachedData.timestamp + + console.log(` 📊 Fresh ADX check: ${currentADX.toFixed(1)} (${(dataAge/1000).toFixed(0)}s old)`) + + if (currentADX < 20) { + console.log(` ❌ REVENGE BLOCKED: ADX ${currentADX.toFixed(1)} < 20 (weak trend, not worth re-entry)`) + + // Update database with failed reason + await this.prisma.stopHunt.update({ + where: { id: stopHunt.id }, + data: { + revengeExecuted: true, + revengeFailedReason: `ADX_TOO_LOW_${currentADX.toFixed(1)}` + } + }) + + // Send Telegram notification about blocked revenge + const { sendTelegramMessage } = await import('../notifications/telegram') + await sendTelegramMessage( + `🚫 REVENGE BLOCKED - Weak Trend\n\n` + + `${stopHunt.symbol} ${stopHunt.direction.toUpperCase()}\n` + + `Original Quality: ${stopHunt.originalQualityScore}\n` + + `Entry would be: $${currentPrice.toFixed(2)}\n\n` + + `❌ Current ADX: ${currentADX.toFixed(1)} < 20\n` + + `Trend too weak for revenge re-entry\n` + + `Protecting capital ✓` + ) + + return + } + + console.log(` ✅ ADX validation passed: ${currentADX.toFixed(1)} ≥ 20 (strong trend)`) + } else { + console.log(` ⚠️ No fresh ADX data (cache age: ${cachedData ? (Date.now() - cachedData.timestamp)/1000 : 'N/A'}s)`) + console.log(` ⚠️ Proceeding with revenge but using original ADX ${stopHunt.originalADX}`) + } + // Call execute endpoint with revenge parameters const response = await fetch('http://localhost:3000/api/trading/execute', { method: 'POST',