Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Trading Game - Proof of Concept</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| body { font-family: 'Inter', sans-serif; } | |
| </style> | |
| </head> | |
| <body class="bg-gray-900 text-white min-h-screen"> | |
| <main class="container mx-auto px-4 py-8 max-w-7xl"> | |
| <h1 class="text-4xl font-bold mb-8 text-center bg-gradient-to-r from-green-400 to-blue-500 bg-clip-text text-transparent"> | |
| Trading Game - Proof of Concept | |
| </h1> | |
| <!-- Current Scenario (Full Width) --> | |
| <div id="scenario-section" class="bg-gradient-to-r from-red-900 to-orange-900 p-6 rounded-xl mb-6 border-2 border-orange-500"> | |
| <h2 class="text-2xl font-bold mb-3 text-yellow-300">⚠️ Current Market Scenario</h2> | |
| <div id="scenario-text" class="text-lg mb-4"> | |
| A typhoon is seen off the coast of New Gregoria, likely impacting the Galvanium Supply Chain. | |
| This may affect logistics companies (NLN) and energy sectors (VCG). | |
| </div> | |
| <button id="next-scenario-button" class="px-4 py-2 bg-orange-600 rounded hover:bg-orange-700 text-sm"> | |
| Next Scenario | |
| </button> | |
| </div> | |
| <!-- Two Column Layout --> | |
| <div class="grid lg:grid-cols-2 gap-6"> | |
| <!-- LEFT SIDE: AI Advisor --> | |
| <div class="space-y-6"> | |
| <!-- AI Parameter Sliders --> | |
| <div class="bg-gray-800 p-6 rounded-xl"> | |
| <h2 class="text-2xl font-bold mb-4 text-blue-400">🤖 AI Advisor Settings</h2> | |
| <div class="space-y-4"> | |
| <div> | |
| <label class="block text-gray-400 mb-2"> | |
| Risk Tolerance: <span id="risk-value" class="text-white font-bold">5.0</span> / 10 | |
| </label> | |
| <input type="range" id="risk-slider" min="0" max="10" step="0.5" value="5.0" | |
| class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer"> | |
| <div class="flex justify-between text-xs text-gray-500 mt-1"> | |
| <span>Conservative</span> | |
| <span>Moderate</span> | |
| <span>Aggressive</span> | |
| </div> | |
| </div> | |
| <div> | |
| <label class="block text-gray-400 mb-2"> | |
| AI Creativity: <span id="temperature-value" class="text-white font-bold">0.7</span> | |
| </label> | |
| <input type="range" id="temperature-slider" min="0" max="2" step="0.1" value="0.7" | |
| class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer"> | |
| <div class="flex justify-between text-xs text-gray-500 mt-1"> | |
| <span>Deterministic</span> | |
| <span>Balanced</span> | |
| <span>Creative</span> | |
| </div> | |
| </div> | |
| <div> | |
| <label class="block text-gray-400 mb-2"> | |
| Confidence Level: <span id="confidence-value" class="text-white font-bold">0</span> | |
| </label> | |
| <input type="range" id="confidence-slider" min="-100" max="100" step="10" value="0" | |
| class="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer"> | |
| <div class="flex justify-between text-xs text-gray-500 mt-1"> | |
| <span>Cautious (-100)</span> | |
| <span>Neutral (0)</span> | |
| <span>Very Confident (+100)</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- AI Chat Section --> | |
| <div id="ai-advice-section" class="bg-gray-800 p-6 rounded-xl flex flex-col" style="height: 600px;"> | |
| <h2 class="text-2xl font-bold mb-4 text-green-400">🤖 AI Trading Advisor</h2> | |
| <!-- Chat Messages Container --> | |
| <div id="chat-messages" class="flex-1 bg-gray-900 rounded-lg p-4 mb-4 overflow-y-auto space-y-3"> | |
| <div class="flex justify-start"> | |
| <div class="bg-blue-600 text-white rounded-lg p-3 max-w-[80%]"> | |
| <p class="text-sm font-semibold mb-1">AI Assistant</p> | |
| <p class="text-sm">Welcome! I'm your AI trading advisor. I can help you with trading decisions, market analysis, and portfolio advice. Ask me anything or try one of the suggested questions below!</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Pre-populated Query Suggestions --> | |
| <div id="query-suggestions" class="mb-3 flex flex-wrap gap-2"> | |
| <button class="query-suggestion-btn px-3 py-1.5 bg-gray-700 text-gray-300 rounded-lg text-sm hover:bg-gray-600" | |
| onclick="sendQuickQuery('What are the best stocks to trade right now?')"> | |
| 📈 Best stocks now? | |
| </button> | |
| <button class="query-suggestion-btn px-3 py-1.5 bg-gray-700 text-gray-300 rounded-lg text-sm hover:bg-gray-600" | |
| onclick="sendQuickQuery('Explain the current market scenario')"> | |
| 📊 Market scenario | |
| </button> | |
| <button class="query-suggestion-btn px-3 py-1.5 bg-gray-700 text-gray-300 rounded-lg text-sm hover:bg-gray-600" | |
| onclick="sendQuickQuery('What is my risk profile?')"> | |
| ⚖️ My risk profile | |
| </button> | |
| <button class="query-suggestion-btn px-3 py-1.5 bg-gray-700 text-gray-300 rounded-lg text-sm hover:bg-gray-600" | |
| onclick="const sym = document.getElementById('trade-symbol').value; sendQuickQuery(`Should I buy ${sym}?`)"> | |
| 💰 Trade advice | |
| </button> | |
| </div> | |
| <!-- Chat Input --> | |
| <div class="flex gap-2"> | |
| <input type="text" id="chat-input" placeholder="Ask me anything about trading..." | |
| class="flex-1 bg-gray-700 text-white rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" | |
| onkeypress="if(event.key === 'Enter') sendChatMessage()"> | |
| <button id="send-chat-button" onclick="sendChatMessage()" | |
| class="px-6 py-2 bg-blue-600 rounded-lg font-bold hover:bg-blue-700"> | |
| Send | |
| </button> | |
| </div> | |
| <!-- Trade Action Buttons (shown when trade advice is given) --> | |
| <div id="ai-actions" class="flex gap-2 mt-3" style="display: none;"> | |
| <button id="follow-advice-button" class="flex-1 py-2 bg-green-600 rounded hover:bg-green-700 text-sm font-semibold"> | |
| ✅ Follow Advice | |
| </button> | |
| <button id="ignore-advice-button" class="flex-1 py-2 bg-gray-600 rounded hover:bg-gray-700 text-sm"> | |
| Ignore & Trade | |
| </button> | |
| <button id="clear-chat-button" class="px-3 py-2 bg-red-600 rounded hover:bg-red-700 text-sm"> | |
| Clear | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- RIGHT SIDE: Trading Portfolio --> | |
| <div class="space-y-6"> | |
| <!-- Portfolio Summary --> | |
| <div class="bg-gray-800 p-6 rounded-xl"> | |
| <h2 class="text-2xl font-bold mb-4">Portfolio</h2> | |
| <div class="grid grid-cols-2 gap-4"> | |
| <div> | |
| <p class="text-gray-400">Balance</p> | |
| <p class="text-3xl font-bold" id="balance">$50,000.00</p> | |
| </div> | |
| <div> | |
| <p class="text-gray-400">Positions</p> | |
| <p class="text-3xl font-bold" id="positions">0</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Trading Form --> | |
| <div class="bg-gray-800 p-6 rounded-xl"> | |
| <h2 class="text-2xl font-bold mb-4">Make a Trade</h2> | |
| <div class="space-y-4 mb-4"> | |
| <div> | |
| <label class="block text-gray-400 mb-2">Symbol</label> | |
| <select id="trade-symbol" class="w-full bg-gray-700 rounded p-3 text-white"> | |
| <option>VCG</option> | |
| <option>CSI</option> | |
| <option>STDY</option> | |
| <option>AUBIO</option> | |
| <option>NLN</option> | |
| </select> | |
| </div> | |
| <div class="grid grid-cols-2 gap-4"> | |
| <div> | |
| <label class="block text-gray-400 mb-2">Quantity</label> | |
| <input id="trade-quantity" type="number" value="10" min="1" | |
| class="w-full bg-gray-700 rounded p-3 text-white"> | |
| </div> | |
| <div> | |
| <label class="block text-gray-400 mb-2">Price</label> | |
| <input id="trade-price" type="number" value="100" min="0" step="0.01" | |
| class="w-full bg-gray-700 rounded p-3 text-white" readonly> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="flex gap-4"> | |
| <button id="buy-button" class="flex-1 py-3 bg-green-600 rounded-lg font-bold hover:bg-green-700"> | |
| Buy | |
| </button> | |
| <button id="sell-button" class="flex-1 py-3 bg-red-600 rounded-lg font-bold hover:bg-red-700"> | |
| Sell | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Recent Trades --> | |
| <div class="bg-gray-800 p-6 rounded-xl"> | |
| <h2 class="text-2xl font-bold mb-4">Recent Trades</h2> | |
| <div id="trade-history" class="space-y-2 max-h-[400px] overflow-y-auto"> | |
| <p class="text-gray-400 text-center">No trades yet</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <script src="game-api-integration.js"></script> | |
| <script> | |
| // Simple game state | |
| let gameState = { | |
| balance: 50000, | |
| positions: [], | |
| trades: [], | |
| currentScenario: { | |
| title: "Typhoon near New Gregoria", | |
| description: "A typhoon is seen off the coast of New Gregoria, likely impacting the Galvanium Supply Chain. This may affect logistics companies (NLN) and energy sectors (VCG).", | |
| affectedSymbols: ["NLN", "VCG"] | |
| } | |
| }; | |
| // Scenario templates | |
| const scenarios = [ | |
| { | |
| title: "Typhoon near New Gregoria", | |
| description: "A typhoon is seen off the coast of New Gregoria, likely impacting the Galvanium Supply Chain. This may affect logistics companies (NLN) and energy sectors (VCG).", | |
| affectedSymbols: ["NLN", "VCG"] | |
| }, | |
| { | |
| title: "Quantum Processor Breakthrough", | |
| description: "Veridian Capital Group (VCG) announces a major quantum computing breakthrough. This could significantly impact energy and tech sectors.", | |
| affectedSymbols: ["VCG", "CSI"] | |
| }, | |
| { | |
| title: "Asteroid Mining Success", | |
| description: "Stellar Dynamics Corp (STDY) successfully completes asteroid mining operations, securing rare earth minerals. Logistics and space commerce stocks may surge.", | |
| affectedSymbols: ["STDY", "NLN"] | |
| }, | |
| { | |
| title: "Biosynthetics Regulatory Approval", | |
| description: "Aurora Biosynthetics (AUBIO) receives approval for commercial distribution of synthetic products, opening new markets worth 200 billion credits.", | |
| affectedSymbols: ["AUBIO"] | |
| } | |
| ]; | |
| // Update slider displays | |
| document.getElementById('risk-slider').addEventListener('input', (e) => { | |
| document.getElementById('risk-value').textContent = parseFloat(e.target.value).toFixed(1); | |
| }); | |
| document.getElementById('temperature-slider').addEventListener('input', (e) => { | |
| document.getElementById('temperature-value').textContent = parseFloat(e.target.value).toFixed(1); | |
| }); | |
| document.getElementById('confidence-slider').addEventListener('input', (e) => { | |
| document.getElementById('confidence-value').textContent = e.target.value; | |
| }); | |
| // Update price when symbol changes | |
| document.getElementById('trade-symbol').addEventListener('change', (e) => { | |
| const prices = { VCG: 150, CSI: 200, STDY: 100, AUBIO: 75, NLN: 120 }; | |
| document.getElementById('trade-price').value = prices[e.target.value] || 100; | |
| }); | |
| // Initialize price | |
| document.getElementById('trade-symbol').dispatchEvent(new Event('change')); | |
| // Next scenario button | |
| document.getElementById('next-scenario-button').addEventListener('click', () => { | |
| const randomScenario = scenarios[Math.floor(Math.random() * scenarios.length)]; | |
| gameState.currentScenario = randomScenario; | |
| document.getElementById('scenario-text').textContent = randomScenario.description; | |
| }); | |
| let pendingTrade = null; | |
| let chatHistory = []; | |
| // Add message to chat UI | |
| function addChatMessage(message, isUser = false) { | |
| const chatMessages = document.getElementById('chat-messages'); | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `flex ${isUser ? 'justify-end' : 'justify-start'}`; | |
| const contentDiv = document.createElement('div'); | |
| contentDiv.className = isUser | |
| ? 'bg-gray-600 text-white rounded-lg p-3 max-w-[80%]' | |
| : 'bg-blue-600 text-white rounded-lg p-3 max-w-[80%]'; | |
| if (!isUser) { | |
| const label = document.createElement('p'); | |
| label.className = 'text-sm font-semibold mb-1'; | |
| label.textContent = 'AI Assistant'; | |
| contentDiv.appendChild(label); | |
| } | |
| const text = document.createElement('p'); | |
| text.className = 'text-sm whitespace-pre-wrap'; | |
| text.textContent = message; | |
| contentDiv.appendChild(text); | |
| messageDiv.appendChild(contentDiv); | |
| chatMessages.appendChild(messageDiv); | |
| // Auto-scroll to bottom | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| } | |
| // Send chat message | |
| async function sendChatMessage() { | |
| const chatInput = document.getElementById('chat-input'); | |
| const question = chatInput.value.trim(); | |
| if (!question) return; | |
| // Add user message to chat | |
| addChatMessage(question, true); | |
| chatInput.value = ''; | |
| // Show thinking indicator | |
| const thinkingDiv = document.createElement('div'); | |
| thinkingDiv.id = 'thinking-indicator'; | |
| thinkingDiv.className = 'flex justify-start'; | |
| const thinkingContent = document.createElement('div'); | |
| thinkingContent.className = 'bg-blue-600 text-white rounded-lg p-3 max-w-[80%]'; | |
| thinkingContent.innerHTML = '<p class="text-sm font-semibold mb-1">AI Assistant</p><p class="text-sm italic">Thinking...</p>'; | |
| thinkingDiv.appendChild(thinkingContent); | |
| document.getElementById('chat-messages').appendChild(thinkingDiv); | |
| document.getElementById('chat-messages').scrollTop = document.getElementById('chat-messages').scrollHeight; | |
| try { | |
| if (window.gameAI && window.gameAI.askAI) { | |
| // Get current slider values | |
| const riskLevel = parseFloat(document.getElementById('risk-slider').value); | |
| const temperature = parseFloat(document.getElementById('temperature-slider').value); | |
| const confidence = parseFloat(document.getElementById('confidence-slider').value); | |
| // Include scenario context in the question | |
| const scenarioText = gameState.currentScenario.description; | |
| const enhancedQuestion = `Current Market Scenario: ${scenarioText}\n\nRisk Profile: ${riskLevel}/10\n\n${question}`; | |
| // Update AI parameters | |
| if (window.gameAI.updateAIParams) { | |
| window.gameAI.updateAIParams(riskLevel, temperature, confidence); | |
| } | |
| const response = await window.gameAI.askAI(enhancedQuestion, { | |
| risk_level: riskLevel, | |
| temperature: temperature, | |
| confidence_boost: confidence | |
| }); | |
| // Remove thinking indicator | |
| const thinking = document.getElementById('thinking-indicator'); | |
| if (thinking) thinking.remove(); | |
| // Add AI response | |
| const answer = response.answer || 'No response available.'; | |
| addChatMessage(answer, false); | |
| // Check if this is a trade-related question | |
| if (question.toLowerCase().includes('buy') || question.toLowerCase().includes('sell') || | |
| question.toLowerCase().includes('trade') || question.toLowerCase().includes('should i')) { | |
| // Show trade action buttons | |
| document.getElementById('ai-actions').style.display = 'flex'; | |
| } | |
| } else { | |
| // Remove thinking indicator | |
| const thinking = document.getElementById('thinking-indicator'); | |
| if (thinking) thinking.remove(); | |
| addChatMessage('AI service not available. Check console for errors.', false); | |
| } | |
| } catch (error) { | |
| console.error('AI chat error:', error); | |
| const thinking = document.getElementById('thinking-indicator'); | |
| if (thinking) thinking.remove(); | |
| addChatMessage('Error getting AI response. Check console.', false); | |
| } | |
| } | |
| // Send quick query from suggestion button | |
| function sendQuickQuery(query) { | |
| const chatInput = document.getElementById('chat-input'); | |
| chatInput.value = query; | |
| sendChatMessage(); | |
| } | |
| // Buy button handler | |
| document.getElementById('buy-button').addEventListener('click', async () => { | |
| const symbol = document.getElementById('trade-symbol').value; | |
| const quantity = parseInt(document.getElementById('trade-quantity').value); | |
| const price = parseFloat(document.getElementById('trade-price').value); | |
| const total = quantity * price; | |
| if (total > gameState.balance) { | |
| alert('Insufficient balance!'); | |
| return; | |
| } | |
| pendingTrade = { symbol, quantity, price, action: 'buy' }; | |
| await showAIAdvice(symbol, quantity, price, 'buy'); | |
| }); | |
| // Sell button handler | |
| document.getElementById('sell-button').addEventListener('click', async () => { | |
| const symbol = document.getElementById('trade-symbol').value; | |
| const quantity = parseInt(document.getElementById('trade-quantity').value); | |
| const price = parseFloat(document.getElementById('trade-price').value); | |
| pendingTrade = { symbol, quantity, price, action: 'sell' }; | |
| await showAIAdvice(symbol, quantity, price, 'sell'); | |
| }); | |
| // Show AI advice (used by Buy/Sell buttons) | |
| async function showAIAdvice(symbol, quantity, price, action) { | |
| const question = `Should I ${action} ${quantity} shares of ${symbol} at $${price.toFixed(2)}?`; | |
| // Add trade question to chat | |
| addChatMessage(question, true); | |
| // Set pending trade | |
| pendingTrade = { symbol, quantity, price, action }; | |
| // Show thinking indicator | |
| const thinkingDiv = document.createElement('div'); | |
| thinkingDiv.id = 'thinking-indicator'; | |
| thinkingDiv.className = 'flex justify-start'; | |
| const thinkingContent = document.createElement('div'); | |
| thinkingContent.className = 'bg-blue-600 text-white rounded-lg p-3 max-w-[80%]'; | |
| thinkingContent.innerHTML = '<p class="text-sm font-semibold mb-1">AI Assistant</p><p class="text-sm italic">Analyzing trade...</p>'; | |
| thinkingDiv.appendChild(thinkingContent); | |
| document.getElementById('chat-messages').appendChild(thinkingDiv); | |
| document.getElementById('chat-messages').scrollTop = document.getElementById('chat-messages').scrollHeight; | |
| try { | |
| if (window.gameAI && window.gameAI.askAI) { | |
| // Get current slider values | |
| const riskLevel = parseFloat(document.getElementById('risk-slider').value); | |
| const temperature = parseFloat(document.getElementById('temperature-slider').value); | |
| const confidence = parseFloat(document.getElementById('confidence-slider').value); | |
| // Include scenario context in the question | |
| const scenarioText = gameState.currentScenario.description; | |
| const enhancedQuestion = `Current Market Scenario: ${scenarioText}\n\nShould I ${action} ${quantity} shares of ${symbol} at $${price.toFixed(2)}? Consider the current scenario and provide a direct recommendation based on my risk tolerance of ${riskLevel}/10.`; | |
| // Update AI parameters | |
| if (window.gameAI.updateAIParams) { | |
| window.gameAI.updateAIParams(riskLevel, temperature, confidence); | |
| } | |
| const response = await window.gameAI.askAI(enhancedQuestion, { | |
| risk_level: riskLevel, | |
| temperature: temperature, | |
| confidence_boost: confidence | |
| }); | |
| // Remove thinking indicator | |
| const thinking = document.getElementById('thinking-indicator'); | |
| if (thinking) thinking.remove(); | |
| // Add AI response | |
| const answer = response.answer || 'No advice available'; | |
| addChatMessage(answer, false); | |
| // Show action buttons | |
| document.getElementById('ai-actions').style.display = 'flex'; | |
| } else { | |
| const thinking = document.getElementById('thinking-indicator'); | |
| if (thinking) thinking.remove(); | |
| addChatMessage('AI service not available. Check console for errors.', false); | |
| } | |
| } catch (error) { | |
| console.error('AI advice error:', error); | |
| const thinking = document.getElementById('thinking-indicator'); | |
| if (thinking) thinking.remove(); | |
| addChatMessage('Error getting AI advice. Check console.', false); | |
| } | |
| } | |
| // Follow AI advice | |
| document.getElementById('follow-advice-button').addEventListener('click', async () => { | |
| if (!pendingTrade) return; | |
| executeTrade(pendingTrade, true); | |
| document.getElementById('ai-actions').style.display = 'none'; | |
| pendingTrade = null; | |
| }); | |
| // Ignore advice but still trade | |
| document.getElementById('ignore-advice-button').addEventListener('click', async () => { | |
| if (!pendingTrade) return; | |
| executeTrade(pendingTrade, false); | |
| document.getElementById('ai-actions').style.display = 'none'; | |
| pendingTrade = null; | |
| }); | |
| // Clear chat button | |
| document.getElementById('clear-chat-button').addEventListener('click', () => { | |
| const chatMessages = document.getElementById('chat-messages'); | |
| chatMessages.innerHTML = ` | |
| <div class="flex justify-start"> | |
| <div class="bg-blue-600 text-white rounded-lg p-3 max-w-[80%]"> | |
| <p class="text-sm font-semibold mb-1">AI Assistant</p> | |
| <p class="text-sm">Chat cleared. How can I help you with your trading today?</p> | |
| </div> | |
| </div> | |
| `; | |
| document.getElementById('ai-actions').style.display = 'none'; | |
| pendingTrade = null; | |
| chatHistory = []; | |
| }); | |
| // Execute trade | |
| function executeTrade(trade, followedAdvice) { | |
| const { symbol, quantity, price, action } = trade; | |
| const total = quantity * price; | |
| if (action === 'buy') { | |
| gameState.balance -= total; | |
| const existingPosition = gameState.positions.find(p => p.symbol === symbol); | |
| if (existingPosition) { | |
| existingPosition.quantity += quantity; | |
| } else { | |
| gameState.positions.push({ symbol, quantity, price }); | |
| } | |
| } else { // sell | |
| gameState.balance += total; | |
| const existingPosition = gameState.positions.find(p => p.symbol === symbol); | |
| if (existingPosition) { | |
| existingPosition.quantity -= quantity; | |
| if (existingPosition.quantity <= 0) { | |
| gameState.positions = gameState.positions.filter(p => p.symbol !== symbol); | |
| } | |
| } | |
| } | |
| // Log trade | |
| gameState.trades.unshift({ | |
| timestamp: new Date().toLocaleTimeString(), | |
| symbol, | |
| action, | |
| quantity, | |
| price: price.toFixed(2), | |
| total: total.toFixed(2), | |
| followedAdvice | |
| }); | |
| // Update UI | |
| updateUI(); | |
| // Log to backend | |
| if (window.gameAI && window.gameAI.logDecision) { | |
| window.gameAI.logDecision(symbol, action, quantity, price, followedAdvice); | |
| } | |
| // Ask for trust score | |
| const trustScore = prompt('How much did you trust the AI advice? (1-10):'); | |
| if (trustScore && window.gameAI && window.gameAI.logDecision) { | |
| window.gameAI.logDecision(symbol, action, quantity, price, followedAdvice, parseFloat(trustScore)); | |
| } | |
| } | |
| // Update UI | |
| function updateUI() { | |
| document.getElementById('balance').textContent = '$' + gameState.balance.toFixed(2); | |
| document.getElementById('positions').textContent = gameState.positions.length; | |
| const tradeHistory = document.getElementById('trade-history'); | |
| if (gameState.trades.length === 0) { | |
| tradeHistory.innerHTML = '<p class="text-gray-400 text-center">No trades yet</p>'; | |
| } else { | |
| tradeHistory.innerHTML = gameState.trades.map(trade => ` | |
| <div class="bg-gray-700 p-3 rounded flex justify-between items-center"> | |
| <div> | |
| <span class="font-bold ${trade.action === 'buy' ? 'text-green-400' : 'text-red-400'}"> | |
| ${trade.action.toUpperCase()} | |
| </span> | |
| ${trade.quantity} ${trade.symbol} @ $${trade.price} | |
| ${trade.followedAdvice ? '✅ (Followed AI)' : '❌ (Ignored AI)'} | |
| </div> | |
| <div class="text-right"> | |
| <p class="font-bold">$${trade.total}</p> | |
| <p class="text-sm text-gray-400">${trade.timestamp}</p> | |
| </div> | |
| </div> | |
| `).join(''); | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> | |