作为一名在量化交易领域摸爬滚打 3 年的开发者,我第一次接触交易所 API 时完全懵了——HMAC 是什么?为什么要签名? nonce 参数怎么填?本文用最通俗的语言,从零讲解加密交易所的 API 认证原理,手把手教你写出第一个能调通交易所接口的代码,并分享我自己踩过的安全坑。
一、先搞懂:为什么交易所要用 HMAC 签名?
想象一下,你给交易所发了一条"把我的 10000 块转给张三"的请求。如果这条请求被黑客在半路截获并篡改成"转给黑客",交易所怎么知道这是不是你本人发的?
HMAC 签名就是解决这个问题的"数字指纹"技术:
- 发送前:用你的密钥 + 请求内容,通过特殊算法生成一个"签名"
- 发送时:把原始请求 + 签名一起发过去
- 收到后:交易所用同样的密钥 + 请求内容,重新算一个签名,和你发来的比对
- 结果:如果签名对不上,说明内容被篡改过,直接拒绝
简单说:HMAC 签名 = 防篡改 + 证明"这条请求是我本人发的"
二、实战准备:获取你的第一个 API Key
我们以币安(Binance)为例,这是国内用户最常用的交易所。
2.1 创建 API Key 步骤
- 登录币安官网,点击右上角【用户中心】→【API 管理】
- (文字模拟截图:显示 API 管理页面)
- 点击【创建 API】,选择【系统生成】
- (文字模拟截图:显示密钥生成中)
- 保存好 API Key 和 Secret Key,关闭页面后 Secret Key 将不再显示
⚠️ 重要提醒:Secret Key 只显示一次!立刻复制保存到本地备忘录(后面代码要用)。
2.2 API Key 权限设置
交易所 API 通常有以下权限级别:
- 只读权限:只能查询账户余额、行情数据,不能下单交易
- 交易权限:可以买卖下单、撤单
- 提币权限:可以将资产转出——强烈建议关闭
对于新手练习,只开只读权限,等熟悉了再加交易权限。提币权限永远不要开!
三、Python 实战:30 行代码调通第一个交易所 API
下面用 Python 实现一个最简单的例子:查询账户余额。
import hashlib
import hmac
import time
import requests
========== 1. 填写你的密钥(替换成你自己的)==========
API_KEY = "YOUR_BINANCE_API_KEY"
SECRET_KEY = "YOUR_BINANCE_SECRET_KEY"
========== 2. 基础配置 ==========
BASE_URL = "https://api.binance.com"
ENDPOINT = "/api/v3/account"
def create_signature(params, secret_key):
"""
生成 HMAC-SHA256 签名
params: 参数字典,如 {'timestamp': '1234567890'}
secret_key: 你的密钥
"""
# 将参数拼接成 query string 格式
query_string = "&".join([f"{k}={v}" for k, v in params.items()])
# 使用 HMAC-SHA256 生成签名
signature = hmac.new(
secret_key.encode('utf-8'), # 密钥转成字节
query_string.encode('utf-8'), # 待签名内容
hashlib.sha256 # 算法:SHA256
).hexdigest()
return signature
def get_account_balance():
"""
查询账户余额(需要有读取权限的 API Key)
"""
# ========== 3. 构造请求参数 ==========
timestamp = int(time.time() * 1000) # 当前时间戳(毫秒)
params = {
'timestamp': timestamp,
'recvWindow': 5000 # 请求有效期,单位毫秒
}
# ========== 4. 生成签名 ==========
signature = create_signature(params, SECRET_KEY)
params['signature'] = signature
# ========== 5. 发送请求 ==========
headers = {
'X-MBX-APIKEY': API_KEY,
'Content-Type': 'application/json'
}
url = f"{BASE_URL}{ENDPOINT}"
response = requests.get(url, headers=headers, params=params)
return response.json()
========== 6. 执行查询 ==========
if __name__ == "__main__":
result = get_account_balance()
print("查询结果:", result)
运行代码,如果看到类似这样的输出,说明你成功了:
查询结果:{
'balances': [
{'asset': 'BTC', 'free': '0.00123400', 'locked': '0.00000000'},
{'asset': 'USDT', 'free': '100.50000000', 'locked': '0.00000000'},
{'asset': 'ETH', 'free': '0.05000000', 'locked': '0.00000000'}
]
}
四、签名算法原理详解
有些读者可能还是觉得公式太抽象,我用做菜来类比 HMAC 签名的过程:
- 食材(待签名内容)= 你的请求参数 + 时间戳
- 秘方(密钥)= 你的 SECRET_KEY
- 烹饪方式(算法)= SHA256
- 成品(签名)= HMAC-SHA256(秘方, 食材)
同样的食材和秘方,做出来的菜味道固定。别人不知道秘方,就算知道食材,也做不出一样的菜。这就是 HMAC 签名安全的核心原理。
4.1 常见签名算法对比
| 交易所 | 算法 | 签名示例 | 难度 |
|---|---|---|---|
| 币安 Binance | HMAC-SHA256 | 64位十六进制字符串 | ⭐ 简单 |
| OKX | HMAC-SHA256 / RSA | 64位十六进制字符串 | ⭐⭐ 中等 |
| Bybit | HMAC-SHA256 | 64位十六进制字符串 | ⭐ 简单 |
| Bitget | HMAC-SHA256 | 64位十六进制字符串 | ⭐ 简单 |
| Deribit | RSA / HMAC-SHA256 | Base64字符串 | ⭐⭐⭐ 复杂 |
大部分主流交易所都用 HMAC-SHA256,这个搞懂了,其他触类旁通。
五、API Key 安全管理:5 个我踩过的坑
做量化交易 3 年,我的 API Key 泄露过两次,都是血泪教训。以下是具体防护方案:
5.1 坑一:硬编码密钥到代码里
❌ 错误写法:
# 千万不要这样做!代码上传到 GitHub 就全网暴露了
API_KEY = "binance_api_key_xxx"
SECRET_KEY = "binance_secret_xxx"
✅ 正确写法:使用环境变量
import os
从环境变量读取,永不硬编码
API_KEY = os.environ.get('BINANCE_API_KEY')
SECRET_KEY = os.environ.get('BINANCE_SECRET_KEY')
或者使用 .env 文件(需要 python-dotenv 库)
from dotenv import load_dotenv
load_dotenv()
API_KEY = os.getenv('BINANCE_API_KEY')
5.2 坑二:IP 白名单不设置
交易所后台允许设置"仅允许以下 IP 调用此 API"。新手往往忽略这个。
建议:如果你的程序跑在固定服务器上,一定加上 IP 白名单限制。这样即使密钥泄露,攻击者也无法使用。
5.3 坑三:权限控制太宽松
我曾经开了一个带"提币权限"的 API Key 做测试,结果账号差点被盗。后来严格遵守"只读权限用于数据查询,交易权限单独申请,提币权限永远不开"的原则。
5.4 坑四:签名有效期太长
有些新手把 recvWindow 设置成 60000(60秒),这其实有安全隐患。正常情况下 5000ms(5秒)足够,如果网络慢再适当延长。
5.5 坑五:日志打印敏感信息
# 错误:日志里打印了密钥
print(f"使用密钥 {SECRET_KEY} 签名")
print(f"请求参数: {params}")
正确:只打印非敏感信息
print(f"请求时间戳: {timestamp}")
print(f"签名生成成功,长度: {len(signature)}")
六、实战进阶:完整下单交易流程
查询只是基础,下面演示如何用 API 下单买入 BTC。理解了签名原理,下单只是多几个参数:
import hashlib
import hmac
import time
import requests
API_KEY = "YOUR_BINANCE_API_KEY"
SECRET_KEY = "YOUR_BINANCE_SECRET_KEY"
BASE_URL = "https://api.binance.com"
def create_signature(params, secret_key):
"""生成 HMAC-SHA256 签名"""
query_string = "&".join([f"{k}={v}" for k, v in params.items()])
signature = hmac.new(
secret_key.encode('utf-8'),
query_string.encode('utf-8'),
hashlib.sha256
).hexdigest()
return signature
def place_market_buy_order(symbol, quantity):
"""
市价买入
symbol: 交易对,如 'BTCUSDT'
quantity: 数量,如 '0.001'
"""
endpoint = "/api/v3/order"
timestamp = int(time.time() * 1000)
params = {
'symbol': symbol, # 交易对
'side': 'BUY', # 买入
'type': 'MARKET', # 市价单
'quantity': quantity, # 数量
'timestamp': timestamp,
'recvWindow': 5000
}
# 生成签名
signature = create_signature(params, SECRET_KEY)
params['signature'] = signature
headers = {
'X-MBX-APIKEY': API_KEY
}
url = f"{BASE_URL}{endpoint}"
response = requests.post(url, headers=headers, params=params)
return response.json()
========== 下单示例 ==========
result = place_market_buy_order('BTCUSDT', '0.001')
print("下单结果:", result)
如果返回包含 "orderId",说明下单成功!
下单结果: {
'orderId': 123456789,
'symbol': 'BTCUSDT',
'status': 'FILLED',
'executedQty': '0.001',
'cummulativeQuoteQty': '650.50'
}
七、常见报错排查
新手最容易遇到的 5 个报错,我都遇到过并给出解决方案:
7.1 错误一:Signature validation failed
{
"code": -1022,
"msg": "Signature for this request was not valid."
}
原因:签名计算错误
排查步骤:
- 检查 SECRET_KEY 是否正确(前后没有多余空格)
- 确认参数是按字母顺序排列拼接的
- 检查时间戳格式是否正确(需要毫秒级整数)
解决代码:
# 调试技巧:打印签名过程,确认每一步正确
query_string = "&".join([f"{k}={v}" for k, v in sorted(params.items())])
print(f"Query String: {query_string}")
print(f"Secret Key: {SECRET_KEY}")
signature = hmac.new(
SECRET_KEY.encode('utf-8'),
query_string.encode('utf-8'),
hashlib.sha256
).hexdigest()
print(f"Signature: {signature}")
7.2 错误二:Timestamp for this request is outside of recvWindow
{
"code": -1021,
"msg": "Timestamp for this request is outside of recvWindow."
}
原因:本地时间与交易所服务器时间偏差太大
解决:增加 recvWindow 或校准本地时间
# 方案1:增加有效期到10秒
params['recvWindow'] = 10000
方案2:校准时间(获取服务器时间后计算偏移量)
server_time_response = requests.get(f"{BASE_URL}/api/v3/time")
server_time = server_time_response.json()['serverTime']
local_time = int(time.time() * 1000)
time_offset = server_time - local_time
之后所有时间戳加上偏移量
params['timestamp'] = int(time.time() * 1000) + time_offset
7.3 错误三:API key not found
{
"code": -2015,
"msg": "Invalid API-key, IP, or permissions for action."
}
原因:API Key 无效或权限不足
排查:
- 检查 API Key 是否复制完整(没有遗漏首尾字符)
- 确认 API Key 已启用(有些创建后需要邮件激活)
- 确认当前 IP 在白名单内
7.4 错误四:参数格式错误
{
"code": -1102,
"msg": "Mandatory parameter 'symbol' was not sent, was empty/null, or malformed."
}
解决:确认参数名称和类型完全正确
# 常见错误:数量精度问题
币安要求 BTC 数量最多 8 位小数,USDT 现货最多 2 位
错误写法
quantity = 0.001234567 # 超过8位,可能报错
正确写法
quantity = "0.00123456" # 用字符串,精确控制位数
7.5 错误五:Reach maximum api request rate
{
"code": -1003,
"msg": "Too many requests; current limit is X requests per minute."
}
原因:请求频率超限
解决:添加请求间隔
import time
每次请求间隔 0.1 秒
time.sleep(0.1)
或者使用 requests 自带的延迟
response = requests.get(url, headers=headers, params=params, timeout=10)
八、给开发者的建议
做加密 API 开发这几年,我的经验是:
- 先读官方文档:每个交易所的错误码文档写得很清楚
- 用测试网练手:币安有测试网,模拟交易不花真钱
- 做好错误重试:网络不稳定时自动重试 3 次
- 记录完整日志:每次请求的参数、响应、时间戳,方便排查问题
- 密钥轮换:每 3 个月换一次 API Key
如果你在开发过程中需要调用 AI 接口做市场分析、情绪判断、新闻解读等,建议使用 立即注册 HolySheep AI。这个平台对国内开发者非常友好:
- 汇率优势:¥1 = $1 无损,而官方汇率 ¥7.3 = $1,节省超过 85%
- 支付便捷:支持微信、支付宝直接充值
- 速度飞快:国内直连延迟 < 50ms,交易所套利策略完全跟得上
- 模型齐全:DeepSeek V3.2 仅 $0.42/MTok,GPT-4.1 $8/MTok,Claude Sonnet 4.5 $15/MTok
我用 HolySheep 的 GPT-4.1 做策略回测分析,配合币安的行情数据,一套完整的量化交易系统成本比自己部署低很多。
九、完整代码模板
import hashlib
import hmac
import time
import requests
from typing import Dict, Optional
import logging
配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class BinanceAPI:
"""币安 API 封装类"""
def __init__(self, api_key: str, secret_key: str, testnet: bool = False):
self.api_key = api_key
self.secret_key = secret_key
self.base_url = "https://testnet.binance.vision" if testnet else "https://api.binance.com"
self.time_offset = 0
self._sync_time()
def _sync_time(self):
"""同步服务器时间,避免时间戳错误"""
try:
resp = requests.get(f"{self.base_url}/api/v3/time", timeout=5)
server_time = resp.json()['serverTime']
self.time_offset = server_time - int(time.time() * 1000)
logger.info(f"时间同步完成,偏移量: {self.time_offset}ms")
except Exception as e:
logger.warning(f"时间同步失败: {e},使用本地时间")
def _create_signature(self, params: Dict) -> str:
"""生成签名"""
query_string = "&".join([f"{k}={v}" for k, v in sorted(params.items())])
return hmac.new(
self.secret_key.encode('utf-8'),
query_string.encode('utf-8'),
hashlib.sha256
).hexdigest()
def _request(self, method: str, endpoint: str, params: Optional[Dict] = None) -> Dict:
"""发送请求(带重试机制)"""
params = params or {}
params['timestamp'] = int(time.time() * 1000) + self.time_offset
params['recvWindow'] = 5000
params['signature'] = self._create_signature(params)
headers = {'X-MBX-APIKEY': self.api_key}
url = f"{self.base_url}{endpoint}"
for attempt in range(3):
try:
if method == 'GET':
resp = requests.get(url, headers=headers, params=params, timeout=10)
else:
resp = requests.post(url, headers=headers, params=params, timeout=10)
result = resp.json()
# 检查错误码
if 'code' in result and result['code'] < 0:
logger.error(f"API错误: {result}")
return result
return result
except requests.exceptions.RequestException as e:
logger.warning(f"请求失败(第{attempt+1}次): {e}")
time.sleep(1)
return {'error': '请求失败,请检查网络'}
def get_balance(self) -> Dict:
"""获取账户余额"""
return self._request('GET', '/api/v3/account')
def get_klines(self, symbol: str, interval: str, limit: int = 100) -> Dict:
"""获取K线数据"""
params = {'symbol': symbol, 'interval': interval, 'limit': limit}
return self._request('GET', '/api/v3/klines', params)
def place_order(self, symbol: str, side: str, order_type: str, quantity: str, **kwargs) -> Dict:
"""下单"""
params = {
'symbol': symbol,
'side': side,
'type': order_type,
'quantity': quantity,
**kwargs
}
return self._request('POST', '/api/v3/order', params)
========== 使用示例 ==========
if __name__ == "__main__":
# 初始化(替换为你的密钥)
client = BinanceAPI(
api_key="YOUR_API_KEY",
secret_key="YOUR_SECRET_KEY",
testnet=True # 测试网模式
)
# 查询余额
balance = client.get_balance()
print("余额:", balance)
# 获取K线
klines = client.get_klines('BTCUSDT', '1h', limit=10)
print("K线数据:", klines)
十、总结
加密交易所 API 认证的核心就两件事:
- 理解签名原理:用密钥对参数进行 HMAC-SHA256 签名,交易所验签确认身份
- 保护好密钥:不硬编码、加 IP 白名单、权限最小化、定期轮换
对于需要 AI 能力辅助交易的开发者,立即注册 HolySheep AI 是一个高性价比的选择。汇率比官方低 85%,微信支付宝秒充,国内延迟 < 50ms,新用户还送免费额度。配合本文的代码模板,你可以快速搭建起自己的量化交易系统。
代码有问题欢迎留言交流,祝各位开发顺利!
👉 免费注册 HolySheep AI,获取首月赠额度