1

I'm building a trading bot that needs to get stock names from separate files. But even I have used async function and await in my code, that doesn't work.

My index file init method.

const init = async () => {
    const symbols = await getDownTrendingStock();
    console.log("All stocks that are down: " + symbols);

    const doOrder = async () => {
        //do stuff
    }
    doOrder();
}

my getDownTrendeingStock file

const downStocks = []

function getDownTrendingStock () {
        for(i = 0; i < data.USDTPairs.length; i++){
      
            const USDTPair = data.USDTPairs[i] + "USDT";
      
            binance.prevDay(USDTPair, (error, prevDay, symbol) => {
                  if(prevDay.priceChangePercent < -2){
                      downStocks.push(symbol)
                  }
                 });
          }
          return downStocks;
}

I have tried to also use async in for loop because the getDownTrendinStock function returns an empty array before for loop is finished. I didn't find the right way to do that because I was confused with all async, promise and callback stuff. What is the right statement to use in this situation?

Output:

All stocks that are down: 

Wanted output:

All stocks that are down: [BTCUSDT, TRXUSDT, ATOMUSDT...]
Oskari Lehtonen
  • 629
  • 5
  • 4
  • `getDownTrendingStock()` needs to return a promise. The callback of `binance.prevDay` is asynchronous – Bergi Feb 13 '21 at 12:20

2 Answers2

1

I think the main issue in the code you posted is that you are mixing callbacks and promises.

This is what's happening in your getDownTrendingStock function:

  1. You start iterating over the data.USDTPairs array, picking the first element
  2. You call binance.prevDay. This does nothing yet, because its an asynchronous function that takes a bit of time. Notably, no data is added to downStocks yet.
  3. You continue doing 1-2, still, no data is added
  4. You return downStocks, which is still empty.
  5. Your function is complete, you print the empty array

Now, at some point, the nodejs event loop continues and starts working on those asynchronous tasks you created earlier by calling binance.prevDay. Internally, it probably calls an API, which takes time; once that call is completed, it calls the function you provided, which pushes data to the downStocks array.

In summary, you didn't wait for the async code to complete. You can achieve this in multiple ways.

One is to wrap this in a promise and then await that promise:

const result= await new Promise((resolve, reject) => {
    binance.prevDay(USDTPair, (error, prevDay, symbol) => {
                  if (error) {
                     reject(error);
                  } else {
                     resolve({prevDay, symbol});
                  }
    });
});

if(result.prevDay.priceChangePercent < -2){
     downStocks.push(result.symbol)
}

Note that you can probably also use promisify for this. Also, this means that you will wait for one request to finish before starting the next, which may slow down your code considerably, depending on how many calls you need; you may want to look into Promise.all as well.

Oliver
  • 136
  • 5
  • Ah, you're right, I confused the placement. Thanks! I edited the post and moved the result part out of the promise. – Oliver Feb 13 '21 at 11:36
  • When I try try to use this, I will get UnhandledPromiseRejectionWarning for not using .catch() any idea for that? – Oskari Lehtonen Feb 13 '21 at 15:54
  • Either put a try/catch around your call to init and log the error to see what is going wrong, or add a catch() call behind your init call. The latter, you can do like this: `init().catch((error) => console.log(error));`. – Oliver Feb 15 '21 at 18:07
1

Generally speaking, I use two technics:

const asyncFunc = () => {smthAsync};
const arrayToProcess = [];

// 1
const result = await arrayToProcess.reduce((acc, value) => acc.then(() => asyncFunc(value)), Promise.resolve(someInitialValue));

// 2
// here will be eslint errors
for(let i = 0 i < arrayToProcess.length; i+=1) {
  const processResult = await asyncFunc(value);
  // do with processResult what you want
};
Dharman
  • 30,962
  • 25
  • 85
  • 135
A Ralkov
  • 1,046
  • 10
  • 19