您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
根据设定的价格条件自动买入、卖出、借入和归还股票,并在页面上显示日志面板
// ==UserScript== // @name AGSV股票自动挂单买卖(带日志面板) // @namespace http://tampermonkey.net/ // @version 2.0 // @description 根据设定的价格条件自动买入、卖出、借入和归还股票,并在页面上显示日志面板 // @author AGSV骄阳 // @match https://stock.agsvpt.cn/* // @grant GM_xmlhttpRequest // @icon https://stock.agsvpt.cn/plugins/stock/favicon.svg // ==/UserScript== (async function () { 'use strict'; /*** 日志面板模块 ***/ (function createLogPanel() { const logPanel = document.createElement("div"); logPanel.id = "logPanel"; logPanel.style.cssText = ` position: fixed; bottom: 0; left: 0; width: 100%; max-height: 200px; overflow-y: auto; background: rgba(0,0,0,0.85); color: #0f0; font-size: 12px; font-family: monospace; padding: 4px; z-index: 99999; `; document.body.appendChild(logPanel); function writeLog(type, args) { const msg = Array.from(args).map(a => (typeof a === "object" ? JSON.stringify(a) : a)).join(" "); const line = document.createElement("div"); line.style.whiteSpace = "pre-wrap"; if (type === "warn") line.style.color = "yellow"; if (type === "error") line.style.color = "red"; if (type === "log") line.style.color = "#0f0"; line.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`; logPanel.appendChild(line); logPanel.scrollTop = logPanel.scrollHeight; // 自动滚动到底部 } // 代理 console 输出 const rawLog = console.log; const rawWarn = console.warn; const rawError = console.error; console.log = function () { writeLog("log", arguments); rawLog.apply(console, arguments); }; console.warn = function () { writeLog("warn", arguments); rawWarn.apply(console, arguments); }; console.error = function () { writeLog("error", arguments); rawError.apply(console, arguments); }; })(); // ======================== 以下是你的原始脚本逻辑 ======================== // API基础URL const API_BASE_URL = 'https://stock.agsvpt.cn/api'; const CONFIG = { STOCK_INFO_URL: `${API_BASE_URL}/stocks/info`, // 股票信息请求的URL TOKEN_KEY: 'auth_token', // 存储token的键名 }; // 获取当前时间的字符串(上海时区) function getCurrentTime() { const now = new Date(); const offset = 8; // 上海时区偏移量(UTC+8) const localTime = new Date(now.getTime() + offset * 60 * 60 * 1000); // 调整为上海时间 return localTime.toISOString().replace('T', ' ').substring(0, 19); // 格式化为 'YYYY-MM-DD HH:MM:SS' } // 自动弹出设置框,获取用户输入的交易参数 const userInput = await createInputDialog(); if (!userInput) return; // 如果用户取消,则退出 main(userInput); // 进入主逻辑 // 创建输入对话框以获取用户的交易设置 function createInputDialog() { return new Promise((resolve) => { const dialogHtml = ` <div id="inputDialog" style="position:fixed; top:50%; left:50%; transform:translate(-50%, -50%); background:white; padding:20px; border:1px solid #ccc; z-index:1000;"> <h2>设置股票交易参数</h2> <label for="operationMode">选择交易模式:</label> <select id="operationMode"> <option value="trade">本金模式</option> <option value="borrow">借入模式</option> </select><br><br> <label for="stockCode">股票代码:</label> <select id="stockCode"> <option value="TSLA">TSLA</option> <option value="AAPL">AAPL</option> <option value="GOOGL">GOOGL</option> </select><br><br> <div id="tradeSettings"> <label for="buyPrice">买入价格:</label> <input type="number" id="buyPrice" value="1500" step="0.01"><br><br> <label for="sellPrice">卖出价格:</label> <input type="number" id="sellPrice" value="1800" step="0.01"><br><br> <label for="buyQuantity">买入数量:</label> <input type="number" id="buyQuantity" value="10000" min="1"><br><br> <label for="sellQuantity">卖出数量:</label> <input type="number" id="sellQuantity" value="10000" min="1"><br><br> </div> <div id="borrowSettings" style="display:none;"> <label for="borrowPrice">借入价格:</label> <input type="number" id="borrowPrice" value="1800" step="0.01"><br><br> <label for="returnPrice">归还价格:</label> <input type="number" id="returnPrice" value="1600" step="0.01"><br><br> <label for="borrowQuantity">借入数量:</label> <input type="number" id="borrowQuantity" value="10000" min="1"><br><br> </div> <label for="checkInterval">检查间隔 (秒):</label> <input type="number" id="checkInterval" value="30" min="1"><br><br> <button id="submitBtn">确认</button> <button id="cancelBtn">取消</button> </div> <div id="overlay" style="position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:999;"></div> `; // 将对话框HTML插入到页面中 document.body.insertAdjacentHTML('beforeend', dialogHtml); // 根据操作模式显示相应的设置 const operationModeSelect = document.getElementById('operationMode'); operationModeSelect.onchange = function () { const tradeSettings = document.getElementById('tradeSettings'); const borrowSettings = document.getElementById('borrowSettings'); if (operationModeSelect.value === 'trade') { tradeSettings.style.display = 'block'; // 显示本金模式设置 borrowSettings.style.display = 'none'; // 隐藏借入模式设置 } else { tradeSettings.style.display = 'none'; // 隐藏本金模式设置 borrowSettings.style.display = 'block'; // 显示借入模式设置 } }; // 确认按钮事件 document.getElementById('submitBtn').onclick = function () { const operationMode = document.getElementById('operationMode').value; // 获取操作模式 const stockCode = document.getElementById('stockCode').value; // 获取股票代码 const buyPrice = parseFloat(document.getElementById('buyPrice').value); // 获取买入价格 const sellPrice = parseFloat(document.getElementById('sellPrice').value); // 获取卖出价格 const borrowPrice = parseFloat(document.getElementById('borrowPrice').value); // 获取借入价格 const returnPrice = parseFloat(document.getElementById('returnPrice').value); // 获取归还价格 const buyQuantity = parseInt(document.getElementById('buyQuantity').value, 10); // 获取买入数量 const sellQuantity = parseInt(document.getElementById('sellQuantity').value, 10); // 获取卖出数量 const borrowQuantity = parseInt(document.getElementById('borrowQuantity').value, 10); // 获取借入数量 const checkInterval = parseInt(document.getElementById('checkInterval').value, 10) * 1000; // 转换为毫秒 // 输入验证 if (operationMode === 'trade' && (isNaN(buyPrice) || isNaN(sellPrice) || isNaN(buyQuantity) || isNaN(sellQuantity) || buyQuantity <= 0 || sellQuantity <= 0)) { alert('请输入有效的买入和卖出价格及数量'); return; } if (operationMode === 'borrow' && (isNaN(borrowPrice) || isNaN(returnPrice) || isNaN(borrowQuantity) || borrowQuantity <= 0)) { alert('请输入有效的借入和归还价格及数量'); return; } // 关闭对话框并返回用户输入 document.getElementById('inputDialog').remove(); document.getElementById('overlay').remove(); resolve({ operationMode, stockCode, buyPrice, sellPrice, borrowPrice, returnPrice, buyQuantity, sellQuantity, borrowQuantity, checkInterval }); }; // 取消按钮事件 document.getElementById('cancelBtn').onclick = function () { document.getElementById('inputDialog').remove(); document.getElementById('overlay').remove(); resolve(null); }; }); } // 获取当前股票价格 async function getCurrentPrice(stockCode) { const url = `${CONFIG.STOCK_INFO_URL}?code=${stockCode}`; // 股票信息请求 try { const response = await fetch(url, { method: 'GET', headers: { 'Authorization': 'Bearer ' + localStorage.getItem(CONFIG.TOKEN_KEY) // 使用本地存储中的token } }); if (!response.ok) { throw new Error('网络响应不正常'); } // 解析响应数据 const data = await response.json(); const stockInfo = data.find(stock => stock.code === stockCode); // 查找对应的股票信息 return stockInfo ? stockInfo.price : undefined; // 返回价格 } catch (error) { console.error(`[${getCurrentTime()}] 获取当前价格时发生错误:`, error); // 打印错误信息时附加时间 return undefined; // 发生错误返回undefined } } // 获取当前可借入的订单信息 async function getBorrowOrders(stockCode) { const url = `${API_BASE_URL}/user/leveraged`; // 获取借入订单的API URL try { const response = await fetch(url, { method: 'GET', headers: { 'Authorization': 'Bearer ' + localStorage.getItem(CONFIG.TOKEN_KEY) // 使用本地存储中的token } }); if (!response.ok) { throw new Error('获取借入订单失败'); } // 解析响应数据 const data = await response.json(); return data; // 返回借入订单信息 } catch (error) { console.error(`[${getCurrentTime()}] 获取借入订单时发生错误:`, error); // 打印错误信息时附加时间 return []; } } // 借入股票的函数 async function borrowStock(stockCode, quantity) { const url = `${API_BASE_URL}/stocks/${stockCode}/borrow`; // 借入股票的API URL try { const response = await fetch(url, { method: 'POST', // 使用POST方法 headers: { 'Authorization': 'Bearer ' + localStorage.getItem(CONFIG.TOKEN_KEY), // 认证token 'Content-Type': 'application/json' // 请求体格式为JSON }, body: JSON.stringify({ quantity }) // 请求体内容 }); if (!response.ok) { throw new Error('借入请求失败'); } console.log(`[${getCurrentTime()}] 成功借入 ${quantity} 股 ${stockCode}`); // 打印成功信息时附加时间 } catch (error) { console.error(`[${getCurrentTime()}] 借入股票时发生错误:`, error); // 打印错误信息时附加时间 } } // 归还股票的函数 async function returnStock(stockCode, quantity, orderId) { const url = `${API_BASE_URL}/stocks/${stockCode}/repay`; // 归还股票的API URL try { const response = await fetch(url, { method: 'POST', // 使用POST方法 headers: { 'Authorization': 'Bearer ' + localStorage.getItem(CONFIG.TOKEN_KEY), // 认证token 'Content-Type': 'application/json' // 请求体格式为JSON }, body: JSON.stringify({ order_id: orderId, quantity }) // 请求体内容 }); if (!response.ok) { throw new Error('归还请求失败'); } console.log(`[${getCurrentTime()}] 成功归还 ${quantity} 股 ${stockCode}`); // 打印成功信息时附加时间 } catch (error) { console.error(`[${getCurrentTime()}] 归还股票时发生错误:`, error); // 打印错误信息时附加时间 } } // 买入股票的函数 async function buyStock(stockCode, quantity) { const url = `${API_BASE_URL}/stocks/${stockCode}/buy`; // 买入股票的API URL try { const response = await fetch(url, { method: 'POST', // 使用POST方法 headers: { 'Authorization': 'Bearer ' + localStorage.getItem(CONFIG.TOKEN_KEY), // 认证token 'Content-Type': 'application/json' // 请求体格式为JSON }, body: JSON.stringify({ quantity }) // 请求体内容 }); if (!response.ok) { throw new Error('买入请求失败'); } console.log(`[${getCurrentTime()}] 成功买入 ${quantity} 股 ${stockCode}`); // 打印成功信息时附加时间 } catch (error) { console.error(`[${getCurrentTime()}] 买入股票时发生错误:`, error); // 打印错误信息时附加时间 } } // 卖出股票的函数 async function sellStock(stockCode, quantity) { const url = `${API_BASE_URL}/stocks/${stockCode}/sell`; // 卖出股票的API URL try { const response = await fetch(url, { method: 'POST', // 使用POST方法 headers: { 'Authorization': 'Bearer ' + localStorage.getItem(CONFIG.TOKEN_KEY), // 认证token 'Content-Type': 'application/json' // 请求体格式为JSON }, body: JSON.stringify({ quantity }) // 请求体内容 }); if (!response.ok) { throw new Error('卖出请求失败'); } console.log(`[${getCurrentTime()}] 成功卖出 ${quantity} 股 ${stockCode}`); // 打印成功信息时附加时间 } catch (error) { console.error(`[${getCurrentTime()}] 卖出股票时发生错误:`, error); // 打印错误信息时附加时间 } } // 主逻辑函数,根据用户输入进行操作 async function main(userInput) { const { operationMode, stockCode, buyPrice, sellPrice, borrowPrice, returnPrice, buyQuantity, sellQuantity, borrowQuantity, checkInterval } = userInput; let lastActionTime = 0; // 用于限制操作频率 const actionCooldown = 60000; // 操作间隔时间 (60秒) while (true) { try { const currentPrice = await getCurrentPrice(stockCode); // 获取当前价格 // 在获取当前价格时输出当前设定的模式、价格和数量 if (currentPrice !== undefined) { console.log(`[${getCurrentTime()}] 当前价格: ${currentPrice}`); console.log(`[${getCurrentTime()}] 当前设定: 交易模式: ${operationMode}, ` + (operationMode === 'trade' ? `买入价格: ${buyPrice}, 卖出价格: ${sellPrice}, 买入数量: ${buyQuantity}, 卖出数量: ${sellQuantity}` : `借入价格: ${borrowPrice}, 归还价格: ${returnPrice}, 借入数量: ${borrowQuantity}`)); } else { console.warn(`[${getCurrentTime()}] 无法获取 ${stockCode} 的当前价格`); // 如果当前价格获取失败,打印警告信息 } if (currentPrice !== undefined) { const currentTime = Date.now(); if (currentTime - lastActionTime < actionCooldown) { console.warn(`[${getCurrentTime()}] 系统限制1分钟交易一次,请稍后再试`); // 提示用户 } else { if (operationMode === 'trade') { // 本金模式 if (currentPrice <= buyPrice) { await buyStock(stockCode, buyQuantity); // 触发买入操作 lastActionTime = currentTime; // 更新操作时间 } else if (currentPrice >= sellPrice) { await sellStock(stockCode, sellQuantity); // 触发卖出操作 lastActionTime = currentTime; // 更新操作时间 } } else if (operationMode === 'borrow') { // 借入模式 if (currentPrice >= borrowPrice) { await borrowStock(stockCode, borrowQuantity); // 触发借入操作 lastActionTime = currentTime; // 更新操作时间 } else if (currentPrice <= returnPrice) { let borrowOrders = await getBorrowOrders(stockCode); // 获取当前借入订单 borrowOrders = borrowOrders.data; const todayDateStr = new Date(Date.now()).toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' }); if (borrowOrders.length > 0) { for (const order of borrowOrders) { if (order.code != stockCode) { continue; } const orderId = order.id; // 获取每一个借入订单ID const num = order.shares; const orderDateStr = new Date(order.time).toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' }); if (orderDateStr == todayDateStr) { console.log(`[${getCurrentTime()}] 订单ID ${orderId} 的 ${num} 股 ${stockCode} 尚未到可归还时间`); continue; } await returnStock(stockCode, num, orderId); // 触发归还操作 console.log(`[${getCurrentTime()}] 归还订单ID ${orderId} 的 ${num} 股 ${stockCode}`); // 打印归还成功信息 console.log("单次逻辑仅归还一条订单, 等待下个循环"); break; } lastActionTime = currentTime; // 更新操作时间 } else { console.warn(`[${getCurrentTime()}] 没有可归还的借入订单`); // 如果没有可归还的订单,打印警告信息 } } } } } await new Promise(resolve => setTimeout(resolve, checkInterval)); // 根据设定的间隔检查价格 } catch (error) { console.error(`[${getCurrentTime()}] 发生错误:`, error); // 发生错误时打印错误信息 await new Promise(resolve => setTimeout(resolve, checkInterval)); // 遇到错误时也延迟检查 } } } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址