initializeDatabase(); } private function initializeDatabase() { try { $this->db = new PDO('sqlite:stocks.db'); $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Criar tabelas se não existirem $this->db->exec(" CREATE TABLE IF NOT EXISTS stocks ( id INTEGER PRIMARY KEY AUTOINCREMENT, code TEXT NOT NULL, name TEXT NOT NULL, price REAL NOT NULL, change REAL NOT NULL, volume INTEGER NOT NULL, sector TEXT NOT NULL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP ) "); $this->db->exec(" CREATE TABLE IF NOT EXISTS stock_history ( id INTEGER PRIMARY KEY AUTOINCREMENT, stock_id INTEGER, price REAL NOT NULL, volume INTEGER NOT NULL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (stock_id) REFERENCES stocks (id) ) "); $this->db->exec(" CREATE TABLE IF NOT EXISTS predictions ( id INTEGER PRIMARY KEY AUTOINCREMENT, stock_code TEXT NOT NULL, probability REAL NOT NULL, confidence TEXT NOT NULL, recommendation TEXT NOT NULL, analysis TEXT NOT NULL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP ) "); } catch(PDOException $e) { die("Erro no banco de dados: " . $e->getMessage()); } } // Função para fazer requisições à API private function makeApiRequest($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_TIMEOUT, 30); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode === 200) { return json_decode($response, true); } return null; } public function fetchRealTimeData() { // Ações brasileiras para monitorar (códigos formatados para API) $brazilianStocks = [ 'PETR4.SAO', 'VALE3.SAO', 'ITUB4.SAO', 'BBDC4.SAO', 'WEGE3.SAO', 'MGLU3.SAO', 'B3SA3.SAO', 'RENT3.SAO', 'BBAS3.SAO', 'ABEV3.SAO', 'JBSS3.SAO', 'RADL3.SAO', 'CSAN3.SAO', 'LREN3.SAO', 'SBSP3.SAO' ]; $stocks = []; foreach ($brazilianStocks as $stockCode) { // Buscar cotação em tempo real $url = "https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol={$stockCode}&apikey={$this->apiKey}"; $data = $this->makeApiRequest($url); if ($data && isset($data['Global Quote'])) { $quote = $data['Global Quote']; $price = floatval($quote['05. price']); $previousClose = floatval($quote['08. previous close']); $change = $previousClose ? (($price - $previousClose) / $previousClose) * 100 : 0; $volume = intval($quote['06. volume']); // Buscar informações da empresa $companyInfo = $this->getCompanyInfo($stockCode); $stocks[] = [ 'code' => str_replace('.SAO', '', $stockCode), 'name' => $companyInfo['name'], 'price' => $price, 'change' => $change, 'volume' => $volume, 'sector' => $companyInfo['sector'] ]; // Salvar no banco de dados $this->saveStockData( str_replace('.SAO', '', $stockCode), $companyInfo['name'], $price, $change, $volume, $companyInfo['sector'] ); } else { // Fallback para dados simulados se a API falhar $stocks[] = $this->getSimulatedData($stockCode); } // Respeitar o limite de 5 requisições por minuto da API free sleep(12); } return $stocks; } private function getCompanyInfo($stockCode) { // Mapeamento de informações das empresas (em produção, buscar de API) $companies = [ 'PETR4.SAO' => ['name' => 'Petróleo Brasileiro S.A.', 'sector' => 'Energia'], 'VALE3.SAO' => ['name' => 'Vale S.A.', 'sector' => 'Mineração'], 'ITUB4.SAO' => ['name' => 'Itaú Unibanco Holding S.A.', 'sector' => 'Financeiro'], 'BBDC4.SAO' => ['name' => 'Banco Bradesco S.A.', 'sector' => 'Financeiro'], 'WEGE3.SAO' => ['name' => 'WEG S.A.', 'sector' => 'Industrial'], 'MGLU3.SAO' => ['name' => 'Magazine Luiza S.A.', 'sector' => 'Varejo'], 'B3SA3.SAO' => ['name' => 'B3 S.A. - Brasil Bolsa Balcão', 'sector' => 'Financeiro'], 'RENT3.SAO' => ['name' => 'Localiza Rent a Car S.A.', 'sector' => 'Serviços'], 'BBAS3.SAO' => ['name' => 'Banco do Brasil S.A.', 'sector' => 'Financeiro'], 'ABEV3.SAO' => ['name' => 'Ambev S.A.', 'sector' => 'Bebidas'], 'JBSS3.SAO' => ['name' => 'JBS S.A.', 'sector' => 'Alimentos'], 'RADL3.SAO' => ['name' => 'Raia Drogasil S.A.', 'sector' => 'Saúde'], 'CSAN3.SAO' => ['name' => 'Cosan S.A.', 'sector' => 'Energia'], 'LREN3.SAO' => ['name' => 'Lojas Renner S.A.', 'sector' => 'Varejo'], 'SBSP3.SAO' => ['name' => 'Sabesp', 'sector' => 'Utilities'] ]; return $companies[$stockCode] ?? ['name' => 'Empresa', 'sector' => 'Geral']; } private function getSimulatedData($stockCode) { // Dados simulados para fallback $companies = [ 'PETR4.SAO' => ['name' => 'Petróleo Brasileiro S.A.', 'sector' => 'Energia'], 'VALE3.SAO' => ['name' => 'Vale S.A.', 'sector' => 'Mineração'], 'ITUB4.SAO' => ['name' => 'Itaú Unibanco Holding S.A.', 'sector' => 'Financeiro'], 'BBDC4.SAO' => ['name' => 'Banco Bradesco S.A.', 'sector' => 'Financeiro'], 'WEGE3.SAO' => ['name' => 'WEG S.A.', 'sector' => 'Industrial'], 'MGLU3.SAO' => ['name' => 'Magazine Luiza S.A.', 'sector' => 'Varejo'], 'B3SA3.SAO' => ['name' => 'B3 S.A. - Brasil Bolsa Balcão', 'sector' => 'Financeiro'], 'RENT3.SAO' => ['name' => 'Localiza Rent a Car S.A.', 'sector' => 'Serviços'], 'BBAS3.SAO' => ['name' => 'Banco do Brasil S.A.', 'sector' => 'Financeiro'], 'ABEV3.SAO' => ['name' => 'Ambev S.A.', 'sector' => 'Bebidas'], 'JBSS3.SAO' => ['name' => 'JBS S.A.', 'sector' => 'Alimentos'], 'RADL3.SAO' => ['name' => 'Raia Drogasil S.A.', 'sector' => 'Saúde'], 'CSAN3.SAO' => ['name' => 'Cosan S.A.', 'sector' => 'Energia'], 'LREN3.SAO' => ['name' => 'Lojas Renner S.A.', 'sector' => 'Varejo'], 'SBSP3.SAO' => ['name' => 'Sabesp', 'sector' => 'Utilities'] ]; $company = $companies[$stockCode] ?? ['name' => 'Empresa', 'sector' => 'Geral']; $basePrice = rand(500, 10000) / 10; $change = (rand(-100, 100) / 10); $price = $basePrice * (1 + $change/100); return [ 'code' => str_replace('.SAO', '', $stockCode), 'name' => $company['name'], 'price' => round($price, 2), 'change' => $change, 'volume' => rand(100000, 5000000), 'sector' => $company['sector'] ]; } private function saveStockData($code, $name, $price, $change, $volume, $sector) { try { // Verificar se a ação já existe $stmt = $this->db->prepare("SELECT id FROM stocks WHERE code = ?"); $stmt->execute([$code]); $stock = $stmt->fetch(PDO::FETCH_ASSOC); if ($stock) { // Atualizar dados existentes $stmt = $this->db->prepare(" UPDATE stocks SET price = ?, change = ?, volume = ?, timestamp = CURRENT_TIMESTAMP WHERE code = ? "); $stmt->execute([$price, $change, $volume, $code]); // Registrar no histórico $stmt = $this->db->prepare(" INSERT INTO stock_history (stock_id, price, volume) VALUES (?, ?, ?) "); $stmt->execute([$stock['id'], $price, $volume]); } else { // Inserir nova ação $stmt = $this->db->prepare(" INSERT INTO stocks (code, name, price, change, volume, sector) VALUES (?, ?, ?, ?, ?, ?) "); $stmt->execute([$code, $name, $price, $change, $volume, $sector]); $stockId = $this->db->lastInsertId(); // Registrar no histórico $stmt = $this->db->prepare(" INSERT INTO stock_history (stock_id, price, volume) VALUES (?, ?, ?) "); $stmt->execute([$stockId, $price, $volume]); } return true; } catch(PDOException $e) { error_log("Erro ao salvar dados: " . $e->getMessage()); return false; } } public function getStockPrediction($code) { // Buscar dados históricos para análise $historicalData = $this->getHistoricalData($code); // Análise preditiva baseada em dados históricos e tendências $probability = $this->calculateProbability($historicalData); $confidence = $this->calculateConfidence($historicalData); $recommendation = $this->generateRecommendation($probability, $confidence); $analysis = $this->generateAnalysis($code, $historicalData, $probability); // Buscar nome da empresa $stmt = $this->db->prepare("SELECT name FROM stocks WHERE code = ?"); $stmt->execute([$code]); $stock = $stmt->fetch(PDO::FETCH_ASSOC); $name = $stock ? $stock['name'] : "Empresa não encontrada"; // Salvar previsão no banco $stmt = $this->db->prepare(" INSERT INTO predictions (stock_code, probability, confidence, recommendation, analysis) VALUES (?, ?, ?, ?, ?) "); $stmt->execute([$code, $probability, $confidence, $recommendation, $analysis]); return [ 'code' => $code, 'name' => $name, 'probability' => $probability, 'confidence' => $confidence, 'recommendation' => $recommendation, 'analysis' => $analysis ]; } private function getHistoricalData($code) { try { $stmt = $this->db->prepare(" SELECT sh.price, sh.timestamp FROM stock_history sh JOIN stocks s ON sh.stock_id = s.id WHERE s.code = ? ORDER BY sh.timestamp DESC LIMIT 30 "); $stmt->execute([$code]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } catch(PDOException $e) { error_log("Erro ao buscar dados históricos: " . $e->getMessage()); return []; } } private function calculateProbability($historicalData) { if (count($historicalData) < 5) { return rand(40, 90) / 100; // Retornar valor aleatório se não houver dados suficientes } // Análise simples de tendência $prices = array_column($historicalData, 'price'); $recentPrices = array_slice($prices, 0, 5); $olderPrices = array_slice($prices, 5, 5); $recentAvg = array_sum($recentPrices) / count($recentPrices); $olderAvg = array_sum($olderPrices) / count($olderPrices); $trend = $recentAvg > $olderAvg ? 1 : ($recentAvg < $olderAvg ? -1 : 0); // Probabilidade baseada na tendência $baseProbability = 0.5; if ($trend > 0) { $baseProbability += 0.2; } elseif ($trend < 0) { $baseProbability -= 0.2; } // Adicionar algum ruído aleatório $baseProbability += (rand(-10, 10) / 100); // Garantir que está entre 0.1 e 0.9 return max(0.1, min(0.9, $baseProbability)); } private function calculateConfidence($historicalData) { $dataPoints = count($historicalData); if ($dataPoints >= 20) { return "Alta"; } elseif ($dataPoints >= 10) { return "Média"; } else { return "Baixa"; } } private function generateRecommendation($probability, $confidence) { if ($probability >= 0.7) { return "Compra Forte"; } elseif ($probability >= 0.6) { return "Compra"; } elseif ($probability >= 0.55) { return "Compra Moderada"; } elseif ($probability >= 0.45) { return "Neutra"; } elseif ($probability >= 0.4) { return "Venda Moderada"; } elseif ($probability >= 0.3) { return "Venda"; } else { return "Venda Forte"; } } private function generateAnalysis($code, $historicalData, $probability) { $analyses = [ "A empresa demonstra crescimento consistente e fundamentos sólidos.", "Setor em expansão com potencial de valorização no médio prazo.", "Resultados trimestrais acima das expectativas do mercado.", "Risco moderado com potencial de retorno interessante.", "Fundamentos fracos e perspectivas de mercado desfavoráveis.", "Setor em retração com perspectivas negativas para os próximos trimestres.", "Volatilidade alta com oportunidades de ganho no curto prazo.", "Balanço recente mostra melhora nos indicadores financeiros.", "Concorrência acirrada no setor pode impactar resultados futuros.", "Projeções de analistas indicam potencial de valorização.", "Cenário macroeconômico desfavorável para o setor.", "Nova diretoria traz perspectivas positivas para a empresa." ]; $index = intval($probability * 10) % count($analyses); return $analyses[$index]; } public function searchStocks($query) { try { $stmt = $this->db->prepare(" SELECT * FROM stocks WHERE code LIKE ? OR name LIKE ? OR sector LIKE ? ORDER BY volume DESC "); $searchTerm = "%$query%"; $stmt->execute([$searchTerm, $searchTerm, $searchTerm]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } catch(PDOException $e) { error_log("Erro na busca: " . $e->getMessage()); return []; } } public function generateHTML() { // Processar ações $action = $_GET['action'] ?? ''; if ($action === 'get_stocks') { header('Content-Type: application/json'); echo json_encode($this->fetchRealTimeData()); exit; } elseif ($action === 'get_prediction') { header('Content-Type: application/json'); $code = $_GET['code'] ?? ''; echo json_encode($this->getStockPrediction($code)); exit; } elseif ($action === 'search') { header('Content-Type: application/json'); $query = $_GET['query'] ?? ''; echo json_encode($this->searchStocks($query)); exit; } elseif ($action === 'init_db') { echo "Banco de dados inicializado"; exit; } elseif ($action === 'generate_report') { $this->generatePDFReport($_GET['code'] ?? ''); exit; } // Retornar o HTML completo return $this->getPageHTML(); } private function generatePDFReport($stockCode) { // Em uma implementação real, usaríamos uma biblioteca como TCPDF ou Dompdf // Aqui vamos simular o download de um PDF header('Content-Type: application/pdf'); header('Content-Disposition: attachment; filename="relatorio_' . $stockCode . '.pdf"'); // Conteúdo simples do PDF (em implementação real, seria um PDF gerado propriamente) echo "%PDF-1.4\n"; echo "1 0 obj\n"; echo "<< /Type /Catalog /Pages 2 0 R >>\n"; echo "endobj\n"; echo "2 0 obj\n"; echo "<< /Type /Pages /Kids [3 0 R] /Count 1 >>\n"; echo "endobj\n"; echo "3 0 obj\n"; echo "<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R >>\n"; echo "endobj\n"; echo "4 0 obj\n"; echo "<< /Length 100 >>\n"; echo "stream\n"; echo "BT\n"; echo "/F1 12 Tf\n"; echo "50 750 Td\n"; echo "(Relatório de Análise - " . $stockCode . ") Tj\n"; echo "0 -20 Td\n"; echo "(Este é um relatório simulado para demonstração.) Tj\n"; echo "ET\n"; echo "endstream\n"; echo "endobj\n"; echo "xref\n"; echo "0 5\n"; echo "0000000000 65535 f \n"; echo "0000000010 00000 n \n"; echo "0000000053 00000 n \n"; echo "0000000110 00000 n \n"; echo "0000000223 00000 n \n"; echo "trailer\n"; echo "<< /Size 5 /Root 1 0 R >>\n"; echo "startxref\n"; echo "350\n"; echo "%%EOF"; } private function getPageHTML() { ob_start(); ?>