4. REST API实战:使用requests库发送GET/POST请求、处理签名认证、解析JSON响应
做市机器人跟交易所打交道,最基础的就是REST API。说白了,就是通过HTTP协议给交易所服务器发指令——查余额、下订单、撤单,全得靠它。我个人习惯把REST API比作「交易所的门卫」,你递上正确的证件(签名),它才让你进门办事。
4.1 准备工作:安装requests库
Python自带的urllib也能发HTTP请求,但用起来太啰嗦。我建议直接用requests库,代码简洁得多。安装就一行命令:
pip install requests
嗯,这里要注意:如果你在虚拟环境里做开发,记得先激活环境再装。我在项目中遇到过有人装到了全局环境,结果项目跑起来报错找不到模块,排查了半天才发现是环境搞混了。
4.2 发送GET请求:查行情、查账户
GET请求通常用来获取数据,比如查最新价格、查账户余额。拿币安的现货行情接口举个例子:
import requests
# 查BTC/USDT的最新价格
url = "https://api.binance.com/api/v3/ticker/price"
params = {"symbol": "BTCUSDT"}
response = requests.get(url, params=params)
print(response.json())
# 输出:{'symbol': 'BTCUSDT', 'price': '50000.00'}
为什么会这样?因为requests库会自动把params字典拼接到URL后面,变成?symbol=BTCUSDT。你想想看,如果手动拼接字符串,万一参数里有特殊字符还得做URL编码,多麻烦。
查账户余额就需要API Key了。交易所会给你一对密钥:
- API Key:相当于你的用户名,明文传输
- Secret Key:相当于你的密码,用来签名,绝不能泄露
api_key = "你的API_KEY"
secret_key = "你的SECRET_KEY"
headers = {"X-MBX-APIKEY": api_key}
url = "https://api.binance.com/api/v3/account"
response = requests.get(url, headers=headers)
print(response.json())
注意:这里只是演示,实际生产环境绝对不能把密钥硬编码在代码里。我曾经见过有人把密钥提交到GitHub,几分钟内账户就被盗了。建议用环境变量或配置文件来管理。
4.3 发送POST请求:下单、撤单
POST请求用来提交数据,比如下订单。下单接口通常需要签名认证,因为涉及资金操作。看一个币安的下单示例:
import requests
import hashlib
import hmac
import time
api_key = "你的API_KEY"
secret_key = "你的SECRET_KEY"
# 构造请求参数
params = {
"symbol": "BTCUSDT",
"side": "BUY",
"type": "LIMIT",
"timeInForce": "GTC",
"quantity": "0.001",
"price": "50000",
"timestamp": int(time.time() * 1000)
}
# 生成签名
query_string = "&".join([f"{k}={v}" for k, v in params.items()])
signature = hmac.new(
secret_key.encode(),
query_string.encode(),
hashlib.sha256
).hexdigest()
params["signature"] = signature
headers = {"X-MBX-APIKEY": api_key}
url = "https://api.binance.com/api/v3/order"
response = requests.post(url, headers=headers, data=params)
print(response.json())
这里有个关键点:timestamp参数必须是毫秒级时间戳。交易所会用这个时间戳来防止重放攻击——如果请求时间跟服务器时间差太多,会被直接拒绝。我建议每次请求前都同步一下服务器时间,避免因本地时钟偏差导致签名失败。
4.4 签名认证的核心逻辑
签名认证说白了就是「证明你是你」。交易所给你Secret Key,你用它对请求参数做HMAC-SHA256哈希,生成一个签名。服务器收到请求后,用同样的Secret Key重新算一遍签名,如果一致就放行。
整个流程可以用这张图来理解:
4.5 解析JSON响应
交易所返回的数据基本都是JSON格式。requests库的.json()方法可以直接把响应体解析成Python字典或列表,用起来非常方便。
response = requests.get(url, params=params)
data = response.json()
# 检查是否成功
if "code" in data and data["code"] != 0:
print(f"请求失败:{data['msg']}")
else:
print(f"当前价格:{data['price']}")
但有个坑要注意:不是所有响应都是200状态码。比如参数错误会返回400,签名错误会返回401,频率超限会返回429。我建议每次请求都检查状态码:
if response.status_code != 200:
print(f"HTTP错误:{response.status_code}")
print(f"错误详情:{response.text}")
# 根据错误码做相应处理
if response.status_code == 429:
time.sleep(60) # 频率限制,等一分钟再试
elif response.status_code == 401:
# 签名过期或密钥错误,需要重新生成签名
pass
response.text打印出来看看原始响应内容。有时候JSON解析失败,是因为交易所返回了HTML格式的错误页面。我遇到过好几次,都是因为请求头没加User-Agent被WAF拦截了。
4.6 实战中的常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 签名验证失败 | 参数顺序不一致、时间戳偏差 | 用OrderedDict排序参数,同步服务器时间 |
| 请求被限频 | 短时间内请求太多 | 加sleep延迟,或者用WebSocket替代 |
| JSON解析报错 | 响应不是JSON格式 | 先打印response.text排查 |
| 连接超时 | 网络问题或交易所挂了 | 设置timeout参数,加重试机制 |
嗯,最后说一句:REST API虽然简单,但做市机器人对延迟要求很高。我个人建议把REST API只用来做非高频操作(比如查余额、设置参数),真正的下单撤单还是用WebSocket更靠谱。不过那是后面章节的内容了,先把REST API玩熟再说。
- GET请求查数据,POST请求写数据
- 签名认证用HMAC-SHA256,注意参数顺序和时间戳
- 解析JSON用
.json(),但别忘了检查状态码 - 密钥绝不能硬编码,用环境变量管理