python-okx 实战:从密钥配置到 WebSocket 行情,OKX v5 交易系统的完整路径
【免费下载链接】python-okx项目地址: https://gitcode.com/GitHub_Trending/py/python-okx
python-okx 是 OKX API v5 的 Python 封装库,覆盖交易所 REST 交易接口与 WebSocket 行情通道,并统一处理请求签名、测试网切换等底层细节。读完本文,你能用几十行 Python 代码写出从行情查询、现货限价单、合约平仓到实时行情订阅的完整链路。
📌 项目能力全景
| 职责域 | 模块 | 边界说明 |
|---|---|---|
| 交易执行 | okx/Trade.py | 下单、撤单、改单、平仓,订单与成交明细查询,批量下单 |
| 行情获取 | okx/MarketData.py | Ticker、深度、K线、成交明细,全部为公共接口、免密钥 |
| 账户与风控 | okx/Account.py | 余额、持仓、杠杆设置、最大可下单量 |
| 资金与多账户 | okx/Funding.py、okx/SubAccount.py | 主账户余额与划转、子账户列表、子账户间转账 |
| 实时推送 | okx/websocket/ | 公共/私有频道订阅,多路复用,内置断线检测与事件推送 |
| 算法产品 | okx/Grid.py、okx/DualInvest.py 等 | 网格策略、双币投资、定投等结构化交易 |
相比裸调 REST,核心差异在 okx/okxclient.py 的封装:每个私有接口请求自动完成「时间戳 + 请求方法 + 路径 + 请求体」的 HMAC-SHA256 签名,拼装 OK-ACCESS-* 四个请求头,并附带模拟盘环境标记。你不需要手写签名,只靠一个flag参数即可在演示与实盘环境间切换。
另外注意:业务拒绝(余额不足、参数错误)时 HTTP 状态码仍是 200,库会原样返回{code, msg, data}结构的 JSON,code不为"0"才算失败。
🔧 最小可运行路径:先调通一个 ticker 只读查询
前提是pip install python-okx,Python 3.7 以上。公共行情接口不需要 API 密钥:
import okx.MarketData as MarketData market_client = MarketData.MarketAPI(flag="1") # "1"演示环境,"0"实盘 ticker_response = market_client.get_ticker(instId="BTC-USDT") print(ticker_response)预期输出(关键字段):
{ "code": "0", "data": [ { "instId": "BTC-USDT", "last": "67821.5", "bidPx": "67820.1", "askPx": "67821.9" } ] }环境切换只有两处:REST 用flag参数("1"演示 /"0"实盘);WebSocket 用连接地址,演示环境换用 wspap.okx.com 域名。能看到非空的data数组,说明链路已通。
⚡ 按交易场景拆解实操
现货限价单全流程
前提条件:已创建具备交易权限的 API 密钥,账户有足额 USDT。
import okx.Trade as Trade trade_client = Trade.TradeAPI(api_key, secret_key, passphrase, flag="1") order_response = trade_client.place_order( instId="BTC-USDT", tdMode="cash", side="buy", ordType="limit", px="65000", sz="0.001" ) order_id = order_response["data"][0]["ordId"] order_status = trade_client.get_order(instId="BTC-USDT", ordId=order_id) print(order_status["data"][0]["state"])关键参数:
| 参数 | 含义 | 备注 |
|---|---|---|
| tdMode | 交易模式 | 现货用 cash,合约用 isolated / cross |
| ordType | 订单类型 | limit / market / post_only / fok / ioc |
| px | 限价 | 限价单必填 |
| sz | 下单数量 | 现货限价买入默认以计价货币计 |
| tgtCcy | sz 单位切换 | base_ccy / quote_ccy |
易错点:下单被拒时返回的仍是正常 JSON,必须显式检查code字段是否为"0",只靠 try/except 会把业务拒绝吞掉。
确认限价单跑通后,同一个 trade_client 就能处理合约仓位,差别只是需要显式指定杠杆与方向。
合约设置杠杆并市价平仓
前提条件:已开通对应合约,并通过get_account_config确认了持仓模式(单向 / 双向)。
account_client = Account.AccountAPI(api_key, secret_key, passphrase, flag="1") account_client.set_leverage( instId="BTC-USD-SWAP", lever="10", mgnMode="cross", posSide="long" ) trade_client.close_positions( instId="BTC-USD-SWAP", mgnMode="cross", posSide="long" )| 参数 | 含义 | 备注 |
|---|---|---|
| mgnMode | 保证金模式 | cross(全仓)/ isolated(逐仓) |
| posSide | 持仓方向 | 仅双向持仓模式使用,单向模式不传 |
易错点:单向(净持仓)模式下传了posSide会导致方向不匹配、平仓失败。开仓前先把lever与mgnMode调好,避免盘中再调触发额外校验。
行情轮询到这里已经够用,但策略真正上线时,你需要让行情主动推过来。
用 WebSocket 订阅 tickers 频道
前提条件:Python 3.8+(asyncio 环境),websockets 依赖已随库安装。
import asyncio, json from okx.websocket.WsPublicAsync import WsPublicAsync async def on_tick(message: str): payload = json.loads(message) if payload.get("arg", {}).get("channel") == "tickers": print(payload["data"][0]["last"]) async def main(): ws_client = WsPublicAsync(url="wss://ws.okx.com:8443/ws/v5/public") await ws_client.start() await ws_client.subscribe([{"channel": "tickers", "instId": "BTC-USDT"}], on_tick) await asyncio.sleep(30) await ws_client.stop() asyncio.run(main())subscribe的入参是列表,追加多个 channel 对象即可一次订阅多个标的。- 私有频道(订单、资金)用 WsPrivateAsync,构造时多传三要素密钥,并先完成登录。
- 完整实现见 okx/websocket/。
易错点:start()返回的是后台收消息任务,必须保存返回值,否则该任务可能被回收,消息会静默中断。
🧩 进阶能力与组合技巧
断线重连的退避策略:这一层该谁做
库的consume()在检测到连接断开时,会先向你的回调推一条ConnClosed错误事件,然后重新抛出ConnectionClosedError——重连本身留给了调用方。设计思路是指数退避加封顶,再叠加随机抖动,避免多个实例同时冲击服务;重连成功后必须重新订阅所有频道,因为订阅关系不跨连接保留。
backoff = 1 while True: try: await run_ws_session() # 连接 + 订阅 + 消费 except Exception: await asyncio.sleep(backoff + random.uniform(0, 1)) backoff = min(backoff * 2, 60)什么时候该用:7×24 常驻的生产服务。什么时候不该用:跑 30 秒的临时脚本,一层异常捕获就够了,别为假想需求加复杂度。
子账户资金调度
主账户密钥可以管理一组子账户:先get_subaccount_list拉取账户清单,再用subAccount_transfer划转资金。froms/to指定账户层级(1=主账户,2=子账户),存在多个子账户时,fromSubAccount/toSubAccount必须传具体账户名。
sub_client = SubAccount.SubAccountAPI(api_key, secret_key, passphrase, flag="1") transfer_response = sub_client.subAccount_transfer( ccy="USDT", amt="100", froms="1", to="2", fromSubAccount="", toSubAccount="sub1" )适合多个策略实例分仓运行、需要互相隔离资金、且策略停用后要快速把资金拉回主账户的场景;单账户运行策略时,这层纯属多余开销,不必引入。
🛠 故障排查速查
| 现象 / 错误码 | 常见原因 | 修复动作 |
|---|---|---|
| code=50011 签名错误 | 本地时钟偏差或时间戳格式不对 | 同步系统时钟;时间戳需为 ISO8601 毫秒格式 |
| code=50013 API key 无效 | 密钥未激活或未加 IP 白名单 | 核对 key / secret / passphrase 三要素与 IP 白名单 |
| code=50102 余额不足 | 可用余额低于下单金额 | 用get_account_balance核对;演示环境需先领取模拟资金 |
| code=51000 参数错误 | instId 格式或交易模式不匹配 | 核对 instId 全称与 tdMode 是否对应 |
| WebSocket 1006 / ConnClosed | 服务端断连,未收到关闭帧 | 按退避策略重连,并重新订阅全部频道 |
通用异常处理模板:
try: order_result = trade_client.place_order(instId=..., tdMode=..., ...) except Exception as exc: print(f"网络层异常: {exc}") else: if order_result.get("code") != "0": print(f"业务拒绝: {order_result['code']} {order_result.get('msg')}")🧭 延伸方向
- 接口参数细节、完整错误码列表与演示环境地址清单,以 OKX API v5 官方文档为准,这是参数定义的第一参考。
- 仓库
test/unit/目录按模块拆分了单元测试,test/目录有可直接改跑的真实集成用例;参数组合不确定时,对照测试用例最不容易出错,新接口需求也可以直接在仓库提 Issue。 - 值得继续深入的主题:把 tick 与 book 频道组合维护本地订单簿,再驱动网格或做市类策略的下单决策。
【免费下载链接】python-okx项目地址: https://gitcode.com/GitHub_Trending/py/python-okx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考