您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
显示实时价格,支持左右选择币种,折线图展示,收起展开,全局控制,缓存50点数据。
// ==UserScript== // @name BTC\ETH等币种实时价格 + 折线图 (支持选择币种) // @namespace http://tampermonkey.net/ // @version 0.7 // @description 显示实时价格,支持左右选择币种,折线图展示,收起展开,全局控制,缓存50点数据。 // @author Tom-dog // @match *://*/* // @grant none // @license MIT // ==/UserScript== (function () { "use strict"; // 动态加载 Chart.js function loadChartJs(callback) { const script = document.createElement("script"); script.src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"; script.onload = callback; document.head.appendChild(script); } loadChartJs(() => { initUI(); setInterval(updatePrices, 5000); }); // ✅ 从 OKX 获取 USDT 交易对,然后写死在这里 // 示例:你可以先请求一次 https://www.okx.com/api/v5/market/tickers?instType=SPOT // 筛选 instId 里包含 "-USDT" 的,把前半部分存进 coinList const coinList = [ "BTC", "ETH", "OKB", "SOL", "XRP", "DOGE", "ADA", "TRX", "DOT", "MATIC", "LTC", "LINK", "FIL", "ATOM", "AVAX", "PEPE", "SHIB", "MEME" ]; // 当前选择 let selectedCoins = { left: "ETH", right: "BTC" }; const charts = {}; const priceSpans = { left: null, right: null }; function initUI() { const wrapper = document.createElement("div"); wrapper.style.position = "fixed"; wrapper.style.top = "0"; wrapper.style.left = "50%"; wrapper.style.transform = "translateX(-50%)"; wrapper.style.backgroundColor = "#fff"; wrapper.style.color = "#000"; wrapper.style.zIndex = "999999"; wrapper.style.width = "650px"; wrapper.style.padding = "5px"; wrapper.style.fontSize = "14px"; wrapper.style.border = "1px solid #ccc"; // 顶部控制栏 const controlBar = document.createElement("div"); controlBar.style.display = "flex"; controlBar.style.justifyContent = "space-between"; controlBar.style.alignItems = "center"; controlBar.style.marginBottom = "8px"; // 左选择框 const leftWrap = document.createElement("div"); const leftSelect = document.createElement("select"); coinList.forEach((c) => { const opt = document.createElement("option"); opt.value = c; opt.text = c; if (c === selectedCoins.left) opt.selected = true; leftSelect.appendChild(opt); }); leftSelect.onchange = () => { selectedCoins.left = leftSelect.value; resetChart("left", selectedCoins.left); }; const leftPrice = document.createElement("span"); leftPrice.style.marginLeft = "6px"; leftPrice.innerText = "--"; priceSpans.left = leftPrice; leftWrap.appendChild(leftSelect); leftWrap.appendChild(leftPrice); // 右选择框 const rightWrap = document.createElement("div"); const rightSelect = document.createElement("select"); coinList.forEach((c) => { const opt = document.createElement("option"); opt.value = c; opt.text = c; if (c === selectedCoins.right) opt.selected = true; rightSelect.appendChild(opt); }); rightSelect.onchange = () => { selectedCoins.right = rightSelect.value; resetChart("right", selectedCoins.right); }; const rightPrice = document.createElement("span"); rightPrice.style.marginLeft = "6px"; rightPrice.innerText = "--"; priceSpans.right = rightPrice; rightWrap.appendChild(rightSelect); rightWrap.appendChild(rightPrice); // 收起展开按钮 const toggleAllBtn = document.createElement("button"); toggleAllBtn.innerText = "收起"; toggleAllBtn.onclick = () => { const boxes = wrapper.querySelectorAll(".chart-box"); const isHidden = Array.from(boxes).every((b) => b.style.display === "none"); boxes.forEach((box) => (box.style.display = isHidden ? "block" : "none")); toggleAllBtn.innerText = isHidden ? "收起" : "展开"; }; controlBar.appendChild(leftWrap); controlBar.appendChild(rightWrap); controlBar.appendChild(toggleAllBtn); wrapper.appendChild(controlBar); // 图表容器 const chartsContainer = document.createElement("div"); chartsContainer.style.display = "flex"; chartsContainer.style.gap = "8px"; ["left", "right"].forEach((pos) => { const section = document.createElement("div"); section.style.flex = "1"; // 折线图容器 const chartBox = document.createElement("div"); chartBox.className = "chart-box"; chartBox.style.height = "150px"; const canvas = document.createElement("canvas"); canvas.id = `chart-${pos}`; chartBox.appendChild(canvas); section.appendChild(chartBox); chartsContainer.appendChild(section); // 初始化图表 charts[pos] = initChart(canvas, selectedCoins[pos]); }); wrapper.appendChild(chartsContainer); document.body.appendChild(wrapper); } // 初始化 Chart function initChart(canvas, coin) { return new Chart(canvas, { type: "line", data: { labels: [], datasets: [ { label: `${coin} Price`, data: [], borderColor: "blue", fill: false, tension: 0.1, }, ], }, options: { responsive: true, animation: false, plugins: { legend: { display: false }, // ✅ 不显示图例 }, scales: { x: { display: false }, y: { beginAtZero: false }, }, }, }); } // 重置图表 function resetChart(pos, coin) { const chart = charts[pos]; // 清空旧数据 chart.data.labels = []; chart.data.datasets[0].data = []; chart.data.datasets[0].label = `${coin} Price`; chart.update(); // 价格置为 -- priceSpans[pos].innerText = "--"; } // 获取并更新价格 async function updatePrices() { const time = new Date().getTime(); for (const pos of ["left", "right"]) { const coin = selectedCoins[pos]; try { const res = await fetch( `https://www.okx.com/api/v5/market/ticker?instId=${coin}-USDT&_=${time}` ).then((r) => r.json()); const price = parseFloat(res.data[0].last); updateChart(pos, coin, price); } catch (e) { console.error(`获取 ${coin} 价格失败:`, e); } } } // 更新图表 function updateChart(pos, coin, price) { const chart = charts[pos]; const label = new Date().toLocaleTimeString(); const dataset = chart.data.datasets[0]; dataset.label = `${coin} Price`; dataset.data.push(price); chart.data.labels.push(label); // 限制最大 50 点 if (dataset.data.length > 50) { dataset.data.shift(); chart.data.labels.shift(); } // ✅ 更新选择框后面的价格 priceSpans[pos].innerText = `$${price}`; chart.update(); } })();