摘要
大宗商品后台开发中,经常需要对接国内商品期货实时行情。WebSocket 长连接开发很容易踩坑:缺少心跳保活、网络断开无自动重连、JSON 报文异常直接造成程序退出。本文使用 python‑websocket‑client 实现完整可运行客户端,支持批量订阅合约,同时提供 HTTP 快照、K 线获取示例,数据源采用脉动行情数据 API。
关键词:Python;WebSocket;国内期货;螺纹钢;铁矿石;行情采集
一、业务痛点
很多网上的 demo 只完成最基础的订阅逻辑,部署到生产环境后暴露出各类稳定性问题:
- 没有定时心跳,空闲一段时间服务端主动关闭连接,程序无感知,不再接收行情;
- 网络抖动断开之后,没有自动重连逻辑,需要人工重启脚本;
- 未对消息解析增加异常捕获,遇到畸形报文直接进程崩溃;
- 没有区分交易时段与休市时段,休市产生大量无效日志输出。
示例合约编码: nf_RB0 螺纹钢,nf_I0 铁矿石,nf_SC0 上海原油,nf_CU0 沪铜
通信约定:连接成功发送订阅报文
{"Key":"合约编码"},多合约逗号分隔;客户端每 10 秒发送
{"ping":10位时间戳}心跳包。
二、依赖安装
pip install websocket-client requests
三、完整 WebSocket 客户端代码
import websocket
import json
import threading
import time
# WebSocket真实服务地址,仅代码内配置
WS_URL = "ws://39.107.99.235/ws"
# 批量订阅螺纹钢、铁矿石
SYMBOL_LIST = "nf_RB0,nf_I0"
def heartbeat_task(ws_conn):
"""10秒心跳守护线程"""
while True:
try:
ping_payload = json.dumps({"ping": int(time.time())})
ws_conn.send(ping_payload)
except Exception:
pass
time.sleep(10)
def on_open(ws):
print("长连接已建立,批量订阅国内期货")
sub_msg = json.dumps({"Key": SYMBOL_LIST})
ws.send(sub_msg)
threading.Thread(target=heartbeat_task, args=(ws,), daemon=True).start()
def on_message(ws, message):
try:
obj = json.loads(message)
if "body" not in obj:
return
body = obj["body"]
print("-" * 60)
print(f"合约:{body['StockCode']} 最新价:{body['Price']}")
print(f"日内最高:{body['High']} 日内最低:{body['Low']}")
print(f"涨跌:{body['Diff']} 涨跌幅:{body['DiffRate']}% 更新时间:{body['Time']}")
print("-" * 60)
except Exception as e:
print(f"行情解析异常: {str(e)}")
def on_close(ws, code, msg):
print(f"连接断开 code={code},3秒后执行自动重连")
time.sleep(3)
start_ws_client()
def start_ws_client():
app = websocket.WebSocketApp(
WS_URL,
on_open=on_open,
on_message=on_message,
on_close=on_close
)
app.run_forever()
if __name__ == "__main__":
start_ws_client()
四、HTTP 快照获取示例(非实时场景)
import requests
url = "http://39.107.99.235:1008/getQuote.php?code=nf_RB0,nf_I0"
headers = {"Accept-Encoding":"gzip"}
resp = requests.get(url, headers=headers, timeout=8)
print(resp.text)
五、K 线历史数据调用示例
import requests
url = "http://39.107.99.235:1008/redis.php?code=nf_RB0&time=1h&rows=200"
resp = requests.get(url, timeout=8)
print(resp.text)
六、返回核心字段
表格
| 字段 | 说明 |
|---|---|
| StockCode | 期货合约编码 |
| Price | 最新成交价 |
| Open | 开盘价 |
| LastClose | 昨结算价 |
| High | 日内最高 |
| Low | 日内最低 |
| Diff | 涨跌数值 |
| DiffRate | 涨跌幅百分比 |
| TotalVol | 当日成交量 |
| Time | 行情更新时间 |
七、生产环境优化要点
- 国内商品期货存在交易日、夜盘、休市,业务层增加交易时段判断,减少无效日志;
- WebSocket 必须按时发送心跳,否则链路会被服务端回收;
- HTTP 接口做好频率控制,避免高频循环请求触发限流;
- 批量合约尽量在一次订阅报文传入全部编码,不要创建多条 WebSocket 连接;
- 正式部署建议输出日志文件,行情数据落库,方便后续回测复盘。
八、总结
本套脚本实现国内商品期货的心跳保活、断线自动重连、异常报文捕获。只需要修改合约编码列表,就可以快速切换沪铜、沪金、原油等其他品种,适合大宗商品监控、量化脚本、行情大屏项目。