let chart, series; export function initChart() { const chartDiv = document.getElementById('chart-container'); chart = LightweightCharts.createChart(chartDiv, { layout: { background: { color: '#ffffff' }, textColor: '#000', fontFamily: 'Space Mono' }, grid: { vertLines: { visible: false }, horzLines: { color: '#f0f0f0', style: 2 } }, crosshair: { mode: 1, vertLine: { labelBackgroundColor: '#000' }, horzLine: { labelBackgroundColor: '#000' } }, timeScale: { borderColor: '#000', timeVisible: true }, rightPriceScale: { borderColor: '#000' }, }); series = chart.addCandlestickSeries({ upColor: '#bef264', downColor: '#fb7185', borderUpColor: '#000', borderDownColor: '#000', wickUpColor: '#000', wickDownColor: '#000', }); new ResizeObserver(e => { const r = e[0].contentRect; chart.applyOptions({ width: r.width, height: r.height }); }).observe(chartDiv); return { chart, series }; } export function getSeries() { return series; } // --- NEW FEATURE: WHALE BUBBLES ON CANDLES --- export function generateSmartMarkers(candles) { // 1. Calculate Volatility (High - Low) to determine what a "Large" order looks like // In a real app, we would use Volume, but Range is a good visual proxy for Price Action const ranges = candles.map(c => c.high - c.low); const avgRange = ranges.reduce((a, b) => a + b, 0) / ranges.length; const threshold = avgRange * 1.5; // Show bubble if candle is 1.5x larger than average const markers = []; candles.forEach(c => { const range = c.high - c.low; const isBigMove = range > threshold; // LOGIC: // If Candle is RED (Close < Open) and Big -> Sell Whale (Red Bubble Above) // If Candle is GREEN (Close > Open) and Big -> Buy Whale (Green Bubble Below) if (isBigMove) { const isBearish = c.close < c.open; markers.push({ time: c.time, position: isBearish ? 'aboveBar' : 'belowBar', color: isBearish ? '#dc2626' : '#16a34a', // Deep Red or Deep Green shape: 'circle', text: isBearish ? 'Whale Sell' : 'Whale Buy', // The text inside/near bubble size: 2, // Making them noticeable }); } }); series.setMarkers(markers); }