mirror of
https://github.com/wassname/libcryptomarket.git
synced 2026-10-29 13:10:23 +08:00
217 lines
6.6 KiB
Python
217 lines
6.6 KiB
Python
#!/bin/python
|
|
import requests
|
|
import hmac
|
|
import hashlib
|
|
import urllib
|
|
import json
|
|
from functools import partial
|
|
from time import time
|
|
|
|
class ExchangeApi:
|
|
"""Exchange API connector.
|
|
"""
|
|
def __init__(self, public_key, private_key, logger=None):
|
|
"""Constructor.
|
|
|
|
:param public_key: Public key.
|
|
:param private_key: Private key.
|
|
:param logger: Logger.
|
|
"""
|
|
self._public_key = public_key
|
|
self._private_key = private_key
|
|
self._logger = logger
|
|
|
|
@classmethod
|
|
def get_url(cls):
|
|
"""Get API url.
|
|
"""
|
|
raise NotImplementedError("Url getter not implemented")
|
|
|
|
@classmethod
|
|
def get_public_url(cls):
|
|
"""Get public API url.
|
|
"""
|
|
raise NotImplementedError("Public url getter not implemented")
|
|
|
|
@classmethod
|
|
def get_private_url(cls):
|
|
"""Get private API url.
|
|
"""
|
|
raise NotImplementedError("Private url getter not implemented")
|
|
|
|
@classmethod
|
|
def get_public_calls(cls):
|
|
"""Get public API calls.
|
|
"""
|
|
raise NotImplementedError("Public API calls getter not implemented")
|
|
|
|
@classmethod
|
|
def get_private_calls(cls):
|
|
"""Get private API calls.
|
|
"""
|
|
raise NotImplementedError("Private API calls getter not implemented")
|
|
|
|
@classmethod
|
|
def translate_call_name(cls, name):
|
|
"""Translate API call name.
|
|
|
|
The class method name is always underscored (aligned with Python
|
|
standard.) This method is to translate underscored name to exchange
|
|
API call name.
|
|
|
|
:param name: Method name (underscored).
|
|
"""
|
|
return name
|
|
|
|
def __getattr__(self, name):
|
|
"""Get attribute.
|
|
"""
|
|
name = self.translate_call_name(name)
|
|
|
|
if name in self.get_public_calls().keys():
|
|
return partial(self._request_public, name=name,
|
|
http_method=self.get_public_calls()[name])
|
|
elif name in self.get_private_calls().keys():
|
|
return partial(self._request_private, name=name,
|
|
http_method=self.get_private_calls()[name])
|
|
else:
|
|
raise AttributeError("Trading method ({0}) ".format(name) +
|
|
"is not defined.")
|
|
|
|
def _request_public(self, name, http_method, **kwargs):
|
|
"""Request public API call.
|
|
|
|
:param name: Method name.
|
|
:param http_method: HTTP method (POST, GET, DELETE).
|
|
"""
|
|
raise NotImplementedError("Public API request not implemented")
|
|
|
|
def _request_private(self, name, http_method, *kwargs):
|
|
"""Request private API call.
|
|
|
|
:param name: Method name.
|
|
:param http_method: HTTP method (POST, GET, DELETE).
|
|
"""
|
|
raise NotImplementedError("Private API request not implemented")
|
|
|
|
# ======================================================================
|
|
# Requests
|
|
# ======================================================================
|
|
|
|
@classmethod
|
|
def _generate_nonce(cls):
|
|
"""Generate an increasing unique number.
|
|
"""
|
|
return int(round(time() * 1000))
|
|
|
|
@classmethod
|
|
def _generate_headers(cls, command, http_method, params, data,
|
|
public_key, private_key):
|
|
"""Generate headers.
|
|
|
|
:param command: Command.
|
|
:param http_method: HTTP method, for example GET.
|
|
:param params: Parameters.
|
|
:param data: Data.
|
|
:param public_key: Public key.
|
|
:param private_key: Private key.
|
|
"""
|
|
raise NotImplementedError("Not yet implemented.")
|
|
|
|
@classmethod
|
|
def _generate_auth(cls, public_key, private_key):
|
|
"""Generate authentication.
|
|
|
|
:param public_key: Public key.
|
|
:param private_key: Private key.
|
|
"""
|
|
raise NotImplementedError("Not yet implemented.")
|
|
|
|
@classmethod
|
|
def _generate_data(cls, data):
|
|
"""Generate data.
|
|
|
|
:param data: Dict containing data information.
|
|
"""
|
|
raise NotImplementedError("Not yet implemented.")
|
|
|
|
|
|
def _send_request(self, command, http_method, params=None, data=None,
|
|
public_method=False):
|
|
"""Send request.
|
|
|
|
:param command: API command.
|
|
:param http_method: Http method.
|
|
:param api_key: API key.
|
|
:param params: Input parameters, which will be parsed
|
|
as "?key1=value1...".
|
|
:param data: Data.
|
|
:param public_method: Indicate if the request is a public method.
|
|
:return: JSON object.
|
|
"""
|
|
http_method = http_method.upper()
|
|
if http_method == "DELETE":
|
|
R = requests.delete
|
|
elif http_method == "GET":
|
|
R = requests.get
|
|
elif http_method == "POST":
|
|
R = requests.post
|
|
else:
|
|
raise ValueError("Http method must be either DELETE, GET or "
|
|
"POST.")
|
|
|
|
# Get url
|
|
url = self.get_url()
|
|
|
|
if url is None:
|
|
if public_method:
|
|
url = self.get_public_url()
|
|
else:
|
|
url = self.get_private_url()
|
|
|
|
if url is None:
|
|
raise NotImplementedError("Url cannot be None.")
|
|
|
|
if command is not None or command == "":
|
|
url = '/'.join([url, command])
|
|
|
|
# Get data
|
|
if data is not None:
|
|
data = self._format_data(data)
|
|
else:
|
|
data = ""
|
|
|
|
# Get headers and auth
|
|
if (self._public_key is not None and self._private_key is not None and
|
|
not public_method):
|
|
headers = self._generate_headers(command, http_method, params,
|
|
data, self._public_key,
|
|
self._private_key)
|
|
auth = self._generate_auth(self._public_key, self._private_key)
|
|
else:
|
|
headers = None
|
|
auth = None
|
|
|
|
if self._logger is not None:
|
|
self._logger.info(">>> OUT:\n%s" % json.dumps({
|
|
"Method": http_method,
|
|
"Url": url,
|
|
"Params": params,
|
|
"Data": data,
|
|
"Headers": headers
|
|
}))
|
|
|
|
if auth is None:
|
|
response = R(url, params=params, data=data, headers=headers)
|
|
else:
|
|
response = R(url, params=params, data=data, headers=headers,
|
|
auth=auth)
|
|
|
|
if self._logger is not None:
|
|
self._logger.info("<<< IN:\n%s" % json.dumps({
|
|
"Status code": response.status_code,
|
|
"Text": response.text
|
|
}))
|
|
|
|
return response
|