About Tradeflow

Tradeflow is your go-to blog for insightful market analysis and practical trading strategies tailored for every investor.

A hand holding a smartphone displaying a stock trading chart with details on stock prices. The phone is above a wooden table where a blurred laptop screen in the background shows similar financial data. Natural light comes in from the window, creating a relaxed working environment.
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TradeFlow MVP - Simulador de Trading Profissional</title>
    <!-- Tailwind CSS para Estilização Moderna -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- Fonte Inter para Legibilidade Excepcional -->
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
    <!-- Ícones Lucide para Interface Minimalista -->
    <script src="https://unpkg.com/lucide@latest"></script>
    
    <style>
        body {
            font-family: 'Inter', sans-serif;
            background-color: #0b0f19;
            color: #f1f5f9;
        }
        /* Scrollbar Personalizada para Visual de Terminal */
        ::-webkit-scrollbar {
            width: 6px;
            height: 6px;
        }
        ::-webkit-scrollbar-track {
            background: #0f172a;
        }
        ::-webkit-scrollbar-thumb {
            background: #334155;
            border-radius: 4px;
        }
        ::-webkit-scrollbar-thumb:hover {
            background: #475569;
        }
        /* Animações de Transição de Cor para Tickers */
        .price-up {
            animation: flashGreen 0.5s ease-out;
        }
        .price-down {
            animation: flashRed 0.5s ease-out;
        }
        @keyframes flashGreen {
            0% { background-color: rgba(34, 197, 94, 0.2); }
            100% { background-color: transparent; }
        }
        @keyframes flashRed {
            0% { background-color: rgba(239, 68, 68, 0.2); }
            100% { background-color: transparent; }
        }
    </style>
</head>
<body class="min-h-screen flex flex-col overflow-x-hidden">

    <header class="border-b border-slate-800 bg-slate-900/80 backdrop-blur-md sticky top-0 z-50 px-4 py-3">
        <div class="max-w-7xl mx-auto flex flex-col sm:flex-row items-center justify-between gap-4">
            <!-- Brand -->
            <div class="flex items-center gap-3">
                <div class="p-2 bg-gradient-to-tr from-emerald-500 to-teal-500 rounded-lg shadow-lg shadow-emerald-500/20">
                    <i data-lucide="trending-up" class="w-6 h-6 text-slate-950 stroke-[2.5]"></i>
                </div>
                <div>
                    <h1 class="text-xl font-extrabold tracking-tight bg-clip-text text-transparent bg-gradient-to-r from-white via-slate-100 to-slate-400">TradeFlow <span class="text-xs bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 px-2 py-0.5 rounded-full font-medium">MVP</span></h1>
                    <p class="text-[10px] text-slate-400 font-medium">Ambiente Profissional de Operações</p>
                </div>
            </div>

            <!-- Centro: Tipo de Conexão (Simulado vs Real) -->
            <div class="flex bg-slate-950 p-1 rounded-xl border border-slate-800">
                <button id="btnModeSim" onclick="setConnectionMode('simulated')" class="px-3 py-1.5 text-xs font-semibold rounded-lg transition-all flex items-center gap-2 bg-slate-800 text-emerald-400 shadow-sm">
                    <i data-lucide="cpu" class="w-3.5 h-3.5"></i> Simulador Local
                </button>
                <button id="btnModeLive" onclick="setConnectionMode('live')" class="px-3 py-1.5 text-xs font-semibold rounded-lg transition-all flex items-center gap-2 text-slate-400 hover:text-white">
                    <i data-lucide="radio" class="w-3.5 h-3.5"></i> Binance Live API
                </button>
            </div>

            <!-- Direita: Informações de Saldo da Carteira -->
            <div class="flex items-center gap-4">
                <div class="text-right">
                    <div class="text-[10px] text-slate-400 uppercase tracking-wider font-semibold">Saldo Disponível</div>
                    <div class="text-lg font-bold text-slate-100" id="walletBalance">S$ 10.000,00</div>
                </div>
                <div class="h-8 w-px bg-slate-800"></div>
                <div class="text-right">
                    <div class="text-[10px] text-slate-400 uppercase tracking-wider font-semibold">P&L Aberto</div>
                    <div class="text-lg font-bold text-slate-400 transition-colors" id="totalFloatingPL">S$ 0,00</div>
                </div>
            </div>
        </div>
    </header>

    <main class="flex-1 max-w-7xl w-full mx-auto p-4 grid grid-cols-1 lg:grid-cols-3 gap-6">
        
        <!-- Coluna Esquerda: Ticker, Gráfico e Sinais (Larga) -->
        <div class="lg:col-span-2 flex flex-col gap-6">
            
            <!-- Card de Cotação de Ativos (Ticker) -->
            <section class="bg-slate-900 border border-slate-800/80 rounded-2xl p-4 flex flex-wrap items-center justify-between gap-4 shadow-xl transition-all duration-300" id="tickerPanel">
                <div class="flex items-center gap-3">
                    <div class="w-10 h-10 rounded-full bg-slate-850 flex items-center justify-center border border-slate-850" id="assetLogo">
                        <!-- Será inserido via JS -->
                        <span class="font-bold text-sm text-emerald-400">BTC</span>
                    </div>
                    <div>
                        <div class="flex items-center gap-2">
                            <span class="font-bold text-base text-slate-100" id="tickerSymbol">BTC/USDT</span>
                            <span class="text-[10px] px-1.5 py-0.5 rounded bg-slate-800 font-medium text-slate-400" id="tickerCategory">Crypto</span>
                        </div>
                        <span class="text-xs text-slate-400" id="tickerName">Bitcoin / Tether US</span>
                    </div>
                </div>

                <div class="flex items-center gap-6">
                    <div class="text-right">
                        <div class="text-2xl font-black font-mono tracking-tight text-emerald-400 transition-all duration-100" id="tickerPrice">$ 65,420.50</div>
                        <div class="text-xs font-semibold text-emerald-400 flex items-center justify-end gap-1" id="tickerPercentChange">
                            <i data-lucide="trending-up" class="w-3.5 h-3.5"></i> +1.24%
                        </div>
                    </div>
                    <div class="hidden sm:block h-10 w-px bg-slate-800"></div>
                    <div class="hidden sm:block text-right">
                        <div class="text-[10px] text-slate-500 font-semibold uppercase">Máxima 24h</div>
                        <div class="text-xs font-mono font-bold text-slate-300" id="tickerHigh">$ 65,980.00</div>
                    </div>
                    <div class="hidden sm:block text-right">
                        <div class="text-[10px] text-slate-500 font-semibold uppercase">Mínima 24h</div>
                        <div class="text-xs font-mono font-bold text-slate-300" id="tickerLow">$ 64,210.00</div>
                    </div>
                </div>
            </section>

            <!-- Card de Gráfico Interativo -->
            <section class="bg-slate-900 border border-slate-800/80 rounded-2xl flex flex-col shadow-xl overflow-hidden min-h-[450px]">
                <!-- Controles do Gráfico -->
                <div class="border-b border-slate-800 p-4 bg-slate-900/50 flex flex-wrap items-center justify-between gap-3">
                    <div class="flex items-center gap-2">
                        <span class="text-xs font-bold text-slate-300 uppercase tracking-wider flex items-center gap-1.5">
                            <i data-lucide="candlestick-chart" class="w-4 h-4 text-emerald-400"></i> Gráfico de Velas (5s)
                        </span>
                    </div>
                    <!-- Ferramentas -->
                    <div class="flex items-center gap-2">
                        <button onclick="changeZoom(1.1)" class="p-1.5 rounded-lg bg-slate-800 text-slate-300 hover:text-white hover:bg-slate-700 transition" title="Aumentar Zoom">
                            <i data-lucide="zoom-in" class="w-4 h-4"></i>
                        </button>
                        <button onclick="changeZoom(0.9)" class="p-1.5 rounded-lg bg-slate-800 text-slate-300 hover:text-white hover:bg-slate-700 transition" title="Diminuir Zoom">
                            <i data-lucide="zoom-out" class="w-4 h-4"></i>
                        </button>
                        <div class="h-6 w-px bg-slate-800"></div>
                        <button onclick="toggleIndicator('sma')" id="btnSma" class="px-2 py-1.5 text-[10px] font-bold rounded-lg bg-emerald-500/20 text-emerald-400 border border-emerald-500/25 hover:bg-emerald-500/30 transition">
                            Média Móvel (SMA)
                        </button>
                        <button onclick="toggleIndicator('rsi')" id="btnRsi" class="px-2 py-1.5 text-[10px] font-bold rounded-lg bg-slate-800 text-slate-400 hover:bg-slate-750 transition">
                            RSI Panel
                        </button>
                    </div>
                </div>
                <!-- Container do Canvas -->
                <div class="flex-1 relative bg-[#090d16] min-h-[300px]" id="canvasContainer">
                    <canvas id="tradingChart" class="absolute inset-0 w-full h-full cursor-crosshair"></canvas>
                </div>
            </section>

            <section class="grid grid-cols-1 md:grid-cols-3 gap-4">
                <div class="bg-slate-900 border border-slate-800/80 rounded-2xl p-4 flex flex-col justify-between shadow-lg">
                    <div class="flex items-center justify-between mb-2">
                        <span class="text-xs font-bold text-slate-400 uppercase tracking-wider">Índice RSI (14)</span>
                        <i data-lucide="activity" class="w-4 h-4 text-blue-400"></i>
                    </div>
                    <div class="flex items-baseline gap-2 mt-1">
                        <span class="text-3xl font-black font-mono" id="rsiVal">54.2</span>
                        <span class="text-xs px-2 py-0.5 rounded-full bg-slate-800 text-slate-300 font-medium" id="rsiState">Neutro</span>
                    </div>
                    <div class="w-full bg-slate-800 h-1.5 rounded-full mt-3 overflow-hidden">
                        <div class="bg-blue-500 h-full transition-all duration-300" id="rsiBar" style="width: 54.2%"></div>
                    </div>
                </div>

                <div class="bg-slate-900 border border-slate-800/80 rounded-2xl p-4 flex flex-col justify-between shadow-lg">
                    <div class="flex items-center justify-between mb-2">
                        <span class="text-xs font-bold text-slate-400 uppercase tracking-wider">Média Móvel (9)</span>
                        <i data-lucide="line-chart" class="w-4 h-4 text-emerald-400"></i>
                    </div>
                    <div class="flex items-baseline gap-2 mt-1">
                        <span class="text-lg font-bold font-mono text-slate-300" id="smaVal">$ 65,410.20</span>
                    </div>
                    <span class="text-xs font-semibold text-emerald-400 flex items-center gap-1 mt-2" id="smaTrend">
                        <i data-lucide="arrow-up-right" class="w-3.5 h-3.5"></i> Tendência de Alta
                    </span>
                </div>

                <div class="bg-slate-900 border border-slate-850 bg-gradient-to-br from-slate-900 to-slate-950 rounded-2xl p-4 flex flex-col justify-between shadow-lg border-l-4 border-l-emerald-500" id="signalCard">
                    <div class="flex items-center justify-between mb-2">
                        <span class="text-xs font-bold text-slate-400 uppercase tracking-wider">Recomendação</span>
                        <span class="animate-pulse flex h-2 w-2 relative">
                            <span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
                            <span class="relative inline-flex rounded-full h-2 w-2 bg-emerald-500"></span>
                        </span>
                    </div>
                    <div class="mt-1">
                        <span class="text-2xl font-black tracking-tight text-emerald-400 uppercase" id="recSignal">Compra Forte</span>
                        <p class="text-[10px] text-slate-400 mt-1">Análise baseada em cruzamento tático e força relativa.</p>
                    </div>
                </div>
            </section>
        </div>

        <div class="flex flex-col gap-6">
            
            <!-- Boleta de Operação Rápida -->
            <section class="bg-slate-900 border border-slate-800/80 rounded-2xl p-5 shadow-xl flex flex-col gap-4">
                <div class="flex items-center justify-between border-b border-slate-800 pb-3">
                    <h3 class="text-sm font-bold uppercase tracking-wider flex items-center gap-2">
                        <i data-lucide="wallet" class="w-4 h-4 text-emerald-400"></i> Boleta de Operações
                    </h3>
                    <span class="text-xs text-slate-400 font-semibold font-mono" id="assetLabel">BTC/USDT</span>
                </div>

                <!-- Abas Compra / Venda -->
                <div class="grid grid-cols-2 gap-2 bg-slate-950 p-1 rounded-xl border border-slate-850">
                    <button onclick="setTradeDirection('BUY')" id="btnBuy" class="py-2.5 text-xs font-bold uppercase rounded-lg transition-all bg-emerald-500 text-slate-950 shadow-md">
                        Compra (Long)
                    </button>
                    <button onclick="setTradeDirection('SELL')" id="btnSell" class="py-2.5 text-xs font-bold uppercase rounded-lg transition-all text-slate-400 hover:text-rose-500">
                        Venda (Short)
                    </button>
                </div>

                <!-- Input Lote (Size) -->
                <div>
                    <label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider block mb-1.5 flex justify-between">
                        <span>Quantidade (Tamanho da Ordem)</span>
                        <span class="text-slate-500 font-mono">Min: 0.01</span>
                    </label>
                    <div class="relative rounded-xl bg-slate-950 border border-slate-800 p-2 focus-within:border-emerald-500 transition">
                        <input type="number" id="tradeSize" value="0.5" step="0.05" min="0.01" class="bg-transparent text-xl font-bold font-mono text-slate-100 outline-none w-full" oninput="calculateMargin()">
                        <span class="absolute right-3 top-1/2 -translate-y-1/2 text-xs font-semibold text-slate-500 font-mono">LOTE</span>
                    </div>
                </div>

                <!-- Alavancagem Simulada -->
                <div>
                    <div class="flex justify-between text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1.5">
                        <span>Alavancagem Cruzada</span>
                        <span class="text-emerald-400 font-mono" id="leverageLabel">20x</span>
                    </div>
                    <input type="range" id="leverageRange" min="1" max="100" value="20" class="w-full accent-emerald-500 h-1 bg-slate-800 rounded-lg cursor-pointer" oninput="updateLeverage(this.value)">
                    <div class="flex justify-between text-[9px] text-slate-500 mt-1 font-semibold">
                        <span>1x</span>
                        <span>25x</span>
                        <span>50x</span>
                        <span>100x</span>
                    </div>
                </div>

                <!-- Stop Loss e Take Profit -->
                <div class="grid grid-cols-2 gap-3">
                    <div>
                        <label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider block mb-1.5">Take Profit (Preço)</label>
                        <div class="relative rounded-xl bg-slate-950 border border-slate-800 p-2.5 focus-within:border-emerald-500 transition">
                            <input type="number" id="tpInput" placeholder="Nenhum" class="bg-transparent text-sm font-bold font-mono text-slate-200 outline-none w-full">
                            <i data-lucide="target" class="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-600"></i>
                        </div>
                    </div>
                    <div>
                        <label class="text-[10px] font-bold text-slate-400 uppercase tracking-wider block mb-1.5">Stop Loss (Preço)</label>
                        <div class="relative rounded-xl bg-slate-950 border border-slate-800 p-2.5 focus-within:border-rose-500 transition">
                            <input type="number" id="slInput" placeholder="Nenhum" class="bg-transparent text-sm font-bold font-mono text-slate-200 outline-none w-full">
                            <i data-lucide="shield-alert" class="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-600"></i>
                        </div>
                    </div>
                </div>

                <!-- Custos e Margem de Risco -->
                <div class="bg-slate-950/60 rounded-xl p-3 border border-slate-850 text-xs flex flex-col gap-2 font-mono">
                    <div class="flex justify-between">
                        <span class="text-slate-500">Custo de Margem (Exigido):</span>
                        <span class="text-slate-300 font-semibold" id="marginRequired">S$ 1.635,51</span>
                    </div>
                    <div class="flex justify-between">
                        <span class="text-slate-500">Exposição Total:</span>
                        <span class="text-slate-300 font-semibold" id="totalExposure">S$ 32.710,25</span>
                    </div>
                </div>

                <!-- Botão de Envio de Ordem -->
                <button onclick="executeOrder()" class="w-full py-4 rounded-xl text-sm font-black uppercase tracking-wider bg-gradient-to-r from-emerald-500 to-teal-500 text-slate-950 shadow-lg shadow-emerald-500/20 hover:shadow-emerald-500/30 active:scale-[0.98] transition-all flex items-center justify-center gap-2" id="btnSubmitOrder">
                    <i data-lucide="zap" class="w-4 h-4 fill-current"></i> Abrir Posição de Compra
                </button>
            </section>

            <section class="bg-slate-900 border border-slate-800/80 rounded-2xl p-5 shadow-xl flex-1 flex flex-col min-h-[300px]">
                <div class="flex bg-slate-950 p-1 rounded-xl border border-slate-850 mb-4">
                    <button onclick="setLedgerTab('positions')" id="tabPos" class="flex-1 py-1.5 text-xs font-bold rounded-lg transition bg-slate-800 text-white shadow-sm">
                        Posições Ativas (<span id="countPos">0</span>)
                    </button>
                    <button onclick="setLedgerTab('history')" id="tabHist" class="flex-1 py-1.5 text-xs font-bold rounded-lg transition text-slate-400 hover:text-white">
                        Histórico
                    </button>
                </div>

                <!-- Container Rolável das Posições ou Histórico -->
                <div class="flex-1 overflow-y-auto max-h-[250px]" id="ledgerContent">
                    <!-- Dinâmico via JS -->
                    <div class="text-center py-10 text-slate-500 text-xs flex flex-col items-center gap-2">
                        <i data-lucide="inbox" class="w-8 h-8 opacity-40"></i>
                        Nenhuma posição aberta no momento.
                    </div>
                </div>
            </section>
        </div>
    </main>

    <div id="toastContainer" class="fixed bottom-4 right-4 z-50 flex flex-col gap-2 pointer-events-none"></div>

    <footer class="border-t border-slate-850 bg-slate-950 px-4 py-3 text-center text-[10px] text-slate-500">
        <p>© 2026 TradeFlow MVP. Todos os direitos reservados. Este é um ambiente de simulação financeira e desenvolvimento de testes táticos.</p>
    </footer>

    <script>
        // --- CONSTANTES & ESTADOS DO APP ---
        const appState = {
            balance: 10000.00,
            floatingPL: 0.00,
            positions: [],
            history: [],
            candles: [],
            connectionMode: 'simulated', // 'simulated' ou 'live'
            activeSymbol: 'BTC/USDT',
            currentPrice: 65420.50,
            priceHigh24h: 65980.00,
            priceLow24h: 64210.00,
            priceChange24h: 1.24,
            activeDirection: 'BUY', // 'BUY' ou 'SELL'
            leverage: 20,
            zoom: 1.0,
            indicators: {
                sma: true,
                rsi: true
            },
            ws: null
        };

        // DOM elements cache
        const dom = {
            walletBalance: document.getElementById('walletBalance'),
            totalFloatingPL: document.getElementById('totalFloatingPL'),
            tickerPrice: document.getElementById('tickerPrice'),
            tickerPercentChange: document.getElementById('tickerPercentChange'),
            tickerHigh: document.getElementById('tickerHigh'),
            tickerLow: document.getElementById('tickerLow'),
            btnModeSim: document.getElementById('btnModeSim'),
            btnModeLive: document.getElementById('btnModeLive'),
            btnBuy: document.getElementById('btnBuy'),
            btnSell: document.getElementById('btnSell'),
            tradeSize: document.getElementById('tradeSize'),
            leverageRange: document.getElementById('leverageRange'),
            leverageLabel: document.getElementById('leverageLabel'),
            tpInput: document.getElementById('tpInput'),
            slInput: document.getElementById('slInput'),
            marginRequired: document.getElementById('marginRequired'),
            totalExposure: document.getElementById('totalExposure'),
            btnSubmitOrder: document.getElementById('btnSubmitOrder'),
            ledgerContent: document.getElementById('ledgerContent'),
            tabPos: document.getElementById('tabPos'),
            tabHist: document.getElementById('tabHist'),
            countPos: document.getElementById('countPos'),
            rsiVal: document.getElementById('rsiVal'),
            rsiState: document.getElementById('rsiState'),
            rsiBar: document.getElementById('rsiBar'),
            smaVal: document.getElementById('smaVal'),
            smaTrend: document.getElementById('smaTrend'),
            recSignal: document.getElementById('recSignal'),
            signalCard: document.getElementById('signalCard'),
            tickerPanel: document.getElementById('tickerPanel'),
            toastContainer: document.getElementById('toastContainer')
        };

        let activeTab = 'positions'; // 'positions' ou 'history'
        
        // Configurações do Gráfico
        const canvas = document.getElementById('tradingChart');
        const ctx = canvas.getContext('2d');
        
        // --- INICIALIZAÇÃO DO APP ---
        window.onload = function() {
            lucide.createIcons();
            initMockCandles();
            resizeCanvas();
            updateDashboard();
            calculateMargin();
            
            // Inicia o loop de simulação local de ticks
            startSimulationLoop();
        };

        function resizeCanvas() {
            const container = document.getElementById('canvasContainer');
            canvas.width = container.clientWidth;
            canvas.height = container.clientHeight;
            drawChart();
        }
        window.addEventListener('resize', resizeCanvas);

        // Gerar Dados Iniciais de Candlestick (Simulando Histórico)
        function initMockCandles() {
            let basePrice = appState.currentPrice - 300;
            const now = Date.now();
            for (let i = 80; i >= 0; i--) {
                const time = now - (i * 5000); // interval de 5 segundos por vela
                const open = basePrice + (Math.random() - 0.5) * 80;
                const close = open + (Math.random() - 0.5) * 85;
                const high = Math.max(open, close) + Math.random() * 40;
                const low = Math.min(open, close) - Math.random() * 40;
                appState.candles.push({ time, open, high, low, close });
                basePrice = close;
            }
            appState.currentPrice = basePrice;
        }

        // --- MOTOR DE SIMULAÇÃO DE TICKERS ---
        let simInterval = null;
        function startSimulationLoop() {
            if (simInterval) clearInterval(simInterval);
            simInterval = setInterval(() => {
                if (appState.connectionMode === 'simulated') {
                    // Flutuação aleatória e tática de mercado
                    const lastCandle = appState.candles[appState.candles.length - 1];
                    const volatility = 15;
                    const change = (Math.random() - 0.49) * volatility; // ligeira tendência de alta natural
                    const oldPrice = appState.currentPrice;
                    appState.currentPrice += change;
                    
                    // Atualiza a vela atual
                    lastCandle.close = appState.currentPrice;
                    if (appState.currentPrice > lastCandle.high) lastCandle.high = appState.currentPrice;
                    if (appState.currentPrice < lastCandle.low) lastCandle.low = appState.currentPrice;

                    // Cria nova vela a cada 5 segundos
                    const now = Date.now();
                    if (now - lastCandle.time >= 5000) {
                        appState.candles.push({
                            time: now,
                            open: lastCandle.close,
                            high: lastCandle.close,
                            low: lastCandle.close,
                            close: lastCandle.close
                        });
                        if (appState.candles.length > 120) appState.candles.shift(); // limite de memória das velas
                    }

                    handleTickUpdate(oldPrice < appState.currentPrice);
                }
            }, 500);
        }

        // --- INTEGRAÇÃO REAL-TIME WEB_SOCKETS (BINANCE LIVE) ---
        function connectBinanceWS() {
            if (appState.ws) {
                appState.ws.close();
            }

            showToast("Conectando ao feed em tempo real da Binance...", "info");
            
            // Stream público do Bitcoin (Velas de 1 Minuto)
            appState.ws = new WebSocket("wss://stream.binance.com:9443/ws/btcusdt@kline_1m");

            appState.ws.onmessage = (event) => {
                if (appState.connectionMode !== 'live') return;
                const data = JSON.parse(event.data);
                const k = data.k; // candle info
                const oldPrice = appState.currentPrice;
                
                appState.currentPrice = parseFloat(k.c);
                appState.priceHigh24h = parseFloat(k.h); // Aproximado para a vela atual
                appState.priceLow24h = parseFloat(k.l);
                
                // Mapeia os dados recebidos para as velas do gráfico local
                const lastCandle = appState.candles[appState.candles.length - 1];
                const incomingTime = parseInt(k.t);
                
                if (lastCandle && incomingTime >= lastCandle.time) {
                    // Atualiza vela atual
                    lastCandle.close = appState.currentPrice;
                    lastCandle.high = parseFloat(k.h);
                    lastCandle.low = parseFloat(k.l);
                    lastCandle.open = parseFloat(k.o);
                } else {
                    // Nova vela recebida
                    appState.candles.push({
                        time: incomingTime,
                        open: parseFloat(k.o),
                        high: parseFloat(k.h),
                        low: parseFloat(k.l),
                        close: appState.currentPrice
                    });
                    if (appState.candles.length > 120) appState.candles.shift();
                }

                handleTickUpdate(oldPrice < appState.currentPrice);
            };

            appState.ws.onerror = (err) => {
                showToast("Erro ao conectar no feed live. Retornando ao Simulador.", "error");
                setConnectionMode('simulated');
            };

            appState.ws.onclose = () => {
                if (appState.connectionMode === 'live') {
                    showToast("Conexão com a Binance encerrada.", "warning");
                }
            };
        }

        // --- LÓGICA CORE DE EXECUÇÃO DE TICKS ---
        function handleTickUpdate(isPositive) {
            // Atualizar cor e efeitos no painel de ticker
            dom.tickerPrice.textContent = `$ ${appState.currentPrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
            
            if (isPositive) {
                dom.tickerPrice.className = "text-2xl font-black font-mono tracking-tight text-emerald-400";
                dom.tickerPanel.classList.add('price-up');
                setTimeout(() => dom.tickerPanel.classList.remove('price-up'), 500);
            } else {
                dom.tickerPrice.className = "text-2xl font-black font-mono tracking-tight text-rose-500";
                dom.tickerPanel.classList.add('price-down');
                setTimeout(() => dom.tickerPanel.classList.remove('price-down'), 500);
            }

            // Monitorar P&L Aberto e gatilhos de stop loss / take profit
            updatePositionsPL();
            updateDashboard();
            drawChart();
        }

        // --- CONTROLES DE INTERFACE (UI INTERACTORS) ---
        function setConnectionMode(mode) {
            appState.connectionMode = mode;
            if (mode === 'live') {
                dom.btnModeLive.className = "px-3 py-1.5 text-xs font-semibold rounded-lg transition-all flex items-center gap-2 bg-slate-800 text-amber-400 shadow-sm";
                dom.btnModeSim.className = "px-3 py-1.5 text-xs font-semibold rounded-lg transition-all flex items-center gap-2 text-slate-400 hover:text-white";
                connectBinanceWS();
            } else {
                dom.btnModeSim.className = "px-3 py-1.5 text-xs font-semibold rounded-lg transition-all flex items-center gap-2 bg-slate-800 text-emerald-400 shadow-sm";
                dom.btnModeLive.className = "px-3 py-1.5 text-xs font-semibold rounded-lg transition-all flex items-center gap-2 text-slate-400 hover:text-white";
                if (appState.ws) {
                    appState.ws.close();
                }
                showToast("Simulador Local de Preço reativado.", "success");
                startSimulationLoop();
            }
        }

        function setTradeDirection(dir) {
            appState.activeDirection = dir;
            if (dir === 'BUY') {
                dom.btnBuy.className = "py-2.5 text-xs font-bold uppercase rounded-lg transition-all bg-emerald-500 text-slate-950 shadow-md";
                dom.btnSell.className = "py-2.5 text-xs font-bold uppercase rounded-lg transition-all text-slate-400 hover:text-rose-500";
                dom.btnSubmitOrder.className = "w-full py-4 rounded-xl text-sm font-black uppercase tracking-wider bg-gradient-to-r from-emerald-500 to-teal-500 text-slate-950 shadow-lg shadow-emerald-500/20 hover:shadow-emerald-500/30 active:scale-[0.98] transition-all flex items-center justify-center gap-2";
                dom.btnSubmitOrder.innerHTML = `<i data-lucide="zap" class="w-4 h-4 fill-current"></i> Abrir Posição de Compra`;
            } else {
                dom.btnSell.className = "py-2.5 text-xs font-bold uppercase rounded-lg transition-all bg-rose-500 text-white shadow-md";
                dom.btnBuy.className = "py-2.5 text-xs font-bold uppercase rounded-lg transition-all text-slate-400 hover:text-emerald-400";
                dom.btnSubmitOrder.className = "w-full py-4 rounded-xl text-sm font-black uppercase tracking-wider bg-gradient-to-r from-rose-500 to-red-600 text-white shadow-lg shadow-rose-500/20 hover:shadow-rose-500/30 active:scale-[0.98] transition-all flex items-center justify-center gap-2";
                dom.btnSubmitOrder.innerHTML = `<i data-lucide="zap" class="w-4 h-4 fill-current"></i> Abrir Posição de Venda`;
            }
            lucide.createIcons();
            calculateMargin();
        }

        function updateLeverage(val) {
            appState.leverage = parseInt(val);
            dom.leverageLabel.textContent = `${val}x`;
            calculateMargin();
        }

        function calculateMargin() {
            const size = parseFloat(dom.tradeSize.value) || 0;
            const exposure = size * appState.currentPrice;
            const margin = exposure / appState.leverage;
            
            dom.totalExposure.textContent = `S$ ${exposure.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
            dom.marginRequired.textContent = `S$ ${margin.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
        }

        function changeZoom(factor) {
            appState.zoom *= factor;
            if (appState.zoom < 0.4) appState.zoom = 0.4;
            if (appState.zoom > 3.0) appState.zoom = 3.0;
            drawChart();
        }

        function toggleIndicator(ind) {
            appState.indicators[ind] = !appState.indicators[ind];
            const btn = ind === 'sma' ? dom.btnSma : dom.btnRsi;
            if (appState.indicators[ind]) {
                btn.className = "px-2 py-1.5 text-[10px] font-bold rounded-lg bg-emerald-500/20 text-emerald-400 border border-emerald-500/25 transition";
            } else {
                btn.className = "px-2 py-1.5 text-[10px] font-bold rounded-lg bg-slate-800 text-slate-400 hover:bg-slate-750 transition";
            }
            drawChart();
        }

        // --- STREAMING_CHUNK: Motor de Execução de Ordens (Trading System) ---
        function executeOrder() {
            const size = parseFloat(dom.tradeSize.value);
            if (isNaN(size) || size <= 0) {
                showToast("Insira um lote de tamanho válido.", "warning");
                return;
            }

            const exposure = size * appState.currentPrice;
            const requiredMargin = exposure / appState.leverage;

            if (requiredMargin > appState.balance) {
                showToast("Saldo insuficiente para cobrir a margem exigida.", "error");
                return;
            }

            const tpPrice = parseFloat(dom.tpInput.value) || null;
            const slPrice = parseFloat(dom.slInput.value) || null;

            // Validações básicas de SL/TP táticos
            if (appState.activeDirection === 'BUY') {
                if (tpPrice && tpPrice <= appState.currentPrice) {
                    showToast("Take Profit de Compra deve ser superior ao preço atual.", "warning");
                    return;
                }
                if (slPrice && slPrice >= appState.currentPrice) {
                    showToast("Stop Loss de Compra deve ser inferior ao preço atual.", "warning");
                    return;
                }
            } else {
                if (tpPrice && tpPrice >= appState.currentPrice) {
                    showToast("Take Profit de Venda deve ser inferior ao preço atual.", "warning");
                    return;
                }
                if (slPrice && slPrice <= appState.currentPrice) {
                    showToast("Stop Loss de Venda deve ser superior ao preço atual.", "warning");
                    return;
                }
            }

            // Deduz margem exigida do saldo operacional
            appState.balance -= requiredMargin;

            // Cria o objeto da posição tática
            const position = {
                id: Date.now() + Math.random().toString(36).substr(2, 5),
                symbol: appState.activeSymbol,
                type: appState.activeDirection,
                entryPrice: appState.currentPrice,
                size: size,
                leverage: appState.leverage,
                margin: requiredMargin,
                takeProfit: tpPrice,
                stopLoss: slPrice,
                floatingPL: 0.00,
                timestamp: Date.now()
            };

            appState.positions.push(position);
            showToast(`Posição de ${position.type === 'BUY' ? 'COMPRA' : 'VENDA'} aberta com sucesso!`, "success");
            
            // Reset de inputs da boleta
            dom.tpInput.value = '';
            dom.slInput.value = '';
            
            updateLedger();
            updateDashboard();
        }

        // Atualização e Monitor de Lucros/Perdas Flutuantes das Posições
        function updatePositionsPL() {
            let totalPL = 0;
            const positionsToClose = [];

            appState.positions.forEach(pos => {
                const diff = appState.currentPrice - pos.entryPrice;
                const percentChange = diff / pos.entryPrice;
                
                if (pos.type === 'BUY') {
                    pos.floatingPL = percentChange * pos.size * pos.entryPrice * pos.leverage;
                } else {
                    pos.floatingPL = -percentChange * pos.size * pos.entryPrice * pos.leverage;
                }

                totalPL += pos.floatingPL;

                // Checagem de Acionamento Automático de Stop Loss / Take Profit
                if (pos.type === 'BUY') {
                    if (pos.takeProfit && appState.currentPrice >= pos.takeProfit) {
                        positionsToClose.push({ pos, reason: 'Take Profit' });
                    } else if (pos.stopLoss && appState.currentPrice <= pos.stopLoss) {
                        positionsToClose.push({ pos, reason: 'Stop Loss' });
                    }
                } else {
                    if (pos.takeProfit && appState.currentPrice <= pos.takeProfit) {
                        positionsToClose.push({ pos, reason: 'Take Profit' });
                    } else if (pos.stopLoss && appState.currentPrice >= pos.stopLoss) {
                        positionsToClose.push({ pos, reason: 'Stop Loss' });
                    }
                }
            });

            appState.floatingPL = totalPL;

            // Processar fechamentos automáticos
            positionsToClose.forEach(({ pos, reason }) => {
                closePosition(pos.id, reason);
            });

            if (appState.positions.length > 0) {
                updateLedger();
            }
        }

        function closePosition(posId, reason = 'Manual') {
            const index = appState.positions.findIndex(p => p.id === posId);
            if (index === -1) return;

            const pos = appState.positions[index];
            const finalPL = pos.floatingPL;
            
            // Devolve margem + adiciona/subtrai P&L ao saldo líquido
            appState.balance += pos.margin + finalPL;

            // Adiciona ao histórico de operações
            appState.history.unshift({
                ...pos,
                exitPrice: appState.currentPrice,
                finalPL: finalPL,
                closeReason: reason,
                closedAt: Date.now()
            });

            // Remove das posições ativas
            appState.positions.splice(index, 1);
            showToast(`Posição encerrada (${reason}). P&L: S$ ${finalPL.toFixed(2)}`, finalPL >= 0 ? "success" : "error");

            updateLedger();
            updateDashboard();
        }

        // --- ATUALIZAÇÕES DE INTERFACE (DASHBOARD & LEDGER) ---
        function updateDashboard() {
            dom.walletBalance.textContent = `S$ ${appState.balance.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
            
            const plText = `S$ ${appState.floatingPL.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
            dom.totalFloatingPL.textContent = plText;
            
            if (appState.floatingPL > 0) {
                dom.totalFloatingPL.className = "text-lg font-bold text-emerald-400";
            } else if (appState.floatingPL < 0) {
                dom.totalFloatingPL.className = "text-lg font-bold text-rose-500";
            } else {
                dom.totalFloatingPL.className = "text-lg font-bold text-slate-400";
            }

            dom.countPos.textContent = appState.positions.length;
            calculateMargin();

            // Computar Sinais Analíticos de Mercado
            updateTechnicalSignals();
        }

        function setLedgerTab(tab) {
            activeTab = tab;
            if (tab === 'positions') {
                dom.tabPos.className = "flex-1 py-1.5 text-xs font-bold rounded-lg transition bg-slate-800 text-white shadow-sm";
                dom.tabHist.className = "flex-1 py-1.5 text-xs font-bold rounded-lg transition text-slate-400 hover:text-white";
            } else {
                dom.tabHist.className = "flex-1 py-1.5 text-xs font-bold rounded-lg transition bg-slate-800 text-white shadow-sm";
                dom.tabPos.className = "flex-1 py-1.5 text-xs font-bold rounded-lg transition text-slate-400 hover:text-white";
            }
            updateLedger();
        }

        function updateLedger() {
            dom.ledgerContent.innerHTML = '';

            if (activeTab === 'positions') {
                if (appState.positions.length === 0) {
                    dom.ledgerContent.innerHTML = `
                        <div class="text-center py-10 text-slate-500 text-xs flex flex-col items-center gap-2">
                            <i data-lucide="inbox" class="w-8 h-8 opacity-40"></i>
                            Nenhuma posição aberta no momento.
                        </div>
                    `;
                    lucide.createIcons();
                    return;
                }

                appState.positions.forEach(pos => {
                    const card = document.createElement('div');
                    card.className = "bg-slate-950 p-3 rounded-xl border border-slate-850 mb-2 flex flex-col gap-2";
                    
                    const isProfit = pos.floatingPL >= 0;
                    const plClass = isProfit ? "text-emerald-400" : "text-rose-500";
                    
                    card.innerHTML = `
                        <div class="flex justify-between items-center text-xs">
                            <span class="font-bold flex items-center gap-1.5">
                                <span class="w-2 h-2 rounded-full ${pos.type === 'BUY' ? 'bg-emerald-500' : 'bg-rose-500'}"></span>
                                ${pos.type === 'BUY' ? 'COMPRA' : 'VENDA'}
                                <span class="text-slate-500 text-[10px] font-mono">${pos.leverage}x</span>
                            </span>
                            <button onclick="closePosition('${pos.id}')" class="px-2 py-1 text-[10px] font-extrabold rounded bg-slate-800 text-slate-300 hover:bg-rose-500 hover:text-white transition uppercase">Fechar</button>
                        </div>
                        <div class="grid grid-cols-3 gap-1 text-[10px] text-slate-400 font-mono">
                            <div>
                                <div class="text-slate-500">Lote</div>
                                <div class="font-semibold text-slate-200">${pos.size} BTC</div>
                            </div>
                            <div>
                                <div class="text-slate-500">Entrada</div>
                                <div class="font-semibold text-slate-200">$ ${pos.entryPrice.toFixed(2)}</div>
                            </div>
                            <div class="text-right">
                                <div class="text-slate-500">P&L Aberto</div>
                                <div class="font-bold ${plClass}">$ ${pos.floatingPL.toFixed(2)}</div>
                            </div>
                        </div>
                        ${(pos.takeProfit || pos.stopLoss) ? `
                        <div class="border-t border-slate-900 pt-1.5 flex gap-3 text-[9px] font-semibold font-mono text-slate-500">
                            ${pos.takeProfit ? `<span>TP: <span class="text-emerald-500">$ ${pos.takeProfit}</span></span>` : ''}
                            ${pos.stopLoss ? `<span>SL: <span class="text-rose-500">$ ${pos.stopLoss}</span></span>` : ''}
                        </div>
                        ` : ''}
                    `;
                    dom.ledgerContent.appendChild(card);
                });
            } else {
                if (appState.history.length === 0) {
                    dom.ledgerContent.innerHTML = `
                        <div class="text-center py-10 text-slate-500 text-xs flex flex-col items-center gap-2">
                            <i data-lucide="archive" class="w-8 h-8 opacity-40"></i>
                            Histórico de operações vazio.
                        </div>
                    `;
                    lucide.createIcons();
                    return;
                }

                appState.history.forEach(hist => {
                    const card = document.createElement('div');
                    card.className = "bg-slate-950/40 p-3 rounded-xl border border-slate-900 mb-2 flex flex-col gap-1.5";
                    
                    const isProfit = hist.finalPL >= 0;
                    const plClass = isProfit ? "text-emerald-400" : "text-rose-500";
                    
                    card.innerHTML = `
                        <div class="flex justify-between text-[10px]">
                            <span class="font-bold flex items-center gap-1">
                                <span class="text-slate-500">[${hist.closeReason}]</span>
                                ${hist.type === 'BUY' ? 'COMPRA' : 'VENDA'}
                            </span>
                            <span class="text-slate-500 font-mono">${new Date(hist.closedAt).toLocaleTimeString()}</span>
                        </div>
                        <div class="flex justify-between items-baseline text-xs font-mono">
                            <span class="text-slate-400">${hist.size} BTC @ $ ${hist.entryPrice.toFixed(2)}</span>
                            <span class="font-bold ${plClass}">$ ${hist.finalPL.toFixed(2)}</span>
                        </div>
                    `;
                    dom.ledgerContent.appendChild(card);
                });
            }
            lucide.createIcons();
        }

        // --- STREAMING_CHUNK: Cálculos e Sinais de Análise Técnica ---
        function updateTechnicalSignals() {
            if (appState.candles.length < 15) return;

            // 1. Simulação Simples de RSI
            // Baseia-se na variação recente do preço para criar um oscilador real de momentum
            const changes = [];
            for (let i = appState.candles.length - 14; i < appState.candles.length; i++) {
                if (appState.candles[i] && appState.candles[i-1]) {
                    changes.push(appState.candles[i].close - appState.candles[i-1].close);
                }
            }
            
            let gains = 0, losses = 0;
            changes.forEach(change => {
                if (change > 0) gains += change;
                else losses += Math.abs(change);
            });

            let rsi = 50;
            if (losses !== 0) {
                const rs = gains / losses;
                rsi = 100 - (100 / (1 + rs));
            }
            
            dom.rsiVal.textContent = rsi.toFixed(1);
            dom.rsiBar.style.width = `${rsi}%`;

            let rsiState = "Neutro";
            if (rsi > 70) {
                rsiState = "Sobrecomprado";
                dom.rsiState.className = "text-xs px-2 py-0.5 rounded-full bg-rose-500/10 text-rose-400 font-medium";
            } else if (rsi < 30) {
                rsiState = "Sobrevendido";
                dom.rsiState.className = "text-xs px-2 py-0.5 rounded-full bg-emerald-500/10 text-emerald-400 font-medium";
            } else {
                dom.rsiState.className = "text-xs px-2 py-0.5 rounded-full bg-slate-800 text-slate-300 font-medium";
            }
            dom.rsiState.textContent = rsiState;

            // 2. Média Móvel Simples (SMA-9)
            let smaSum = 0;
            const period = 9;
            for (let i = appState.candles.length - period; i < appState.candles.length; i++) {
                smaSum += appState.candles[i].close;
            }
            const sma = smaSum / period;
            dom.smaVal.textContent = `$ ${sma.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;

            // 3. Recomendação Tática Inteligente
            let recommendation = "NEUTRO";
            let recColorClass = "text-slate-300 uppercase";
            let borderClass = "border-l-slate-600";

            if (appState.currentPrice > sma && rsi < 65) {
                recommendation = "COMPRA FORTE";
                recColorClass = "text-emerald-400 uppercase font-black";
                borderClass = "border-l-4 border-l-emerald-500";
            } else if (appState.currentPrice < sma && rsi > 35) {
                recommendation = "VENDA";
                recColorClass = "text-rose-500 uppercase font-black";
                borderClass = "border-l-4 border-l-rose-500";
            } else if (rsi < 30) {
                recommendation = "SUPERCOMPRA";
                recColorClass = "text-emerald-400 uppercase font-black animate-pulse";
                borderClass = "border-l-4 border-l-emerald-500";
            } else if (rsi > 70) {
                recommendation = "SUPERVENDA";
                recColorClass = "text-rose-500 uppercase font-black animate-pulse";
                borderClass = "border-l-4 border-l-rose-500";
            }

            dom.recSignal.textContent = recommendation;
            dom.recSignal.className = `text-2xl font-black tracking-tight ${recColorClass}`;
            dom.signalCard.className = `bg-slate-900 border border-slate-850 bg-gradient-to-br from-slate-900 to-slate-950 rounded-2xl p-4 flex flex-col justify-between shadow-lg ${borderClass}`;
        }

        // --- STREAMING_CHUNK: Renderização Customizada do Gráfico de Velas ---
        function drawChart() {
            if (!ctx || appState.candles.length === 0) return;

            // Limpa o canvas
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            const paddingLeft = 10;
            const paddingRight = 80;
            const paddingTop = 20;
            const paddingBottom = 40;

            const chartWidth = canvas.width - paddingLeft - paddingRight;
            const chartHeight = canvas.height - paddingTop - paddingBottom;

            // Quantidade de velas visíveis baseada no zoom
            const maxCandlesVisible = Math.floor(45 * appState.zoom);
            const visibleCandles = appState.candles.slice(-maxCandlesVisible);

            if (visibleCandles.length === 0) return;

            // Encontrar máxima e mínima do preço do corte visível para o Auto-scale
            let maxPrice = -Infinity;
            let minPrice = Infinity;
            visibleCandles.forEach(c => {
                if (c.high > maxPrice) maxPrice = c.high;
                if (c.low < minPrice) minPrice = c.low;
            });

            // Dar um respiro de 5% acima e abaixo para encaixe estético
            const priceRange = maxPrice - minPrice;
            maxPrice += priceRange * 0.05;
            minPrice -= priceRange * 0.05;

            const candleWidth = chartWidth / visibleCandles.length;

            // Desenhar Grade de Fundo (Grids)
            ctx.strokeStyle = '#1e293b';
            ctx.lineWidth = 0.5;
            ctx.fillStyle = '#64748b';
            ctx.font = '9px font-mono';

            // Grade Horizontal (Preços)
            const gridLines = 5;
            for (let i = 0; i <= gridLines; i++) {
                const y = paddingTop + (chartHeight / gridLines) * i;
                const priceLabel = maxPrice - ((maxPrice - minPrice) / gridLines) * i;
                
                ctx.beginPath();
                ctx.moveTo(paddingLeft, y);
                ctx.lineTo(paddingLeft + chartWidth, y);
                ctx.stroke();

                // Desenha etiqueta do preço à direita
                ctx.fillText(`$ ${priceLabel.toFixed(1)}`, paddingLeft + chartWidth + 5, y + 3);
            }

            // Desenhar Velas (Candlesticks)
            visibleCandles.forEach((c, index) => {
                const x = paddingLeft + (index * candleWidth) + (candleWidth * 0.1);
                const w = candleWidth * 0.8;

                // Mapear preço para Y no canvas
                const yOpen = paddingTop + chartHeight * (1 - (c.open - minPrice) / (maxPrice - minPrice));
                const yClose = paddingTop + chartHeight * (1 - (c.close - minPrice) / (maxPrice - minPrice));
                const yHigh = paddingTop + chartHeight * (1 - (c.high - minPrice) / (maxPrice - minPrice));
                const yLow = paddingTop + chartHeight * (1 - (c.low - minPrice) / (maxPrice - minPrice));

                const isBullish = c.close >= c.open;
                ctx.strokeStyle = isBullish ? '#10b981' : '#f43f5e';
                ctx.fillStyle = isBullish ? '#10b981' : '#f43f5e';
                ctx.lineWidth = 1.5;

                // Linha de pavio (sombra)
                ctx.beginPath();
                ctx.moveTo(x + w / 2, yHigh);
                ctx.lineTo(x + w / 2, yLow);
                ctx.stroke();

                // Corpo da vela
                const bodyHeight = Math.max(Math.abs(yClose - yOpen), 1);
                ctx.fillRect(x, Math.min(yOpen, yClose), w, bodyHeight);
            });

            // Média Móvel Tática (SMA) sobreposta
            if (appState.indicators.sma && visibleCandles.length > 9) {
                ctx.strokeStyle = '#38bdf8';
                ctx.lineWidth = 1.8;
                ctx.beginPath();

                for (let i = 0; i < visibleCandles.length; i++) {
                    const idxInGlobal = appState.candles.indexOf(visibleCandles[i]);
                    if (idxInGlobal >= 9) {
                        let sum = 0;
                        for (let j = 0; j < 9; j++) {
                            sum += appState.candles[idxInGlobal - j].close;
                        }
                        const avg = sum / 9;
                        const x = paddingLeft + (i * candleWidth) + (candleWidth / 2);
                        const y = paddingTop + chartHeight * (1 - (avg - minPrice) / (maxPrice - minPrice));

                        if (i === 0) ctx.moveTo(x, y);
                        else ctx.lineTo(x, y);
                    }
                }
                ctx.stroke();
            }

            // Desenhar Linhas de Posições Ativas (Visual Trading!)
            appState.positions.forEach(pos => {
                if (pos.entryPrice >= minPrice && pos.entryPrice <= maxPrice) {
                    const y = paddingTop + chartHeight * (1 - (pos.entryPrice - minPrice) / (maxPrice - minPrice));
                    
                    ctx.strokeStyle = pos.type === 'BUY' ? '#10b981' : '#f43f5e';
                    ctx.setLineDash([5, 3]);
                    ctx.lineWidth = 1;
                    
                    ctx.beginPath();
                    ctx.moveTo(paddingLeft, y);
                    ctx.lineTo(paddingLeft + chartWidth, y);
                    ctx.stroke();
                    ctx.setLineDash([]); // limpa o tracejado

                    // Etiqueta de Posição
                    ctx.fillStyle = pos.type === 'BUY' ? '#10b981' : '#f43f5e';
                    ctx.fillRect(paddingLeft + 5, y - 12, 60, 10);
                    ctx.fillStyle = '#0b0f19';
                    ctx.font = 'bold 8px font-mono';
                    ctx.fillText(`${pos.type} ${pos.size}`, paddingLeft + 8, y - 4);
                }
            });

            // Preço Atual Linha Guia Dinâmica (Glow Tracker)
            if (appState.currentPrice >= minPrice && appState.currentPrice <= maxPrice) {
                const y = paddingTop + chartHeight * (1 - (appState.currentPrice - minPrice) / (maxPrice - minPrice));
                ctx.strokeStyle = 'rgba(255, 255, 255, 0.25)';
                ctx.lineWidth = 0.8;
                ctx.setLineDash([2, 2]);
                ctx.beginPath();
                ctx.moveTo(paddingLeft, y);
                ctx.lineTo(paddingLeft + chartWidth, y);
                ctx.stroke();
                ctx.setLineDash([]);

                // Caixa de Preço de Mercado à direita
                ctx.fillStyle = '#0f172a';
                ctx.fillRect(paddingLeft + chartWidth + 2, y - 7, 75, 14);
                ctx.strokeStyle = '#64748b';
                ctx.lineWidth = 0.5;
                ctx.strokeRect(paddingLeft + chartWidth + 2, y - 7, 75, 14);

                ctx.fillStyle = '#f8fafc';
                ctx.font = '9px font-mono';
                ctx.fillText(`$ ${appState.currentPrice.toFixed(2)}`, paddingLeft + chartWidth + 6, y + 3);
            }
        }

        // --- SISTEMA INTERNO DE NOTIFICAÇÕES (TOAST MANAGER) ---
        function showToast(message, type = 'info') {
            const id = Date.now().toString();
            const toast = document.createElement('div');
            toast.id = id;
            toast.className = `transform translate-y-2 opacity-0 transition-all duration-300 pointer-events-auto flex items-center gap-3 p-4 rounded-xl shadow-2xl border text-sm max-w-sm ${
                type === 'success' ? 'bg-emerald-950/95 text-emerald-400 border-emerald-500/30' :
                type === 'error' ? 'bg-rose-950/95 text-rose-400 border-rose-500/30' :
                type === 'warning' ? 'bg-amber-950/95 text-amber-400 border-amber-500/30' :
                'bg-slate-900/95 text-slate-300 border-slate-800'
            }`;

            let icon = 'info';
            if (type === 'success') icon = 'check-circle';
            if (type === 'error') icon = 'alert-triangle';
            if (type === 'warning') icon = 'alert-circle';

            toast.innerHTML = `
                <i data-lucide="${icon}" class="w-5 h-5 flex-shrink-0"></i>
                <div class="flex-1 font-medium">${message}</div>
                <button onclick="removeToast('${id}')" class="text-slate-500 hover:text-white transition"><i data-lucide="x" class="w-4 h-4"></i></button>
            `;

            dom.toastContainer.appendChild(toast);
            lucide.createIcons();

            // Animação de Entrada
            setTimeout(() => {
                toast.classList.remove('translate-y-2', 'opacity-0');
            }, 10);

            // Auto descarte após 4 segundos
            setTimeout(() => {
                removeToast(id);
            }, 4000);
        }

        function removeToast(id) {
            const toast = document.getElementById(id);
            if (toast) {
                toast.classList.add('translate-y-2', 'opacity-0');
                setTimeout(() => {
                    toast.remove();
                }, 300);
            }
        }
    </script>
</body>
</html>

A dimly lit workspace featuring a desktop monitor displaying a website development page and a laptop showing a digital growth insights page. The setup includes a keyboard, mouse, two cups, a pen holder, and a clock displaying '02 36'. The atmosphere suggests a cozy, focused work environment.