我们用python程序进行代币交易时,经常会用到ccxt等的库进行交易。但是,我经常遇到,因为库不完善一些功能现有的库无法实现,再有就是随着库的升级你编写的程序可能不能正常运行,我经常遇到这样的情况。于是,我想能不能自己建立最基础的api接口,然后再通过api接口来实现我们的特定要求。那我们来试一下吧。 通过学习okx的api文档,我们要如下操作:
创建自己的APIKey
打开这个链接:https://www.okx.com/zh-hans/account/my-api
如下图:
创建APIKey后,您将获得3个必须记住的信息:
-
APIKey
-
SecretKey
-
Passphrase
APIKey和SecretKey将由平台随机生成和提供,Passphrase将由您提供以确保API访问的安全性。平台将存储Passphrase加密后的哈希值进行验证,但如果您忘记Passphrase,则无法恢复,请您通过交易网站重新生成新的APIKey。
注意APIKey 权限
APIKey 有如下3种权限,一个 APIKey 可以有一个或多个权限。
-
读取 :查询账单和历史记录等 读权限
-
提现 :可以进行提币
-
交易 :可以下单和撤单,转账,调整配置 等写权限
为了我们资金的安全一定不要选择”提现“!!!
APIKey 安全性
-
每个APIKey最多可绑定20个IP地址,IP地址支持IPv4/IPv6和网段的格式。 未绑定IP且拥有交易或提币权限的APIKey,将在闲置14天之后自动删除。(模拟盘的 API key 不会被删除)
-
用户调用了需要 APIKey 鉴权的接口,才会被视为 APIKey 被使用。
-
调用了不需要 APIKey 鉴权的接口,即使传入了 APIKey的信息,也不会被视为使用过。
-
Websocket 只有在登陆的时候,才会被视为 APIKey 被使用过。在登陆后的连接中做任何操作(如 订阅/下单),也不会被认为 APIKey 被使用,这点需要注意。
用户可以在 安全中心 中看到未绑定IP且拥有交易/提现权限的 APIKey 最近使用记录。
REST 请求验证
发起请求
所有REST私有请求头都必须包含以下内容:
-
OK-ACCESS-KEY字符串类型的APIKey。
-
OK-ACCESS-SIGN使用HMAC SHA256哈希函数获得哈希值,再使用Base-64编码(请参阅签名)。
-
OK-ACCESS-TIMESTAMP发起请求的时间(UTC),如:2020-12-08T09:08:57.715Z
-
OK-ACCESS-PASSPHRASE您在创建API密钥时指定的Passphrase。
所有请求都应该含有application/json类型内容,并且是有效的JSON。
签名
OK-ACCESS-SIGN的请求头是对timestamp + method + requestPath + body字符串(+表示字符串连接),以及SecretKey,使用HMAC SHA256方法加密,通过Base-64编码输出而得到的。
如:sign=CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(timestamp + ‘GET’ + ‘/api/v5/account/balance?ccy=BTC’, SecretKey))
其中,timestamp的值与OK-ACCESS-TIMESTAMP请求头相同,为ISO格式,如2020-12-08T09:08:57.715Z。
method是请求方法,字母全部大写:GET/POST。
requestPath是请求接口路径。如:/api/v5/account/balance
body是指请求主体的字符串,如果请求没有主体(通常为GET请求)则body可省略。如:{“instId”:”BTC-USDT”,”lever”:”5”,”mgnMode”:”isolated”}
GET请求参数是算作requestPath,不算body SecretKey为用户申请APIKey时所生成。如:22582BD0CFF14C41EDBF1AB98506286D
程序
获取apikey等相关参数
OKX_API_KEY= # 你的API_KEY OKX_SECRET_KEY= # 你的Secret_KEY OKX_PASSPHRASE= # 你的Passphrase
获取时间戳
我们可以定义一个函数来获取时间戳:
import time
def get_timestamp():
return time.strftime('%Y-%m-%dT%H:%M:%S.000Z', time.gmtime())
构造签名函数
import hmac
import base64
def sign(timestamp, method, path, body=""):
message = timestamp + method + path + body
mac = hmac.new(
SECRET_KEY.encode(),
message.encode(),
hashlib.sha256
)
return base64.b64encode(mac.digest()).decode()
构造headers函数
def get_headers(method, path, body=""):
timestamp = get_timestamp()
method=method.upper()
return {
"OK-ACCESS-KEY": API_KEY,
"OK-ACCESS-SIGN": sign(timestamp, method, path, body),
"OK-ACCESS-TIMESTAMP": timestamp,
"OK-ACCESS-PASSPHRASE": PASSPHRASE,
"Content-Type": "application/json"
}
构造request函数
import josn
session = requests.Session()
session.proxies=proxies
def request(method, path, params=None):
url = BASE_URL + path
method=method.upper()
# 构建完整URL
if method == "GET" and params:
query_string = urlencode(params)
full_path = f"{path}?{query_string}"
url = f"{BASE_URL}{full_path}"
body_str = ""
else:
full_path = path
url = f"{BASE_URL}{path}"
body_str = json.dumps(params) if params else ""
headers = get_headers(method, full_path, body_str)
# 确保Content-Type正确
headers["Content-Type"] = "application/json"
# print('url=',url)
# print('body_str=',body_str)
try:
if method == "GET":
r = session.get(url,headers=headers,timeout=10)
else:
# body = json.dumps(params) if params else ""
r = session.post(url,headers=headers,data=body_str,timeout=10)
# 检查HTTP状态码
r.raise_for_status()
# 解析响应
result = r.json()
# 检查API返回码
if result.get('code') != '0':
print(f"API错误: {result.get('msg', '未知错误')}")
return result
except requests.exceptions.RequestException as e:
print(f"请求异常: {e}")
return {"code": "-1", "msg": str(e)}
except json.JSONDecodeError as e:
print(f"JSON解析错误: {e}")
return {"code": "-1", "msg": "响应解析失败"}
except Exception as e:
print(f"未知错误: {e}")
return {"code": "-1", "msg": str(e)}
return r.json()
函数调用
这样我们的接口函数就构造完成了,只要知道paht,method,和一些参数就可以访问了。下面我们以查询账户余额为例说明如何调用接口函数。
BASE_URL='https://www.okx.com'
path=path = "/api/v5/account/balance"
method='GET'
def get_balance(ccy):
"""
查询指定币种余额
ccy: 币种,比如 'BTC'、'USDT'
"""
ccy=ccy.upper()
path = "/api/v5/account/balance"
params={'ccy':ccy}
data=request("get",path,params)
if data['code']!='0':
print("获取余额失败:", data['msg'])
return None
else:
return data['data'][0]['details'][0]['availBal']
这样,我们自己构造的api接口函数就完成了,使用也很简单。我们可以根据自己的需要随意构建自己需要的函数。


