我尝试向bybit api发送一个简单的post请求,但一直收到10004 sign错误。以下是响应:
{"ret_code":10004,"ret_msg":"error sign! origin_string[api_key=(my api key)\u0026symbol=BTCUSDT\u0026timestamp=1635967650768]","ext_code":"","ext_info":"","result":null,"time_now":"1635967651.397800"}这是我用来发送请求的代码。
public async static Task<string> cancelAllOrders()
{
string ts = await GenerateTimeStamp();
string paramString = "api_key=" + apiKey + "&symbol=BTCUSDT" + "timestamp=" + ts;
string sign = CreateSignature(secretKey, paramString);
CancelOrderContent co = new CancelOrderContent(apiKey, "BTCUSDT", ts, sign);
var client = new RestClient(ApiUrl + "/v2/private/order/cancelAll");
var request = new RestRequest();
request.AddJsonBody(co);
var response = client.Post(request);
Trace.WriteLine(response.StatusCode.ToString() + " " + response);
return "";
}下面是我为请求正文序列化为JSON的类。
public class CancelOrderContent
{
public string api_key;
public string sign;
public string symbol;
public string timestamp;
public CancelOrderContent(string api_key, string symbol, string timestamp,string sign)
{
this.api_key = api_key;
this.symbol = symbol;
this.timestamp = timestamp;
this.sign = sign;
}
}下面是我用来创建签名的代码:
public static string CreateSignature(string secret, string message)
{
var signatureBytes = Hmacsha256(Encoding.UTF8.GetBytes(secret), Encoding.UTF8.GetBytes(message));
return ByteArrayToString(signatureBytes);
}
private static byte[] Hmacsha256(byte[] keyByte, byte[] messageBytes)
{
using (var hash = new HMACSHA256(keyByte))
{
return hash.ComputeHash(messageBytes);
}
}我尝试了各种方法来解决这个问题,但我似乎无法摆脱它。我尝试了多个端点,但仍然得到相同的错误。
发布于 2021-12-01 15:13:14
2022/01/17仍然有效。
嘿@Vexatious我在bybit-api尝试提交订单时遇到了类似的问题,尽管我知道我的密钥设置正确,但我仍然收到密钥被拒绝,权限不足的错误。
也许ByBit改变了什么?Lib过时了?谁知道呢。
我注意到的一件主要事情是,在将签名附加到请求正文之前,它们要求您按字母顺序对参数进行排序。
编辑:更新是因为我认识到GET请求也同样令人困惑。向下滚动查看POST请求示例。
GET和POST请求的处理方式不同
数据{
签名
两个的:在生成签名之前,您必须按字母顺序排列参数。
例如:"aParam=foo&bParam=bar",
这就是我们要处理的sign参数。
GET请求:将sign参数附加到QueryString的末尾并发送,可能需要使用标头
// Might still need {'Content-Type': 'application/x-www-form-urlencoded'}
// header depending on what request lib you're using.
const url = "https://api-testnet.bybit.com/GET?aParam=foo&bParam=bar&sign=" + signPOST请求:要求对象作为请求数据(仍然是类似于上面的QueryString的形式)发送,而不是类似于GET请求的完全构建的Http字符串。将sign参数添加到您用来生成签名的QueryString的末尾,将其分配给您的请求处理程序data参数,然后继续执行!
我确实想出了一个最小的工作版本,成功地在他们的testnet上发布了一个现货订单,这是jest测试。
./bybit.test.ts
test("WORKING BYBIT TRADE.", async () => {
const serverTime:number = (await axios.get(`https://api-testnet.bybit.com/spot/v1/time`)).data
// These need to be within 1000ms of eachother (I'm pree sure, their formula is kinda confusing)
console.log(`Their Timestamp`, serverTime)
console.log(`Our Timestamp`, Date.now())
const queryParams = {
// Alphabetically ordered
// (Sign generation function should deal with unordered params using .sort())
'api_key': bybitApiKey,
qty:10,
recvWindow: 10000,
side:"BUY",
symbol:"ETHUSDT",
timestamp: Date.now(),
type:"MARKET",
}
const queryString = querystring.stringify(queryParams)
const sign = "&sign=" + getSignature(queryParams, bybitSecret)
const fullQuery = queryString + sign
console.log(`FullQuery example`, fullQuery)
// api_key=...&qty=10&recvWindow=10000&side=BUY&symbol=ETHUSDT×tamp=1638371037593&type=MARKET&sign=...
let result = await axios(`https://api-testnet.bybit.com/spot/v1/order`, {
withCredentials: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: "POST",
data: fullQuery,
})
console.log(`Post Status`, result.status)
console.log(`Post Body`, result.data)
})
/**
Post Status 200
Post Body {
ret_code: 0,
ret_msg: '',
ext_code: null,
ext_info: null,
result: {
accountId: '...',
symbol: 'ETHUSDT',
symbolName: 'ETHUSDT',
orderLinkId: '...',
orderId: '...',
transactTime: '...',
price: '0',
origQty: '10',
executedQty: '0',
status: 'FILLED',
timeInForce: 'GTC',
type: 'MARKET',
side: 'BUY'
}
*/
}./sign.ts
import crypto from 'crypto'
export function getSignature(parameters: any, secret: string) {
var orderedParams = "";
Object.keys(parameters).sort().forEach(function(key) {
orderedParams += key + "=" + parameters[key] + "&";
});
orderedParams = orderedParams.substring(0, orderedParams.length - 1);
return crypto.createHmac('sha256', secret).update(orderedParams).digest('hex');
}希望这能有所帮助!
发布于 2021-11-06 04:37:16
我刚刚为Javascript应用编程接口弄明白了这一点,但使用的是ByBit而不是C#。然而,我确实了解C#,所以希望这能为你工作。
使用POST的HMAC端点需要与GET请求中相同的ByBit数据加密。您可以执行以下操作,而不是对查询字符串中的参数进行签名(并向其追加&sign=xxxx ):
这就是C#类变得棘手的地方。您有一个带有sign属性的CancelOrderContent。这将使用空值序列化键'sign‘。但是,ByBit应用编程接口不会接受这一点,因为签名的数据将不同。
你要么必须
发布序列化对象
或者..。
,"sign":''部件。然后,我相信这将会起作用,因为我必须这样做才能让它在JS中工作。但是,添加符号键/值更容易,因为没有类。
它的一个变体是将CancelOrderContent设置为动态类型,其中直到序列化/签名之后才添加“sign”键/值。
注意,当您手动将对象序列化为JSON时(不要使用paramString),理论上序列化程序应该与RestRequest.AddJsonBody()中使用或配置的序列化程序相同。
抱歉,我没有C#代码,但这应该可以工作。
https://stackoverflow.com/questions/69830871
复制相似问题