Kraken API 'EAPI: неверный ключ' с Python3
Я попытался сделать простую функцию, которая делает HTTP-запрос к API обмена Kraken. Метод частный, я пытаюсь получить остаток на моем счете.
Согласно документации Kraken ( https://www.kraken.com/features/api):
Заголовок HTTP:
API-ключ = API-ключ
API-Sign = подпись сообщения с использованием HMAC-SHA512 (URI-путь + SHA256(nonce + POST-данные)) и декодированного секретного ключа API base64
Данные POST:
nonce = всегда увеличивать 64-разрядное целое число без знака
otp = двухфакторный пароль (если двухфакторный включен, в противном случае не требуется)
Я попытался сделать генерацию моей подписи похожей на библиотеку Python "veox" (доступна по адресу: https://github.com/veox/python3-krakenex/blob/master/krakenex/api.py).
Я использую Python 3.6.7 на Ubuntu 18.04.
2FA (otp) включен для моей учетной записи на обмене Kraken, хотя я не уверен, что мне нужно включить в запрос.
Я искал переполнение стека для решения, но я не могу ничего получить из доступных сообщений. (Пожалуйста, имейте в виду, что я довольно плохо знаком с Python и Stack Overflow)
Я получаю 200 ответ от сервера, поэтому я уверен, что проблема заключается в создании подписи.
Вот мой код (переменные xxx, yyy и zzz специально написаны так):
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)
1 ответ
Поэтому я понял, почему мой код не работает.
Короткий ответ:
- Данные POST, используемые в вызове API Kraken, должны быть в кодировке URL. Это означает, что для правильной работы API "nonce" и "otp" должны быть закодированы в URL. Я использовал метод "urllib.parse.urlencode" из модуля "urllib", чтобы заставить API работать должным образом.
- Значения заголовка должны явно называться теми же именами, что и в руководстве по Kraken API.
Длинный ответ:
- Это может быть потому, что я новичок в программировании API, но в руководстве по Kraken API не указано, что данные POST должны быть закодированы в URL. OTP (двухфакторная аутентификация) в этом случае не повлияла на мой код, поэтому я избавился от этой части данных POST в вызове.
В моем случае единственными данными POST, которые я использовал, было значение "nonce". Так, например, если в приведенном выше коде одноразовый номер был равен
'nonce': 666999
то же значение, которое используется в вызове, но URL-адрес, закодированный с помощью метода urllib.parse.urlencode, будет равен
"nonce=666999"
- Опять же, вероятно, это не проблема для более опытных разработчиков, но для меня не было очевидным, что значения заголовков должны явно называться теми же именами, что и в руководстве по API Kraken.
Так в приведенном выше коде
Kraken_headers ={
'Kraken_API_key': 'yyy'
}
а также
Kraken_headers['Kraken_API_Signature'] = Kraken_signature_digest.decode()
следует переименовать в
Kraken_headers ={
'API-Key': 'yyy'
}
а также
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)