From 702d08b0baeb5f0fb078d4776d57bfbf9dad08f6 Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Thu, 27 Nov 2025 10:16:59 +0100 Subject: [PATCH] feat: Integrate ADX validation into revenge system using 1-min market data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ENHANCEMENTS: - Revenge system now checks fresh ADX from 1-minute market data cache - Blocks revenge if ADX < 20 (weak trend - not worth re-entering) - Executes revenge if ADX >= 20 (strong trend - high probability) - Saves revengeFailedReason='ADX_TOO_LOW_X.X' for blocked attempts - Telegram notification shows ADX check result DATABASE: - Added revengeFailedReason field to StopHunt table - Added revengePnL field to track revenge trade outcomes INTEGRATION: - Uses getPythPriceMonitor().getCachedPrice() for fresh data - Falls back to originalADX if cache unavailable - Logs ADX validation: 'ADX check: X.X (threshold: 20)' 1-MINUTE DATA COLLECTION COMPLETE: - TradingView alerts recreated with new format - Bot correctly filters timeframe='1' → BlockedSignal - Market data cache updates every 60 seconds - Verified working: 2 signals collected, 0 trades executed --- lib/notifications/telegram.ts | 34 ++++++++++++++++++++++++ lib/trading/stop-hunt-tracker.ts | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) 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',