I'm trying to create a wrapper for a bitcoin exchange API in python. However, the API requires you to generate signature with each request. I'm having difficulty generating the SHA394 signature correctly using the hmac module in python. Here's how my following code looks like so far:
# private_client.py
# Mohammad Usman
#
# A python wrapper for Gemini's public API
from cached import Cached
import requests
import json
import uuid
import hmac
import hashlib
import base64
from datetime import datetime
class PrivateClient(metaclass=Cached):
def __init__(self, PUBLIC_API_KEY, PRIVATE_API_KEY):
self._public_key = PUBLIC_API_KEY
self._private_key = PRIVATE_API_KEY
self._base_url = 'https://api.gemini.com/'
def api_query(self, method, payload=None):
if payload is None:
payload = {}
request_url = self._base_url + method
payload['request'] = method
payload['nonce'] = str(uuid.uuid4())
b64_payload = base64.b64encode(json.dumps(payload).encode('utf-8'))
signature = hmac.new(self._private_key.encode('utf-8'), msg=b64_payload, digestmod=hashlib.sha256).digest()
headers = {
'Content-Type': "text/plain",
'Content-Length': "0",
'X-GEMINI-APIKEY': self._public_key,
'X-GEMINI-PAYLOAD': b64_payload,
'X-GEMINI-SIGNATURE': signature,
'Cache-Control': "no-cache"
}
r = requests.request('POST', request_url, headers=headers)
return r.json()
def new_order(self, symbol, amount, price, side, options):
payload = {
'symbol': symbol,
'amount': amount,
'price': amount,
'side': side,
'options': options,
'type': 'exchange limit'
}
return self.api_query('/v1/order/new', payload)
a = PrivateClient('public_key', 'private_key')
b = a.new_order('BTCUSD', '20.2', '4500.2', 'buy', ["immediate-or-cancel"])
print(b)
However, I keep getting the following error:
Traceback (most recent call last):
File "C:\Users\uzman\Documents\Python\Gemini- Python API Wrapper\gemini\private_client.py", line 58, in <module>
b = a.new_order('BTCUSD', '20.2', '4500.2', 'buy', ["immediate-or-cancel"])
File "C:\Users\uzman\Documents\Python\Gemini- Python API Wrapper\gemini\private_client.py", line 54, in new_order
return self.api_query('/v1/order/new', payload)
File "C:\Users\uzman\Documents\Python\Gemini- Python API Wrapper\gemini\private_client.py", line 42, in api_query
r = requests.request('POST', request_url, headers=headers)
File "C:\Users\uzman\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\api.py", line 58, in request
return session.request(method=method, url=url, **kwargs)
File "C:\Users\uzman\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\sessions.py", line 488, in request
prep = self.prepare_request(req)
File "C:\Users\uzman\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\sessions.py", line 431, in prepare_request
hooks=merge_hooks(request.hooks, self.hooks),
File "C:\Users\uzman\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\models.py", line 306, in prepare
self.prepare_headers(headers)
File "C:\Users\uzman\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\models.py", line 440, in prepare_headers
check_header_validity(header)
File "C:\Users\uzman\AppData\Local\Programs\Python\Python36\lib\site-packages\requests\utils.py", line 869, in check_header_validity
raise InvalidHeader("Invalid return character or leading space in header: %s" % name)
requests.exceptions.InvalidHeader: Invalid return character or leading space in header: X-GEMINI-SIGNATURE
Any help ?