BitMEX / api-connectors

Libraries for connecting to the BitMEX API.

Home Page:https://www.bitmex.com/app/restAPI

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

python post request

art1313 opened this issue · comments

commented

I am trying to place an order on testnet, but get this error{"error":{"message":"Unexpected token s in JSON at position 0","name":"SyntaxError"}}
Does anyone know what is the issue here? My code is below:

import json
import requests
import aiohttp
import asyncio
import urllib
import time
import hashlib, hmac
import urllib.parse
import json
from future.builtins import bytes
from future.standard_library import hooks
with hooks():  # Python 2/3 compat
    from urllib.parse import urlparse

api_key = "api_key"
api_secret = "api_secret"
base_url = 'https://testnet.bitmex.com' ###
method = 'POST'

data = json.loads('{"symbol":"XBTUSD","orderQty":1,"price":9395.5}')
path = '/api/v1/order'
url = base_url + path
print(url)
nonce = int(time.time() * 1000) + 5
print(nonce)
message = bytes(method + path + str(nonce) + str(data), 'utf-8')
print(message)

def generate_signature(secret, verb, url, nonce, data):
    """Generate a request signature compatible with BitMEX."""
    # Parse the url so we can remove the base and extract just the path.
    parseURL = urlparse(url)
    path = parseURL.path
    if parseURL.query:
        path = path + '?' + parseURL.query
    
    if isinstance(data, (bytes, bytearray)):
        data = data.decode('utf8')

    message = verb + path + str(nonce) + str(data)

    signature = hmac.new(bytes(secret, 'utf8'), bytes(message, 'utf8'), digestmod=hashlib.sha256).hexdigest()
    return signature

signature = generate_signature(api_secret, method, path, nonce, data)
print(signature)
headers = {'api-expires':str(nonce),'api-key':api_key,'api-signature':signature, 'Content-Type':'application/json', 'Accept':'application/json'}
print(headers)

r = requests.post(url, data=data,  headers=headers)
print('error: ',r.status_code)
print(r.text)
https://testnet.bitmex.com/api/v1/order
1590914238614
b"POST/api/v1/order1590914238614{'symbol': 'XBTUSD', 'orderQty': 1, 'price': 9395.01}"
7632d3f663d638c8a48ba4035d0f19b9fc2d984e651f507bcd9724323faa0aab
{'api-expires': '1590914238614', 'api-key': 'api_key', 'api-signature': '7632d3f663d638c8a48ba4035d0f19b9fc2d984e651f507bcd9724323faa0aab', 'Content-Type': 'application/json', 'Accept': 'application/json'}
error:  400
{"error":{"message":"Unexpected token s in JSON at position 0","name":"SyntaxError"}}

By default, requests is going to post form-encoded data. https://requests.readthedocs.io/en/master/user/quickstart/#more-complicated-post-requests

Try using json.dumps(data) in your request:

r = requests.post(url, data=json.dumps(data), headers=headers)
commented

Thanks for a quick response Samuel. The code below works fine:

import json
import requests
import aiohttp
import asyncio
import urllib
import time
import hashlib, hmac
import urllib.parse
import json
from future.builtins import bytes
from future.standard_library import hooks
with hooks():  # Python 2/3 compat
    from urllib.parse import urlparse

api_key = "api_key"
api_secret = "api_secret"
base_url = 'https://testnet.bitmex.com' ###
method = 'POST'

data = '{"symbol":"XBTUSD","orderQty":1,"price":9395.5}'
path = '/api/v1/order'
url = base_url + path
print(url)
nonce = int(time.time() * 1000) + 5
print(nonce)
message = bytes(method + path + str(nonce) + data, 'utf-8')
print(message)

def generate_signature(secret, verb, url, nonce, data):
    """Generate a request signature compatible with BitMEX."""
    # Parse the url so we can remove the base and extract just the path.
    parseURL = urlparse(url)
    path = parseURL.path
    if parseURL.query:
        path = path + '?' + parseURL.query
    
    if isinstance(data, (bytes, bytearray)):
        data = data.decode('utf8')

    message = verb + path + str(nonce) + data

    signature = hmac.new(bytes(secret, 'utf8'), bytes(message, 'utf8'), digestmod=hashlib.sha256).hexdigest()
    return signature

signature = generate_signature(api_secret, method, path, nonce, data)
print(signature)
headers = {'api-expires':str(nonce),'api-key':api_key,'api-signature':signature, 'Content-Type':'application/json', 'Accept':'application/json'}
print(headers)

r = requests.post(url, data=data, headers=headers)
print('error: ',r.status_code)
print(r.text)

This seems to be the same code as the original?

commented

Sam in the original:
data = json.loads('{"symbol":"XBTUSD","orderQty":1,"price":9395.5}') vs in the new one
data = '{"symbol":"XBTUSD","orderQty":1,"price":9395.5}'

Ah yes. Either way will work, it's just important that the data passed to requests.post() is a string.