Estoy tratando de usar Python para acceder a la API comercial en poloniex.com, un intercambio de criptomonedas. Para ello debo seguir esta prescripción:
Todas las llamadas a la API comercial se envían a través de HTTP POST a https://poloniex.com/tradingApi y deben contener los siguientes encabezados:
Clave: su clave API.
Firmar: los datos POST de la consulta firmados por el "secreto" de su clave de acuerdo con el método HMAC-SHA512.Además, todas las consultas deben incluir un parámetro POST "nonce". El parámetro nonce es un número entero que siempre debe ser mayor que el nonce anterior utilizado.
Esto es lo que tengo hasta ahora. Mi problema actual es que no sé cómo compilar la URL POST para que pueda firmarse sin enviar primero la solicitud incompleta. Esto obviamente no funciona.
import requests import hmac import hashlib import time headers = { 'nonce': '', 'Key' : 'myKey', 'Sign': '',} payload = { 'command': 'returnCompleteBalances', 'account': 'all'} secret = 'mySecret' headers['nonce'] = int(time.time()) response = requests.post( 'https://poloniex.com/tradingApi', params= payload, headers= headers ) headers['Sign'] = hmac.new( secret, response.url, hashlib.sha512)Crear una solicitud preparada ; puede agregar encabezados a eso después de que se haya creado el cuerpo:
import requests import hmac import hashlib request = requests.Request( 'POST', 'https://poloniex.com/tradingApi', data=payload, headers=headers) prepped = request.prepare() signature = hmac.new(secret, prepped.body, digestmod=hashlib.sha512) prepped.headers['Sign'] = signature.hexdigest() with requests.Session() as session: response = session.send(prepped) Cambié su argumento params a data ; para una solicitud POST, se acostumbra enviar los parámetros en el cuerpo, no la URL.
Por el momento, usaría un objeto itertools.count() , sembrado desde la hora actual para que los reinicios no lo afecten. De acuerdo con la documentación de la API de Poloniex (que citó en su pregunta), el nonce es parte del cuerpo POST, no de los encabezados, así que póngalo en el diccionario de payload :
from itertools import count import time # store as a global variable NONCE_COUNTER = count(int(time.time() * 1000)) # then every time you create a request payload['nonce'] = next(NONCE_COUNTER) Usar int(time.time()) volvería a usar el mismo número si creaste más de una solicitud por segundo. El código de ejemplo proporcionado por Poloniex usa int(time.time()*1000) para hacer posible crear una solicitud cada microsegundo, pero usar su propio contador que aumenta monótonamente (sembrado de time.time() ) es mucho más sólido.
También puede encapsular el proceso de firma de resumen en un objeto de autenticación personalizado ; dicho objeto se pasa en la solicitud preparada como último paso en la preparación:
import hmac import hashlib class BodyDigestSignature(object): def __init__(self, secret, header='Sign', algorithm=hashlib.sha512): self.secret = secret self.header = header self.algorithm = algorithm def __call__(self, request): body = request.body if not isinstance(body, bytes): # Python 3 body = body.encode('latin1') # standard encoding for HTTP signature = hmac.new(self.secret, body, digestmod=self.algorithm) request.headers[self.header] = signature.hexdigest() return request Use esto con sus requests de llamadas:
response = requests.post( 'https://poloniex.com/tradingApi', data=payload, headers=headers, auth=BodyDigestSignature(secret))El argumento pasado es el secreto utilizado en el resumen de HMAC; también puede pasar un nombre de encabezado diferente.