您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
backpack 刷成交量脚本,支持手动开启关闭,设置买入卖出点
当前为
// ==UserScript== // @name backpack // @namespace http://tampermonkey.net/ // @version v0.0.6 // @description backpack 刷成交量脚本,支持手动开启关闭,设置买入卖出点 // @author zhowiny // @match https://backpack.exchange/trade/* // @icon https://backpack.exchange/favicon-32x32.png // @grant none // @license MIT // @require https://update.gf.qytechs.cn/scripts/491401/1352455/vue.js // @require https://update.gf.qytechs.cn/scripts/491414/1352613/template_vue.js // ==/UserScript== // 请使用在浏览器控制台里 const LANG_MAP = { Limit: '限制', Market:'市场', Max: '最大', Buy: '购买', Sell: '出售', Cancel: '取消', } const MIN_WAIT_MS = 300; const MAX_WAIT_MS = 1000; const MIN_SWITCH_MS = 500; const MAX_SWITCH_MS = 2000; let tradeCount = 0; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const findElementsByText = (text, tag, parent = document) => { const elements = parent.querySelectorAll(`${tag}:not(:empty):not(:has(*))`); return Array.from(elements).filter((ele) => ele.textContent === text || ele.textContent === LANG_MAP[text]); }; const getElement = (text, tag) => { let element = findElementsByText(text, tag)[0]; if (!element) { element = findElementsByText(LANG_MAP[text] || text, tag)[0]; if (!element) return } return element; } const clickElementByText = async (text, tag) => { const element = getElement(text, tag); if (!element) return; element.click(); await sleep(getRandomWait(MIN_WAIT_MS, MAX_WAIT_MS)); }; const getPriceCnt = () => { return document.querySelector('.flex.flex-col.no-scrollbar.h-full.flex-1.snap-mandatory.overflow-y-auto.font-sans'); } const getPriceElement = (type, num) => { const isBuy = type === 'Buy'; const priceCnt = getPriceCnt(); const priceElement = priceCnt.querySelector(`& > div:${isBuy ? 'last' : 'first'}-child > div > div:nth-child(${num}) button div`); return priceElement; } const setPrice = async (type, num) => { const price = getPriceElement(type, num); price.classList.add('border'); price.click(); await sleep(300); } let buyCount = 0; let sellCount = 0; let cancelCount = 0; const clickTradeButton = async (type) => { const element = getElement(type, 'button'); if (!element) return; element.addEventListener('click', () => { if (type === 'Buy') { buyCount++; console.log(`%c第${buyCount}次买入`, 'color: #afa;'); } else { sellCount++; console.log(`%c第${sellCount}次卖出`, 'color: #faf;'); } }, {once: true}); element.click(); await sleep(getRandomWait(MIN_WAIT_MS, MAX_WAIT_MS)); } const executeTrade = async (type, params) => { if (!window.running) return console.log('已暂停'); await clickElementByText(type, "p"); await clickElementByText(params.mode || 'Limit', "div"); await setPrice(type, params[type]); await clickElementByText("Max", "div"); //await clickElementByText(type, "button"); await clickTradeButton(type); }; const getRandomWait = (min, max) => Math.floor(Math.random() * max + min); const performTradeCycle = async (params) => { try { tradeCount++; await executeTrade("Buy", params); await sleep(getRandomWait(MIN_SWITCH_MS, MAX_SWITCH_MS)); await executeTrade("Sell", params); await sleep(getRandomWait(MIN_SWITCH_MS, MAX_SWITCH_MS)); } catch (error) { console.error("发生错误:", error); } }; const orderTimeoutMap = new Map(); const checkOrderTimeout = (orderList) => { orderList.forEach(order => { const timeoutTime = orderTimeoutMap.get(order.orderText); if (!timeoutTime) return; if (Date.now() > timeoutTime) { order.cancel(); cancelCount++; console.log(`%c订单【${order.orderText}】超时未成交,已取消!订单取消次数:${cancelCount}`, 'color: #ffa;') } }) } const getTabs = () => { const anchorElement = findElementsByText('My Assets', 'div')[0]; const tabsElement = anchorElement.parentElement.parentElement; const openOrderTab = tabsElement.children[0]; return { openOrderTab, tabsElement, }; } const getOrderListElement = (tabsElement) => tabsElement.parentElement.nextElementSibling.children[0].children[1]; const getOrderList = (tradingParams) => { const element = getOrderListElement(getTabs().tabsElement); const {timeout = 0} = tradingParams; const orderList = [...(element?.children ?? [])].reduce((res, ele, i) => { const orderText = ele.textContent; if (orderText.includes('No open Orders')) return []; const order = { orderText, ele, cancel: () => findElementsByText('Cancel', 'p', ele)[0].click(), data: ele.innerText.split('\n').filter(i => i), } res.push(order) const timeoutTime = timeout ? orderTimeoutMap.get(orderText) || (Date.now() + timeout * 1000) : 0; orderTimeoutMap.set(orderText, timeoutTime); return res }, []) return orderList; } const main = () => { const {ref, nextTick} = window.Vue; window.TAMPERMONKEY_VUE_APP.template = ` <div class='backpack-tool grid gap-2 text-sm text-white bg-base-700 p-2 rounded' style='grid-template-areas: "a a . ." "a a . ." "a a . ." "a a . ." "b b b b" ". . . .";' > <button class='bg-greenText rounded p-2 h-12 self-center' style='grid-area: a;' :class='{"bg-redText": running}' @click='handleStart' > {{running ? '脚本运行中,点击关闭交易' : '启动脚本,点击开始交易'}} </button> <label> <span>限价:</span> <input type="radio" value="Limit" :disabled='running' v-model="tradingParams.mode" /> </label> <label> <span>市场:</span> <input type="radio" value="Market" :disabled='running' v-model="tradingParams.mode" /> </label> <span :class='{"opacity-10": tradingParams.mode === "Market"}'>第几个买入:</span> <input class='w-12 h-2 py-2 text-center bg-black text-greenText' :class='{"bg-black/25": running, "opacity-10": tradingParams.mode === "Market"}' type='number' :min='1' :max='20' :step='1' :disabled='running || tradingParams.mode === "Market"' v-model.number='tradingParams.Buy' @input='e => handleNumberInput(e, "Buy")' /> <span :class='{"opacity-10": tradingParams.mode === "Market"}'>第几个卖出:</span> <input class='w-12 h-2 py-2 text-center bg-black text-redText' :class='{"bg-black/25": running, "opacity-10": tradingParams.mode === "Market"}' type='number' :min='1' :max='20' :step='1' :disabled='running || tradingParams.mode === "Market"' v-model.number='tradingParams.Sell' @input='e => handleNumberInput(e, "Sell")' /> <span>超时时间(秒):</span> <input class='w-12 h-2 py-2 text-center bg-black text-accentBlue' :class='{"bg-black/25": running}' type='number' :min='0' :max='600' :step='1' :disabled='running' v-model.number='tradingParams.timeout' @input='e => handleNumberInput(e, "timeout", {min: 0, max: 600})' /> <p class='mt-4 px-2 pt-2 border-t' style='grid-area: b;'>超时时间:超时自动取消订单,<code>0</code>为不取消!</p> <div>当前订单数:{{currentOrder.length}}</div> <div>买入次数:<span style='color: #afa;'>{{orderCount.buy}}</span></div> <div>卖出次数:<span style='color: #faf;'>{{orderCount.sell}}</span></div> <div>取消次数:<span style='color: #ffa;'>{{orderCount.cancel}}</span></div> </div> ` window.TAMPERMONKEY_VUE_APP.setup = () => { const running = ref(false); const tradingParams = ref({ Buy: 2, Sell: 2, timeout: 0, mode: 'Market', }); const orderCount = ref({ buy: 0, sell: 0, cancel: 0, }); const currentOrder = ref([]); const handleNumberInput = (e, type, options = {min: 1, max: 20}) => { const {min, max} = options let value = parseInt(e.target.value); if (value > max) value = max; if (value < min || isNaN(value)) value = min; tradingParams.value[type] = Math.max(min, Math.min(max, value)); } const startTrading = async () => { await performTradeCycle(tradingParams.value); orderCount.value.buy = buyCount; orderCount.value.sell = sellCount; await sleep(3000); if (running.value) { window.requestAnimationFrame(() => startTrading()); } }; const queryOrderListTask = async () => { const {openOrderTab, tabsElement} = getTabs(); openOrderTab.click(); await sleep(300); const orderList = getOrderList(tradingParams.value); currentOrder.value = orderList; checkOrderTimeout(orderList); orderCount.value.cancel = cancelCount; await sleep(2000); if (running.value) { window.requestAnimationFrame(() => queryOrderListTask()); } } const handleStart = async () => { window.running = running.value = !running.value; console.log(running.value ? 'start' : 'stop'); running.value && startTrading(); running.value && queryOrderListTask(); !running.value && getPriceElement('Buy', tradingParams.value.Buy).classList.remove('border'); !running.value && getPriceElement('Sell', tradingParams.value.Sell).classList.remove('border'); } return { running, currentOrder, orderCount, tradingParams, handleNumberInput, handleStart, } } } (function() { 'use strict'; main(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址