4. Python网络编程基础:Socket编程、HTTP请求、WebSocket协议基础
做量化交易,说白了就是跟数据打交道。而数据从哪来?网络。你写的策略再牛,拿不到行情数据也是白搭。这一章,我们就来聊聊Python网络编程里最核心的三个东西:Socket、HTTP和WebSocket。
我个人习惯把网络编程比作「打电话」。Socket就是电话线,HTTP是你说「喂,你好」,WebSocket则是你俩一直通着话,随时能聊。嗯,这个比喻虽然糙,但道理不差。
4.1 Socket编程:最底层的「电话线」
Socket是网络通信的基石。几乎所有上层协议(HTTP、FTP、WebSocket)底层都是Socket。说白了,它就是两个程序之间的一条数据通道。
我在项目中遇到过一个问题:用Socket接收期货行情,结果数据老是丢包。后来发现是缓冲区设得太小了。你想想看,行情数据一秒刷几十次,缓冲区不够用,数据自然就丢了。
核心要点:Socket编程分为TCP和UDP两种。期货行情通常用UDP(速度快,允许少量丢包),交易指令用TCP(必须可靠)。
TCP Socket 示例(客户端)
import socket
# 创建TCP Socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 8888))
# 发送数据
client.send(b'Hello, 行情服务器!')
# 接收数据
data = client.recv(1024)
print(f'收到: {data.decode()}')
client.close()
UDP Socket 示例(接收行情)
import socket
# 创建UDP Socket
udp_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定到本地端口(模拟接收行情)
udp_client.bind(('0.0.0.0', 9999))
while True:
data, addr = udp_client.recvfrom(65535) # 最大UDP包大小
print(f'来自 {addr} 的行情数据: {data[:50]}...')
避坑指南:我曾经在UDP接收时没设超时,结果程序卡死了一整天。记得用 socket.settimeout() 设置超时时间。
4.2 HTTP请求:RESTful API的敲门砖
HTTP请求大家应该不陌生。获取历史K线、查询账户信息,基本都是通过HTTP。Python里最常用的就是 requests 库,简单到令人发指。
但这里有个坑:很多量化平台的HTTP接口有频率限制。我见过有人写了个死循环去拉数据,结果IP直接被封了。嗯,这种事我也干过。
GET请求示例
import requests
url = 'https://api.xxx.com/v1/kline'
params = {
'symbol': 'BTCUSDT',
'interval': '1h',
'limit': 100
}
resp = requests.get(url, params=params, timeout=5)
if resp.status_code == 200:
data = resp.json()
print(f'获取到 {len(data)} 条K线数据')
else:
print(f'请求失败: {resp.status_code}')
POST请求示例(带认证)
import requests
url = 'https://api.xxx.com/v1/order'
headers = {
'X-API-Key': 'your_api_key',
'Content-Type': 'application/json'
}
payload = {
'symbol': 'BTCUSDT',
'side': 'BUY',
'quantity': 0.01
}
resp = requests.post(url, json=payload, headers=headers)
print(resp.json())
注意:千万别把API Key硬编码在代码里!我习惯用环境变量或配置文件来管理。你想想看,代码一上传到GitHub,Key就全暴露了。
4.3 WebSocket协议:实时行情的「高速公路」
HTTP有个致命缺点:你得主动去问服务器「有数据吗?」。服务器说「没有」,你就得等一会儿再问。这叫轮询,效率极低。
WebSocket就不一样了。客户端和服务器建立连接后,服务器可以主动推数据过来。期货行情一秒几十次变化,用WebSocket再合适不过。
我记得第一次用WebSocket接期货行情时,看到数据哗哗地流进来,那种感觉——嗯,就像打开了水龙头。
WebSocket客户端示例
import websocket
import json
def on_message(ws, message):
"""收到消息时的回调"""
data = json.loads(message)
print(f'最新行情: {data["price"]}')
def on_error(ws, error):
print(f'发生错误: {error}')
def on_close(ws, close_status_code, close_msg):
print('连接已关闭')
def on_open(ws):
"""连接建立后,订阅行情"""
subscribe_msg = {
'op': 'subscribe',
'args': ['btcusdt@ticker']
}
ws.send(json.dumps(subscribe_msg))
print('已订阅BTCUSDT实时行情')
# 创建WebSocket连接
ws = websocket.WebSocketApp(
'wss://stream.xxx.com/ws',
on_open=on_open,
on_message=on_message,
on_error=on_error,
on_close=on_close
)
# 启动连接(阻塞运行)
ws.run_forever()
实战技巧:WebSocket连接可能会断开。我习惯在 on_close 里加个自动重连逻辑,比如等待5秒后重新连接。毕竟行情不能断。
4.4 三种方式对比
| 特性 | Socket (TCP/UDP) | HTTP | WebSocket |
|---|---|---|---|
| 通信模式 | 双向 | 请求-响应 | 双向实时 |
| 适用场景 | 低延迟行情、交易指令 | 历史数据、账户查询 | 实时行情、订单推送 |
| 连接开销 | 低 | 高(每次请求新建连接) | 中(一次连接持续使用) |
| 数据格式 | 二进制/自定义 | JSON/XML | JSON/二进制 |
| 可靠性 | TCP可靠,UDP不可靠 | 可靠 | 可靠(基于TCP) |
4.5 知识体系总览
下面这张图,是我梳理的本章知识结构。你可以把它当作一张地图,随时回来对照。
好了,这一章的内容就到这。Socket、HTTP、WebSocket这三个东西,你只要搞懂了,后面写行情采集程序就会顺手很多。记住一点:没有最好的协议,只有最合适的场景。