pythonapirestsha256bybit

Bybit api connection "retCode":10004,"retMsg":"error sign!"


According to official documentation https://bybit-exchange.github.io/docs/derivativesV3/unified_margin/#t-constructingtherequest I try to get account balance endpoint: GET /unified/v3/private/account/wallet/balance. But anyway I get this response: {"retCode":10004,"retMsg":"error sign!","result":null,"retExtInfo":null,"time":1665751778451}

from urllib.parse import urlencode
import requests
import hashlib
import time
import hmac
import uuid

api_key = 'xxxxxxxxxxxx'
secret_key = 'xxxxxxxxxxxxxxxxxxxx'
httpClient = requests.Session()
recv_window = "5000"
url = "https://api.bybit.com"
    
def HTTP_Request(endPoint, method, payload):

    time_stamp = requests.get(url + "/v3/public/time").json()
    time_stamp = str(time_stamp["time"])
    
    signature = genSignature(params, time_stamp)
    
    headers = {
            'X-BAPI-SIGN-TYPE': '2',
            'X-BAPI-SIGN': signature,
            'X-BAPI-API-KEY': api_key,
            'X-BAPI-TIMESTAMP': time_stamp,
            'X-BAPI-RECV-WINDOW': recv_window
    }
    
    response = httpClient.request(method, url+endpoint+"?"+payload, headers=headers)
    print(response.text)


def genSignature(payload, time_stamp):
    # encoding list obj to url format str
    peyload_url_enc = urlencode(
        sorted(payload.items(), key=lambda tup: tup[0])
    )

    param_str = str(time_stamp) + api_key + recv_window + peyload_url_enc
    hash = hmac.new(
        key=bytes(secret_key, "utf-8"),
        msg=param_str.encode("utf-8"),
        digestmod="sha256"
    )
    
    signature = hash.hexdigest()
    return signature
    
    
endpoint = "/unified/v3/private/account/wallet/balance"
method = "GET"
params = {"coin": "USDT"}
HTTP_Request(endpoint, method, str(params))

The problem seems to be in genSignature, but no matter how I change the function, the error remains the same


Solution

  • Thanks to this repository I found another method of connecting to the Bybit. So if you faced with similar problem, open the link, there are also some examples of creating different post/get queries

    My working variant:

    def bybit_spot_balance(AccessKey: str, SecretKey: str) -> dict:
        
        params = {
            "api_key": AccessKey,
            "timestamp": round(time.time() * 1000),
            "recv_window": 10000
        }
    
        # Create the param str
        param_str = urlencode(
            sorted(params.items(), key=lambda tup: tup[0])
        )
    
        # Generate the signature
        hash = hmac.new(
            bytes(SecretKey, "utf-8"),
            param_str.encode("utf-8"),
            hashlib.sha256
        )
        
        signature = hash.hexdigest()
        sign_real = {
            "sign": signature
        }
    
        param_str = quote_plus(param_str, safe="=&")
        full_param_str = f"{param_str}&sign={sign_real['sign']}"
    
        # Request information
        url = "https://api.bybit.com/spot/v3/private/account"
        headers = {"Content-Type": "application/json"}
        
        body = dict(params, **sign_real)
        urllib3.disable_warnings()
    
        response = requests.get(f"{url}?{full_param_str}", headers=headers, verify=False).json()
    
        return response