如何异步调用函数?币安订单监控程序异步执行异常问题
问题解决:Binance异步订单监控无法执行后续代码
核心问题
你编写的new_position是同步阻塞函数,内部的while死循环会持续占用主线程,导致调用该函数后,后续代码完全没有执行机会。哪怕尝试用async修饰函数,只要内部还是同步API调用+死循环,依然会阻塞事件循环,无法实现后台运行的需求。
修复方案
1. 切换到Binance异步客户端
Binance官方提供了异步版本的客户端,配合asyncio可以避免阻塞主线程,先替换导入:
from binance.asyncio.client import Client as AsyncClient
2. 重构new_position为异步函数
将所有同步Binance调用替换为异步版本,同时在监控循环中加入休眠,避免API限流:
class Position: async def new_position(side, symbol, price, stopl, takep): print('OK') close_side = "SELL" if side == "BUY" else "BUY" # 计算仓位(异步调用) b = await async_client.futures_account_balance() b = pd.DataFrame.from_dict(b) b = b.loc[b['asset']=='USDT'] balance = float(b['balance'].values) * 0.05 q = balance / price * info.laverage # 获取精度参数(异步版本) info_exchange = await async_client.futures_exchange_info() q_size = None price_size = None for item in info_exchange['symbols']: if item['symbol'] == symbol: for f in item['filters']: if f['filterType'] == 'LOT_SIZE': q_size = f['stepSize'] elif f['filterType'] == 'PRICE_FILTER': price_size = f['tickSize'] break # 精度处理 price = round_step_size(float(price), float(price_size)) stopl = round_step_size(float(stopl), float(price_size)) takep = round_step_size(float(takep), float(price_size)) q = round_step_size(q, q_size) take_q = round_step_size(q/2, q_size) # 提交开仓及止盈止损订单(异步) await async_client.futures_change_leverage(symbol=symbol, leverage=info.laverage) buyorder = await async_client.futures_create_order( symbol=symbol, side=side, type="MARKET", quantity=q, isIsolated='TRUE' ) stop = await async_client.futures_create_order( symbol=symbol, side="SELL", type="STOP_MARKET", stopPrice=stopl, closePosition="true" ) take = await async_client.futures_create_order( symbol=symbol, side="SELL", type="TAKE_PROFIT_MARKET", stopPrice=takep, quantity=take_q ) # 异步监控订单状态 while True: orders = await async_client.futures_get_open_orders(symbol=symbol) if len(orders) == 1: try: await async_client.futures_cancel_order( symbol=symbol, orderId=take['orderId'] ) break except Exception as e: print(f"取消订单失败: {e}") break # 每2秒查询一次,避免触发API限流 await asyncio.sleep(2)
3. 异步启动任务,不阻塞后续代码
使用asyncio.create_task启动订单监控任务,主线程会直接跳过任务执行后续代码:
# 初始化异步客户端 async_client = AsyncClient(api_key=info.api, api_secret=info.secret_api, testnet=False) # 启动订单任务,后台运行 asyncio.create_task(Position.new_position("BUY", "BTCUSDT", 30000, 29000, 31000)) # 后续代码会正常执行 print("订单任务已启动,继续执行后续逻辑...")
4. 适配Discord Bot的异步环境
因为你使用的discord.ext.commands.Bot本身基于asyncio,直接在命令函数中使用create_task即可:
@DS.command() async def start_trade(ctx): # 启动后台监控任务 asyncio.create_task(Position.new_position("BUY", "BTCUSDT", 30000, 29000, 31000)) await ctx.send("交易任务已启动") # 此处代码会立即执行,无需等待监控任务结束
关键注意事项
- 必须使用Binance异步客户端,同步客户端的所有调用都会阻塞线程
- 异步循环中必须加入
asyncio.sleep,否则会高频请求API触发限流 - 用
create_task而非直接await,才能让任务后台运行,不阻塞主线程
内容的提问来源于stack exchange,提问作者Wolky
相关产品推荐
相关产品推荐

