Pythonanywhere运行币安异步交易脚本卡在await语句问题求助
问题描述
我尝试在Pythonanywhere.com平台运行如下Python脚本,程序运行时卡在main函数while循环内的await语句处,但该代码在本地电脑上可无错误正常运行。
代码片段
async def main(coin, minQty, minNotional, histdata, open_position=False, cross_below=True, gotbalance=False): bm = BinanceSocketManager(client) ts = bm.trade_socket(coin) last_high = 0 async with ts as tscm: while True: res = await tscm.recv() if res: frame = createframe(res) if last_high < frame.Price[0]: last_high = frame.Price[0]
完整代码
import nest_asyncio import asyncio import pandas as pd from binance import BinanceSocketManager from binance.client import Client from keys import api_key, api_secret import numpy as np from datetime import datetime import winsound import urllib.request nest_asyncio.apply() client = Client(api_key, api_secret) ST = 7 LT = 25 coin = 'BTCUSDT' def gethistoricals(symbol, LT): df = pd.DataFrame(client.get_historical_klines(symbol, '5m', str((LT - 1) * 5) + 'mins ago UTC')) df = df.iloc[:, :6] df.columns = ['Timestamp', 'Open', 'High', 'Low', 'Close', 'Volume'] df.Open = df.Open.astype('float') df.High = df.High.astype('float') df.Low = df.Low.astype('float') df.Close = df.Close.astype('float') df.Volume = df.Volume.astype('float') df['ST'] = df.Close.rolling(ST - 1).mean() df['LT'] = df.Close.rolling(LT - 1).mean() high_low = df['High'] - df['Low'] high_close = np.abs(df['High'] - df['Close'].shift()) low_close = np.abs(df['Low'] - df['Close'].shift()) ranges = pd.concat([high_low, high_close, low_close], axis=1) true_range = np.max(ranges, axis=1) df['ATR'] = true_range.rolling(14).sum()/14 df['Datetime'] = df['Timestamp'].iloc[-1] df.Datetime = pd.to_datetime(df.Datetime, unit='ms') df.dropna(inplace=True) # print(df) return df def liveSMA(hist, live): liveST = (hist['ST'].values + live.Price.values) / ST liveLT = (hist['LT'].values + live.Price.values) / LT return liveST, liveLT def createframe(msg): df = pd.DataFrame([msg]) df = df.loc[:, ['E', 's', 'E', 'p']] df.columns = ['Timestamp', 'symbol', 'Time', 'Price'] df.Price = df.Price.astype(float) df.Time = pd.to_datetime(df.Time, unit='ms') return df pnl = [] async def main(coin, minQty, minNotional, histdata, open_position=False, cross_below=True, gotbalance=False): bm = BinanceSocketManager(client) ts = bm.trade_socket(coin) last_high = 0 async with ts as tscm: while True: res = await tscm.recv() if res: frame = createframe(res) if last_high < frame.Price[0]: last_high = frame.Price[0] last_hist_time = datetime.strptime( str(np.datetime_as_string(histdata['Datetime'].values[0], unit='ms')), '%Y-%m-%dT%H:%M:%S.%f') if int((frame.Time[0] - last_hist_time).total_seconds()) >= 305: histdata = gethistoricals(coin, LT) livest, livelt, atr = histdata['ST'].values, histdata['LT'].values, histdata['ATR'].values try: if not open_position: if not gotbalance: balance = client.get_asset_balance(asset='USDT') balance = float(balance['free'])*0.95 gotbalance = True if balance >= minNotional: qty = round(balance/frame.Price[0], 5) print(qty) print(livest[0] > livelt[0], cross_below, qty >= minQty) else: print('Minimum Notional Error') if livest[0] > livelt[0] and cross_below and qty >= minQty: order = client.create_order(symbol=coin, side='BUY', type='MARKET', quantity=qty) print(order) buyprice = float(order['fills'][0]['price']) winsound.Beep(1000, 100) open_position = True cross_below = False if open_position: if frame.Price[0] < (last_high - (2 * atr[0])) or livest[0] < livelt[0]: print(f'SL Trigger: {frame.Price[0] < (last_high - (2 * atr[0]))}') print(f'Cross Trigger: {livest[0] < livelt[0]}') order = client.create_order(symbol=coin, side='SELL', type='MARKET', quantity=qty) print(order) sellprice = float(order['fills'][0]['price']) winsound.Beep(1000, 100) open_position = False print(f'PnL : {(buyprice - sellprice) / buyprice}') pnl.append((buyprice - sellprice) / buyprice) print(f'Mean PnL : {np.mean(pnl)}') if livest[0] < livelt[0]: cross_below = True except Exception as e: print(e) if __name__ == "__main__": winsound.Beep(1000, 100) info = client.get_symbol_info(coin) # print(info) minQty = float(info['filters'][2]['minQty']) minNotional = float(info['filters'][3]['minNotional']) historicals = gethistoricals(coin, LT) loop = asyncio.get_event_loop() loop.run_until_complete(main(coin, minQty, minNotional, historicals))
原因与解决方案
核心原因
- winsound是Windows平台专属库,Pythonanywhere服务器为Linux系统,导入该库会直接触发运行错误,本地Windows环境无此问题。
- Pythonanywhere免费账户的出站网络做了限制,仅允许白名单站点的HTTP/HTTPS请求走官方代理,币安WebSocket接口使用wss协议,不受免费层支持,会导致连接无法建立,
await tscm.recv()进入无限等待状态。 - Binance客户端未设置超时参数,网络不通时会无限等待返回。
修复步骤
- 移除所有winsound相关代码,包括
import winsound和所有winsound.Beep()调用,适配Linux运行环境。 - 初始化客户端时增加超时参数,避免无限制等待:
client = Client(api_key, api_secret, requests_params={'timeout': 30})
- 给WebSocket接收逻辑增加超时处理,卡住时自动触发重连:
# 替换原来的res = await tscm.recv() try: res = await asyncio.wait_for(tscm.recv(), timeout=30) except asyncio.TimeoutError: print("WebSocket连接超时,准备重连") break
- 如果使用Pythonanywhere免费账户,升级到付费套餐解锁全端口出站权限,免费层不支持自定义WebSocket连接。
内容的提问来源于stack exchange,提问作者Ajay Ramprasad
相关产品推荐
相关产品推荐

