likes
comments
collection
share

记录采用前端js技术刷空投脚本

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

代码分析

这段代码看起来是一个用于在网络平台上进行交易活动的JavaScript脚本。让我们逐步分析其功能:

  1. 翻译映射:代码中有一个名为 LANG_MAP 的对象,它将某些术语从一种语言映射到另一种语言。这可能有助于对交易界面进行语言本地化。

  2. 常量:脚本定义了各种常量,如 MIN_WAIT_MSMAX_WAIT_MSMIN_SWITCH_MSMAX_SWITCH_MS,用于设置时间间隔。

  3. 实用函数

    • sleep:该函数使用 setTimeout 创建执行延迟。
    • findElementsByText:该函数根据文本内容和指定的标签在文档中查找元素。它利用了之前定义的翻译映射。
    • getElement:该函数通过文本内容和标签检索特定元素。
    • clickElementByText:该函数在随机等待后点击由文本内容和标签标识的元素。
  4. 交易执行函数

    • getPriceCntgetPriceElement:这些函数根据类型(买入或卖出)和索引检索价格元素。
    • setPrice:该函数为交易设置价格。
    • clickTradeButton:该函数点击交易按钮,并记录已完成的交易次数。
  5. 交易执行executeTrade 函数通过点击基于提供的参数的各种元素来协调交易流程。

  6. 交易周期performTradeCycle 函数在循环中执行买入和卖出交易,并在两者之间随机等待。

  7. 订单超时处理:脚本通过检查订单下单后经过的时间来管理订单超时,并在超过指定超时持续时间时取消订单。

  8. Vue组件设置:脚本设置了一个Vue组件,具有模板标记和相关逻辑,用于管理交易参数、启动/停止交易流程和显示交易统计信息。

  9. 主函数main 函数初始化Vue组件,并将其与现有的JavaScript中的交易逻辑集成。

  10. 脚本初始化:脚本将其主要逻辑封装在立即调用的函数表达式(IIFE)中,以封装其作用域并防止变量污染。

总之,这段代码自动化了在网络平台上的交易过程,允许用户设置交易参数、启动交易会话和管理订单超时。它利用Vue.js来管理用户界面,并与纯JavaScript中实现的现有交易逻辑集成。

使用

记录采用前端js技术刷空投脚本

使用教程

greasyfork.org/en/scripts/…