mirror of
https://github.com/wassname/libcryptomarket.git
synced 2026-09-04 16:34:49 +08:00
Merge pull request #8 from libcryptomarket/feature/#7
[#7] Add exchange Poloniex for private API
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
#!/bin/python
|
||||
import requests
|
||||
import hmac
|
||||
import hashlib
|
||||
import urllib
|
||||
from functools import partial
|
||||
|
||||
from libcryptomarket.api.rest_api_connector import RestApiConnector
|
||||
API_URL = "https://poloniex.com/public?command="
|
||||
VALID_PERIODS = [300, 900, 1800, 7200, 14400, 86400]
|
||||
|
||||
@@ -58,3 +64,116 @@ def get_return_order_book(currency_pair, depth=10):
|
||||
raise ValueError("Query error from Poloniex API ({0})".format(rjson))
|
||||
|
||||
return r.json()
|
||||
|
||||
|
||||
class PoloniexApi(RestApiConnector):
|
||||
"""Poloniex API.
|
||||
"""
|
||||
|
||||
URL = 'https://poloniex.com/tradingApi'
|
||||
|
||||
AVAILABLE_TRADING_API = [
|
||||
"returnBalances",
|
||||
"returnCompleteBalances",
|
||||
"returnDepositAddresses",
|
||||
"generateNewAddress",
|
||||
"returnDepositsWithdrawals",
|
||||
"returnOpenOrders",
|
||||
"returnTradeHistory",
|
||||
"returnOrderTrades",
|
||||
"buy",
|
||||
"sell",
|
||||
"cancelOrder",
|
||||
"moveOrder",
|
||||
"withdraw",
|
||||
"returnFeeInfo",
|
||||
"returnAvailableAccountBalances",
|
||||
"returnTradableBalances",
|
||||
"transferBalance",
|
||||
"returnMarginAccountSummary",
|
||||
"marginBuy",
|
||||
"marginSell",
|
||||
"getMarginPosition",
|
||||
"closeMarginPosition",
|
||||
"createLoanOffer",
|
||||
"cancelLoanOffer",
|
||||
"returnOpenLoanOffers",
|
||||
"returnActiveLoans",
|
||||
"returnLendingHistory",
|
||||
"toggleAutoRenew",
|
||||
]
|
||||
|
||||
def __init__(self, public_key, private_key, logger=None):
|
||||
"""Constructor.
|
||||
|
||||
:param public_key: Public key.
|
||||
:param private_key: Private key.
|
||||
"""
|
||||
RestApiConnector.__init__(self, url=PoloniexApi.URL, logger=logger)
|
||||
|
||||
self.__public_key = public_key
|
||||
self.__private_key = private_key
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Get attribute.
|
||||
"""
|
||||
if name in PoloniexApi.AVAILABLE_TRADING_API:
|
||||
return partial(self._request, command=name, http_method="POST")
|
||||
else:
|
||||
raise AttributeError("Trading method ({0}) ".format(name) +
|
||||
"is not defined.")
|
||||
|
||||
def _request(self, command, **kwargs):
|
||||
"""Send request.
|
||||
|
||||
:param kwargs: Named arguments.
|
||||
"""
|
||||
kwargs["command"] = command
|
||||
kwargs["nonce"] = self._generate_nonce()
|
||||
|
||||
return self._send_request(
|
||||
command="",
|
||||
http_method="POST",
|
||||
public_key=self.__public_key,
|
||||
private_key=self.__private_key,
|
||||
params=None,
|
||||
data=kwargs)
|
||||
|
||||
def _generate_auth(self, public_key, private_key):
|
||||
"""Generate authentication.
|
||||
|
||||
:param public_key: Public key.
|
||||
:param private_key: Private key.
|
||||
"""
|
||||
return None
|
||||
|
||||
def _generate_headers(self, 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.
|
||||
"""
|
||||
signature = hmac.new(private_key.encode(),
|
||||
urllib.parse.urlencode(data).encode(),
|
||||
digestmod=hashlib.sha512).hexdigest()
|
||||
header = {
|
||||
'Key': public_key,
|
||||
'Sign': signature
|
||||
}
|
||||
|
||||
return header
|
||||
|
||||
def _format_data(self, data):
|
||||
"""Format the data to exchange desirable format.
|
||||
|
||||
:param data: Data.
|
||||
"""
|
||||
if data is None:
|
||||
return ""
|
||||
else:
|
||||
return data
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
#!/bin/python
|
||||
import requests
|
||||
import urllib
|
||||
import json
|
||||
from time import time
|
||||
|
||||
|
||||
class RestApiConnector(object):
|
||||
"""REST API connector.
|
||||
"""
|
||||
|
||||
def __init__(self, url, logger=None):
|
||||
"""Constructor.
|
||||
|
||||
:param url: URL address.
|
||||
:param logger: Logger. Default is None.
|
||||
"""
|
||||
self._logger = logger
|
||||
self._url = url
|
||||
|
||||
@classmethod
|
||||
def _generate_nonce(cls):
|
||||
"""Generate an increasing unique number.
|
||||
"""
|
||||
return int(round(time() * 1000))
|
||||
|
||||
def _generate_headers(self, 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.")
|
||||
|
||||
def _generate_auth(self, public_key, private_key):
|
||||
"""Generate authentication.
|
||||
|
||||
:param public_key: Public key.
|
||||
:param private_key: Private key.
|
||||
"""
|
||||
raise NotImplementedError("Not yet implemented.")
|
||||
|
||||
def _format_data(self, data):
|
||||
"""Format the data to exchange desirable format.
|
||||
|
||||
:param data: Data.
|
||||
"""
|
||||
raise NotImplementedError("Not yet implemented.")
|
||||
|
||||
def _send_request(self, command, http_method, public_key, private_key,
|
||||
params=None, data=None):
|
||||
"""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.
|
||||
: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.")
|
||||
|
||||
url = urllib.parse.urljoin(self._url, command)
|
||||
data = self._format_data(data)
|
||||
headers = self._generate_headers(command, http_method, params,
|
||||
data, public_key, private_key)
|
||||
auth = self._generate_auth(public_key, private_key)
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user