I am trying to use the Binance Websocket API to send a trade request. I have already successfully implemented communicating with the REST-API to place a order, but the websocket for some reason keeps failing...
This is the error I get:
-1022 Signature for this request is not valid.
Binance API requires you to sign your payload to validate the request. Examples of it being implemented can be found here:
Running websocket_api_client.py with my API-keys works. So it has nothing to do with using invalid API-keys.
This is my code:
let api_key = "";
let api_secret = "";
// Make websocket connection.
let url = url::Url::parse("wss://testnet.binance.vision/ws-api/v3").unwrap();
let (ws_stream, _) = connect_async(url).await.expect("Failed to connect");
let (mut send, mut read) = ws_stream.split();
// Get timestamp.
let timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis().to_string();
// Set parameters payload for order request.
let mut params = std::collections::HashMap::<&str, &str>::new();
params.insert("symbol", "BTCUSDT");
params.insert("side", "BUY");
params.insert("type", "MARKET");
params.insert("quantity", "0.01");
params.insert("apiKey", api_key);
params.insert("timestamp", &*timestamp);
// URL encode parameters so we can hash the signature.
let url_encoded = ser::to_string(¶ms).unwrap();
println!("url_encoded: {}", url_encoded);
// Generate signature.
let mut hmac = HmacSha256::new_from_slice(api_secret.as_bytes()).unwrap();
hmac.update(url_encoded.as_bytes());
let signature = hex::encode(hmac.finalize().into_bytes());
println!("signature: {}", signature);
// Add signature to parameters.
params.insert("signature", &*signature);
let json =
format!("
{{
\"id\": \"1nsfjknfdwkonfkookeeor\",
\"method\": \"order.place\",
\"params\": {}
}}
", serde_json::to_string(¶ms).unwrap());
let json = serde_json::from_str::<serde_json::Value>(&*json).unwrap();
println!("\n\njson:\n{}\n", json);
// Send to websocket.
send.send(Message::Text(json.to_string().trim().to_string())).await;
// Retrieve data.
while let Some(message) = read.next().await {
let data = message.unwrap().into_data();
let data = &*String::from_utf8(data).unwrap();
println!("\nresponse: {:?}", data);
}
This is the full output:
url_encoded: type=MARKET&side=BUY&quantity=0.01&apiKey=my_actual_api_key×tamp=1704763468960&symbol=BTCUSDT
signature: d0154884d6d9e7a4a369b2f9f68f6337c2da86b40f8bbdf1371f338645e7ba8d
json:
{"id":"1nsfjknfdwkonfkookeeor","method":"order.place","params":{"apiKey":"my_actual_api_key","quantity":"0.01","side":"BUY","signature":"d0154884d6d9e7a4a369b2f9f68f6337c2da86b40f8bbdf1371f338645e7ba8d","symbol":"BTCUSDT","timestamp":"1704763468960","type":"MARKET"}}
response: "{\"id\":\"1nsfjknfdwkonfkookeeor\",\"status\":400,\"error\":{\"code\":-1022,\"msg\":\"Signature for this request is not valid.\"},\"rateLimits\":[{\"rateLimitType\":\"REQUEST_WEIGHT\",\"interval\":\"MINUTE\",\"intervalNum\":1,\"limit\":6000,\"count\":3}]}"
response: "disconnected"
I am stuck on this issue for days already. I think I am overlooking something small like encoding something wrong or whatever. Does anyone have an idea?