Skip to main content
Glama

MCP Trader Server

by Af7007
index.html28.4 kB
<!DOCTYPE html> <html lang="pt-BR"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Trading Chatbot - IA Conversacional</title> <!-- Font Awesome for icons --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <!-- Custom CSS --> <style> /* Reset and base styles */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; color: #333; } .container { max-width: 1200px; margin: 0 auto; padding: 20px; } /* Header */ .header { text-align: center; margin-bottom: 30px; color: white; } .header h1 { font-size: 2.5rem; margin-bottom: 10px; text-shadow: 2px 2px 4px rgba(0,0,0,0.3); } .header p { font-size: 1.1rem; opacity: 0.9; } /* Status indicators */ .status-bar { display: flex; justify-content: center; gap: 20px; margin-bottom: 20px; } .mode-toggle { display: flex; align-items: center; gap: 10px; padding: 8px 16px; background: rgba(255, 255, 255, 0.1); border-radius: 20px; color: white; font-size: 0.9rem; } .mode-toggle label { display: flex; align-items: center; gap: 8px; cursor: pointer; } .mode-toggle input[type="checkbox"] { display: none; } .mode-slider { position: relative; display: inline-block; width: 50px; height: 24px; background-color: #ccc; border-radius: 24px; transition: .4s; } .mode-slider:before { position: absolute; content: ""; height: 18px; width: 18px; left: 3px; bottom: 3px; background-color: white; -webkit-transition: .4s; transition: .4s; border-radius: 50%; } input:checked + .mode-slider { background-color: #2196F3; } input:checked + .mode-slider:before { -webkit-transform: translateX(26px); -ms-transform: translateX(26px); transform: translateX(26px); } .mode-text { font-weight: bold; } .mode-hint { transition: all 0.3s ease; } .status-item { display: flex; align-items: center; gap: 8px; padding: 8px 16px; background: rgba(255, 255, 255, 0.1); border-radius: 20px; color: white; font-size: 0.9rem; } .status-dot { width: 8px; height: 8px; border-radius: 50%; background: #ff6b6b; } .status-dot.healthy { background: #51cf66; } .status-dot.warning { background: #ffd43b; } /* Main chat interface */ .chat-container { display: flex; height: calc(100vh - 200px); min-height: 600px; background: white; border-radius: 20px; overflow: hidden; box-shadow: 0 20px 40px rgba(0,0,0,0.1); } .sidebar { width: 300px; background: #f8f9fa; border-right: 1px solid #e9ecef; padding: 20px; display: flex; flex-direction: column; } .sidebar h3 { color: #495057; margin-bottom: 20px; font-size: 1.1rem; } .sidebar-section { margin-bottom: 30px; } .quick-commands { display: grid; gap: 10px; } .quick-btn { width: 100%; padding: 12px; background: #667eea; color: white; border: none; border-radius: 8px; cursor: pointer; transition: all 0.3s ease; font-size: 0.9rem; text-align: left; } .quick-btn:hover { background: #5a67d8; transform: translateY(-2px); } .quick-btn:active { transform: translateY(0); } .symbol-list { max-height: 300px; overflow-y: auto; } .symbol-item { padding: 8px 12px; border-radius: 6px; cursor: pointer; margin-bottom: 4px; transition: background 0.2s; } .symbol-item:hover { background: #e9ecef; } /* Chat area */ .chat-area { flex: 1; display: flex; flex-direction: column; position: relative; } .chat-messages { flex: 1; overflow-y: auto; padding: 20px; background: #fafbfc; } .message { margin-bottom: 20px; animation: fadeIn 0.3s ease-in; } .message.user { text-align: right; } .message-content { display: inline-block; max-width: 70%; padding: 12px 18px; border-radius: 18px; font-size: 0.95rem; line-height: 1.4; } .message.user .message-content { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; margin-left: auto; } .message.bot .message-content { background: white; color: #495057; border: 1px solid #e9ecef; } .message.bot .message-content.confirmed { border-left: 4px solid #51cf66; } .message.bot .message-content.error { border-left: 4px solid #ff6b6b; } .message.bot .message-content.warning { border-left: 4px solid #ffd43b; } .confirmation-buttons { margin-top: 10px; text-align: right; } .confirm-btn { padding: 6px 12px; border: none; border-radius: 6px; cursor: pointer; font-size: 0.8rem; margin-left: 8px; } .confirm-btn.confirm { background: #51cf66; color: white; } .confirm-btn.cancel { background: #ff6b6b; color: white; } .intent-info { font-size: 0.8rem; opacity: 0.7; margin-top: 4px; } /* Input area */ .input-area { padding: 20px; background: white; border-top: 1px solid #e9ecef; display: flex; gap: 10px; align-items: flex-end; } .message-input { flex: 1; min-height: 50px; max-height: 150px; padding: 12px 16px; border: 2px solid #e9ecef; border-radius: 25px; resize: none; font-family: inherit; font-size: 1rem; outline: none; transition: border-color 0.3s; } .message-input:focus { border-color: #667eea; } .send-btn { width: 50px; height: 50px; border: none; border-radius: 50%; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; justify-content: center; } .send-btn:hover { transform: scale(1.05); } .send-btn:active { transform: scale(0.95); } .send-btn:disabled { opacity: 0.5; cursor: not-allowed; } /* Loading animation */ .loading { display: inline-block; width: 20px; height: 20px; border: 2px solid #f3f3f3; border-top: 2px solid #667eea; border-radius: 50%; animation: spin 1s linear infinite; } /* Animations */ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /* Typing indicator */ .typing { display: none; font-style: italic; color: #6c757d; padding: 10px 0; } /* Responsive design */ @media (max-width: 768px) { .chat-container { flex-direction: column; height: calc(100vh - 160px); } .sidebar { width: 100%; height: 200px; border-right: none; border-bottom: 1px solid #e9ecef; } .header h1 { font-size: 2rem; } .status-bar { flex-wrap: wrap; } } /* Dark mode support */ @media (prefers-color-scheme: dark) { body { background: linear-gradient(135deg, #2d3748 0%, #1a202c 100%); color: #e2e8f0; } .chat-messages { background: #2d3748; } .message.bot .message-content { background: #4a5568; color: #e2e8f0; border-color: #718096; } } </style> </head> <body> <div class="container"> <div class="header"> <h1><i class="fas fa-robot"></i> Trading Chatbot</h1> <p>IA Conversacional para Operações de Trading Automatizadas</p> </div> <!-- Status Bar --> <div class="status-bar"> <div class="status-item" id="ollama-status"> <div class="status-dot" id="ollama-dot"></div> <span>Ollama</span> </div> <div class="status-item" id="mt5-status"> <div class="status-dot" id="mt5-dot"></div> <span>MetaTrader 5</span> </div> <div class="status-item" id="chatbot-status"> <div class="status-dot" id="chatbot-dot"></div> <span>Chatbot</span> </div> <!-- MODE TOGGLE --> <div class="mode-toggle"> <span class="mode-text" id="mode-text">🤖 Modo Direto MT5</span> <label class="toggle-label"> <input type="checkbox" id="mode-toggle" onchange="toggleAIMode(event)"> <span class="mode-slider"></span> </label> <span class="mode-hint" id="mode-hint">Use 'ok' para confirmar</span> </div> </div> <!-- Chat Interface --> <div class="chat-container"> <!-- Sidebar --> <div class="sidebar"> <div class="sidebar-section"> <h3><i class="fas fa-lightning-bolt"></i> Comandos Rápidos</h3> <div class="quick-commands"> <button class="quick-btn" onclick="sendQuickMessage('Quanto tenho de saldo?')"> <i class="fas fa-dollar-sign"></i> Ver Saldo </button> <button class="quick-btn" onclick="sendQuickMessage('Mostrar minhas posições abertas')"> <i class="fas fa-chart-line"></i> Ver Posições </button> <button class="quick-btn" onclick="sendQuickMessage('Qual é a melhor oportunidade de trading agora?')"> <i class="fas fa-search"></i> Análise de Mercado </button> <button class="quick-btn" onclick="sendQuickMessage('Comprar EURUSD 0.01 lots')"> <i class="fas fa-shopping-cart"></i> Compra EURUSD </button> <button class="quick-btn" onclick="sendQuickMessage('Vender BTCUSD 0.001 lots')"> <i class="fas fa-sell"></i> Venda BTCUSD </button> </div> </div> <div class="sidebar-section"> <h3><i class="fas fa-coins"></i> Símbolos Populares</h3> <div class="symbol-list" id="symbols-list"> <!-- Populated by JavaScript --> </div> </div> </div> <!-- Chat Area --> <div class="chat-area"> <!-- Messages Container --> <div class="chat-messages" id="messages"> <div class="message bot"> <div class="message-content"> <i class="fas fa-robot"></i> <strong>Trading Bot:</strong><br><br> Olá! Sou seu assistente de trading inteligente. Posso ajudar você com:<br><br> • <strong>Ordens de compra/venda:</strong> "Comprar 100 EURUSD" ou "Vender 0.01 BTCUSD com stop loss"<br> • <strong>Informações da conta:</strong> "Quanto tenho de saldo?" ou "Mostrar posições"<br> • <strong>Análises:</strong> "Analisar EURUSD" ou "Melhores oportunidades agora"<br> • <strong>Ordens pendentes:</strong> "Mostrar ordens ativas" ou "Cancelar ordem 123"<br><br> 🛡️ <strong>Segurança:</strong> Sempre confirmo operações de alto risco antes de executar. </div> </div> </div> <!-- Typing Indicator --> <div class="typing" id="typing-indicator"> <i class="fas fa-circle"></i> <i class="fas fa-circle"></i> <i class="fas fa-circle"></i> O chatbot está digitando... </div> <!-- Input Area --> <div class="input-area"> <textarea id="message-input" class="message-input" placeholder="Digite sua mensagem aqui... (ex: 'Comprar EURUSD 0.01 lots')" rows="1" onkeydown="handleKeyDown(event)" oninput="autoResizeTextarea()" ></textarea> <button id="send-btn" class="send-btn" onclick="sendMessage()"> <i class="fas fa-paper-plane"></i> </button> </div> </div> </div> </div> <!-- JavaScript --> <script> // Global variables let isInitialized = false; let isTyping = false; let aiMode = false; // Start in MT5 direct mode // DOM elements const messagesContainer = document.getElementById('messages'); const messageInput = document.getElementById('message-input'); const sendBtn = document.getElementById('send-btn'); const typingIndicator = document.getElementById('typing-indicator'); const modeText = document.getElementById('mode-text'); const modeHint = document.getElementById('mode-hint'); const modeToggle = document.getElementById('mode-toggle'); // Initialize when page loads window.onload = async () => { updateStatusDots(); await initializeChatbot(); loadSymbols(); messageInput.focus(); }; // Update status dots based on current status async function updateStatusDots() { try { const response = await fetch('/api/chatbot/status'); const status = await response.json(); // Accept 'available' or 'healthy' as green status const ollamaHealthy = status.ollama?.status === 'healthy' || status.ollama?.status === 'available'; const mt5Healthy = status.mt5?.status === 'connected' || status.mt5?.status === 'healthy'; updateDot('ollama', ollamaHealthy ? 'healthy' : 'error'); updateDot('mt5', mt5Healthy ? 'healthy' : 'error'); updateDot('chatbot', status.status === 'initialized' ? 'healthy' : status.status === 'not_initialized' ? 'warning' : 'error'); } catch (error) { console.error('Failed to update status:', error); } } function updateDot(service, status) { const dot = document.getElementById(`${service}-dot`); if (dot) { dot.className = `status-dot ${status}`; } } // Initialize chatbot async function initializeChatbot() { try { setTyping(true); const response = await fetch('/api/chatbot/initialize', { method: 'POST', headers: { 'Content-Type': 'application/json' } }); const result = await response.json(); if (result.success) { isInitialized = true; addMessage('Sistema inicializado com sucesso!', 'info'); } else { addMessage(`Erro na inicialização: ${result.message}`, 'error'); } } catch (error) { console.error('Initialization failed:', error); addMessage('Falha ao inicializar o chatbot', 'error'); } finally { setTyping(false); await updateStatusDots(); } } // Load trading symbols async function loadSymbols() { try { const response = await fetch('/api/trading/symbols'); const result = await response.json(); if (result.success) { const symbolsList = document.getElementById('symbols-list'); symbolsList.innerHTML = ''; result.symbols.forEach(symbol => { const symbolDiv = document.createElement('div'); symbolDiv.className = 'symbol-item'; symbolDiv.textContent = symbol; symbolDiv.onclick = () => sendQuickMessage(`Mostrar preço de ${symbol}`); symbolsList.appendChild(symbolDiv); }); } } catch (error) { console.error('Failed to load symbols:', error); } } // Send message async function sendMessage() { const message = messageInput.value.trim(); if (!message) return; if (!isInitialized) { addMessage('Aguarde a inicialização do chatbot...', 'warning'); return; } // Add user message to UI addMessage(message, 'user'); messageInput.value = ''; autoResizeTextarea(); // Disable input while processing setInputEnabled(false); try { setTyping(true); const response = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: message, use_ollama: aiMode // Include AI mode flag }) }); const result = await response.json(); if (result.success) { const intent = result.intent; const botResponse = result.response; const statusClass = getStatusClass(result.result); addMessage(botResponse, 'bot', statusClass); // Handle confirmations if (result.result && result.result.status === 'confirmation_required') { addConfirmationButtons(result.result); } } else { addMessage(`Erro: ${result.message}`, 'error'); } } catch (error) { console.error('Failed to send message:', error); addMessage('Falha ao enviar mensagem', 'error'); } finally { setTyping(false); setInputEnabled(true); messageInput.focus(); } } // Send quick message function sendQuickMessage(message) { messageInput.value = message; autoResizeTextarea(); sendMessage(); } // Add message to chat function addMessage(content, type = 'bot', statusClass = '') { const messageDiv = document.createElement('div'); messageDiv.className = `message ${type}`; const contentDiv = document.createElement('div'); contentDiv.className = `message-content ${statusClass}`; contentDiv.innerHTML = type === 'user' ? content : formatBotMessage(content); messageDiv.appendChild(contentDiv); messagesContainer.appendChild(messageDiv); scrollToBottom(); return messageDiv; } // Format bot message with HTML function formatBotMessage(content) { return content .replace(/\n/g, '<br>') .replace(/\• /g, '• ') .replace(/\🛡️ /g, '<i class="fas fa-shield-alt"></i> ') .replace(/\📊 /g, '<i class="fas fa-chart-bar"></i> ') .replace(/\💰 /g, '<i class="fas fa-dollar-sign"></i> ') .replace(/(BUY|SELL|LONG|SHORT)/gi, '<strong>$1</strong>'); } // Get status class for message styling function getStatusClass(result) { if (!result || !result.status) return ''; switch (result.status) { case 'success': return 'confirmed'; case 'error': return 'error'; case 'confirmation_required': return 'warning'; default: return ''; } } // Add confirmation buttons for high-risk trades function addConfirmationButtons(params) { const lastMessage = messagesContainer.lastElementChild; if (!lastMessage || !lastMessage.classList.contains('bot')) return; const buttonsDiv = document.createElement('div'); buttonsDiv.className = 'confirmation-buttons'; const confirmBtn = document.createElement('button'); confirmBtn.className = 'confirm-btn confirm'; confirmBtn.textContent = 'Confirmar'; confirmBtn.onclick = () => confirmTrade(params.command, params.params); const cancelBtn = document.createElement('button'); cancelBtn.className = 'confirm-btn cancel'; cancelBtn.textContent = 'Cancelar'; buttonsDiv.appendChild(confirmBtn); buttonsDiv.appendChild(cancelBtn); lastMessage.appendChild(buttonsDiv); } // Confirm trade execution async function confirmTrade(command, params) { try { setTyping(true); const response = await fetch('/api/chat/confirm', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ command: command, params: params }) }); const result = await response.json(); if (result.success) { addMessage(`✅ ${result.message}`, 'confirmed'); } else { addMessage(`❌ Erro: ${result.message}`, 'error'); } } catch (error) { console.error('Failed to confirm trade:', error); addMessage('Falha ao confirmar operação', 'error'); } finally { setTyping(false); } } // Set typing indicator function setTyping(typing) { isTyping = typing; typingIndicator.style.display = typing ? 'block' : 'none'; if (typing) scrollToBottom(); } // Enable/disable input function setInputEnabled(enabled) { messageInput.disabled = !enabled; sendBtn.disabled = !enabled; } // Handle keyboard shortcuts function handleKeyDown(event) { if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); sendMessage(); } } // Auto-resize textarea function autoResizeTextarea() { messageInput.style.height = 'auto'; messageInput.style.height = Math.min(messageInput.scrollHeight, 150) + 'px'; } // Scroll to bottom of messages function scrollToBottom() { setTimeout(() => { messagesContainer.scrollTop = messagesContainer.scrollHeight; }, 100); } // Toggle AI mode function toggleAIMode(event) { const isChecked = event.target.checked; aiMode = isChecked; if (isChecked) { modeText.textContent = '🧠 Modo IA Inteligente'; modeHint.textContent = 'IA pensa e analisa antes agir'; messageInput.placeholder = 'Pergunte à IA inteligente... (ex: "O que você recomenda hoje?")'; addMessage('🤖 <strong>MODO IA INTELIGENTE ATIVADO</strong><br><br>Agora a IA irá analisar suas solicitações, pensar sobre estratégias, avaliar riscos e executar operações com raciocínio avançado!<br><br>🔄 Funcionalidades IA:<br>• Análise inteligente de intenções<br>• Avaliação de risco automático<br>• Análise de mercado<br>• Execução automática ou confirmação', 'system'); } else { modeText.textContent = '🤖 Modo Direto MT5'; modeHint.textContent = 'Use \'ok\' para confirmar'; messageInput.placeholder = 'Digite sua mensagem aqui... (ex: \'Comprar EURUSD 0.01 lots\')'; addMessage('⚡ <strong>MODO DIRETO MT5 ATIVADO</strong><br><br>Agora você conversa diretamente com o MetaTrader 5 através de comandos simples em português.', 'system'); } // Save preference localStorage.setItem('tradingChatbotAIMode', aiMode); } // Load saved mode preference if (localStorage.getItem('tradingChatbotAIMode') === 'true') { modeToggle.checked = true; aiMode = true; modeText.textContent = '🧠 Modo IA Inteligente'; modeHint.textContent = 'IA pensa e analisa antes agir'; messageInput.placeholder = 'Pergunte à IA inteligente... (ex: "O que você recomenda hoje?")'; } // Update status periodically setInterval(updateStatusDots, 30000); // Every 30 seconds </script> </body> </html>

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Af7007/mcp-trader'

If you have feedback or need assistance with the MCP directory API, please join our Discord server