├── .gitattributes ├── README.md └── alpha_tool.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Binance Alpha Tool 2 | 3 | 这是一个用于自动化币安(Binance)交易的浏览器脚本工具。该工具可以自动执行买入和卖出操作,适用于需要aplha刷分。 4 | 5 | ## 功能特点 6 | 7 | - 自动执行买入和卖出操作 8 | - 支持自定义交易金额 9 | - 内置随机延迟,模拟真实用户操作 10 | - 自动处理确认弹窗 11 | - 支持循环执行多次交易 12 | 13 | ## 使用前提 14 | 15 | 1. 币安账户已开通现货交易权限 16 | 2. 已登录币安网页版 17 | 3. 已选择要交易的币种对 18 | 19 | ## 安装步骤 20 | 21 | 1. 打开币安网页版并登录 22 | 2. 打开浏览器的开发者工具(按 F12 或右键选择"检查") 23 | 3. 切换到 Console(控制台)标签 24 | 4. 将 `alpha_tool.js` 的代码复制到控制台中 25 | 26 | ## 使用方法 27 | 28 | 1. 在币安网页版中选择要交易的币种对 29 | 2. 确保交易面板处于打开状态 30 | 3. 在控制台中执行以下命令开始自动交易: 31 | 32 | ```javascript 33 | runTradeLoop(20); // 20是交易次数,可以根据需要修改 34 | ``` 35 | 36 | ## 注意事项 37 | 38 | - 脚本默认买入金额为8(单位取决于您选择的币种) 39 | - 卖出时会自动设置为100%卖出 40 | - 每次操作之间会有随机延迟(1-3秒),以模拟真实用户操作 41 | - 请确保账户中有足够的资金进行交易 42 | - 建议先使用小额资金测试脚本功能 43 | - 交易过程中请勿关闭或刷新页面 44 | 45 | ## 安全提示 46 | 47 | - 请勿将您的币安账户信息分享给他人 48 | - 建议在测试时使用小额资金 49 | - 请确保您的网络连接稳定 50 | - 建议在使用脚本时保持浏览器窗口处于活动状态 51 | - 小心风控 52 | 53 | ## 故障排除 54 | 55 | 如果遇到问题,请检查: 56 | 57 | 1. 是否已正确登录币安账户 58 | 2. 是否已选择正确的交易对 59 | 3. 账户余额是否充足 60 | 4. 网络连接是否稳定 61 | 5. 浏览器控制台是否有错误信息 62 | 63 | ## 免责声明 64 | 65 | 本工具仅供学习和研究使用,使用本工具进行交易的风险由用户自行承担。作者不对使用本工具造成的任何损失负责。在使用本工具之前,请确保您了解相关的交易风险。 -------------------------------------------------------------------------------- /alpha_tool.js: -------------------------------------------------------------------------------- 1 | let value = 8; // 购买金额 2 | let runtime = 10; // 运行次数 3 | let customize = 0.1; // 滑点设置 4 | 5 | // 通用函数:设置输入框或滑块的值(React 兼容) 6 | const setInputValue = (element, value, options = {}) => { 7 | if (!element) { 8 | console.error('Element not found for setting value'); 9 | return false; 10 | } 11 | 12 | const isSlider = element.getAttribute('role') === 'slider'; 13 | const { triggerChange = isSlider, updateAria = isSlider } = options; 14 | 15 | // 检查禁用或只读状态 16 | const wasDisabled = element.disabled; 17 | const wasReadOnly = element.readOnly; 18 | if (wasDisabled) element.disabled = false; 19 | if (wasReadOnly) element.readOnly = false; 20 | 21 | try { 22 | // 使用原生的 value setter 23 | const nativeInputValueSetter = Object.getOwnPropertyDescriptor( 24 | window.HTMLInputElement.prototype, 25 | 'value' 26 | ).set; 27 | 28 | // 创建 React 兼容的 input 事件 29 | const inputEvent = new Event('input', { bubbles: true, cancelable: true }); 30 | Object.defineProperty(inputEvent, 'target', { writable: false, value: element }); 31 | Object.defineProperty(inputEvent, 'currentTarget', { writable: false, value: element }); 32 | 33 | // 设置值 34 | nativeInputValueSetter.call(element, value); 35 | element.setAttribute('value', value); 36 | 37 | // 更新 ARIA 属性(滑块) 38 | if (updateAria) { 39 | element.setAttribute('aria-valuenow', value); 40 | element.setAttribute('aria-valuetext', `${value} units`); 41 | } 42 | 43 | // 模拟焦点(滑块) 44 | if (isSlider) { 45 | element.focus(); 46 | } 47 | 48 | // 触发 input 事件 49 | element.dispatchEvent(inputEvent); 50 | 51 | // 触发 change 事件(如果需要) 52 | if (triggerChange) { 53 | const changeEvent = new Event('change', { bubbles: true, cancelable: true }); 54 | Object.defineProperty(changeEvent, 'target', { writable: false, value: element }); 55 | Object.defineProperty(changeEvent, 'currentTarget', { writable: false, value: element }); 56 | element.dispatchEvent(changeEvent); 57 | } 58 | 59 | // 模拟失焦(滑块) 60 | if (isSlider) { 61 | element.blur(); 62 | } 63 | 64 | console.log(`${isSlider ? 'Slider' : 'Input'} value after set:`, element.value); 65 | } catch (error) { 66 | console.error('Error setting input value:', error); 67 | return false; 68 | } finally { 69 | // 恢复状态 70 | if (wasDisabled) element.disabled = true; 71 | if (wasReadOnly) element.readOnly = true; 72 | } 73 | 74 | return true; 75 | }; 76 | 77 | // 通用函数:模拟点击 78 | const simulateClick = (element, type = 'button') => { 79 | if (!element) { 80 | console.error(`${type} not found`); 81 | return false; 82 | } 83 | 84 | if (element.disabled) { 85 | console.warn(`${type} is disabled, click ignored`); 86 | return false; 87 | } 88 | 89 | const mouseClickEvent = new MouseEvent('click', { 90 | bubbles: true, 91 | cancelable: true, 92 | view: window, 93 | clientX: element.getBoundingClientRect().left + 10, 94 | clientY: element.getBoundingClientRect().top + 10 95 | }); 96 | const mouseDownEvent = new MouseEvent('mousedown', { bubbles: true, cancelable: true, view: window }); 97 | const mouseUpEvent = new MouseEvent('mouseup', { bubbles: true, cancelable: true, view: window }); 98 | 99 | element.focus(); 100 | element.dispatchEvent(mouseDownEvent); 101 | element.dispatchEvent(mouseClickEvent); 102 | element.dispatchEvent(mouseUpEvent); 103 | console.log(`${type} clicked`); 104 | return true; 105 | }; 106 | 107 | // 通用函数:点击标签 108 | const clickTab = (id, text) => { 109 | const element = Array.from(document.querySelectorAll(`div[role="tab"][id="${id}"].bn-tab.bn-tab__buySell`)) 110 | .find(el => el.textContent.trim() === text); 111 | 112 | if (!element) { 113 | console.error(`Tab "${text}" not found with id "${id}"`); 114 | return false; 115 | } 116 | 117 | return simulateClick(element, `Tab "${text}"`); 118 | }; 119 | 120 | // 异步延迟函数 121 | const randomDelay = (min = 1000, max = 3000) => { 122 | const ms = Math.floor(Math.random() * (max - min + 1)) + min; 123 | console.log(`Waiting for ${ms}ms`); 124 | return new Promise(resolve => setTimeout(resolve, ms)); 125 | }; 126 | 127 | // 点击确认按钮 128 | const clickConfirmButton = () => { 129 | const button = document.querySelector('.bn-modal-footer .bn-button.bn-button__primary'); 130 | if (!button) { 131 | console.error('Confirm button not found'); 132 | return false; 133 | } 134 | return simulateClick(button, 'Confirm button'); 135 | }; 136 | 137 | // 重置交易面板 138 | const resetTradePanel = async () => { 139 | try { 140 | // 关闭模态框 141 | const modal = document.querySelector('.bn-modal-footer'); 142 | if (modal) { 143 | const cancelButton = document.querySelector('.bn-modal-footer .bn-button:not(.bn-button__primary)'); 144 | if (cancelButton) { 145 | if (!simulateClick(cancelButton, 'Cancel button')) { 146 | console.warn('Failed to click cancel button'); 147 | } 148 | await randomDelay(500, 1000); // 较短延迟以关闭模态框 149 | } 150 | } 151 | 152 | // 确保回到买入标签 153 | if (!clickTab('bn-tab-0', '买入')) { 154 | console.error('Failed to reset to Buy tab'); 155 | return false; 156 | } 157 | await randomDelay(500, 1000); 158 | 159 | // 等待页面稳定 160 | const buyInput = document.querySelector('#fromCoinAmount'); 161 | const slider = document.querySelector('input[role="slider"]'); 162 | if (!buyInput || !slider) { 163 | console.error('Trade panel elements not found after reset'); 164 | return false; 165 | } 166 | 167 | return true; 168 | } catch (error) { 169 | console.error('Error resetting trade panel:', error); 170 | return false; 171 | } 172 | }; 173 | 174 | // 主函数:执行交易 175 | const executeTrade = async (iteration) => { 176 | try { 177 | console.log(`Starting trade iteration ${iteration}`); 178 | 179 | // 重置状态 180 | if (!(await resetTradePanel())) { 181 | throw new Error('Failed to reset trade panel'); 182 | } 183 | 184 | // 获取最新元素 185 | const buyInput = document.querySelector('#fromCoinAmount'); 186 | const slider = document.querySelector('input[role="slider"]'); 187 | console.log('Buy input:', buyInput, 'Slider:', slider); 188 | if (!buyInput || !slider) { 189 | throw new Error('Required elements not found'); 190 | } 191 | console.log('Buy input disabled:', buyInput.disabled, 'value:', buyInput.value); 192 | console.log('Slider disabled:', slider.disabled, 'value:', slider.value); 193 | 194 | // 1. 点击买入标签 195 | if (!clickTab('bn-tab-0', '买入')) { 196 | throw new Error('Failed to click Buy tab'); 197 | } 198 | await randomDelay(500, 1000); 199 | 200 | // 2. 输入买入金额 8 201 | if (!setInputValue(buyInput, value)) { 202 | throw new Error('Failed to set buy input value'); 203 | } 204 | console.log('Buy input after set:', buyInput.value); 205 | await randomDelay(2000, 4000); 206 | 207 | 208 | // 设置滑点 209 | // 定位包含设置滑点元素 210 | const button = document.querySelector('div.t-subtitle3.text-PrimaryText div.bn-flex.cursor-pointer'); 211 | // 触发点击事件 212 | if (button) { 213 | button.click(); 214 | } else { 215 | console.error('未找到目标按钮'); 216 | } 217 | await randomDelay(500, 1000); 218 | 219 | // 定位包含“自定义”文本的 div 元素 220 | const buttonList = document.querySelectorAll('div.t-subtitle1.text-PrimaryText'); 221 | let targetButton = null; 222 | 223 | for (let button of buttonList) { 224 | if (button.textContent.includes('自定义')) { 225 | targetButton = button; 226 | break; 227 | } 228 | } 229 | await randomDelay(500, 1000); 230 | 231 | // 触发点击事件 232 | if (targetButton) { 233 | targetButton.click(); 234 | } else { 235 | console.error('未找到包含“自定义”的按钮'); 236 | } 237 | await randomDelay(500, 1000); 238 | const customizeinput = document.querySelector('#customize-slippage'); 239 | setInputValue(customizeinput, customize) 240 | await randomDelay(500, 1000); 241 | // 8. 点击确认按钮 242 | if (!clickConfirmButton()) { 243 | throw new Error('Failed to click Confirm button for sell'); 244 | } 245 | await randomDelay(3000, 5000); 246 | 247 | // 3. 点击买入按钮 248 | const buyButton = document.querySelector('.bn-button.bn-button__buy'); 249 | if (!buyButton || !simulateClick(buyButton, 'Buy button')) { 250 | throw new Error('Failed to click Buy button'); 251 | } 252 | await randomDelay(500, 1000); 253 | 254 | // 4. 点击确认按钮 255 | if (!clickConfirmButton()) { 256 | throw new Error('Failed to click Confirm button for buy'); 257 | } 258 | await randomDelay(3000, 5000); // 额外延迟以确保交易完成 259 | 260 | // 5. 点击卖出标签 261 | if (!clickTab('bn-tab-1', '卖出')) { 262 | throw new Error('Failed to click Sell tab'); 263 | } 264 | await randomDelay(500, 1000); 265 | 266 | // 6. 滑动100%卖出 267 | if (!setInputValue(slider, '100', { triggerChange: true, updateAria: true })) { 268 | throw new Error('Failed to set slider value'); 269 | } 270 | console.log('Slider after set:', slider.value); 271 | await randomDelay(3000, 5000); 272 | 273 | // 设置滑点 274 | // 定位包含设置滑点元素 275 | const cursorbutton = document.querySelector('div.t-subtitle3.text-PrimaryText div.bn-flex.cursor-pointer'); 276 | if (cursorbutton) { 277 | cursorbutton.click(); 278 | } else { 279 | console.error('未找到目标按钮'); 280 | } 281 | await randomDelay(500, 1000); 282 | 283 | // 定位包含“自定义”文本的 div 元素 284 | // 定位包含“自定义”文本的 div 元素 285 | const buttonList2 = document.querySelectorAll('div.t-subtitle1.text-PrimaryText'); 286 | let targetButton2 = null; 287 | for (let button of buttonList2) { 288 | if (button.textContent.includes('自定义')) { 289 | targetButton2 = button; 290 | break; 291 | } 292 | } 293 | await randomDelay(500, 1000); 294 | 295 | // 触发点击事件 296 | if (targetButton2) { 297 | targetButton2.click(); 298 | } else { 299 | console.error('未找到包含“自定义”的按钮'); 300 | } 301 | await randomDelay(500, 1000); 302 | const customizeinput2 = document.querySelector('#customize-slippage'); 303 | setInputValue(customizeinput2, customize) 304 | await randomDelay(500, 1000); 305 | // 8. 点击确认按钮 306 | if (!clickConfirmButton()) { 307 | throw new Error('Failed to click Confirm button for sell'); 308 | } 309 | await randomDelay(3000, 5000); 310 | 311 | // 7. 点击卖出按钮 312 | const sellButton = document.querySelector('.bn-button.bn-button__sell'); 313 | if (!sellButton || !simulateClick(sellButton, 'Sell button')) { 314 | throw new Error('Failed to click Sell button'); 315 | } 316 | await randomDelay(500, 1000); 317 | 318 | // 8. 点击确认按钮 319 | if (!clickConfirmButton()) { 320 | throw new Error('Failed to click Confirm button for sell'); 321 | } 322 | await randomDelay(1000, 2000); 323 | 324 | console.log(`Trade iteration ${iteration} completed successfully`); 325 | } catch (error) { 326 | console.error(`Error during trade iteration ${iteration}:`, error.message); 327 | throw error; // 抛出错误以便循环处理 328 | } 329 | }; 330 | 331 | // 循环执行主函数 20 次 332 | const runTradeLoop = async (maxIterations = runtime) => { 333 | let successfulIterations = 0; 334 | let failedIterations = 0; 335 | 336 | for (let i = 1; i <= maxIterations; i++) { 337 | try { 338 | console.log(`=== Starting iteration ${i} of ${maxIterations} ===`); 339 | await executeTrade(i); 340 | successfulIterations++; 341 | console.log(`=== Iteration ${i} succeeded ===`); 342 | } catch (error) { 343 | failedIterations++; 344 | console.error(`=== Iteration ${i} failed: ${error.message} ===`); 345 | // 等待较短时间后继续下一次循环 346 | await randomDelay(1000, 2000); 347 | } 348 | // 在每次迭代后添加额外延迟以确保页面状态稳定 349 | await randomDelay(3000, 7000); 350 | } 351 | 352 | console.log(`Trade loop completed: ${successfulIterations} successful, ${failedIterations} failed`); 353 | }; 354 | 355 | // 启动循环 356 | runTradeLoop(runtime).catch(error => { 357 | console.error('Trade loop encountered an unexpected error:', error); 358 | }); --------------------------------------------------------------------------------