/** * 실시간 호가창 (OrderBook) 렌더러 * 0D: 주식호가잔량, 0w: 프로그램매매 */ // 호가창 초기화 function initOrderBook() { renderOrderBook(null); renderProgram(null); } // 호가창 렌더링 // asks[0] = 매도1호가(최우선, 가장 낮은 매도가), asks[9] = 매도10호가 // bids[0] = 매수1호가(최우선, 가장 높은 매수가), bids[9] = 매수10호가 function renderOrderBook(ob) { const tbody = document.getElementById('orderbookBody'); if (!tbody) return; if (!ob) { tbody.innerHTML = `호가 데이터 수신 대기 중...`; return; } // 최대 잔량 (진행바 비율 계산용) const maxVol = Math.max( ...ob.asks.map(a => a.volume), ...ob.bids.map(b => b.volume), 1 ); let html = ''; // 매도호가: 10호가부터 1호가 순으로 위에서 아래 (asks[9]→asks[0]) for (let i = 9; i >= 0; i--) { const ask = ob.asks[i] || { price: 0, volume: 0 }; const pct = Math.round((ask.volume / maxVol) * 100); html += `
${ask.volume > 0 ? ask.volume.toLocaleString('ko-KR') : ''}
${ask.price > 0 ? ask.price.toLocaleString('ko-KR') : '-'} `; } // 예상체결 행 (스프레드 사이) if (ob.expectedPrc > 0) { html += ` 예상 ${ob.expectedPrc.toLocaleString('ko-KR')} ${ob.expectedVol > 0 ? ob.expectedVol.toLocaleString('ko-KR') : ''} `; } // 매수호가: 1호가부터 10호가 순으로 위에서 아래 (bids[0]→bids[9]) for (let i = 0; i < ob.bids.length; i++) { const bid = ob.bids[i] || { price: 0, volume: 0 }; const pct = Math.round((bid.volume / maxVol) * 100); html += ` ${bid.price > 0 ? bid.price.toLocaleString('ko-KR') : '-'}
${bid.volume > 0 ? bid.volume.toLocaleString('ko-KR') : ''}
`; } tbody.innerHTML = html; // 호가행 클릭 → 주문창 단가 자동 입력 tbody.querySelectorAll('tr[data-price]').forEach(row => { row.addEventListener('click', () => { const price = parseInt(row.dataset.price, 10); if (price > 0 && window.setOrderPrice) window.setOrderPrice(price); }); }); // 총잔량 업데이트 const totalAsk = document.getElementById('totalAskVol'); const totalBid = document.getElementById('totalBidVol'); if (totalAsk) totalAsk.textContent = ob.totalAskVol.toLocaleString('ko-KR'); if (totalBid) totalBid.textContent = ob.totalBidVol.toLocaleString('ko-KR'); // 호가 시간 업데이트 const askTime = document.getElementById('askTime'); if (askTime && ob.askTime && ob.askTime.length >= 6) { const t = ob.askTime; askTime.textContent = `${t.slice(0,2)}:${t.slice(2,4)}:${t.slice(4,6)}`; } } // 프로그램 매매 렌더링 function renderProgram(pg) { const container = document.getElementById('programTrading'); if (!container) return; if (!pg) { container.innerHTML = `프로그램 매매 데이터 수신 대기 중...`; return; } const netClass = pg.netBuyVolume >= 0 ? 'text-red-500' : 'text-blue-500'; const netSign = pg.netBuyVolume >= 0 ? '+' : ''; container.innerHTML = `

매도

${(pg.sellVolume||0).toLocaleString('ko-KR')}

${formatMoney(pg.sellAmount)}원

순매수

${netSign}${(pg.netBuyVolume||0).toLocaleString('ko-KR')}

${netSign}${formatMoney(pg.netBuyAmount)}원

매수

${(pg.buyVolume||0).toLocaleString('ko-KR')}

${formatMoney(pg.buyAmount)}원

`; } // 금액을 억/만 단위로 포맷 function formatMoney(n) { if (!n) return '0'; const abs = Math.abs(n); if (abs >= 100000000) return (n / 100000000).toFixed(1) + '억'; if (abs >= 10000) return Math.round(n / 10000) + '만'; return n.toLocaleString('ko-KR'); }