摘要
比特币 BTC 作为市值最大的加密货币,7×24 小时不间断交易,对行情采集程序的稳定性要求极高。传统同步 WebSocket 客户端单连接性能有限,本文基于 Python asyncio 异步框架实现高并发行情监听,支持多币种批量订阅,内置心跳、自动重连、协程级异常捕获,数据源采用脉动行情数据 API。
关键词:Python;asyncio;比特币;BTC;WebSocket
一、为什么用 asyncio 替代同步写法
之前很多教程用同步 websocket-client 库写行情监听,问题在于:
- 接收和心跳在不同线程,共享状态需要加锁;
- 多币种订阅时单线程阻塞,消息处理慢;
- 异步生态下,和 FastAPI/Starlette 业务集成不友好。
asyncio 单线程事件循环,无锁、高并发,天然适合 I/O 密集的行情推送场景。
示例币种编码:btcusdt(比特币)、ethusdt(以太坊)、solusdt(Solana)
二、依赖安装
pip install websockets
三、完整异步客户端代码
import asyncio
import json
import time
import logging
import websockets
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s")
logger = logging.getLogger()
# WebSocket真实地址,仅代码内配置
WS_URL = "ws://39.107.99.235/ws"
# 批量订阅
SYMBOL_LIST = "btcusdt,ethusdt,solusdt"
HEARTBEAT_INTERVAL = 10
RECONNECT_DELAY = 3
async def heartbeat(ws):
"""异步心跳协程"""
while True:
try:
ping = json.dumps({"ping": int(time.time())})
await ws.send(ping)
await asyncio.sleep(HEARTBEAT_INTERVAL)
except Exception as e:
logger.error("心跳异常: %s", e)
return
async def receive_loop(ws):
"""异步接收循环"""
async for raw_msg in ws:
try:
data = json.loads(raw_msg)
body = data.get("body")
if not body:
continue
print(
f"[{body.get('Time')}] "
f"{body.get('StockCode')} "
f"价格:{body.get('Price')} "
f"24h高:{body.get('High')} "
f"24h低:{body.get('Low')}"
)
except Exception as e:
logger.error("行情解析异常: %s", e)
async def client():
while True:
try:
async with websockets.connect(WS_URL, ping_interval=None) as ws:
logger.info("WebSocket连接成功,批量订阅: %s", SYMBOL_LIST)
await ws.send(json.dumps({"Key": SYMBOL_LIST}))
# 并发跑心跳和接收
await asyncio.gather(
heartbeat(ws),
receive_loop(ws),
)
except Exception as e:
logger.warning("连接断开: %s,%d秒后重连", e, RECONNECT_DELAY)
await asyncio.sleep(RECONNECT_DELAY)
if __name__ == "__main__":
try:
asyncio.run(client())
except KeyboardInterrupt:
logger.info("服务退出")
四、HTTP 快照异步获取示例
import aiohttp
import asyncio
async def fetch_quote():
url = "http://39.107.99.235:1008/getQuote.php?code=btcusdt,ethusdt"
headers = {"Accept-Encoding": "gzip"}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers, timeout=8) as resp:
data = await resp.text()
print(data)
if __name__ == "__main__":
asyncio.run(fetch_quote())
五、核心字段说明
表格
| 字段 | 说明 |
|---|---|
| StockCode | 币种编码 |
| Price | 最新成交价 |
| Open | 24h 开盘价 |
| High | 24h 最高价 |
| Low | 24h 最低价 |
| BP1 | 买一价 |
| SP1 | 卖一价 |
| TotalVol | 24h 成交量 |
| Time | 更新时间 |
六、生产环境优化
- 加密货币 7×24 小时交易,无休市概念,心跳必须持续发送;
- asyncio 单线程事件循环,不要在消息处理里写 CPU 密集任务,阻塞会拖慢整条链路;
- 高频行情建议直接 gjson 流式解析,避免完整 json.loads 性能损耗;
- 生产环境用 uvicorn 或 gunicorn 部署,配合 systemd 守护;
- 行情数据建议落 ClickHouse 或 InfluxDB,方便回测查询。
七、总结
asyncio 异步方案在加密货币行情采集场景下,单线程即可轻松处理多币种高频推送,和 Python 后端生态无缝集成。修改订阅币种列表,即可扩展到更多加密货币对,适合量化交易、行情监控类项目。