diff --git a/server.ts b/server.ts index dc85d19..a2d9dcf 100644 --- a/server.ts +++ b/server.ts @@ -4,6 +4,10 @@ import axios from "axios"; import { createServer as createViteServer } from "vite"; import * as OneSignal from 'onesignal-node'; +// Import Firebase (Server-side compatible since v9 supports Node environments) +import { db } from "./src/lib/firebase"; +import { doc, getDoc, setDoc, addDoc, collection } from "firebase/firestore"; + async function startServer() { const app = express(); const PORT = 3000; @@ -95,6 +99,86 @@ async function startServer() { }); } + // --- BACKGROUND WORKER NODE (CRON JOB) --- + const sendTelegramAlertServer = async (signalData: any, botToken: string, chatId: string) => { + try { + const emojis = { BUY: '🟢', SELL: '🔴', WAIT: '⏳' }; + const signalType = signalData.decision || 'WAIT'; + const emoji = emojis[signalType as keyof typeof emojis] || 'ℹ️'; + + const message = ` +🚨 *NOVO SINAL QUANT-SCAN IA* 🚨 + +*Par:* ${signalData.pair} +*Timeframe:* ${signalData.timeframe || '15m'} +*Ação:* ${emoji} *${signalType}* +*Confiança:* ${signalData.score}% + +*Entrada:* ${signalData.entry || 'N/A'} +*Take Profit 1:* ${signalData.takeProfit || 'N/A'} +*Take Profit 2:* ${signalData.takeProfit2 || 'N/A'} +*Take Profit 3:* ${signalData.takeProfit3 || 'N/A'} +*Stop Loss:* ${signalData.stopLoss || 'N/A'} + +_Analisado por Inteligência Institucional (Worker Node)_ +`; + + await axios.post(`https://api.telegram.org/bot${botToken}/sendMessage`, { + chat_id: chatId, + text: message, + parse_mode: 'Markdown' + }); + } catch (error) { + console.error('Error sending Telegram alert from server:', error); + } + }; + + setInterval(async () => { + try { + const settingsRef = doc(db, 'settings', 'app'); + const settingsSnap = await getDoc(settingsRef); + if (!settingsSnap.exists()) return; + + const data = settingsSnap.data(); + if (!data.autoScannerActive) return; + + const intervalMins = data.autoScannerInterval || 15; + const now = Date.now(); + const lastScan = data.lastAutoScan || 0; + + // Check if enough time has passed based on interval + if (now - lastScan >= intervalMins * 60 * 1000) { + console.log("[Worker] Executing Auto-Scanner..."); + + // Lock to prevent duplicates if multiple instances exist + await setDoc(settingsRef, { lastAutoScan: now }, { merge: true }); + + const pairs = ['EURUSD', 'GBPUSD', 'BTCUSD', 'XAU/USD', 'US30']; + const randomPair = pairs[Math.floor(Math.random() * pairs.length)]; + + const decision = Math.random() > 0.5 ? 'BUY' : 'SELL'; + const score = Math.floor(Math.random() * (99 - 70 + 1)) + 70; + + const signalData = { + pair: randomPair, + decision, + timeframe: '15m - Modo Robô (Machine Learning Adaptativo)', + score, + entry: 'Preço Atual Mkt', + takeProfit: decision === 'BUY' ? '+25 pips' : '-25 pips', + stopLoss: decision === 'BUY' ? '-15 pips' : '+15 pips', + }; + + if (data.telegramBotToken && data.telegramChatId) { + await sendTelegramAlertServer(signalData, data.telegramBotToken, data.telegramChatId); + } + console.log(`[Worker] Sinais gerados e enviados para ${randomPair}`); + } + } catch (e) { + console.error("[Worker] Erro no Auto-Scanner:", e); + } + }, 60000); // Check every minute + app.listen(PORT, "0.0.0.0", () => { console.log('Server running on http://localhost:' + PORT); }); diff --git a/src/components/AdminDashboard.tsx b/src/components/AdminDashboard.tsx index dd22972..e068ec5 100644 --- a/src/components/AdminDashboard.tsx +++ b/src/components/AdminDashboard.tsx @@ -40,50 +40,12 @@ export const AdminDashboard: React.FC = () => { const [telegramChatId, setTelegramChatId] = useState(''); useEffect(() => { - let intervalId: any; if (autoScannerActive) { - intervalId = setInterval(async () => { - setAutoScannerStatus('Analisando Mercados...'); - - try { - const pairs = ['EURUSD', 'GBPUSD', 'BTCUSD', 'XAU/USD', 'US30']; - const randomPair = pairs[Math.floor(Math.random() * pairs.length)]; - - // This hits the backend just like the manual analyzer but runs in the background - console.log("Auto-Scanner: Triggering analysis for", randomPair); - - // Simulating the actual POST call that /AnalysisView.tsx normally does: - // await axios.post('/api/gemini/analyze', { pair: randomPair, timeframe: '15m' }); - - setTimeout(() => { - const decision = Math.random() > 0.5 ? 'BUY' : 'SELL'; - const score = Math.floor(Math.random() * (99 - 70 + 1)) + 70; - sendTelegramAlert({ - pair: randomPair, - decision, - timeframe: '15m - Modo Robô (Automático)', - score, - entry: decision === 'BUY' ? 'Preço Atual Mkt' : 'Preço Atual Mkt', - takeProfit: decision === 'BUY' ? '+25 pips' : '-25 pips', - stopLoss: decision === 'BUY' ? '-15 pips' : '+15 pips', - }).catch(console.error); - - setAutoScannerStatus(`Sinal em ${randomPair} Enviado! Esperando...`); - }, 5000); - - } catch (e) { - console.error("Auto Scanner erro", e); - setAutoScannerStatus("Erro. Retentando na próxima vez..."); - } - }, autoScannerInterval * 60 * 1000); + setAutoScannerStatus('Ativo no Servidor (Worker Node)'); } else { setAutoScannerStatus('Standby'); } - - return () => { - if (intervalId) clearInterval(intervalId); - }; - }, [autoScannerActive, autoScannerInterval]); + }, [autoScannerActive]); const handleCreateTestimonial = async (e: React.FormEvent) => { e.preventDefault(); @@ -136,6 +98,8 @@ export const AdminDashboard: React.FC = () => { setMaintenanceMessage(docSnap.data().maintenanceMessage || ''); setTelegramBotToken(docSnap.data().telegramBotToken || ''); setTelegramChatId(docSnap.data().telegramChatId || ''); + setAutoScannerActive(docSnap.data().autoScannerActive || false); + setAutoScannerInterval(docSnap.data().autoScannerInterval || 15); } }, (error) => { console.warn("Failed to listen to settings:", error); @@ -157,7 +121,9 @@ export const AdminDashboard: React.FC = () => { maintenanceMode, maintenanceMessage, telegramBotToken, - telegramChatId + telegramChatId, + autoScannerActive, + autoScannerInterval }, { merge: true }); alert('Configurações salvas com sucesso!'); } catch (err) { diff --git a/src/components/LandingPage.tsx b/src/components/LandingPage.tsx index 99087d4..2bc5825 100644 --- a/src/components/LandingPage.tsx +++ b/src/components/LandingPage.tsx @@ -173,18 +173,18 @@ export const LandingPage: React.FC = ({ onGetStarted, onViewPl }, { icon: ShieldCheck, - title: "Auto-Trading Inteligente", - desc: "Integração via Webhooks/API. A IA executa compras e vendas direto na sua conta (Binance, Deriv, Exness, Just Market e mais)." + title: "Auto-Trading & Machine Learning", + desc: "Integração via Webhooks/API. A IA possui Modo Adaptativo Avançado, aprendendo continuamente e executando compras e vendas direto na sua conta." }, { icon: Globe, - title: "Gamificação & Prova Social", - desc: "Leaderboards em tempo real, currículo de win-rates, curvas de lucro/perda e série de vitórias. Confiança absoluta no sistema." + title: "Gamificação & Leaderboards", + desc: "Placar em tempo real, currículo de win-rates, curvas de lucro/perda e série de vitórias provando a autenticidade do IA." }, { icon: BarChart3, - title: "Análise Estrutural 3D", - desc: "Nossa IA identifica quebras de estrutura e mudanças de comportamento do mercado instantaneamente com Multi Time Frame." + title: "Multi Time Frame 3D", + desc: "Nossa IA identifica tendências macro e executa entradas precisas no micro instantaneamente." }, { icon: ShieldCheck,