What causes the percentages to become jumbled after the website has been active for a full day?

Within this piece of code, the intention is for the month to reset "every month of the week", "every week and day", and "every day."

As per the coding logic, upon running it for a single day, the daily percentage should be distinct while maintaining consistency between the weekly and monthly percentages, aligning with the daily value. However, upon executing the code for one day, both the weekly and daily percentages are identical, but the monthly percentage varies. I am perplexed by this discrepancy as the weekly and monthly percentages are expected to remain consistent until a week has passed.

Moreover, I am contemplating whether this anomaly could be influenced by operating a Next.js application on my local machine and sporadically turning my computer off and on throughout the day. Could this be interfering with storing the values?

Below is the provided code snippet:

import { NextResponse } from 'next/server';

let holdersCount: number | null = null;
let priceData: { priceUsd: number, marketCap: string ,liquidity: string} = { priceUsd: 0, marketCap: '' ,liquidity: ''};
let priceHistory = {
  month: 0, // Utilize numeric values
  day: 0,
  week: 0,
};

let pctChange = {
  month: '0.00', // Maintain as strings for output
  day: '0.00',
  week: '0.00',
};

let isInitialFetch = true;

{/* Reduced complexity by removing the fetch holder function */}

const fetchPriceData = async () => {
  try {
    const response = await fetch('https://api.dexscreener.com/latest/dex/tokens/0x9a26F5433671751C3276a065f57e5a02D2817973');
    const data = await response.json();
    priceData = {
      priceUsd: parseFloat(data.pairs[0].priceUsd) || 0, // Ensure it's always a valid number
      marketCap: data.pairs[0].marketCap,
      liquidity: data.pairs[0].liquidity.usd 
    };

    if (isInitialFetch) {
      // Only set the initial prices after the first successful fetch
      priceHistory.month = priceData.priceUsd;
      priceHistory.day = priceData.priceUsd;
      priceHistory.week = priceData.priceUsd;
      isInitialFetch = false; // Disable the flag after setting the initial prices
      console.log('inital state done')
    }

    console.log("Old price:", priceHistory.month);
    console.log("Current price:", priceData.priceUsd);

    // Calculate the percentage change for each timeframe
    const calculatePercentChange = (oldPrice: number, newPrice: number): string => {
      if (oldPrice === 0 || isNaN(oldPrice) || isNaN(newPrice)) {
        return '0'; // Avoid invalid calculations or division by 0
      }

      const percentChange = ((newPrice - oldPrice) / oldPrice) * 100;
      return percentChange > 0 ? `+${percentChange.toFixed(2)}` : percentChange.toFixed(2);
    };

    // Only calculate percentage change if the old prices have been set and are valid
    if (priceHistory.month > 0) {
      pctChange.month = calculatePercentChange(priceHistory.month, priceData.priceUsd);
    }
    if (priceHistory.day > 0) {
      pctChange.day = calculatePercentChange(priceHistory.day, priceData.priceUsd);
    }
    if (priceHistory.week > 0) {
      pctChange.week = calculatePercentChange(priceHistory.week, priceData.priceUsd);
    }

    console.log("Price data updated:", priceData);
    console.log("Percentage change:", pctChange);
  } catch (error) {
    console.error('Error fetching price data:', error);
  }
};

// Fetch holders data every 8 hrs
setInterval(fetchHoldersData, 8 * 60 * 60 * 1000);

// Fetch price data every 8 hrs
setInterval(fetchPriceData, 8 * 60 * 60 * 1000);

// Reset the price history every hour, day, and week
setInterval(() => {
  priceHistory.month = priceData.priceUsd;
},31 * 24 * 60 * 60 * 1000); // Every month

setInterval(() => {
  priceHistory.day = priceData.priceUsd;
}, 24 * 60 * 60 * 1000); // Every day

setInterval(() => {
  priceHistory.week = priceData.priceUsd;
}, 7 * 24 * 60 * 60 * 1000); // Every week

// Initial fetch
fetchHoldersData();
fetchPriceData();

export async function GET() {
  return NextResponse.json({
    holders: holdersCount,
    price: priceData.priceUsd.toFixed(2),
    marketCap: priceData.marketCap,
    liquidity: priceData.liquidity,
    percentChanges: pctChange,
  });
}

Captured results after 24 hours

The day value is anticipated to differ from the week and month values rather than observing the month value differing from the week and day’s values after a 24-hour period.

To troubleshoot, debug statements were included, and the code was executed multiple times endeavoring to pinpoint the issue.

Answer №1

Upon examination, there are several key points to consider

First and foremost: it's important to note that time intervals like a day or week may not always consist of the standard 24 or 168 hours due to occurrences like Daylight Saving Time switches. Additionally, months do not consistently have 31 days. While this factor might seem minor, it could potentially impact your scenario. Ultimately, the applicability of these nuances is for you to determine.

Secondly: Does the issue occur immediately following the first 24 hours, or does it manifest after an extended period within your backend system? From the provided code snippet, it's unclear how the callback for the "monthly" interval triggers before the "daily" or "weekly" ones during the initial 31 days. Is the segment where priceHistory.month gets altered (apart from the initial request) the only instance?

Thirdly: In prolonged scenarios exceeding a month, a complication may arise when multiple intervals align perfectly with one another. For instance, after 31 days, all callbacks—excluding the weekly one—could be scheduled simultaneously. Consequently, it's plausible that they won't execute in the expected sequence. This potential discrepancy could lead to discrepancies in percentage calculations among the daily, weekly, and monthly metrics.

To address these challenges, it would be advisable to adopt a different approach by utilizing an alternative data structure and updating strategy.

Create a timestamp alongside each value to track when the updates occurred:

let priceHistory = { 
  day: 0, 
  dayupdated: 0, 
  week: 0, 
  weekupdated: 0, 
  month: 0,
  monthupdated: 0
};

let priceData = {...};
let priceUpdated = 0;

...

Subsequently, utilize a single interval—which can be more frequent if necessary—and evaluate the required actions within its callback function:

setInterval(doWork, 3600000);
doWork(); //initialize the call


async function fetchPriceData() {
  const response = await fetch('https://api.dexscreener.com/latest/dex/tokens/0x9a26F5433671751C3276a065f57e5a02D2817973');
  const data = await response.json();
  priceData = {
    priceUsd: parseFloat(data.pairs[0].priceUsd) || 0, // Ensure it's always a valid number
    marketCap: data.pairs[0].marketCap,
    liquidity: data.pairs[0].liquidity.usd 
  };
}

function calcChanges() {
  if (priceHistory.month > 0) {
    pctChange.month = calculatePercentChange(priceHistory.month, priceData.priceUsd);
  }
  if (priceHistory.day > 0) {
    pctChange.day = calculatePercentChange(priceHistory.day, priceData.priceUsd);
  }
  if (priceHistory.week > 0) {
    pctChange.week = calculatePercentChange(priceHistory.week, priceData.priceUsd);
  }
}

async function doWork() {
  let now = Date.now();

  if (now - priceUpdated >= 8 * 3600000) {
    await fetchPriceData();
    priceUpdated = now;
  }

  if (now - priceHistory.dayUpdated >= 24*3600000) {
    priceHistory.day = priceData.priceUsd;
    priceHistory.dayUpdated = now;
  }

  if (now - priceHistory.weekUpdated >= 24*7*3600000) {
    priceHistory.week= priceData.priceUsd;
    priceHistory.weekUpdated = now;
  }

  if (now - priceHistory.monthUpdated >= 24*7*31*3600000) {
    priceHistory.month = priceData.priceUsd;
    priceHistory.monthUpdate = now;
  }

  calcChanges();  
}

Moreover, it's essential to ensure that alterations to priceHistory.* values occur exclusively within this particular callback function. With the current code configuration, the update of priceHistory.month prior to at least 31 days passing (or 31 * 24 hours) is unattainable, except during the initial request process.

This methodology guarantees that historical prices maintain their accurate values before undergoing calculations, ensuring updates only transpire at specified intervals. Eliminating interdependencies between callbacks aids in preventing execution order abnormalities and unintended modifications to dataset parameters.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can you please provide guidance on how to dynamically add number values from an array to a select tag in Vue.js?

I'm trying to populate a select tag with options from an array variable that contains arrays of number values. However, the values being output appear to be blank. Here is the HTML code: <select required id="dropDown"> <option>Sele ...

Getting a JSON response from a JSP page through an AJAX request

I'm encountering an issue with a JSP page that is supposed to send a JSON response when requested through an AJAX call. However, the response is being directed to the error part of the AJAX call instead of the success part. Below is the code in my JS ...

The login page is not being served by Express.static

After setting the homepage to login.html, why is index.html still showing as the homepage? I attempted to delete index.html, but then the web displayed login.html instead. This left me puzzled. app.js const express = require('express') const ...

What techniques can be used to modify HTML elements that are dynamically added to the page?

Initially, the code I am working on queries the database to determine if there are any available workstations in the office. If workstations are available, "option" elements are dynamically added to a "select" element using jQuery: $('#idofselectel ...

Leveraging Prisma Client alongside Supabase Edge Functions

I encounter an issue when trying to integrate the generated @prisma/client with Supabase Edge functions. Running npx prisma generate places the client in the default location within my node_modules folder, inaccessible for edge function usage. To resolve t ...

Retrieve a particular element from a JavaScript object by iterating through it with the .each()

Welcome, fellow developers! I am currently facing a challenge in my ticketing system project involving getting the 'title' variable from a node.js loop. The objective is to use this variable as a placeholder so that when a user wants to edit a t ...

Is it possible to use jQuery for drag-and-drop functionality?

Currently, I am working on developing a drag-and-drop widget that consists of 3 questions and corresponding answers. The user should only be able to fill in 2 answers in any order, while the third drop area should be disabled. This third drop area can be l ...

Enhancing retrieved data with Node.js and MongoDB (utilizing Mongoose)

The current code snippet I am working with looks like this: User.find({ featuredMerchant: true }) .lean() .limit(2) .exec(function(err, users) { if (err) { console.log(err); return res.status(400).send({ message: errorHandl ...

Can a variable be assigned to an innerHTML id?

Currently in the process of mastering JavaScript, one question that remains at the forefront of my mind: is it feasible to assign a variable to an ID? <div id="example"> Code </div> Is it possible for me to use document.getElementbyID("exampl ...

Exploring the Power of jQuery Deferreds in Sequencing Code Execution

I've been exploring the advantages of jQuery's Deferred functionality. From what I gather, Deferred doesn't replace callbacks but rather enhances their management. If I want to ensure that a method has finished executing before moving on to ...

The feature to hide columns in Vue-tables-2 seems to be malfunctioning

The issue I'm facing is with the hiddenColumns option not working as expected. Even when I set it to hiddenColumns:['name'], the name column remains visible. I've updated to the latest version, but the problem persists. UPDATE I am tr ...

Having difficulty moving the menu buttons to the right

Take a look at the code snippet below: https://jsfiddle.net/fcx0wkq3/1/ When you expand the result window, you'll notice the menu buttons on the left. I am trying to adjust the position of these menu buttons to bring them towards the center or the r ...

"Creating a dynamic TreeList in Ignite UI by linking pairs of names and corresponding

I recently developed a drag and drop tree list inspired by the tutorial on IgniteUI website. The main tree list functions properly, but I encountered an issue with the child nodes displaying as undefined, as illustrated in the image below: https://i.sstat ...

The PDF file appeared blank after receiving a response from the API using Node.js

When I call a REST API that returns a PDF file, the document appears blank when opened. The console indicates that the data may be corrupted. let url ="API-URL"; var options = { 'method': 'GET', 'url': url ...

Showing text on an ajax loader

While making an ajax call, I have implemented functions that are called on success. To enhance user experience, I am displaying a spinner during the call and hiding it once completed. My goal is to show a message along with the spinner to indicate which fu ...

Converting PHP variables to JavaScript variables: A step-by-step guide

I'm trying to figure out the most efficient method for retrieving PHP variables using AJAX and then transforming them into JavaScript variables. Imagine I have the following code in my PHP file: echo $total; echo $actual; Edit: JSON echo json_enco ...

Navigating to a webpage using the href attribute in JavaScript

Due to specific design constraints, I am unable to wrap elements with an Anchor tag. However, I can implement a click event on those elements. How can I navigate to the link correctly? The code snippet from before: <a href="Page1.html"> <but ...

The callback keeps getting triggered repeatedly, and I'm struggling to understand the reason behind it

One of the challenges I am facing revolves around a utility function responsible for launching a child process. The goal is to halt the listening process and trigger the callback as soon as the child process outputs a specific message to stdout: export co ...

Steps for incorporating the getElementByClassName() method

I have developed an application that features a list displayed as shown below: https://i.stack.imgur.com/BxWF2.png Upon clicking each tick mark, the corresponding Book name is added to a textbox below. I desire the tick mark to be replaced by a cross sym ...

Is there a way to retrieve bookmarks (TOC) from a PDF document using technologies such as NodeJS, ReactJS, or PHP?

I'm sure most people have noticed that when you open a PDF in the browser or Acrobat PDF reader, a bookmarks tab appears like the one shown here: https://i.stack.imgur.com/obFer.png If the PDF doesn't have any bookmarks, the list will be empty. ...