Torn Stocks Info

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
})();