开发时会遇到两个问题。
一、网上的python代码,生成sign后,需要再从byte转一下str。否则requests请求时,会报错:Object of type bytes is not JSON serializable
完整代码如下:
import base64
import datetime as dt
import hmac
import requests
import json
class OkexBot:
def __init__(self, APIKEY: str, APISECRET: str, PASS: str):
self.apikey = APIKEY
self.apisecret = APISECRET
self.password = PASS
self.baseURL = 'https://www.okx.com'
@staticmethod
def get_time():
return dt.datetime.utcnow().isoformat()[:-3] + 'Z'
@staticmethod
def signature(timestamp, method, request_path, body, secret_key):
message = timestamp + method + request_path + body
mac = hmac.new(bytes(secret_key, encoding='utf8'), bytes(message, encoding='utf-8'), digestmod='sha256')
output = mac.digest()
base1=base64.b64encode(output)
str1=str(base1, encoding='gbk')
return str1
def get_header(self, request='GET', endpoint='', body=''):
cur_time = self.get_time()
header = dict()
header['CONTENT-TYPE'] = "application/json"
header['OK-ACCESS-KEY'] = self.apikey
header['OK-ACCESS-SIGN'] = self.signature(cur_time, request, endpoint, body, self.apisecret)
header['OK-ACCESS-TIMESTAMP'] = cur_time
header['OK-ACCESS-PASSPHRASE'] = self.password
header['x-simulated-trading'] = "1"
return header
def place_market_order(self, pair, side, amount, tdMode='cash'):
endpoint = '/api/v5/trade/order'
url = self.baseURL + '/api/v5/trade/order'
request = 'POST'
body = {
"instId": pair,
"tdMode": tdMode,
"side": side,
"ordType": "market",
"sz": str(amount) #str(Decimal(str(amount)))
}
body = json.dumps(body)
header = self.get_header(request, endpoint, str(body))
print(header)
response = requests.post(url, headers=header, data=body)
return response
if __name__ == '__main__':
ApiKey = "aef0bf16- "
ApiSecret = "2CBA2 "
ApiPassword = "19 "
instId = "BTC-USDT"
ordType = "market"
#posSide = "long",
side = "buy"
sz = 0.03
tdMode = "cash"
bot=OkexBot(ApiKey,ApiSecret,ApiPassword)
res=bot.place_market_order(instId,side,sz,tdMode)
print(res)
二、使用nodejs、C#实现的下单,23年上半年还是正常的,后来报错:Invalid Sign",“code”:"50113 。(Post请求会报这个错,Get请求不会)
对比调试了python代码,python可以成功下单,发现差别就在data转json时的差别。
python生成的json,在冒号、逗号后有一个空格(如下示例)。而nodejs、C# 默认是没有这个空格的。估计是okx的人把代码用python重构时没有做好测试吧。
{"instId": "BTC-USDT-SWAP", "ordType": "market", "posSide": "long", "side": "buy", "sz": "20", "tdMode": "cross"}
另外还要注意下生成json时,要按字段名的字母顺序排序。
C#示例代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
public class SignHelper
{
public static string SignOk(string data, string secretKey)
{
if (string.IsNullOrEmpty(secretKey))
return "";
byte[] keyBytes = Encoding.UTF8.GetBytes(secretKey);
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
using (HMACSHA256 hmac = new HMACSHA256(keyBytes))
{
byte[] hashBytes = hmac.ComputeHash(dataBytes);
string cryptoStr = Convert.ToBase64String(hashBytes);
return cryptoStr;
}
}
public static string JsonAddSpace(string json1)
{
var out1 = "";
for(var i=0;i<json1.Length; i++)
{
var b = json1[i];
out1 += b;
if (b == ',' || b == ':')
{
out1 += ' ';
}
}
return out1;
}
}
js签名代码:
const crypto = require('crypto');
dbUtil.sign_ok=function (data, SecretKey) {
const hmac = crypto.createHmac('sha256', SecretKey);
let cryptostr = hmac.update(data).digest('base64');//hex
return cryptostr;
}