256 lines
7.3 KiB
Python
256 lines
7.3 KiB
Python
|
# -*- coding: utf-8 -*-
|
|||
|
import sys
|
|||
|
import time
|
|||
|
import hashlib
|
|||
|
import requests
|
|||
|
import json
|
|||
|
from queue import Queue, Empty
|
|||
|
from multiprocessing.dummy import Pool
|
|||
|
from threading import Thread
|
|||
|
|
|||
|
# 此处为APIID SECRET
|
|||
|
apiid = ' '
|
|||
|
secret = ' '
|
|||
|
|
|||
|
# 此处为API请求地址及参数
|
|||
|
REST_HOST = "http://api.coinbene.com"
|
|||
|
market_url = "http://api.coinbene.com/v1/market/"
|
|||
|
trade_url = "http://api.coinbene.com/v1/trade/"
|
|||
|
header_dict = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko",\
|
|||
|
"Content-Type":"application/json;charset=utf-8","Connection":"keep-alive"}
|
|||
|
|
|||
|
FUNCTIONCODE_GET_ORDERBOOK_COINBENE = "orderbook"
|
|||
|
FUNCTIONCODE_GET_TICKER_COINBENE = "ticker"
|
|||
|
FUNCTIONCODE_GET_TRADE_COINBENE = "trades"
|
|||
|
FUNCTIONCODE_POST_BALANCE_COINBENE = "balance"
|
|||
|
FUNCTIONCODE_POST_CANCEL_COINBENE = "order/cancel"
|
|||
|
FUNCTIONCODE_POST_INFO_COINBENE = "order/info"
|
|||
|
FUNCTIONCODE_POST_ORDERPLACE_COINBENE = "order/place"
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
class coinbeneRestApi(object):
|
|||
|
|
|||
|
def __init__(self):
|
|||
|
self.apiKey = ''
|
|||
|
self.apiSecret = ''
|
|||
|
|
|||
|
self.active = False
|
|||
|
self.reqid = 0
|
|||
|
self.queue = Queue()
|
|||
|
self.pool = None
|
|||
|
self.sessionDict = {} # 会话对象字典
|
|||
|
|
|||
|
self.header = {
|
|||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|||
|
'Accept': 'application/json'
|
|||
|
}
|
|||
|
|
|||
|
# ----------------------------------------------------------------------
|
|||
|
def init(self, apiKey, apiSecret):
|
|||
|
"""初始化"""
|
|||
|
self.apiKey = apiKey
|
|||
|
self.apiSecret = apiSecret
|
|||
|
|
|||
|
# ----------------------------------------------------------------------
|
|||
|
def start(self, n=3):
|
|||
|
"""启动"""
|
|||
|
if self.active:
|
|||
|
return
|
|||
|
|
|||
|
self.active = True
|
|||
|
self.pool = Pool(n)
|
|||
|
self.pool.map_async(self.run, range(n))
|
|||
|
|
|||
|
# ----------------------------------------------------------------------
|
|||
|
def close(self):
|
|||
|
"""关闭"""
|
|||
|
self.active = False
|
|||
|
|
|||
|
if self.pool:
|
|||
|
self.pool.close()
|
|||
|
self.pool.join()
|
|||
|
|
|||
|
# ----------------------------------------------------------------------
|
|||
|
|
|||
|
def addReq(self, method, path, callback, params=None, postdict=None):
|
|||
|
"""添加请求"""
|
|||
|
self.reqid += 1
|
|||
|
req = (method, path, callback, params, postdict, self.reqid)
|
|||
|
self.queue.put(req)
|
|||
|
return self.reqid
|
|||
|
|
|||
|
# ----------------------------------------------------------------------
|
|||
|
|
|||
|
def processReq(self, req, i):
|
|||
|
"""处理请求"""
|
|||
|
method, callback, params, postdict, reqid = req
|
|||
|
|
|||
|
# 使用长连接的session,比短连接的耗时缩短80%
|
|||
|
session = self.sessionDict[i]
|
|||
|
resp = session.request(method, url, headers=header, params=params, data=postdict)
|
|||
|
|
|||
|
# resp = requests.request(method, url, headers=header, params=params, data=postdict)
|
|||
|
|
|||
|
code = resp.status_code
|
|||
|
d = resp.json()
|
|||
|
|
|||
|
if code == 200:
|
|||
|
callback(d, reqid)
|
|||
|
else:
|
|||
|
self.onError(code, d)
|
|||
|
|
|||
|
# ----------------------------------------------------------------------
|
|||
|
|
|||
|
def run(self, i):
|
|||
|
"""连续运行"""
|
|||
|
self.sessionDict[i] = requests.Session()
|
|||
|
|
|||
|
while self.active:
|
|||
|
try:
|
|||
|
req = self.queue.get(timeout=1)
|
|||
|
self.processReq(req, i)
|
|||
|
except Empty:
|
|||
|
pass
|
|||
|
|
|||
|
# ----------------------------------------------------------------------
|
|||
|
def onError(self, code, error):
|
|||
|
"""错误回调"""
|
|||
|
print(u'on error {} {}'.format(code, error),file=sys.stderr)
|
|||
|
|
|||
|
# ----------------------------------------------------------------------
|
|||
|
def onData(self, data, reqid):
|
|||
|
"""通用回调"""
|
|||
|
print(u'on data:{} reqid:{}'.format(data, reqid))
|
|||
|
|
|||
|
# 生成签名sign
|
|||
|
def sign(self,**kwargs):
|
|||
|
"""
|
|||
|
将传入的参数生成列表形式,排序后用&拼接成字符串,用hashbli加密成生sign
|
|||
|
"""
|
|||
|
sign_list = []
|
|||
|
for key, value in kwargs.items():
|
|||
|
sign_list.append("{}={}".format(key, value))
|
|||
|
sign_list.sort()
|
|||
|
sign_str = "&".join(sign_list)
|
|||
|
mysecret = sign_str.upper().encode()
|
|||
|
m = hashlib.md5()
|
|||
|
m.update(mysecret)
|
|||
|
return m.hexdigest()
|
|||
|
|
|||
|
# 生成时间戳
|
|||
|
def create_timestamp(self):
|
|||
|
timestamp = int(round(time.time() * 1000))
|
|||
|
return timestamp
|
|||
|
|
|||
|
#timestamp = create_timestamp()
|
|||
|
|
|||
|
def http_get_nosign(self, url, i=0):
|
|||
|
return self.http_request(url, data=None,i=i)
|
|||
|
|
|||
|
def http_post_sign(self,url,dic,i=0):
|
|||
|
mysign = self.sign(**dic)
|
|||
|
del dic['secret']
|
|||
|
dic['sign'] = mysign
|
|||
|
return self.http_request(url,data=dic,i=i)
|
|||
|
|
|||
|
def http_request(self, url, data,i=0):
|
|||
|
session = self.sessionDict[i]
|
|||
|
if data == None:
|
|||
|
reponse = session.request(method, url, headers=header_dict, params=params, data=postdict)
|
|||
|
reponse = requests.get(url,headers=header_dict)
|
|||
|
else:
|
|||
|
reponse = requests.post(url,data=json.dumps(data),headers=header_dict)
|
|||
|
try:
|
|||
|
if reponse.status_code == 200:
|
|||
|
return json.loads(reponse.text)
|
|||
|
else:
|
|||
|
return None
|
|||
|
except Exception as e:
|
|||
|
print('http failed : %s' % e)
|
|||
|
return None
|
|||
|
|
|||
|
|
|||
|
# 获取最新价
|
|||
|
def get_ticker(self, symbol):
|
|||
|
"""
|
|||
|
symbol必填,为all或交易对代码:btcusdt
|
|||
|
"""
|
|||
|
url = market_url + "ticker?symbol=" + str(symbol)
|
|||
|
return self.http_get_nosign(url)
|
|||
|
|
|||
|
|
|||
|
# 获取挂单
|
|||
|
def get_orderbook(self, symbol, depth=200):
|
|||
|
"""
|
|||
|
depth为选填项,默认为200
|
|||
|
"""
|
|||
|
url = market_url + "orderbook?symbol=" + symbol + "&depth=" + str(depth)
|
|||
|
return self.http_get_nosign(url)
|
|||
|
|
|||
|
|
|||
|
# 获取成交记录
|
|||
|
def get_trade(self, symbol, size=300):
|
|||
|
"""
|
|||
|
size:获取记录数量,按照时间倒序传输。默认300
|
|||
|
"""
|
|||
|
url = market_url + "trades?symbol=" + symbol + "&size=" + str(size)
|
|||
|
return self.http_get_nosign(url)
|
|||
|
|
|||
|
|
|||
|
# 查询账户余额
|
|||
|
def post_balance(self, dic):
|
|||
|
"""
|
|||
|
以字典形式传参
|
|||
|
apiid:可在coinbene申请,
|
|||
|
secret:个人密钥(请勿透露给他人),
|
|||
|
timestamp:时间戳,
|
|||
|
account:默认为exchange,
|
|||
|
"""
|
|||
|
url = trade_url + "balance"
|
|||
|
return self.http_post_sign(url, dic)
|
|||
|
|
|||
|
|
|||
|
# 下单
|
|||
|
def post_order_place(self, dic):
|
|||
|
"""
|
|||
|
以字典形式传参
|
|||
|
apiid,symbol,timestamp
|
|||
|
type:可选 buy-limit/sell-limit
|
|||
|
price:购买单价
|
|||
|
quantity:购买数量
|
|||
|
"""
|
|||
|
url = trade_url + "order/place"
|
|||
|
return self.http_post_sign(url, dic)
|
|||
|
|
|||
|
|
|||
|
# 查询委托
|
|||
|
def post_info(self, dic):
|
|||
|
"""
|
|||
|
以字典形式传参
|
|||
|
apiid,timestamp,secret,orderid
|
|||
|
"""
|
|||
|
url = trade_url + "order/info"
|
|||
|
return self.http_post_sign(url, dic)
|
|||
|
|
|||
|
|
|||
|
# 查询当前委托
|
|||
|
def post_open_orders(self, dic):
|
|||
|
"""
|
|||
|
以字典形式传参
|
|||
|
apiid,timestamp,secret,symbol
|
|||
|
"""
|
|||
|
url = trade_url + "order/open-orders"
|
|||
|
return self.http_post_sign(url, dic)
|
|||
|
|
|||
|
|
|||
|
# 撤单
|
|||
|
def post_cancel(self, dic):
|
|||
|
"""
|
|||
|
以字典形式传参
|
|||
|
apiid,timestamp,secret,orderid
|
|||
|
"""
|
|||
|
url = trade_url + "order/cancel"
|
|||
|
return self.http_post_sign(url, dic)
|