September 19, 2024

NodeJS – Plot Ethereum price on a series chart

Let’s explore together how to use CanvasJS in order to create a historical series chart of the Ethereum price (in EUR). We will use an HTML template and generate the series data in NodeJS.

I am using the same code base as the last article and the code is pushed to this Github repo. You can watch the full video from my YouTube channel or follow up with the blog text down below.

The data format

Before starting out, we need some data for the ETH prices. I managed to scrape data from the beginning of 2024 up till beginning of August same year. I’ve saved the price for each day in a separate JSON file which contains the ETHEUR pair and the UTC timestamp in seconds.

We can observe that the format of the JSON is very straighforward:

  1. currency: equals to ETH
  2. fiat: equals to EUR since this is the fiat currency I was interested in
  3. price: the actual price in fiat money for 1 ETH
  4. utcSeconds: the UTC timestamp in seconds

The CanvasJS template

Now let’s have a look at our visualization framework. CanvasJS seems very easy to use and supports multiple chart types. We will focus on the line series chart for now since it’ll be enough for us to display the historic prices and observe the Ethereum fluctuations.

We can jump start from a simple line chart and we are lucky enough to find what we need on the CanvasJS website.

This chart already looks fantastic and I can’t wait to see the actual Ethereum prices plotted on the screen 🙂 But first let’s break the HTML sample provided there in order to understand a bit the mechanics under the hood:

var chart = new CanvasJS.Chart("chartContainer", {
  animationEnabled: true,
  theme: "light2",
  title:{
    text: "Simple Line Chart"
  },
  data: [{        
    type: "line",
    indexLabelFontSize: 16,
    dataPoints: [
      // Excluded for brevity          
    ]
  }]
});
chart.render();

The function above executes at each page load. It instantiates a chart object with the necessary parameters like the title and data. The render function is called at the end in order to actually show the chart in the container with ID “chartContainer”.

Next notable section from this HTML is taking care of defining the div container and the CanvasJS script inclusion tag:

<div id="chartContainer" style="height: 370px; width: 100%;"></div>
<script src="https://cdn.canvasjs.com/canvasjs.min.js"></script>

Our custom Ethereum price template

Starting off with the above template, we will modify the chart configuration to reflect the data shown and we will include the data from an external file called eth-price.data.js (which will be generated by our script).

<script src="./eth-price.data.js"></script>

This file will declare a global variable called CHART_DATA which will hold our Ethereum prices for each day. The data is structured as an array of objects, each one containing the X and Y for the UTC timestamp and price respectively.

Note that this timestamp is now in milliseconds because CanvasJS expects it so. Speaking of the HTML, this is how the new chart configuration looks like now:

var chart = new CanvasJS.Chart("chartContainer", {
  animationEnabled: true,
  title: {
    text: "ETH-EUR historical price"
  },
  axisX: {
    title: "Date"
  },
  axisY: {
    title: "EUR",
  },
  zoomEnabled: true,
  data: [{
    type: "line",
    name: "ETH-EUR price",
    xValueType: "dateTime",
    dataPoints: CHART_DATA,
  }]
});

Notable modifications can be observed:

  1. We changed the chart title as well as the X and Y axis
  2. We enabled the zoom capability which is very useful for larger data
  3. The line series value type for X axis was changed to dateTime
  4. Now the inline dataPoints are assigned to the CHART_DATA variable

History Ethereum price data generation

Time to proceed to the data generation. We will basically load all the input files from the history-daily folder and write the output to the eth-price.data.js file. First we import the path and fs libraries and define the main variables for input and output folders:

const path = require('path');
const fs = require('fs').promises;

const inputDir = 'history-daily';
const outputDir = 'html';

const inputDirectoryPath = path.join(__dirname, inputDir)
const outputDirectoryPath = path.join(__dirname, outputDir)

Remember that __dirname is a predefined NodeJS variable which holds the absolute path to the script being executed. We use the path library to form the final paths in a platform agnostic way.

Next we proceed listing the input files in the folder and loading each one of them into an array. We have no guarantee on the order of the files, so we also sort them chronologically:

const files = await fs.readdir(inputDirectoryPath);
  const chartData = [];

  for (const file of files) {
    const text = await fs.readFile(path.join(inputDirectoryPath, file));
    const jsonObject = JSON.parse(text);

    chartData.push(jsonObject);
  }

  chartData.sort((a, b) => a.utcSeconds < b.utcSeconds);

The next step is to build our chart data into memory. A string array is what we’ll use to represent the lines of the final output file:


const bufArray = [
  'var CHART_DATA =[ \n'
];

for (const data of chartData) {
  bufArray.push(`{ x: ${data.utcSeconds * 1000}, y: ${data.price} },\n`);
}

bufArray.push(']\n');

As you can notice, we convert the UTC from seconds to milliseconds by multiplying with 1000. For the price, no transformation is necessary. The final step is to write the output file:


const outputFile = path.join(outputDirectoryPath, 'eth-price.data.js');

await fs.writeFile(outputFile, bufArray.join(''));

We should be able to run our script with node history.js to generate our file.

Check the visual chart

Time to open our HTML in browser. If everything is generated correctly, we will see this nice looking line series chart with the historical Ethereum prices:

Don’t forget to checkout the zoom functionality since it’s really useful!

Conclusion

The chart looks amazing and the code is clean and easy to understand. This is what I would call a good coding day! Let me know if you have comments, ideas and suggestions for future articles and videos. Wishing you all the best!

Thanks for reading, I hope you found this article useful and interesting. If you have any suggestions don’t hesitate to contact me. If you found my content useful please consider a small donation. Any support is greatly appreciated! Cheers  😉

afivan

Enthusiast adventurer, software developer with a high sense of creativity, discipline and achievement. I like to travel, I like music and outdoor sports. Because I have a broken ligament, I prefer safer activities like running or biking. In a couple of years, my ambition is to become a good technical lead with entrepreneurial mindset. From a personal point of view, I’d like to establish my own family, so I’ll have lots of things to do, there’s never time to get bored 😂

View all posts by afivan →