您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
加強網格利潤顯功能
// ==UserScript== // @name Pionex 網格利潤顯示 // @namespace http://tampermonkey.net/ // @version 2024-12-14 // @description 加強網格利潤顯功能 // @author Rick // @match https://www.pionex.com/*/orders/bot/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; const profitItems = [ { label: '網格年化報酬率', className: 'annualized-profit' }, { label: '日均網格利潤 (USDT)', className: 'daily-profit' }, { label: '累計格利潤 (USDT)', className: 'total-profit' }, ]; function extractDateFromRuntime(runtimeText) { const dateMatch = runtimeText.match(/(\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2})/); if (dateMatch) { return new Date(dateMatch[1]); } return null; } function parseRuntimeToSeconds(runtimeText) { const durationMatch = runtimeText.match(/(?:(\d+)日 )?(?:(\d+)時 )?(?:(\d+)分 )?(?:(\d+)秒)/) || runtimeText.match(/Lasting (?:(\d+)d )?(?:(\d+)h )?(?:(\d+)m )?(?:(\d+)s)/); let totalSeconds = 0; if (durationMatch) { const days = parseInt(durationMatch[1] || 0, 10); const hours = parseInt(durationMatch[2] || 0, 10); const minutes = parseInt(durationMatch[3] || 0, 10); const seconds = parseInt(durationMatch[4] || 0, 10); totalSeconds += days * 86400; // 一天有 86400 秒 totalSeconds += hours * 3600; // 一小時有 3600 秒 totalSeconds += minutes * 60; // 一分鐘有 60 秒 totalSeconds += seconds; } return totalSeconds; } function appendGrid(item) { const profitTextElement = item.querySelector('span.mr-4px.text-increase') if (!profitTextElement) { return; } const grid = item.querySelector('div.grid'); if (!grid) { return; } profitItems.forEach(({ label, value, className }) => { let profitDiv = grid.querySelector(`.${className}`); if (!profitDiv) { const profitDiv = document.createElement('div'); profitDiv.className = `flex flex-col gap-2px text-increase ${className}`; profitDiv.innerHTML = ` <div class="text-secondary text-sm font-r">${label}</div> <div class="text-base font-b">--</div> `; grid.prepend(profitDiv); // 插入到最前面 } }); } function updateGrid(item, {investmentAmount, totalProfitAmount, runtimeInDays}) { const grid = item.querySelector('div.grid'); if (!grid || !investmentAmount || !runtimeInDays) { return; } const totalProfitRate = totalProfitAmount / investmentAmount; const dailyProfitAmount = totalProfitAmount / runtimeInDays; const dailyProfitRate = dailyProfitAmount / investmentAmount; const annualizedProfitAmount = dailyProfitAmount * 365; const annualizedProfitRate = dailyProfitRate * 365; const values = { 'annualized-profit': `${(100 * annualizedProfitRate).toFixed(2)}%`, 'daily-profit': `+${dailyProfitAmount.toFixed(4)} (${(100 * dailyProfitRate).toFixed(2)}%)`, 'total-profit': `+${totalProfitAmount.toFixed(4)} (${(100 * totalProfitRate).toFixed(2)}%)`, } profitItems.forEach(({ label, className }) => { const value = values[className] let profitDiv = grid.querySelector(`.${className}`); const valueDiv = profitDiv.querySelector('.text-base.font-b'); if (valueDiv) { valueDiv.innerText = value; } }); } function findTotalProfitElement (item) { const profitTextElement = item.querySelector('span.mr-4px.text-increase') if (!profitTextElement) { return; } const profitText = profitTextElement.textContent.trim().replace('+','') const tooltipElements = document.querySelectorAll('div.flex.justify-between.text-base.gap-12px>div.text-accent-sub') const currentProfitElementArray = Array.from(tooltipElements).filter(element => element.firstChild.textContent.trim() === '總網格利潤' || element.firstChild.textContent.trim() === '當前網格利潤').map(element => element.nextSibling); const currentProrfitElement = currentProfitElementArray.find(element => profitText.includes(element.textContent.trim().split(' ')[0])) if (!currentProrfitElement) return; return currentProrfitElement.parentElement.parentElement.lastChild.lastChild; } function updateItem(item) { const rect = item.getBoundingClientRect() if (rect.y > window.innerHeight || rect.y < 0) return; const investmentAmountElement = item.querySelector('div.rounded-6px.rounded-tr-none>div.text-lg.font-sb') if (!investmentAmountElement) return; const investmentAmount = Number(investmentAmountElement.textContent.trim()); const runtimeElement = item.querySelector( 'div.text-sm.text-secondary.font-r' ); const runtimeText = runtimeElement ? runtimeElement.textContent.trim() : null; if (!runtimeText) { return; } const runtime = parseRuntimeToSeconds(runtimeText); const runtimeInDays = runtime / (60 * 60 * 24); const totalProfitElement = findTotalProfitElement(item); if (totalProfitElement) { const totalProfitAmount = Number(totalProfitElement.textContent.split(' ')[0]); updateGrid(item, {investmentAmount, totalProfitAmount, runtimeInDays}) return } const hoverSvg = item.querySelector('svg > path[fill="#E1E2E5"], svg > path[fill="#27282A"]'); if (hoverSvg) { hoverSvg.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, cancelable: true, })); // 等待 tooltip 顯示後,再抓取利潤數據 setTimeout(() => { const totalProfitElement = findTotalProfitElement(item); hoverSvg.dispatchEvent(new MouseEvent('mouseout', { bubbles: true, cancelable: true, })); if (!totalProfitElement) { return; } const totalProfitAmount = Number(totalProfitElement.textContent.split(' ')[0]) updateGrid(item, {investmentAmount, totalProfitAmount, runtimeInDays}) }, 100); } } const observedElements = new Set(); const intersectingElements = new Set(); const intersectionObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { intersectingElements.add(entry.target) } else { intersectingElements.delete(entry.target) } }); }, { root: null, threshold: 0 }); function updateIntersectionObserverItems() { const elements = document.querySelectorAll('div[data-index]'); elements.forEach(element => { if (!observedElements.has(element)) { intersectionObserver.observe(element); observedElements.add(element); } }); } function update() { updateIntersectionObserverItems(); intersectingElements.forEach(element => { appendGrid(element); updateItem(element); }) } update(); setInterval(update, 500); })();