1

I have a script which calls Binance API. I receive a response for specific symbol like BTCUSDT. API doesn't allow to call multiple symbols in API endpoint. This string - var j = schedule.scheduleJob('0 * * * *', function() is a node-schedule package which will call the script every hour at 00minutes(15:00/16:00/17:00...).

FULLCODE

var requestPromise = require('request-promise');
 const { MongoClient } = require('mongodb');
 const schedule = require('node-schedule');
 var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
 const fetch = require("node-fetch");

 var today = new Date();
 var date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate();
 var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
 var dateTime = date + ' ' + time;

 var symbols = ["BTCUSDT", "ETHUSDT", "ATOMBTC"];
 let cnt = 0;

 const callIt = () => {
     fetch(`https://api.binance.com/api/v3/klines?symbol=${symbols[cnt]}&interval=1h&limit=1`)
         .then(res => res.json())
         .then(data => {
             const btcusdtdata = data.map(d => {
                 return {
                     Open: parseFloat(d[1]),
                     High: parseFloat(d[2]),
                     Low: parseFloat(d[3]),
                     Close: parseFloat(d[4]),
                     Volume: parseFloat(d[5])
                 }
             });
             console.log(btcusdtdata);
             cnt++;
             if (cnt < symbols.length) setTimeout(callIt, 3000)
         })
         .catch((err) => {
             console.log(err);
         })

 };
 const j = schedule.scheduleJob('0 * * * *', callIt)

Problem: This script call the properties inside an array one after another which is perfect for me. My problem is my node-schedule(0 * * * *)doesn't work. I run the script and it's immediately send me the data. But I wan't to receive data only every hour and only after it call for properties in array. How I can insert a node-schedule function - const j = schedule.scheduleJob('0 * * * *', callIt) inside a main function. Everything works well, only that the script suppose to receive data every hour not immediately when I start it.

9
  • @mplungjan my bad, i'm sorry. Commented Jun 15, 2020 at 10:35
  • Please remove callIt() in your code, that was to test it also replace reject with console.log Commented Jun 15, 2020 at 11:25
  • @mplungjan main question edited accordingly to your comment. Commented Jun 15, 2020 at 11:37
  • @mplungjan main question is edited. All errors are gone. Still the question in calling the properties in array one after another Commented Jun 15, 2020 at 12:33
  • What happens if you comment out const j = schedule.scheduleJob('* * * * * *', callIt) and just have callIt() instead ? Commented Jun 15, 2020 at 12:40

2 Answers 2

2

Don't do Ajax in an interval. Instead use setTimeout in a callback

something like this - note I added a reject in a catch() to see the error when you abuse the API:

the code here does not work at SO due to CORS issues

NOTE: ${symbols[cnt]} is the trick

const symbols = ["BTCUSDT", "ETHUSDT", "ATOMBTC"];
let cnt = 0;


const callIt = () => {
  fetch(`https://api.binance.com/api/v3/klines?symbol=${symbols[cnt]}&interval=1h&limit=1`)
    .then(res => res.json())
    .then(data => {
      const btcusdtdata = data.map(d => {
        return {
          Open: parseFloat(d[1]),
          High: parseFloat(d[2]),
          Low: parseFloat(d[3]),
          Close: parseFloat(d[4]),
          Volume: parseFloat(d[5])
        }
      })
      console.log(btcusdtdata);
      cnt++;
      if (cnt < symbols.length) setTimeout(callIt, 3000)
    })
    .catch((err) => {
      console.log(err);
    })
};

// callIt(); // only to test without scheduler
const j = schedule.scheduleJob('* * * * * *', callIt); // assuming this will call it first time

I wanted to destruct but failed. Still more elegant

// https://api.binance.com/api/v3/klines?symbol=BTCUSDT&interval=1h&limit=1

const data = [
  [1592215200000, "9147.70000000", "9150.00000000", "9107.00000000", "9114.93000000", "1335.61921100", 1592218799999, "12190574.36418155", 16160, "624.21625600", "5697793.49077209", "0"]
]
const d = data[0].slice(1,6);
const btcusdtdata = {};
["Open", "High", "Low", "Close", "Volume"].forEach((name,i) => btcusdtdata[name]=+d[i]);
console.log(btcusdtdata)

Sign up to request clarification or add additional context in comments.

7 Comments

Thank you for your answer. Unfortunately it hits me up with an error - here const callIt => SyntaxError: Missing initializer in const declaration in =>
it's all fine thank you. Still I receive some dumb error again Cannot access 'callIt' before initialization I will upload full code in my main question.
that's another problem which appears now is exactly with data.map . Say's that data.map is not a fucntion
Then there is something wrong in the call. Perhaps you reached the limit when you tested
|
0

If you want to perform tasks with fix amount of time in between, a wait function as shown below will come in handy:

const symbols = ["BTCUSDT", "ETHUSDT", "ATOMBTC"];

function wait(ms) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, ms);
  });
}

const j = schedule.scheduleJob("* * * * * *", function () {
  ["BTCUSDT", "ETHUSDT", "ATOMBTC"].forEach((symbol, index) => {
    wait(2000 * index)
      .then(() =>
        fetch(
          `https://api.binance.com/api/v3/klines?symbol=${BTCUSDT}&interval=1h&limit=1`
        )
      )
      .then((res) => res.json())
      .then((data) => {
        console.log(data);
      })
      .catch(e => // do something with the error);
  });
});

If you want to perform async tasks one after another, async/await keywords can help you write cleaner code:

const symbols = ["BTCUSDT", "ETHUSDT", "ATOMBTC"];

const j = schedule.scheduleJob("* * * * * *", async function () {
  for (let i = 0; i < symbols.length; i++) {
    try {
      const symbol = symbols[i];
      const res = await fetch(
        `https://api.binance.com/api/v3/klines?symbol=${BTCUSDT}&interval=1h&limit=1`
      );
      const data = await res.json();
      conosle.log(data);
    } catch (e) { // do something with the error }
  }
});

4 Comments

I strongly recommend to NOT run as an "interval" which is what your first code does. Mine only calls the next fetch if successful return. If you can, add a reject to the promise and a catch to the fetch
Personally I would use the second method (or other async flow control methods) instead of a fixed delay. The first method is only proposed in response to the goal of the question. Errors should always be caught somewhere depending on the desired result. Using setTimeout is not wrong if one understands the logic of the code and know what to expect,
I am not saying setTimeout is wrong. I use it in my own answer. I just recommend to stop if there are issues instead of hammering the server after being rejected
Got it. Your concern is totally valid and I agree that it should be taken into consideration, as a responsible developer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.