- 行情、K 線等公共介面不需要 API Key,用 requests 發一個 GET 請求就能拿到資料。
- 私有介面要帶 4 個請求頭,簽名 = Base64(HMAC-SHA256(時間戳 + 請求方法 + 請求路徑 + 請求體, Secret Key))。
- GET 請求的查詢引數要拼進請求路徑一起簽名,時間戳必須是 UTC 毫秒格式,與伺服器相差超過 30 秒會被拒絕。
- 先用模擬盤 Key 加上 x-simulated-trading 請求頭把程式跑通,確認無誤後再考慮實盤。
歐易提供 REST 和 WebSocket 兩套 API。本文用 Python 和 requests 庫演示最常用的 REST 操作:先拿公開行情和 K 線,再按官方規則生成簽名,查詢餘額、下單、查單和撤單。文中程式碼都在 2026 年 10 月實際執行過,介面和欄位名以歐易 API v5 官方文件為準。
本文是程式設計教程,不構成任何投資建議。涉及下單的程式碼請一律先在模擬盤執行,程式寫錯一個引數,在實盤就是真金白銀的損失。
準備工作
- 安裝 Python 3 和
requests:
pip install requests
-
只做第一部分(公共行情)不需要任何 Key。要呼叫私有介面,先按 歐易 API 申請教程 建立一把模擬盤 API Key,許可權勾選「讀取」和「交易」即可。
-
把金鑰放進環境變數,不要直接寫在程式碼裡。程式碼檔案容易被分享、截圖或上傳到網上,環境變數則只存在於你的電腦中。macOS / Linux 終端:
export OKX_API_KEY="你的 API Key"
export OKX_SECRET_KEY="你的 Secret Key"
export OKX_PASSPHRASE="你的 Passphrase"
Windows PowerShell 用 $env:OKX_API_KEY="你的 API Key" 的寫法,其餘兩項同理。
API v5 基礎
- 介面地址:歐易文件當前給出的 REST 地址是
https://openapi.okx.com,實盤和模擬盤共用這個地址,靠請求頭區分。如果你是在歐易美國、澳洲站(app.okx.com)註冊的,要改用us.okx.com;在歐洲站(my.okx.com)註冊的用eea.okx.com; - 返回格式:統一是 JSON,包含
code、msg、data三個欄位。code為"0"表示成功,data是一個數組; - 數值都是字串:價格、數量都以字串返回,計算前要用
float()或Decimal()轉換。
公共介面:獲取行情和 K 線
公共介面不需要簽名:
from datetime import datetime, timezone
import requests
BASE_URL = "https://openapi.okx.com"
def public_get(path, params=None):
resp = requests.get(BASE_URL + path, params=params, timeout=10)
resp.raise_for_status()
data = resp.json()
if data["code"] != "0":
raise RuntimeError(f"歐易返回錯誤:{data['code']} {data['msg']}")
return data["data"]
# 1. 最新行情
ticker = public_get("/api/v5/market/ticker", {"instId": "BTC-USDT"})[0]
print("最新成交價:", ticker["last"])
print("買一 / 賣一:", ticker["bidPx"], "/", ticker["askPx"])
print("24 小時最高 / 最低:", ticker["high24h"], "/", ticker["low24h"])
print("24 小時成交量(BTC):", ticker["vol24h"])
# 2. 最近 5 根 1 小時 K 線(最新的在最前面)
candles = public_get(
"/api/v5/market/candles",
{"instId": "BTC-USDT", "bar": "1H", "limit": "5"},
)
for ts, o, h, l, c, vol, vol_ccy, vol_ccy_quote, confirm in candles:
t = datetime.fromtimestamp(int(ts) / 1000, tz=timezone.utc)
state = "已收盤" if confirm == "1" else "進行中"
print(t.strftime("%m-%d %H:%M UTC"), "開", o, "高", h, "低", l, "收", c, state)
執行後會列印 BTC-USDT 的最新價、買一賣一,以及最近 5 根小時 K 線。要點:
instId是產品 ID,現貨寫成BTC-USDT,永續合約寫成BTC-USDT-SWAP;- ticker 常用欄位:
last最新成交價、bidPx/askPx買一 / 賣一價、high24h/low24h24 小時最高 / 最低價、vol24h24 小時成交量(現貨以交易幣計); - K 線的每一行是陣列,順序為
[ts, o, h, l, c, vol, volCcy, volCcyQuote, confirm],ts是開盤時間的毫秒時間戳,confirm為"1"表示這根 K 線已收盤; bar區分大小寫:分鐘用小寫1m、15m,小時用大寫1H、4H,日線1D;寫成1h會返回 51000 引數錯誤;limit預設 100,最大 300,這個介面最多能取最近 1,440 根,更早的資料要用/api/v5/market/history-candles。
簽名規則
私有介面的每個請求都必須帶上 4 個請求頭:
| 請求頭 | 內容 |
|---|---|
| OK-ACCESS-KEY | 你的 API Key |
| OK-ACCESS-SIGN | 簽名(見下文) |
| OK-ACCESS-TIMESTAMP | UTC 時間戳,ISO 8601 格式精確到毫秒,如 2026-10-22T08:30:15.123Z |
| OK-ACCESS-PASSPHRASE | 建立 Key 時設定的 Passphrase |
簽名的生成方法:
- 拼接字串:
時間戳 + 請求方法 + 請求路徑 + 請求體; - 請求方法必須大寫,如
GET、POST; - GET 請求的查詢引數屬於請求路徑,例如
/api/v5/account/balance?ccy=BTC;GET 請求沒有請求體,這部分留空; - POST 請求的請求體是 JSON 字串,簽名用的字串必須和實際傳送的一模一樣;
- 用 Secret Key 對拼接結果做 HMAC-SHA256,再做 Base64 編碼。
時間戳與歐易伺服器相差超過 30 秒會被拒絕(錯誤碼 50102),所以一定要用 UTC 時間,而不是本地時區。
把這些規則寫成一個通用函式,儲存為 okx_client.py:
import base64
import hashlib
import hmac
import json
import os
from datetime import datetime, timezone
import requests
BASE_URL = "https://openapi.okx.com"
API_KEY = os.environ["OKX_API_KEY"]
SECRET_KEY = os.environ["OKX_SECRET_KEY"]
PASSPHRASE = os.environ["OKX_PASSPHRASE"]
DEMO = True # True = 模擬盤;確認一切正常前不要改成 False
def get_timestamp():
# ISO 8601 UTC 時間,精確到毫秒,例如 2026-10-22T08:30:15.123Z
now = datetime.now(timezone.utc)
return now.isoformat(timespec="milliseconds").replace("+00:00", "Z")
def make_sign(timestamp, method, request_path, body):
prehash = timestamp + method + request_path + body
mac = hmac.new(SECRET_KEY.encode(), prehash.encode(), hashlib.sha256)
return base64.b64encode(mac.digest()).decode()
def private_request(method, path, params=None, body=None):
method = method.upper()
request_path = path
if params: # GET 引數要拼進 requestPath 一起簽名
request_path += "?" + "&".join(f"{k}={v}" for k, v in params.items())
body_str = json.dumps(body, separators=(",", ":")) if body else ""
timestamp = get_timestamp()
headers = {
"OK-ACCESS-KEY": API_KEY,
"OK-ACCESS-SIGN": make_sign(timestamp, method, request_path, body_str),
"OK-ACCESS-TIMESTAMP": timestamp,
"OK-ACCESS-PASSPHRASE": PASSPHRASE,
"Content-Type": "application/json",
}
if DEMO:
headers["x-simulated-trading"] = "1"
resp = requests.request(
method, BASE_URL + request_path,
headers=headers, data=body_str or None, timeout=10,
)
data = resp.json()
if data.get("code") != "0":
raise RuntimeError(
f"歐易返回錯誤:code={data.get('code')} msg={data.get('msg')} data={data.get('data')}"
)
return data["data"]
注意 body_str 先生成、再同時用於簽名和傳送,這樣能保證兩者一致。
私有介面:查餘額、下單、查單、撤單
在 okx_client.py 同一目錄下新建一個指令碼:
from okx_client import private_request
# 1. 查詢交易賬戶餘額
for acct in private_request("GET", "/api/v5/account/balance", {"ccy": "USDT,BTC"}):
print("賬戶總權益(美元):", acct["totalEq"])
for d in acct["details"]:
print(d["ccy"], "可用:", d["availBal"], "凍結:", d["frozenBal"])
# 2. 下一個遠低於市價的限價買單(模擬盤)
order = private_request("POST", "/api/v5/trade/order", body={
"instId": "BTC-USDT",
"tdMode": "cash", # 現貨非槓桿
"side": "buy",
"ordType": "limit",
"px": "50000", # 限價:USDT
"sz": "0.0001", # 數量:BTC
"clOrdId": "demo001", # 自定義訂單號,可選
})[0]
print("下單結果:", order["sCode"], order["sMsg"], "訂單號:", order["ordId"])
# 3. 查詢訂單狀態
info = private_request("GET", "/api/v5/trade/order",
{"instId": "BTC-USDT", "ordId": order["ordId"]})[0]
print("狀態:", info["state"], "已成交數量:", info["accFillSz"])
# 4. 撤單
cancel = private_request("POST", "/api/v5/trade/cancel-order",
body={"instId": "BTC-USDT", "ordId": order["ordId"]})[0]
print("撤單結果:", cancel["sCode"], cancel["sMsg"])
幾個關鍵引數:
- 餘額:
totalEq是以美元計的賬戶總權益;details裡每個幣種的availBal是可用餘額,frozenBal是被掛單等佔用的凍結餘額。ccy可以不傳,表示查詢全部幣種; - 下單:
tdMode現貨非槓桿填cash;side為buy或sell;ordType為limit(限價)時必須帶px;現貨限價單的sz以交易幣計(這裡是 BTC)。最小下單量等規則可以用公共介面/api/v5/public/instruments?instType=SPOT&instId=BTC-USDT查詢minSz、lotSz、tickSz; - 下單結果:每一筆訂單的成敗看
data裡的sCode,"0"表示成功,同時返回歐易生成的ordId; - 訂單狀態
state:live等待成交、partially_filled部分成交、filled完全成交、canceled已撤銷; - 查單和撤單都可以用
ordId或你自定義的clOrdId。
示例故意把價格設得遠低於當前市價,下單後不會立即成交,方便練習查詢和撤單,請根據當時行情調整。
模擬盤與實盤切換
模擬盤和實盤使用同一個介面地址和簽名方式,區別只有兩點:
- 使用在「交易 → 模擬交易 → 個人中心」裡建立的模擬盤 API Key;
- 請求頭加
x-simulated-trading: 1(上面程式碼裡DEMO = True時自動新增)。
用實盤 Key 訪問模擬盤,或者反過來,都會返回 50101。強烈建議先在模擬盤連續執行一段時間,確認下單數量、方向、異常處理都沒有問題,再考慮換成實盤 Key 並把 DEMO 改為 False。
介面限速
| 介面 | 限速 | 計算依據 |
|---|---|---|
| 行情 /api/v5/market/ticker | 20 次 / 2 秒 | IP |
| K 線 /api/v5/market/candles | 40 次 / 2 秒 | IP |
| 餘額 /api/v5/account/balance | 10 次 / 2 秒 | 使用者 ID |
| 下單、撤單、查單 | 各 60 次 / 2 秒 | 使用者 ID + 產品 ID |
超過限速會返回 50011。程式裡應控制請求頻率,需要即時推送行情時,官方推薦改用 WebSocket。
常見錯誤碼
| 錯誤碼 | 含義 | 常見原因 |
|---|---|---|
| 50011 | 超過限速 | 請求太頻繁 |
| 50101 | API Key 與當前環境不匹配 | 實盤 / 模擬盤 Key 用錯,或請求頭漏加、多加 |
| 50102 | 時間戳過期 | 沒用 UTC 時間或電腦時鐘不準 |
| 50105 | Passphrase 錯誤 | 口令輸錯 |
| 50110 | IP 不在白名單內 | 換了伺服器或網路 |
| 50111 / 50119 | API Key 無效 / 不存在 | Key 複製錯誤或已被刪除 |
| 50113 | 簽名無效 | 見下方 FAQ 的排查步驟 |
| 51000 | 引數錯誤 | 引數名或取值不對 |
| 51008 | 餘額不足 | 可用餘額不夠下單 |
官方 SDK 與第三方庫
熟悉原理後,也可以使用現成的庫:歐易官方 Python SDK(pip install python-okx,官方文件的示例程式碼就基於它),或支援多家交易所的開源庫 ccxt。無論用哪個,金鑰都應當放在環境變數裡。
下一步
- API Key 許可權與安全設定:歐易 API 申請教程
- 不想寫程式碼,可以試試官方的策略工具:歐易策略交易新手教程
- 合約交易前先了解保證金和強平:歐易合約新手入門
- 程式化交易更要算清成本:歐易手續費說明
常見問題
呼叫歐易行情介面需要 API Key 嗎?
不需要。ticker、K 線、深度等公共行情介面可以直接訪問,按 IP 限速。只有查詢餘額、下單、撤單等涉及賬戶的私有接口才需要 API Key 和簽名。
簽名一直報 50113 怎麼辦?
50113 表示簽名無效。逐項檢查:請求方法是否大寫;GET 請求的查詢引數是否拼進了簽名用的路徑;POST 請求籤名用的 body 字串是否和實際傳送的完全一致;Secret Key 是否複製完整、沒有多餘空格。
報錯 50102 是什麼原因?
50102 表示時間戳過期,即請求時間和歐易伺服器相差超過 30 秒。最常見的原因是用了本地時區而不是 UTC 時間,或者電腦時鐘不準。可以呼叫 /api/v5/public/time 獲取伺服器時間對比。
模擬盤和實盤的程式碼有什麼區別?
介面地址和簽名方式完全一樣,區別只有兩點:要使用在模擬交易裡建立的 API Key,並在請求頭加上 x-simulated-trading 值為 1。實盤請求去掉這個請求頭,換成實盤 Key。
有沒有現成的 Python 庫?
歐易官方提供 Python SDK(PyPI 包名 python-okx),開源庫 ccxt 也支援歐易。不過先用本文的原生寫法理解簽名原理,排查問題時會輕鬆很多。
歐易的介面、費率和規則會調整,如與本文不一致,請以歐易官網最新資訊為準。