您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A Robinhood quality of life script
// ==UserScript== // @name Robinhood QOL Trading // @namespace Trading // @match https://robinhood.com/legend/layout/* // @grant none // @version 1.4 // @license MIT // @author AdSam // @description A Robinhood quality of life script // ==/UserScript== const MOD_KEY = "ctrl"; const Hotkeys = { BUY: "b", SELL: "s", TRAILING_STOP: "l", SET_SHARES: "z", SET_AMOUNT: "x", }; const Actions = { [Hotkeys.BUY]: async () => await buy(shares), [Hotkeys.SELL]: async () => await sell(shares), [Hotkeys.TRAILING_STOP]: async () => await trailing_stop(shares, amount), [Hotkeys.SET_SHARES]: () => { shares = input("Enter number of shares:", shares); }, [Hotkeys.SET_AMOUNT]: () => { amount = input("Enter trailing amount:"); }, }; const TIMEOUT = 5; function findElement(selector, index, timeout = 0) { let iter = 0; return new Promise((resolve, reject) => { const interval = setInterval(() => { if (timeout != 0 && iter >= timeout * 1000) { reject(new Error("Timeout")); } const elements = document.querySelectorAll(selector); if (elements[index]) { clearInterval(interval); resolve(elements[index]); } iter++; }, 1); }); } function input(message, _default) { userInput = prompt(message); if (userInput != null) { userInput = userInput .split("") .filter((char) => !isNaN(char) || char === ".") .join(""); return parseFloat(userInput || _default); } else { return parseFloat(_default); } } async function buy(shares) { let menuBtn = await findElement( '[data-testid="legend_buy_button"]', 0, TIMEOUT ); menuBtn.click(); let dropdown = await findElement('[role="combobox"]', 0, TIMEOUT); dropdown.click(); let market = await findElement('[role="option"]', 1, TIMEOUT); market.click(); let quantity = await findElement('[name="quantity"]', 0, TIMEOUT); quantity.focus(); document.execCommand("selectAll"); document.execCommand("insertText", false, shares.toString()); while (quantity.value != shares.toString()) {} let buyBtn = await findElement('[type="submit"]', 0, TIMEOUT); buyBtn.click(); } async function sell(shares) { let menuBtn = await findElement( '[data-testid="legend_sell_button"]', 0, TIMEOUT ); menuBtn.click(); let dropdown = await findElement('[role="combobox"]', 0, TIMEOUT); dropdown.click(); let market = await findElement('[role="option"]', 1, TIMEOUT); market.click(); let quantity = await findElement('[name="quantity"]', 0, TIMEOUT); quantity.focus(); document.execCommand("selectAll"); document.execCommand("insertText", false, shares.toString()); while (quantity.value != shares.toString()) {} let sellBtn = await findElement('[type="submit"]', 0, TIMEOUT); sellBtn.click(); } async function trailing_stop(shares, amount) { let menuBtn = await findElement( '[data-testid="legend_sell_button"]', 0, TIMEOUT ); menuBtn.click(); let dropdown = await findElement('[role="combobox"]', 0, TIMEOUT); dropdown.click(); let ts = await findElement('[role="option"]', 4, TIMEOUT); ts.click(); let quantity = await findElement('[name="quantity"]', 0, TIMEOUT); quantity.focus(); document.execCommand("selectAll"); document.execCommand("insertText", false, shares.toString()); let trail = await findElement('[role="combobox"]', 1, TIMEOUT); trail.click(); let a = await findElement('[role="option"]', 8, TIMEOUT); a.click(); let ta = await findElement('[name="trailAmount"]', 1, TIMEOUT); ta.focus(); document.execCommand("selectAll"); document.execCommand("insertText", false, amount.toString()); let tif = await findElement('[role="combobox"]', 2, TIMEOUT); tif.click(); let gtc = await findElement('[role="option"]', 6, TIMEOUT); gtc.click(); while ( quantity.value != shares.toString() || !ta.value.includes(amount.toString()) ) {} await new Promise((r) => setTimeout(r, 100)); let sellBtn = await findElement('[type="submit"]', 0, TIMEOUT); sellBtn.click(); } let shares = 0; let amount = 0; let debounce = false; document.addEventListener("keydown", async (event) => { if (!debounce) { debounce = true; try { if ( event[MOD_KEY.toLowerCase() + "Key"] && Actions[event.key.toLowerCase()] ) { event.preventDefault(); await Actions[event.key](); } } catch (e) { console.warn(e); } debounce = false; } });
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址