// ==UserScript== // @name Stonks // @namespace hardy.stonks.new3 // @version 0.5.8 // @description Stonks Helper // @author Hardy [2131687] // @match https://www.torn.com/page.php?sid=stocks* // @updateURL https://raw.githubusercontent.com/sid-the-sloth1/torn-qol-scripts/main/stonks.user.js // @downloadURL https://raw.githubusercontent.com/sid-the-sloth1/torn-qol-scripts/main/stonks.user.js // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_addStyle // @run-at document-start // @connect script.google.com // ==/UserScript== //For instructions: https://github.com/sid-the-sloth1/torn-qol-scripts/blob/main/Stonks.md (function() { 'use strict'; var darkMode = false; let state = {}; var metadata = {}; var portfolioData = {}; var stockLossObj = {}; var storageObj = {}; var stonksTotalVal = 0; var moneyOnHand = "hardy"; let acrArray = []; var localData = localStorage.getItem("hardy_stonks"); let rev_met = {}; var savedPrefs; var recentlyBought = {}; let investedIn = 0; let moneyInvested = 0; //////////; let pageurl = window.location.href; const nativeWebSocket = unsafeWindow.WebSocket; unsafeWindow.WebSocket = function(...args){ const socket = new nativeWebSocket(...args); if (socket.url === "wss://ws-centrifugo.torn.com/connection/websocket") { socket.addEventListener("message", (t) => { let data = JSON.parse(t.data); if (data.result && data.result.channel && data.result.channel == "stockMarket") { let msg = data.result.data.data.message; if (msg.action == "refreshStocksPrice") { moneyInvested = 0; let stocks = msg.data.stocks; for (const stock of stocks) { let id = stock.id; let price = stock.chartsData[0][1].value; metadata[id].price = price; moneyInvested += Math.ceil(price*metadata[id].ownedShares); } stockLossObj = {}; stonksTotalVal = 0; for (const blocks in portfolioData) { for (const block of portfolioData[blocks]) { let id = block[0]; let amount = block[3]; let price = metadata[id].price; block[6] = price; let total = Math.ceil(amount* price); block[7] = total; let fee = Math.round((0.1/100)*total); block[8] = total -block[5]-fee; if (stockLossObj[id]) { stockLossObj[id] += block[8]; } else { stockLossObj[id] = block[8]; } stonksTotalVal += block[8]; } } makeRecentList(); if (pageurl.includes("link=hardy")) { document.querySelector("#hardyPortfolioBox").innerHTML = returnHtml(); } else { addProfitLossInfo(); changeTitle(); document.querySelector(".hardy_stonks_text_info").innerHTML = `${stonksTotalVal >= 0?'Current Profit: ':'Current Loss: '}${formatNumber(stonksTotalVal)}
Current Holdings: ${formatNumber(moneyInvested)}
Invested Into ${investedIn} Stocks`; } //console.log(metadata); } } else if (data.result && data.result.data && data.result.data.data && data.result.data.data.message) { let msg = data.result.data.data.message; if (msg.namespaces && msg.namespaces.sidebar && msg.namespaces.sidebar.actions && msg.namespaces.sidebar.actions.updateMoney) { moneyOnHand = msg.namespaces.sidebar.actions.updateMoney.money; } } }); } return socket; }; let original_fetch = unsafeWindow.fetch; unsafeWindow.fetch = async (url, init) => { let response = await original_fetch(url, init) let respo = response.clone(); if (url.includes("page.php?sid=StockMarket&step=getInitialData")) { respo.json().then((info) => { let stocks = info.stocks; for (const stock of stocks) { let id = stock.id; metadata[id] = {}; metadata[id].name = stock.profile.name; metadata[id].acronym = stock.profile.acronym; acrArray.push(stock.profile.acronym); rev_met[stock.profile.acronym] = id; metadata[id].req = stock.dividends.requirements.forOne; let logos = stock.profile.bigLogo; metadata[id].light = logos.light; metadata[id].dark = logos.dark; metadata[id].price = stock.sharesPrice.chartData[1].value; metadata [id].type = stock.dividends.type; metadata[id].days = stock.dividends.progress.total; metadata[id].progress = stock.dividends.progress.current; let userData = stock.userOwned; metadata[id].ownedShares = userData.sharesAmount; let price = stock.sharesPrice.chartData[1].value; if (userData.sharesAmount > 0) { investedIn += 1; moneyInvested += Math.ceil(price*userData.sharesAmount); portfolioData[id] = []; for (const transaction of userData.transactions) { let totalBuy = Math.ceil(transaction.amount*transaction.boughtPrice); let totalWorth = Math.floor(transaction.amount *price); let fee = Math.round((0.1/100)*totalWorth); let diff = totalWorth - totalBuy - fee; portfolioData[id].push([id, transaction.timestamp, metadata[id].acronym, transaction.amount, transaction.boughtPrice, totalBuy , price, totalWorth, diff ]); if (stockLossObj[id]) { stockLossObj[id] += diff; } else { stockLossObj[id] = diff; } stonksTotalVal += diff; } } } //console.log(metadata); waitForElement("ul[class^='stock_']", addIndex); if (pageurl.includes("&link=hardyportfolio")) { waitForLoad("#stockmarketroot", createPortfolio); } }); } else if (url.includes("page.php?sid=StockMarket&step=buyShares")) { respo.json().then((info) => { if (info.success) { let id = init.body.get("stockId"); let obj = {}; obj.key = "hardy"; obj.stock = metadata[id].acronym; obj.stamp = Date.now(); obj.amount = parseInt(init.body.get("amount")); obj.price = metadata[id].price; obj.total = Math.ceil(obj.amount *obj.price); obj.type = "buy"; sendData(obj); if (!portfolioData[id]) { portfolioData[id] = []; } let oldShares = metadata[id].ownedShares; if (oldShares === 0) { investedIn += 1; } metadata[id].ownedShares += obj.amount; portfolioData[id].push([id, obj.stamp/1000, obj.stock, obj.amount, obj.price, obj.total, obj.price, obj.total, 0]); } }); } else if (url.includes("page.php?sid=StockMarket&step=sellShares")) { respo.json().then((info) => { if (info.success) { let fee = 0.1; let id = init.body.get("stockId"); let obj = {}; obj.amount = init.body.get("amount"); obj.stock = metadata[id].acronym; obj.type = "sell"; obj.key = "hardy"; obj.stamp = Date.now(); obj.price = metadata[id].price; obj.total = Math.ceil(obj.amount *obj.price); obj.fee = Math.round(obj.total *0.001); obj.netTotal = obj.total-obj.fee; sendData(obj); let oldShares = metadata[id].ownedShares; let remainingShares = oldShares - obj.amount; if (remainingShares === 0) { investedIn = investedIn - 1; } metadata[id].ownedShares = remainingShares; let transList = document.querySelectorAll("div[class^='transactionsList'] ul[class^='transaction_']"); if (transList.length > 0) { portfolioData[id] = []; for (const trans of transList) { let amount = parseInt(trans.querySelector("li[class^='shares']").innerText.replace(/,/g, "")); let buyP = parseFloat(trans.querySelector("li[class^='bought']").innerText.replace(/\$/, "").replace(/,/g, "")); let buyTotal = Math.ceil(amount * buyP); let price = metadata[id].price; let total = Math.round(price*amount); portfolioData[id].push([id, dateToStamp(trans.querySelector("li[class^='date']").innerText), obj.stock, amount, buyP, buyTotal, price, total, total-buyTotal]); } } else { delete portfolioData[id]; } } }); } else if (url.includes("step=withdrawDividend")) { respo.json().then((info) => { if (info.success) { let uid = init.body.get("stockId"); metadata[uid].progress = 0; let array = []; for (const id in metadata) { if (metadata[id].days === metadata[id].progress && metadata[id].type === "active") { array.push(metadata[id].acronym); } } checkPayout(array); } }); } else if (url.includes("sid=StockMarket&step=getTransactions")) { respo.json().then((info) => { if (info.success) { setTimeout( ()=> { let uid = init.body.get("stockId"); let transList = document.querySelectorAll("div[class^='transactionsList'] ul[class^='transaction_']"); if (transList.length > 0) { portfolioData[uid] = []; for (const trans of transList) { let amount = parseInt(trans.querySelector("li[class^='shares']").innerText.replace(/,/g, "")); let buyP = parseFloat(trans.querySelector("li[class^='bought']").innerText.replace(/\$/, "").replace(/,/g, "")); let buyTotal = Math.ceil(amount * buyP); let price = metadata[uid].price; let total = Math.round(price*amount); portfolioData[uid].push([uid, dateToStamp(trans.querySelector("li[class^='date']").innerText), metadata[uid].acronym, amount, buyP, buyTotal, price, total, total-buyTotal]); } } }, 700); } }); } return response; }; function sendData(data) { // console.log(data); let url = savedPrefs.link; if (url != "" && url !== null && typeof url != "undefined") { GM_xmlhttpRequest({ method: "POST", url:url, data: JSON.stringify(data), onload: () => { console.log("Data Sent"); } }); } //alert(JSON.stringify(data)); } function createPortfolio(elem) { let node = elem.children; node[1].setAttribute("style", "display: none;"); node[2].setAttribute("style", "display: none;"); let box = document.createElement("div"); box.id = "hardyPortfolioBox"; //console.log(array); box.innerHTML = returnHtml(); document.querySelector("#stockmarketroot").appendChild(box); } function formatNumber(num) { if (num >= 0) { return "$"+num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); } else { let numb = -1*num; return "-$"+numb.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); } } function formatNum(num) { return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); } function waitForLoad(element, callbackFunc) { storageObj[element] = setInterval(() => { let node = document.querySelector(element); if (node) { clearInterval(storageObj[element]); callbackFunc(node); } }, 200); } function waitForElement(element, callbackFunc) { storageObj[element] = setInterval(() => { let node = document.querySelector(element); if (node) { clearInterval(storageObj[element]); callbackFunc(); } }, 400); } function addIndex() { let payoutArray = []; let moneyNode = document.querySelector("span[id='user-money']"); if (moneyNode) { moneyOnHand = moneyNode.getAttribute("data-money"); } for (const id in metadata) { let node = document.querySelector(`li[aria-label*="${metadata[id].name}"]`).parentNode; node.setAttribute("info", `${metadata[id].acronym}_${id}`); if (metadata[id].days === metadata[id].progress && metadata[id].type === "active") { payoutArray.push(metadata[id].acronym); } let logoDiv = node.querySelector("div[class^='logoContainer_']"); let inner = logoDiv.innerHTML; logoDiv.innerHTML = `
${inner}
${metadata[id].acronym}
`; } if (!pageurl.includes("link=hardy")) { let icon = document.createElement("a"); icon.setAttribute("role", "button"); icon.setAttribute("aria-labelledby", "portfolio"); icon.setAttribute("href", "https://www.torn.com/page.php?sid=stocks&link=hardyportfolio") let footer = document.querySelector("a[class^='linkContainer_']") icon.className = footer.className; icon.classList.remove("link-container-City"); let spanSvg = footer.children; let svg = `Portfolio`; icon.innerHTML = svg; footer.parentNode.insertBefore(icon, footer); let div = document.createElement("div"); div.className = "hardy_stonks_boxdef" div.innerHTML = `
Stonks
`; let root = document.querySelector("#stockmarketroot ul[class*='titles_']"); root.parentNode.insertBefore(div, root); acrArray.sort(); let array = ['']; for (const acronym of acrArray) { array.push(``); } document.querySelector("#stonksAcrSelect").innerHTML = array.join(""); checkPayout(payoutArray); addListeners(); makeRecentList(); if (localData === null || typeof localData == "undefined") { let tempobj = {}; tempobj.link = ''; for (const id in metadata) { tempobj[id] = {}; tempobj[id].lowerThan = 0; tempobj[id].higherThan = 0; } tempobj.prefs = {}; tempobj.prefs.select1 = "def"; tempobj.prefs.select2 = "def"; tempobj.prefs.irr_list = []; localStorage.setItem("hardy_stonks", JSON.stringify(tempobj)); savedPrefs = tempobj; } else { savedPrefs = JSON.parse(localData); } if (savedPrefs.prefs) { let val1 = savedPrefs.prefs.select1; let val2 = savedPrefs.prefs.select2; if (val1 !== "def") { handleSelectInput(val1); document.querySelector("#stonks_select").value = val1; } else { if (val2 !== "def") { applyAcrFilter(val2); document.querySelector("#stonksAcrSelect").value = val2; } } } addProfitLossInfo(); if (moneyOnHand !== "hardy") { modifyStockDiv(); } state.title = "original"; changeTitle(); } else { let icon = document.createElement("a"); icon.setAttribute("role", "button"); icon.setAttribute("aria-labelledby", "stonks"); icon.setAttribute("href", "https://www.torn.com/page.php?sid=stocks"); let footer = document.querySelector("a[class^='linkContainer_']") icon.className = footer.className; icon.classList.remove("link-container-City"); let spanSvg = footer.children; let svg = `Stock Exchange`; icon.innerHTML = svg; footer.parentNode.insertBefore(icon, footer); } } function returnHtml() { let html1 = ''; let html2 = '
NameInfo
'; let array = []; darkMode = document.body.classList.contains("dark-mode"); for (let blocks in portfolioData) { for (const block of portfolioData[blocks]) { let id = block[0]; let img = darkMode? metadata[id].dark: metadata[id].light; let change = block[8] < 0? "stonksDown": "stonksUp" array.push(`${block[2]}
  • Shares: ${formatNum(block[3])}
  • Current: ${formatNumber(block[6])}
  • Length: ${block[1]}
  • Worth: ${formatNumber(block[7])}
  • Bought: ${formatNumber(block[4])}
  • Change: ${formatNumber(block[8])} (${+(((block[7]/block[5])*100)-100).toFixed(2)}%)
`); } } return html1+array.join("")+html2; } function addProfitLossInfo() { let lowerArray = []; let higherArray = []; let nodeList = document.querySelectorAll("ul[class^='stock_']"); for (const node of nodeList) { let id = node.getAttribute("info").split("_")[1]; node.setAttribute("isGreen", "no"); let price = metadata[id].price; if (savedPrefs[id]) { if (savedPrefs[id].lowerThan > 0 && savedPrefs[id].lowerThan > price) { node.setAttribute("isGreen", "yes"); lowerArray.push(metadata[id].acronym); } if (savedPrefs[id].higherThan > 0 && savedPrefs[id].higherThan < price ) { node.setAttribute("isGreen", "yes"); higherArray.push(metadata[id].acronym) } } else { savedPrefs[id] = {}; savedPrefs[id].higherThan = 0; savedPrefs[id].lowerThan = 0; } let profit = stockLossObj[id] ? stockLossObj[id]: 0; //node.setAttribute("profit", 'h'+profit); let parent = node.querySelector("li[class^='stockOwned']"); let p = document.createElement("p"); let para = document.createElement("p"); p.className = profit < 0? "stonksDownli": "stonksUpli"; para.className = profit < 0? "stonksDownli": "stonksUpli"; let currVal = parseInt(parent.querySelector("p[class^='value']").innerText.replace(/,/g, "").replace(/\$/, "")); let boughtVal = currVal - profit; let percent = +(((profit/boughtVal))*100).toFixed(2) p.innerText = `${formatNumber(profit)}`; para.innerText = `${isNaN(percent)? 0: percent} %`; p.setAttribute("change", "role"); para.setAttribute("change", "role"); let elements = parent.querySelectorAll("p[change='role']"); if (elements.length > 0) { for (const element of elements) { element.remove(); } } parent.appendChild(p); parent.appendChild(para); } //console.log(higherArray); let length1 = lowerArray.length; if (length1 > 0) { if (length1 > 1) { if (length1 > 2) { let lastElem = lowerArray[length1 -1]; lowerArray.length = length1 - 1; document.querySelector("#lowerBulletin").innerText = `Stocks ${lowerArray.join(", ")} and ${lastElem} are at prices lower than your selected values.`; } else { document.querySelector("#lowerBulletin").innerText = `Stocks ${lowerArray[0]} and ${lowerArray[1]} are at prices lower than your selected values.`; } } else { document.querySelector("#lowerBulletin").innerText = `Stock ${lowerArray[0]} is at a price lower than your selected value.`; } } else { document.querySelector("#lowerBulletin").innerText = ''; } let length2 = higherArray.length; if (length2 > 0) { if (length2 > 1) { if (length2 > 2) { let lastElem = higherArray[length2 -1]; higherArray.length = length2- 1; document.querySelector("#higherBulletin").innerText = `Stocks ${higherArray.join(", ")} and ${lastElem} are at prices higher than your selected values.`; } else { document.querySelector("#higherBulletin").innerText = `Stocks ${higherArray[0]} and ${higherArray[1]} are at prices higher than your selected values.`; } } else { document.querySelector("#higherBulletin").innerText = `Stock ${higherArray[0]} is at a price higher than your selected value.`; } } else { document.querySelector("#higherBulletin").innerText = ''; } let val = document.querySelector("#stonks_select").value; if (val !== "def") { handleSelectInput(val); } } function validNumber(num) { if (num == "" || num === null || typeof num == "undefined" || isNaN(parseFloat(num))) { return 0; } else { return parseFloat(num); } } function checkPayout(array) { let length = array.length; if (length > 0) { if (length > 1) { if (length > 2) { let lastElem = array[length -1]; array.length = length-1; document.querySelector("#readyPayout").innerText = `Stocks ${array.join(", ")} and ${lastElem} are ready for payout.`; } else { document.querySelector("#readyPayout").innerText = `Stocks ${array[0]} and ${array[1]} are ready for payout.`; } } else { document.querySelector("#readyPayout").innerText = `Stock ${array[0]} is ready for payout.`; } } else { document.querySelector("#readyPayout").innerText = ''; } } function handleSelectInput(value) { document.querySelector("#stonksAcrSelect").value = "def"; if (value === "owned") { let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { let id = stock.getAttribute("info").split("_")[1]; stock.setAttribute("isShow", "yes"); if (!portfolioData[id]) { stock.setAttribute("isShow", "no"); } } } else if (value === "def") { let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { stock.setAttribute("isShow", "yes"); } } else if (value === "unowned") { let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { let id = stock.getAttribute("info").split("_")[1]; stock.setAttribute("isShow", "yes"); if (portfolioData[id]) { stock.setAttribute("isShow", "no"); } } } else if (value === "green") { let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { let id = stock.getAttribute("info").split("_")[1]; stock.setAttribute("isShow", "yes"); if (!stockLossObj[id]) { stock.setAttribute("isShow", "no"); } else { let profit = stockLossObj[id]; if (profit < 0) { stock.setAttribute("isShow", "no"); } } } } else if (value === "red") { let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { let id = stock.getAttribute("info").split("_")[1]; stock.setAttribute("isShow", "yes"); if (!stockLossObj[id]) { stock.setAttribute("isShow", "no"); } else { let profit = stockLossObj[id]; if (profit > 0) { stock.setAttribute("isShow", "no"); } } } } else if (value === "payout") { let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { let id = stock.getAttribute("info").split("_")[1]; stock.setAttribute("isShow", "yes"); if (metadata[id].type === "passive") { stock.setAttribute("isShow", "no"); } } } else if (value === "passive") { let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { let id = stock.getAttribute("info").split("_")[1]; stock.setAttribute("isShow", "yes"); if (metadata[id].type === "active") { stock.setAttribute("isShow", "no"); } } } else if (value === "ready") { let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { let id = stock.getAttribute("info").split("_")[1]; stock.setAttribute("isShow", "yes"); if (metadata[id].days !== metadata[id].progress || metadata[id].type === "passive") { stock.setAttribute("isShow", "no"); } } } else if (value === "recent") { let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { let id = stock.getAttribute("info").split("_")[1]; stock.setAttribute("isShow", "yes"); if (!recentlyBought[id]) { stock.setAttribute("isShow", "no"); } } } else if (value === "relevant") { if (savedPrefs.prefs.irr_list) { let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { let acr = stock.getAttribute("info").split("_")[0]; stock.setAttribute("isShow", "yes"); if (savedPrefs.prefs.irr_list.indexOf(acr) !== -1) { stock.setAttribute("isShow", "no"); } } } else { document.querySelector("#selectOutput").innerHTML = ``; } } } function applyAcrFilter(value) { if (value === "def") { document.querySelector("#selectInput").innerHTML = ''; document.querySelector("#selectOutput").innerHTML = ''; let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { stock.setAttribute("isShow", "yes"); } } else { document.querySelector("#selectOutput").innerHTML = ''; let acronym = value.toUpperCase(); let id = rev_met[acronym]; document.querySelector("#selectInput").innerHTML = `
`; let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { let uid = stock.getAttribute("info").split("_")[1]; stock.setAttribute("isShow", "no"); if (uid == id) { stock.setAttribute("isShow", "yes"); } } } } function makeRecentList() { recentlyBought = {}; let now = Math.round(Date.now()/1000); for (const id in portfolioData) { let transactions = portfolioData[id]; for (const transaction of transactions) { if (now-transaction[1] <= 86400*7) { recentlyBought[id] = "hardy"; } } } } function dateToStamp(entry) { let args = entry.split("/"); let monthArray = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; let month = monthArray[parseInt(args[1])-1]; let stamp = new Date(`${args[0]} ${month} 20${args[2]}`).getTime(); return Math.round(stamp/1000); } function modifyStockDiv() { setInterval(function() { if (window.location.href.includes("tab=owned")) { createAmountInput(); } }, 300); } function createAmountInput() { let mainDiv = document.querySelector("div[class^='stockDropdown']"); if (mainDiv) { let id = window.location.href.split("stockID=")[1].split("&")[0]; let manageBlock = mainDiv.querySelector("div[class^='manageTab_'] div[class^='manageContainer']"); if (manageBlock && !manageBlock.querySelector(".buyHint")) { let buyDiv = manageBlock.querySelector("div[class^='buyBlock'] div[class^='manageBlock']"); if (buyDiv.querySelector(".input-money-group")) { let height = parseInt(manageBlock.style.height.split("px")[0]); if (height < 140) { manageBlock.style.height = "140px"; } let div = document.createElement("div"); div.innerHTML = `

Enter amount of money you want to spend:

`; div.style.margin = "4px 0"; div.style.textAlign = "center"; buyDiv.appendChild(div); } } } } function sendManual(str) { let timePortion = str.split(" You")[0].split(" - "); let dayStamp = dateToStamp(timePortion[1]); let timeHMS = timePortion[0].split(":"); let stamp = dayStamp + parseInt(timeHMS[2]) + (parseInt(timeHMS[1])*60) + (parseInt(timeHMS[0])*3600); let obj = {}; obj.key = "hardy"; let text = str.substring(20).split(" "); obj.amount = parseInt(text[2].replace(/,/g, "").replace(/x/, "")); let type = text[1]; text.splice(0, 3); let afterParse = text.join(" ").split(" shares at $"); let stockName = afterParse[0].trim(); console.log(stockName); obj.stock = nameToAcr(stockName); obj.stamp = stamp*1000; let split = afterParse[1].split(" "); obj.price = split[0].replace(/,/g, ""); obj.total = parseInt(split[6].replace(/,/g, "").replace(/\$/, "")); if (type === "sold") { obj.type = "sell"; obj.fee = parseInt(split[8].replace(/,/g, "").replace(/\$/, "")); obj.netTotal = obj.total; obj.total = obj.netTotal + obj.fee; } else { obj.type = "buy"; } sendData(obj); document.querySelector("#selectOutput").innerHTML = ``; } function nameToAcr(name) { for (const id in metadata) { if (metadata[id].name === name) { return metadata[id].acronym; } } } function changeTitle() { let url = window.location.href; if (url.includes("stockID")) { let id = url.split("stockID=")[1].split("&")[0]; document.title = `${metadata[id].acronym}: ${metadata[id].price} | TORN`; state.title = "custom"; } else { if (state.title === "custom") { document.title = `Stock Market | TORN`; state.title = "original"; } } } function addListeners() { //Select Drop-down Stock Acronyms document.querySelector(".hardy_stonks_box").addEventListener("input", (t) => { let target = t.target; //console.log(t); if (target.id === "stonks_select") { document.querySelector("#selectInput").innerHTML = ''; document.querySelector("#selectOutput").innerHTML = ''; document.querySelector("#prefBox_stonks").innerHTML = ''; let val = target.value; if (!savedPrefs.prefs) { savedPrefs.prefs = {}; } savedPrefs.prefs.select1 = val; savedPrefs.prefs.select2 = "def"; localStorage.setItem("hardy_stonks", JSON.stringify(savedPrefs)); handleSelectInput(val); } else if (target.id === "stonksAcrSelect") { let value = target.value; if (!savedPrefs.prefs) { savedPrefs.prefs = {}; } savedPrefs.prefs.select1 = "def"; savedPrefs.prefs.select2 = value; localStorage.setItem("hardy_stonks", JSON.stringify(savedPrefs)); document.querySelector("#stonks_select").value = "def"; document.querySelector("#prefBox_stonks").innerHTML = ''; applyAcrFilter(value); } }); //Select Output Div document.querySelector("#selectOutput").addEventListener("click", (g) => { let target = g.target; if (target.id === "sendManual2") { let val = document.querySelector("#stonks_manual_input").value; let str = val.trim(); let buyRegex = /[0-9]{2}:[0-9]{2}:[0-9]{2} - [0-9]{2}\/[0-9]{2}\/[0-9]{2} You bought ([\d,]+)x (.+) (?:shares|share) at \$([\d,.]+) each for a total of \$([\d,]+)/gm; let sellRegex = /[0-9]{2}:[0-9]{2}:[0-9]{2} - [0-9]{2}\/[0-9]{2}\/[0-9]{2} You sold ([\d,]+)x (.+) (?:shares|share) at \$([\d,.]+) each for a total of \$([\d,]+) after \$([\d,]+) in fees/gm; if (buyRegex.test(str) || sellRegex.test(str)) { sendManual(str); } else { document.querySelector("#selectOutput").innerHTML = ``; } } else if (target.id === "cancelManualSend") { document.querySelector("#selectOutput").innerHTML = ''; } }); document.querySelector("div[class^='stockMarket_']").addEventListener("input", function(g) { if (g.target.className == "hardy_stonk_buy_input") { let inpu = g.target.value; if (inpu == "" || inpu.startsWith("N") || inpu == "$") { return; } else { let inp = inpu.replace(/,/g, "").replace(/\$/g, "").replace(/\s/g, ""); let val = inp.split(""); let lastLetter = val[val.length -1]; //console.log(lastLetter); var digits; if (lastLetter == "b" || lastLetter == "B") { val.splice(val.length-1, 1); digits = parseFloat(val.join(""))*1000000000.0 } else if (lastLetter == "k" || lastLetter == "K") { val.splice(val.length-1, 1); digits = parseFloat(val.join(""))*1000.0; } else if (lastLetter == "m" || lastLetter == "M") { val.splice(val.length-1, 1); digits = parseFloat(val.join(""))*1000000.0 } else { let joined = val.join(""); if (joined.includes(".")) { digits = joined.replace(/./g, "h") } else { digits = joined; } } if (isNaN(parseInt(digits))) { g.target.setAttribute("isError", "yes"); g.target.value = val.join(""); //console.log(val); } else if (digits === "") { g.target.setAttribute("isError", "yes"); } else { g.target.value = formatNum(digits); g.target.setAttribute("isError", "no"); } } } }); document.querySelector("div[class^='stockMarket_']").addEventListener("click", (t) => { let target = t.target; if (target.className === "hardy_amount_max") { document.querySelector(".hardy_stonk_buy_input").value = formatNum(moneyOnHand); } else if (target.className === "money_to_quant") { let inputBox = document.querySelector(".hardy_stonk_buy_input"); if (inputBox.getAttribute("isError") !== "yes") { let money = parseInt(inputBox.value.replace(/,/g, "")); let id = inputBox.getAttribute("info"); let outputBox = document.querySelector("div[class^='buyBlock'] .input-money"); let lastVal = outputBox.value; let placeHolderVal; if (money <= moneyOnHand) { let amount = Math.floor(money/metadata[id].price); outputBox.value = formatNum(amount); placeHolderVal = formatNum(amount); } else { let amount = Math.floor(moneyOnHand/metadata[id].price); outputBox.value = formatNum(amount); placeHolderVal = formatNum(amount); } let event = new Event('input', { bubbles: true }); let tracker = outputBox._valueTracker; if (tracker) { tracker.setValue(lastVal); } outputBox.dispatchEvent(event); } } }); document.querySelector("#clearFilter").addEventListener("click", (e) => { if (!savedPrefs.prefs) { savedPrefs.prefs = {}; } savedPrefs.prefs.select1 = "def"; savedPrefs.prefs.select2 = "def"; localStorage.setItem("hardy_stonks", JSON.stringify(savedPrefs)); document.querySelector("#stonksAcrSelect").value = "def"; document.querySelector("#stonks_select").value = "def"; document.querySelector("#selectInput").innerHTML = ''; document.querySelector("#selectOutput").innerHTML = ''; document.querySelector("#prefBox_stonks").innerHTML = ''; let stockList = document.querySelectorAll("ul[class^='stock_']"); for (const stock of stockList) { stock.setAttribute("isShow", "yes"); } }); document.querySelector("#selectInput").addEventListener("click", (e) => { let target = e.target; if (!target.id) { if (target.className.includes("hardy_stonks_hideList")) { if (target.classList.contains("hardyStonkHidden")) { target.classList.remove("hardyStonkHidden"); } else { target.classList.add("hardyStonkHidden"); } } } else { if (target.id === "saveCondi") { let lessNode = document.querySelector("#lower_than"); let id = lessNode.getAttribute("aria").split("_")[1]; let higherNode = document.querySelector("#higher_than"); savedPrefs[id].lowerThan = validNumber(lessNode.value); savedPrefs[id].higherThan = validNumber(higherNode.value); localStorage.setItem("hardy_stonks", JSON.stringify(savedPrefs)); document.querySelector("#selectOutput").innerHTML = ``; } else if (target.id == "saveLink") { let link = document.querySelector("#stonksLink").value; if (link == "" || link === null || typeof link == "undefined") { document.querySelector("#selectOutput").innerHTML = ``; } else { savedPrefs.link = link; localStorage.setItem("hardy_stonks", JSON.stringify(savedPrefs)); document.querySelector("#selectOutput").innerHTML = ``; } } else if (target.id === "closeLink") { document.querySelector("#selectInput").innerHTML = ''; document.querySelector("#selectOutput").innerHTML = ''; document.querySelector("#prefBox_stonks").innerHTML = ''; } else if (target.id === "sendManual1") { let val = document.querySelector("#stonks_manual_input").value; let str = val.trim(); let buyRegex = /[0-9]{2}:[0-9]{2}:[0-9]{2} - [0-9]{2}\/[0-9]{2}\/[0-9]{2} You bought ([\d,]+)x (.+) (?:shares|share) at \$([\d,.]+) each for a total of \$([\d,]+)/gm; let sellRegex = /[0-9]{2}:[0-9]{2}:[0-9]{2} - [0-9]{2}\/[0-9]{2}\/[0-9]{2} You sold ([\d,]+)x (.+) (?:shares|share) at \$([\d,.]+) each for a total of \$([\d,]+) after \$([\d,]+) in fees/gm; if (buyRegex.test(str) || sellRegex.test(str)) { document.querySelector("#selectOutput").innerHTML = `

`; } else { document.querySelector("#selectOutput").innerHTML = ``; } } else if (target.id === "selectAllStonks") { let nodeList = document.querySelectorAll(".hardy_stonks_hideList:not(.hardyStonkHidden)"); for (const node of nodeList) { node.classList.add("hardyStonkHidden"); } } else if (target.id === "unselectAllStonks") { let nodeList = document.querySelectorAll(".hardy_stonks_hideList.hardyStonkHidden"); for (const node of nodeList) { node.classList.remove("hardyStonkHidden"); } } else if (target.id === "saveHiddenStonks") { let array = []; let nodeList = document.querySelectorAll(".hardy_stonks_hideList.hardyStonkHidden"); for (const node of nodeList) { array.push(node.innerText); } savedPrefs.prefs.irr_list = array; localStorage.setItem("hardy_stonks", JSON.stringify(savedPrefs)); document.querySelector("#selectOutput").innerHTML = ``; } } }); document.querySelector("#prefBox_stonks").addEventListener("click", (g) => { let target = g.target; if (target.id === "openprompt") { document.querySelector("#selectInput").innerHTML = ``; document.querySelector("#selectOutput").innerHTML = ``; } else if (target.id === "stonkPrefClose") { document.querySelector("#prefBox_stonks").innerHTML = ''; document.querySelector("#selectOutput").innerHTML = ``; document.querySelector("#selectInput").innerHTML = ``; } else if (target.id === "stonks_hide_list") { if (savedPrefs.prefs) { if (!savedPrefs.prefs.irr_list) { savedPrefs.prefs.irr_list = []; } } else { savedPrefs.prefs = {}; savedPrefs.prefs.irr_list = []; savedPrefs.prefs.select1 = "def"; savedPrefs.prefs.select2 = "def"; } let array = []; for (const acr of acrArray) { if (savedPrefs.prefs.irr_list.indexOf(acr) !== -1) { array.push(`${acr}`); } else { array.push(`${acr}`); } } document.querySelector("#selectInput").innerHTML = `${array.join("")}

`; document.querySelector("#selectOutput").innerHTML = ``; } }); document.querySelector(".hardy_icon").addEventListener("click", () => { document.querySelector("#selectInput").innerHTML = ''; document.querySelector("#selectOutput").innerHTML = ''; document.querySelector("#prefBox_stonks").innerHTML = ``; }); document.querySelector("#manualEntry").addEventListener("click", () => { document.querySelector("#prefBox_stonks").innerHTML = ''; document.querySelector("#selectInput").innerHTML = ``; }); document.querySelector(".hardy_stonks_box_header").addEventListener("click", ()=> { let node = document.querySelector(".hardy_stonks_box"); if (node.getAttribute("style")) { node.removeAttribute("style"); } else { node.setAttribute("style", "display: none;"); } }); } GM_addStyle(` /*PC*/ td.stonkAcr { font-size: 20px!important; text-align: center; padding: 3px 18px!important; } td.stonkInfo td { padding: 0 8px; } td.stonkInfo tr { width: 100%; font-size: 16px; } #hardyPortfolioBox img { height: 60px; width: 60px; padding: 5px 0 5px 15px; } #innerTable td:first-child { padding-left: 18px; width: 50%; } /*.hardy_acr { display: none; }*/ div[class^='manageContainer_'] { padding: 6px 0; min-height: 150px!important;} /* mobile*/ @media screen and (max-width: 600px) { .hardy_acr { display: block; font-size: 14px;} td.stonkAcr { font-size: 16px!important; text-align: center; padding: 3px 6px!important; } td.stonkInfo td { padding: 0 8px; } td.stonkInfo tr { width: 100%; font-size: 14px; } #hardyPortfolioBox img { height: 40px; width: 40px; padding: 5px; } #innerTable td:first-child { padding: 6px; width: auto; } div[class^='manageContainer_'] { padding: 6px 0; min-height: 250px!important;} div[class^='buyBlock_'] {min-height: 150px!important;} } /* Portfolio*/ body:not(.dark-mode) #hardyPortfolioBox tbody { background-color: #fff; padding: 8px; } body.dark-mode #hardyPortfolioBox tbody { background-color: #333; padding: 8px; color: #ffffff; } #hardyPortfolioBox thead { background-color: black; color: white; font-size: 20px; text-align: center; } #hardyPortfolioBox li { list-style-type: none; } body.dark-mode #hardyPortfolioTable td { vertical-align: middle; color: #ffffff; } body:not(.dark-mode) #hardyPortfolioTable td { vertical-align: middle; } #hardyPortfolioTable th, #hardyPortfolioTable td, #hardyPortfolio { border-collapse: collapse; border: 2px solid #ddd; } #hardyPortfolioTable { -moz-border-radius: 10px; -webkit-border-radius: 10px; border-radius: 10px; } #hardyPortfolioTable th { padding: 4px; } .stonksDownli { color: #de5b30; } .stonksUpli { color: #5c940d; } /*Custom box*/ body:not(.dark-mode) .hardy_stonks_box { background-color: #f2f2f2; margin: 0 0 6px 0; padding: 6px 6px 6px 6px; border-radius: 0 5px 5px 5px; } body.dark-mode .hardy_stonks_box { background-color: #333; margin: 0 0 6px 0; padding: 6px 6px 6px 6px; border-radius: 0 5px 5px 5px; } .hardy_stonks_options { margin: 6px; display: block; position: relative; width: 100%; } .hardy_stonks_text_info { margin: 16px; text-align: center; font-size: 18px; display: block; } ul[isShow='no'] { display: none; } div[class^='stockMarket'] ul[class^="stock_"] { height: 80px; } .hardy_stonks_options select { padding: 9px 6px; font-size: 16px; border-radius: 4px; margin: 6px 0; } #openprompt, #manualEntry, #stonks_hide_list, #selectAllStonks, #unselectAllStonks { border-style: solid; border-color: rgb(169, 169, 169); padding: 8px 8px; font-size: 16px; border-radius: 4px; margin: 6px 8px; color: black; } body.dark-mode #openprompt, body.dark-mode #manualEntry, body.dark-mode #stonks_hide_list,body.dark-mode #selectAllStonks, body.dark-mode #unselectAllStonks { color: #ffffff; } #stonksAcrSelect { margin-left: 10px; } body.dark-mode .hardy_stonks_options select { background-color: #333; color: #ffffff;} body:not(.dark-mode) .hardy_stonks_options select { background-color: #f2f2f2; } #selectInput { font-size: 16px; margin: 8px 0; width: 100%; } #selectInput input[type='number'] { margin: 0 6px; padding: 3px; border-radius: 2px; width: 80px; } #selectInput input[type='text'] { margin: 0 6px; padding: 3px; border-radius: 2px; width: 50%; } #saveCondi, #saveLink, #sendManual1, #sendManual2, #saveHiddenStonks {font-size: 16px; padding: 8px 10px; border-radius: 4px; margin-left: 8px; background-color: #008000e8; color: white; } #closeLink, #cancelManualSend, #stonkPrefClose { font-size: 16px; padding: 8px 10px; border-radius: 4px; margin-left: 8px; background-color: #973335; color: white; } #selectOutput { font-size: 15px; text-align: center; } body:not(.dark-mode) ul[isGreen='yes'] { background-color: #ccfbcc; } body.dark-mode ul[isGreen='yes'] { background-color: #036203; } .hardy_stonks_box_header {background-color: black; color: white; padding: 5px 0; border-radius: 5px 5px 0 0; font-weight: bold; font-size: 17px; text-align: center; display: block;} .hardy_stonks_boxdef {margin: 0 0 5px 0} .hardy_icon {vertical-align: middle;} .hardy_stonks_hideList {display: inline-block; padding: 4px 6px; margin: 4px; border: 1px solid #939292; border-radius: 5px;} .hardyStonkHidden {background-color: #aa6f6f; color:white;} /*Test*/ .buyHint { margin: 4px; white-space: normal; font-weight: bold; display: block; text-align: center; } .hardy_stonk_buy_input { padding: 2px; border: 1px solid #b0aaaa; border-radius: 0 4px 4px 0; display: inline; } body.dark-mode .hardy_stonk_buy_input {background-color: #000000; color: rgb(255, 255, 255);} body:not(.dark-mode) .hardy_amount_max { display: inline; padding: 4px 9px; color: #757373; background: linear-gradient(to bottom, #ffffff 0%, #dddddd 100%); border-bottom-left-radius: 5px; border-top-left-radius: 5px; border: 1px solid #ccc; } body.dark-mode .hardy_amount_max {background-color: #5b5a5a; display: inline; padding: 4px 9px; color: #c1bfbf; border-bottom-left-radius: 5px; border-top-left-radius: 5px; border: 1px solid #7d7b7b;} .money_to_quant {margin-left: 3px; padding: 4px 8px; border-radius: 5px; background: transparent linear-gradient(180deg, #E5E5E5 0%, #BBBBBB 60%, #999999 100%) 0 0 no-repeat; color: #333; font-size: 14px; font-weight: 700; width: 20px;} input[isError='yes'] {background-color: #ecc8c8;} body.dark-mode input[isError='yes'] {background-color: #ecc8c8; color: black;} input[isError='no'] {background-color: #caeeca;} body.dark-mode input[isError='no'] {background-color: #caeeca; color: black;} div[class^='manageBlock_'] { padding: 6px 0!important;} #clearFilter { border-style: solid; border-color: rgb(169, 169, 169); padding: 8px 8px; font-size: 16px; border-radius: 4px; margin: 6px 8px; background-color: #c52323; color: #f1ecec; } `); })();