I tried making a simple function which makes a HTTP request to Kraken exchange API. The method is private, I am trying to fetch my account balance.
According to Kraken documentation (https://www.kraken.com/features/api#general-usage):
HTTP header:
API-Key = API key
API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
POST data:
nonce = always increasing unsigned 64 bit integer
otp = two-factor password (if two-factor enabled, otherwise not required)
I tried to make my signature generation similar to the "veox" Python library (available at: https://github.com/veox/python3-krakenex/blob/master/krakenex/api.py).
I am using Python 3.6.7 on Ubuntu 18.04.
2FA (otp) is turned on for my account on Kraken exchange, though I am not sure if I need to include in the request.
I searched stack overflow for the solution, but I can't seem to get anything from the posts available. (Please keep in mind I'm fairly new to Python and Stack Overflow)
I get 200 response from the server so I am pretty sure the problem is in generating the signature.
Here is my code (xxx, yyy and zzz variables are purposefully written like that):
Kraken_secret_key = 'xxx'
Kraken_headers ={
'Kraken_API_key': 'yyy'
}
def Kraken_account_balance(Kraken_headers):
URI_path= '/0/private/Balance'
URL_path = 'https://api.kraken.com/0/private/Balance'
Kraken_nonce = str(int(time.time()*1000))
otp = 'zzz'
Kraken_POST_data = {
'nonce': Kraken_nonce,
'otp': str(otp)
}
encoded = (str(Kraken_nonce)+str(otp)).encode()
message = URI_path.encode() + hashlib.sha256(encoded).digest()
Kraken_signature = hmac.new(base64.b64decode(Kraken_secret_key), message, digestmod=hashlib.sha512)
Kraken_signature_digest = base64.b64encode(Kraken_signature.digest())
Kraken_headers['Kraken_API_Signature'] = Kraken_signature_digest.decode()
response = requests.post(URL_path,data= Kraken_POST_data, headers = Kraken_headers)
result = response.json()
print(result)
So I figured out why my code was not working.
In my case, the only POST data I used was the "nonce" value. So for example, if in the above code nonce was equal to
'nonce': 666999
the same value used in the call, but URL encoded with 'urllib.parse.urlencode' method would be equal to
"nonce=666999"
So in the above code
Kraken_headers ={
'Kraken_API_key': 'yyy'
}
and
Kraken_headers['Kraken_API_Signature'] = Kraken_signature_digest.decode()
should be renamed to
Kraken_headers ={
'API-Key': 'yyy'
}
and
Kraken_headers['API-Sign'] = Kraken_signature_digest.decode()
import requests
import time
import hmac
import hashlib
import json
import base64
import urllib
Kraken_secret_key = 'xxx'
Kraken_headers ={
'API-Key': 'yyy'
}
def Kraken_account_balance(Kraken_headers):
URI_path= '/0/private/Balance'
URL_path = 'https://api.kraken.com/0/private/Balance'
Kraken_nonce = str(int(time.time()*1000))
Kraken_POST_data = {
'nonce': Kraken_nonce
}
url_encoded_post_data = urllib.parse.urlencode(Kraken_POST_data)
encoded = (str(Kraken_POST_data['nonce'])+url_encoded_post_data).encode()
message = URI_path.encode() + hashlib.sha256(encoded).digest()
Kraken_signature = hmac.new(base64.b64decode(Kraken_secret_key), message,
hashlib.sha512)
Kraken_signature_digest = base64.b64encode(Kraken_signature.digest())
Kraken_headers['API-Sign'] = Kraken_signature_digest.decode()
response = requests.post(URL_path,data= Kraken_POST_data, headers =
Kraken_headers)
result = response.json()
print(result)
Kraken_account_balance(Kraken_headers)