I'm not sure why im getting this async error in python

Viewed 453

I managed to get my api request asynchronous but then received this error when trying to implement it into the main project. What does this mean that I have done wrong?

ERROR

Exception has occurred: SynchronousOnlyOperation
You cannot call this from an async context - use a thread or sync_to_async.
  File "C:\Users\Admin\Desktop\djangoProjects\dguac\Signal.py", line 124, in main
    await asyncio.wait([sigBuy(count) for count, bot in enumerate(activeBots)])
  File "C:\Users\Admin\Desktop\djangoProjects\dguac\Signal.py", line 126, in <module>
    loop.run_until_complete(main())

I don't understand what this error means and how I would be able to fix it.

Here is my code

async def sigBuy(count):

            bot_dict = Bot.to_dict(activeBots[count])
            sigSettings_dict = Bot.to_dict(activeBots[count].sigSettings)

            # Binance API and Secret Keys
            Bclient = CryptoXLib.create_binance_client(sigSettings_dict['API_key'], sigSettings_dict['API_secret_key'])
            
            p = round(float(percentage(7, bot_dict['ct_balance']) / (float(bin_asset_price['price']) / 1)), 8)
            # Round and Asign the asset_amount
            asset_amount = round(p, 2)

            # shouldILog = await makeBuy(market, asset_amount, Bclient, sigSettings_dict['base_currency'])
            shouldILog = 2
            if shouldILog == 2:
                asset_amount = int(asset_amount)

            last_trade = await Bclient.get_all_orders(pair = Pair(market, sigSettings_dict['base_currency']))
            last_trade = last_trade['response'][-1]
            print(last_trade)

            # asset_price = float(last_trade['cummulativeQuoteQty']) / float(last_trade['executedQty'])
            asset_price = 0.00000123
            buyInPrice = float(last_trade['cummulativeQuoteQty'])

            for otrade in activeBots[count].opentrades.all():
                trade = Bot.to_dict(otrade)
                del trade['id']
                otradesUpdate.append(trade)
            
            openTrades_dict = {'bot_ID': bot_dict['id'], 'date': date, 'market': market, 'trade_mode': 'Buy', 'price': asset_price, 'amount': asset_amount, 'amount_in_base_currency': buyInPrice, 'result': 0}

            otradesUpdate.append(openTrades_dict)
            BotsUpdate.append(bot_dict)
            SigSettingsUpdate.append(sigSettings_dict)

            await Bclient.close()


        async def main():
            await asyncio.wait([sigBuy(count) for count, bot in enumerate(activeBots)])
        
        loop.run_until_complete(main())

2 Answers

await asyncio.wait seemed right since you can have a list of iterables (even though asyncio.wait is supposed to be deprecated iirc) but the exception message kinda threw me off. What OP should've done was wrap around the queryset of the Django ORM and let that execute, but Django's ORM lazy loading can cause some issues.


Wrong original answer

You're not awaiting the correct thing. You mean to await sigBuy but your asyncio.wait is being awaited. In the meantime, you now have a list of coroutines that haven't executed anything.

I recommend you try two things:

  • If you want to run concurrently, keep the list but don't await it. Instead, use asyncio.gather to run them at the same time. asyncio.gather([sigBuy(count) for count, bot in enumerate(activeBots)])
  • If you want to run them one at a time, sure the list comprehension works the same way: [await sigBuy(count) for count, bot in enumerate(activeBots)]

I solved this error by using

    async def main():
        await asyncio.wait([sigBuy(count) for count, bot in enumerate(activeBots)])

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(main())

and also first appended each item in a filtered and prefetched django query to a new activeBots list so the async code would accept it.

Related