您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Fetch Torn stocks information using API and display adjusted profit/loss percentage as a list on the stocks page with manual and automatic refresh
// ==UserScript== // @name Torn Stocks Info // @namespace Pampas // @version 1.6 // @description Fetch Torn stocks information using API and display adjusted profit/loss percentage as a list on the stocks page with manual and automatic refresh // @author You // @match https://www.torn.com/page.php?sid=stocks // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // ==/UserScript== (function() { 'use strict'; // Function to prompt the user for their API key function promptForApiKey() { const apiKey = prompt('Please enter your Torn API key:'); if (apiKey) { GM_setValue('tornApiKey', apiKey); } else { alert('Invalid API key. Please refresh the page and try again.'); } } // Function to calculate adjusted profit/loss percentage considering the sale fee function calculateAdjustedPercentage(boughtPrice, currentPrice) { const rawPercentage = ((currentPrice - boughtPrice) / boughtPrice) * 100; const adjustedPercentage = (rawPercentage - 0.1).toFixed(2); return adjustedPercentage; } // Function to create and update the list container function createListContainer() { const listContainer = document.createElement('div'); listContainer.id = 'tornStockList'; listContainer.style.position = 'fixed'; listContainer.style.padding = '10px'; listContainer.style.background = 'rgba(0, 0, 0, 0.8)'; listContainer.style.color = 'white'; listContainer.style.borderRadius = '5px'; listContainer.style.bottom = '50%'; // Adjusted position to the middle right listContainer.style.right = '5px'; // Adjusted position to the middle right listContainer.style.zIndex = '1000'; document.body.appendChild(listContainer); return listContainer; } // Function to update the list container with stock information function updateListContainer(listContainer, stockInfo) { // Clear the content of the list container before updating listContainer.innerHTML = ''; for (const stockId in stockInfo) { const stockData = stockInfo[stockId]; const listItem = document.createElement('div'); listItem.textContent = `${stockData.name}: ${stockData.adjustedProfitLossPercentage}%`; listItem.style.marginBottom = '5px'; if (stockData.adjustedProfitLossPercentage < 0) { listItem.style.color = 'red'; } else { listItem.style.color = 'green'; } listContainer.appendChild(listItem); } // Add a manual refresh button const refreshButton = document.createElement('button'); refreshButton.textContent = 'Refresh'; refreshButton.style.marginTop = '5px'; refreshButton.style.color = 'white'; refreshButton.style.background = 'black'; // Set the background color refreshButton.style.border = '1px solid white'; // Add a border refreshButton.addEventListener('click', fetchAndUpdateStockInfo); listContainer.appendChild(refreshButton); } // Function to get the stored API key or prompt the user for a new one function getApiKey() { let apiKey = GM_getValue('tornApiKey'); if (!apiKey) { promptForApiKey(); apiKey = GM_getValue('tornApiKey'); } return apiKey; } // Function to fetch and update stock information function fetchAndUpdateStockInfo() { const apiUrl = `https://api.torn.com/user/?selections=stocks&key=${getApiKey()}`; const stockInfo = GM_getValue('tornStockInfo', {}); GM_xmlhttpRequest({ method: 'GET', url: apiUrl, onload: function(response) { const stockData = JSON.parse(response.responseText).stocks; // Extract stock ID and bought price for (const stockId in stockData) { const boughtPrice = stockData[stockId].transactions[Object.keys(stockData[stockId].transactions)[0]].bought_price; // URL for the second API request to get detailed stock information const secondApiUrl = `https://api.torn.com/torn/?selections=stocks&key=${getApiKey()}&stock_id=${stockId}&bought_price=${boughtPrice}`; // Make the second API request GM_xmlhttpRequest({ method: 'GET', url: secondApiUrl, onload: function(secondResponse) { const detailedStockInfo = JSON.parse(secondResponse.responseText); // Calculate adjusted profit/loss percentage considering the sale fee const currentPrice = detailedStockInfo.stocks[stockId].current_price; const adjustedProfitLossPercentage = calculateAdjustedPercentage(boughtPrice, currentPrice); // Update stock information stockInfo[stockId] = { name: detailedStockInfo.stocks[stockId].name, adjustedProfitLossPercentage: adjustedProfitLossPercentage }; // Update the list container with stock information updateListContainer(listContainer, stockInfo); // Store updated stock information GM_setValue('tornStockInfo', stockInfo); }, onerror: function(error) { console.error('Error making second API request:', error); } }); } // Remove stocks that are not present in the current API response for (const storedStockId in stockInfo) { if (!stockData[storedStockId]) { delete stockInfo[storedStockId]; } } // Update the list container with stock information updateListContainer(listContainer, stockInfo); // Store updated stock information GM_setValue('tornStockInfo', stockInfo); }, onerror: function(error) { console.error('Error making API request:', error); } }); } // Create or get the list container let listContainer = document.getElementById('tornStockList'); if (!listContainer) { listContainer = createListContainer(); } // Initial fetch on page load fetchAndUpdateStockInfo(); // Automatic refresh every 30 seconds setInterval(fetchAndUpdateStockInfo, 30000); // 30000 milliseconds = 30 seconds })();