0

I am attempting to build a bot that will periodically poll an API using axios for the price of multiple cryptocurrencies across multiple exchanges. I need to be able to then look at this stored data to analyse price differences of a given token between multiple exchanges to calculate if there is profit to be made if I were to purchase it on one and then sell on another.

So far I am able to get access to the price data and console.log it as the request is returned, however I need to add this data to an array so that it can be analysed at a later point. I understand that I will need to use promises to handle this but I find it slightly confusing.

The following code immediately outputs an empty array and then outputs all the individual prices. How can I gain access to those values at a later point in the code?

const axios = require('axios');
const { exchanges } = require('./resources/exchanges.json');
const { currencies } = require('./resources/currencies.json');

const buyCurrency = currencies.buy[0];

const poll = async () => {
    const data = new Array();

    await currencies.sell.forEach(async sellCurrency => {
        await exchanges.forEach(async exchange => {
            try {
                const allOtherExchanges = exchanges.filter(x => x !== exchange).map(x => `,${x}`).join();
                const response = await axios.get(`https://api.0x.org/swap/v1/quote?buyToken=${buyCurrency}&sellToken=${sellCurrency}&sellAmount=1000000000000000000&excludedSources=0x${allOtherExchanges}`)
                if (response && response.data.price) {
                    console.log(exchange, sellCurrency, response.data.price)
                    data.push({
                        exchange,
                        price: response.data.price
                    });
                }
            } catch {}
        });
    });
    
    console.log(data);
};

poll()
J. Whitehead
  • 451
  • 4
  • 21
  • 1
    If you want to do the requests in parallel, take a look at `Promise.all`. If you want to do them one after each other use a classic `for` loop instead of `forEach` (forEach won't wait until a promise from a callback is resolved, it only calls them one after each other and then continues) – A_A Aug 28 '21 at 16:55
  • 1
    `await currencies.sell.forEach` understand that `await`ing a non-Promise doesn't do anything (`forEach` doesn't return anything at all). You want `await Promise.all(currencies.sell.map(...));`. Note that you'll have to repeat the same pattern on the interior function. – Jared Smith Aug 28 '21 at 16:55
  • 1 - `async/await` in a forEach callback rarely does what you expect, two nested async/await forEach works twice as bad - 2. since `forEach` returns `undefined`, immediately, which is not a Promise, `await x.forEach` doesn't even make sense – Bravo Aug 28 '21 at 16:59
  • Just use a normal for loop. Its not jQuery, you dont need `forEach` – Evert Aug 28 '21 at 17:14
  • Does this answer your question? [Using async/await with a forEach loop](https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop) – Evert Aug 28 '21 at 17:17

1 Answers1

1

One of the solutions would be as follows:

const axios = require('axios');
const { exchanges } = require('./resources/exchanges.json');
const { currencies } = require('./resources/currencies.json');

const buyCurrency = currencies.buy[0];
const poll = async () => {
    const data = new Array();
    const promises = [];

    currencies.sell.forEach(sellCurrency => {
        exchanges.forEach(exchange => {
            const allOtherExchanges = exchanges.filter(x => x !== exchange).map(x => `,${x}`).join();
            promises.push(
                axios.get(`https://api.0x.org/swap/v1/quote?buyToken=${buyCurrency}&sellToken=${sellCurrency}&sellAmount=1000000000000000000&excludedSources=0x${allOtherExchanges}`)
                .then(response => {
                    if (response && response.data &&response.data.price) {
                        console.log(exchange, sellCurrency, response.data.price)
                        data.push({
                            exchange,
                            price: response.data.price
                        });
                    }
                }).catch(err => console.error(err))
            );
        });
    });
    await Promise.all(promises);
    console.log(data);
};
poll();
Praveen Tamil
  • 1,076
  • 11
  • 22
  • You could return `{ exchange, price: response.data.price }` and then use `const data = await Promise.all(promises)`. This would assure the order (and imo is cleaner) – A_A Aug 28 '21 at 17:13
  • 1
    Yes, you are maybe right. But in the response, he checks for the price key and pushes that item only if the price key exists. – Praveen Tamil Aug 28 '21 at 17:16