import React from 'react'; import StockHeatmap from '@rongmz/react-stock-heatmap'; import '@rongmz/react-stock-heatmap/example/src/index.css'; function formatTimestamp(timestamp) { // 创建一个新的 Date 对象 const date = new Date(timestamp); // 获取小时、分钟和秒 const hours = date.getHours(); const minutes = date.getMinutes(); const seconds = date.getSeconds(); // 获取毫秒 const milliseconds = date.getMilliseconds(); // 将小时、分钟、秒、毫秒格式化为两位数字(除了毫秒可能是三位) const formattedHours = hours.toString().padStart(2, '0'); const formattedMinutes = minutes.toString().padStart(2, '0'); const formattedSeconds = seconds.toString().padStart(2, '0'); const formattedMilliseconds = milliseconds.toString().padStart(3, '0'); // 返回格式化的时间字符串 return `${formattedHours}:${formattedMinutes}:${formattedSeconds}.${formattedMilliseconds}`; } function parseStockData(data) { // Extracting values from the input data const { asks, bids, last_price, last_qty, total_qty, time, side } = data; // Convert asks and bids to the required format const processOrders = (orders) => orders.map(([rate, qty]) => ({ rate: rate, orders: 1, // Assuming each price level has one order qty })); // Calculate additional values const high = Math.max(...asks.map(a => a[0]), last_price); const low = Math.min(...bids.map(b => b[0]), last_price); const open = bids[0][0]; // Assuming the first bid rate as open const close = last_price; const volume = total_qty; // Total traded volume // Calculate average price (simplified as an average of high and low) const avgPrice = (high + low) / 2; // Construct the final object return { marketDepth: { lastBuyPrice: side === 'buy' ? last_price : 0, lastBuyQty: side === 'buy' ? last_qty : 0, lastSellPrice: side === 'sell' ? last_price : 0, lastSellQty: side === 'sell' ? last_qty : 0, priceChangeAmt: last_price - open, // Simplified price change amount priceChangePct: ((last_price - open) / open * 100).toFixed(2), lastTradedTS: Date.now(), open, high, low, close, volume, avgPrice, buyOrderVolume: bids.reduce((sum, [, qty]) => sum + qty, 0), buys: processOrders(bids), sellOrderVolume: asks.reduce((sum, [, qty]) => sum + qty, 0), sells: processOrders(asks), side: side }, ts: formatTimestamp(time), time: time, tradingsymbol: "XYZ123", pendingOrders: [] }; } export default () => { const [isActivation, setIsActivation] = React.useState(false); const [activationCode, setActivationCode] = React.useState(); const [loading, setLoading] = React.useState(true); const progressRef = React.useRef(null); /** @type {React.MutableRefObject} */ const heatmapRef = React.useRef(null); const [windowDim, setWindowDim] = React.useState([0, 0]); const [autoScroll, setAutoScroll] = React.useState(true); const toggleAutoScroll = (value) => { setAutoScroll(value); }; // ------------ Load data ------------- React.useEffect(() => { const ws = new WebSocket('ws://localhost:6789'); let ref = heatmapRef.current console.log('ws创建完成') ws.onmessage = function(event) { const message = JSON.parse(event.data); let stock = parseStockData(message) ref.addData(stock) if (progressRef.current !== null) { progressRef.current.innerHTML = ` 等待数据推送 ${(100 * ref.data.length / ref.windowLength + 1).toFixed(0)}% ...` if (ref.data.length >= ref.windowLength) { setLoading(false) } } }; ws.onerror = function(event) { console.error("WebSocket error observed:", event); }; }, []); // ------------ Load data ------------- const handleActivation = ()=>{ console.log(activationCode) setIsActivation(true) } // ---------- window update ------------ React.useEffect(() => { const updateFn = () => { setWindowDim([ window.innerWidth, window.innerHeight ]); } updateFn(); window.addEventListener('resize', updateFn); return () => window.removeEventListener('resize', updateFn); }, []); // ---------- window update ------------ return (
{loading &&
等待数据推送...
等待数据推送 0%
}
{!autoScroll &&
{ setAutoScroll(true) }}> 继续
} {/* */}
{!isActivation &&
软件激活
{ setActivationCode(e.target.value) }} />
激 活
}
) }