PhilippeGe
PhilippeGe

Reputation: 11

Signed request with python to binance future

I have been struggling to send a signed request to binance future using signature.

I found that example code on StackOverflow ("Binance API call with SHA56 and Python requests") and an answer has been given to it mentioning to use hmac as below: but unfortunately i still don't see how to write this example. Could anyone show how the code of this example should look like? i am really uncomfortable with signed request. Thanks a lot for your understanding and your help advice given:

params = urlencode({
    "signature" : hashedsig,
    "timestamp" : servertimeint,
})
hashedsig = hmac.new(secret.encode('utf-8'), params.encode('utf-8'), hashlib.sha256).hexdigest()

Original example:

import requests, json, time, hashlib

apikey = "myactualapikey"
secret = "myrealsecret"
test = requests.get("https://api.binance.com/api/v1/ping")
servertime = requests.get("https://api.binance.com/api/v1/time")

servertimeobject = json.loads(servertime.text)
servertimeint = servertimeobject['serverTime']

hashedsig = hashlib.sha256(secret)

userdata = requests.get("https://api.binance.com/api/v3/account",
    params = {
        "signature" : hashedsig,
        "timestamp" : servertimeint,
    },
    headers = {
        "X-MBX-APIKEY" : apikey,
    }
)

print(userdata)

Upvotes: 1

Views: 3865

Answers (2)

carkod
carkod

Reputation: 2230

At the time of writing, Binance themselves are mainting a repo with some examples*, using the requests library. Here is a sample in case the link goes down or is moved:

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

KEY = ''
SECRET = ''
# BASE_URL = 'https://fapi.binance.com' # production base url
BASE_URL = 'https://testnet.binancefuture.com' # testnet base url

''' ======  begin of functions, you don't need to touch ====== '''
def hashing(query_string):
    return hmac.new(SECRET.encode('utf-8'), query_string.encode('utf-8'), hashlib.sha256).hexdigest()

def get_timestamp():
    return int(time.time() * 1000)

def dispatch_request(http_method):
    session = requests.Session()
    session.headers.update({
        'Content-Type': 'application/json;charset=utf-8',
        'X-MBX-APIKEY': KEY
    })
    return {
        'GET': session.get,
        'DELETE': session.delete,
        'PUT': session.put,
        'POST': session.post,
    }.get(http_method, 'GET')

# used for sending request requires the signature
def send_signed_request(http_method, url_path, payload={}):
    query_string = urlencode(payload)
    # replace single quote to double quote
    query_string = query_string.replace('%27', '%22')
    if query_string:
        query_string = "{}&timestamp={}".format(query_string, get_timestamp())
    else:
        query_string = 'timestamp={}'.format(get_timestamp())

    url = BASE_URL + url_path + '?' + query_string + '&signature=' + hashing(query_string)
    print("{} {}".format(http_method, url))
    params = {'url': url, 'params': {}}
    response = dispatch_request(http_method)(**params)
    return response.json()

# used for sending public data request
def send_public_request(url_path, payload={}):
    query_string = urlencode(payload, True)
    url = BASE_URL + url_path
    if query_string:
        url = url + '?' + query_string
    print("{}".format(url))
    response = dispatch_request('GET')(url=url)
    return response.json()


response = send_signed_request('POST', '/fapi/v1/order', params)
print(response)

Some additional thoughts from myself:

  • You can also use a new library also from Binance called Binance connector. It is a bit new, it has some issues, but it can do the basic operations without you worrying about signed requests.
  • I wouldn't use serverTime because that means you need to make an additional request and networks can be slow, I'd follow this example and use the int(time.time() * 1000) you may not even need the function.
  • I purposedly used the POST example, because this is more complicated as you need to also encode and hash your custom parameters
  • At the time of writing, v3 is the latest version

Hope it helps.


* https://github.com/binance/binance-signature-examples/blob/master/python/futures.py

Upvotes: 1

Josep Chulvi
Josep Chulvi

Reputation: 41

The proper way would be:

apikey = "myKey"
secret = "mySecret"

servertime = requests.get("https://api.binance.com/api/v1/time")

servertimeobject = json.loads(servertime.text)
servertimeint = servertimeobject['serverTime']

params = urlencode({
    "timestamp" : servertimeint,
})

hashedsig = hmac.new(secret.encode('utf-8'), params.encode('utf-8'), 
hashlib.sha256).hexdigest()

userdata = requests.get("https://api.binance.com/api/v3/account",
    params = {
        "timestamp" : servertimeint,
        "signature" : hashedsig,      
    },
    headers = {
        "X-MBX-APIKEY" : apikey,
    }
)
print(userdata)
print(userdata.text)

Make sure to put the signature as the last parameter or the request will return [400]...

Incorrect:

params = {
    "signature" : hashedsig,
    "timestamp" : servertimeint,                  
}

Correct:

params = {
    "timestamp" : servertimeint,
    "signature" : hashedsig,      
}

Upvotes: 4

Related Questions