diff --git a/vn.lhang/README.md b/vn.lhang/README.md new file mode 100644 index 00000000..aaf7d942 --- /dev/null +++ b/vn.lhang/README.md @@ -0,0 +1,16 @@ +# vn.lhang + +### 简介 + +链行的比特币交易接口,基于Rest API开发。 + +### 特点 +vn.lhang的一些特点: + +1. 面向对象的API设计,接近CTP API的结构,对于国内用户而言更容易上手 + +2. 参考CTP API的设计,主动函数调用的结果通过异步(回调函数)的方式推送到程序中,适用于开发稳定可靠的实盘交易程序 + +### API版本 +日期:2017 - 02 +来源:链行官方API交流群 325248096 \ No newline at end of file diff --git a/vn.lhang/test.py b/vn.lhang/test.py new file mode 100644 index 00000000..f59fd509 --- /dev/null +++ b/vn.lhang/test.py @@ -0,0 +1,47 @@ +# encoding: utf-8 + +from time import time, sleep + +from vnlhang import LhangApi + + +if __name__ == '__main__': + apiKey = '259ad3a4-3e19-489e-935d-71b43ad65be8' + secretKey = '9A4D9094315681F62FB4C7FB6494FBD2' + + # 创建API对象并初始化 + api = LhangApi() + api.DEBUG = True + api.init(apiKey, secretKey) + + # 查询行情 + api.getTicker('btc_cny') + + # 查询深度 + api.getDepth('btc_cny', '60', '1') + + # 查询历史成交 + #api.getTrades('btc_cny', '1', str(int(time()))) + + # 查询K线 + #t = int(time()) + #sleep(300) + #api.getKline('btc_cny', '20', 'minute1', str(t)) + + # 查询账户 + #api.getUserInfo() + + # 发送委托 + #api.createOrder('btc_cny', 'sell', '8000', '0.001') + + # 撤单 + #api.cancelOrder('btc_cny', '725bd2da-73aa-419f-8090-f68488074e8f') + + # 查询委托 + #api.getOrdersInfo('btc_cny', '725bd2da-73aa-419f-8090-f68488074e8f') + + # 查询委托历史 + #api.getOrdersInfoHistory('btc_cny', '0', '1', '100') + + # 阻塞 + raw_input() diff --git a/vn.lhang/vnlhang.py b/vn.lhang/vnlhang.py new file mode 100644 index 00000000..72b7225b --- /dev/null +++ b/vn.lhang/vnlhang.py @@ -0,0 +1,298 @@ +# encoding: utf-8 + +import urllib +import hashlib + +import requests +from Queue import Queue, Empty +from threading import Thread + + +LHANG_API_ROOT ="https://api.lhang.com/v1/" + +FUNCTION_TICKER = ('ticker.do', 'get') +FUNCTION_DEPTH = ('depth.do', 'get') +FUNCTION_TRADES = ('trades.do', 'get') +FUNCTION_KLINE = ('kline.do', 'get') + +FUNCTION_USERINFO = ('user_info.do', 'post') +FUNCTION_CREATEORDER = ('create_order.do', 'post') +FUNCTION_CANCELORDER = ('cancel_order.do', 'post') +FUNCTION_ORDERSINFO = ('orders_info.do', 'post') +FUNCTION_ORDERSINFOHISTORY = ('orders_info_history.do', 'post') + + +#---------------------------------------------------------------------- +def signature(params, secretKey): + """生成签名""" + params = sorted(params.iteritems(), key=lambda d:d[0], reverse=False) + params.append(('secret_key', secretKey)) + message = urllib.urlencode(params) + + m = hashlib.md5() + m.update(message) + m.digest() + + sig=m.hexdigest() + return sig + + +######################################################################## +class LhangApi(object): + """""" + DEBUG = True + + #---------------------------------------------------------------------- + def __init__(self): + """Constructor""" + self.apiKey = '' + self.secretKey = '' + + self.active = False # API工作状态 + self.reqID = 0 # 请求编号 + self.reqQueue = Queue() # 请求队列 + self.reqThread = Thread(target=self.processQueue) # 请求处理线程 + + #---------------------------------------------------------------------- + def init(self, apiKey, secretKey): + """初始化""" + self.apiKey = apiKey + self.secretKey = secretKey + + self.active = True + self.reqThread.start() + + #---------------------------------------------------------------------- + def exit(self): + """退出""" + self.active = False + self.reqThread.join() + + #---------------------------------------------------------------------- + def processRequest(self, req): + """处理请求""" + # 读取方法和参数 + api, method = req['function'] + params = req['params'] + url = LHANG_API_ROOT + api + + # 在参数中增加必须的字段 + params['api_key'] = self.apiKey + + # 添加签名 + sign = signature(params, self.secretKey) + params['sign'] = sign + + # 发送请求 + payload = urllib.urlencode(params) + + r = requests.request(method, url, params=payload) + if r.status_code == 200: + data = r.json() + return data + else: + return None + + #---------------------------------------------------------------------- + def processQueue(self): + """处理请求队列中的请求""" + while self.active: + try: + req = self.reqQueue.get(block=True, timeout=1) # 获取请求的阻塞为一秒 + callback = req['callback'] + reqID = req['reqID'] + + data = self.processRequest(req) + + # 请求失败 + if data is None: + error = u'请求失败' + self.onError(error, reqID) + elif 'error_code' in data: + error = u'请求出错,错误代码:%s' % data['error_code'] + self.onError(error, reqID) + # 请求成功 + else: + if self.DEBUG: + print callback.__name__ + callback(data, reqID) + + except Empty: + pass + + #---------------------------------------------------------------------- + def sendRequest(self, function, params, callback): + """发送请求""" + # 请求编号加1 + self.reqID += 1 + + # 生成请求字典并放入队列中 + req = {} + req['function'] = function + req['params'] = params + req['callback'] = callback + req['reqID'] = self.reqID + self.reqQueue.put(req) + + # 返回请求编号 + return self.reqID + + #---------------------------------------------------------------------- + def onError(self, error, reqID): + """错误推送""" + print error, reqID + + ############################################### + # 行情接口 + ############################################### + + #---------------------------------------------------------------------- + def getTicker(self, symbol): + """查询行情""" + function = FUNCTION_TICKER + params = {'symbol': symbol} + callback = self.onGetTicker + return self.sendRequest(function, params, callback) + + # ---------------------------------------------------------------------- + def getDepth(self, symbol, size, merge): + """查询深度""" + function = FUNCTION_DEPTH + params = { + 'symbol': symbol, + 'size': size, + 'mege': merge + } + callback = self.onGetDepth + return self.sendRequest(function, params, callback) + + # ---------------------------------------------------------------------- + def getTrades(self, symbol, size, time): + """查询历史成交""" + function = FUNCTION_TRADES + params = { + 'symbol': symbol, + 'size': size, + 'time': time + } + callback = self.onGetTrades + return self.sendRequest(function, params, callback) + + # ---------------------------------------------------------------------- + def getKline(self, symbol, size, type_, time): + """查询K线""" + function = FUNCTION_TRADES + params = { + 'symbol': symbol, + 'size': size, + 'type': type_, + 'time': time + } + callback = self.onGetKline + return self.sendRequest(function, params, callback) + + #---------------------------------------------------------------------- + def onGetTicker(self, data, reqID): + """查询行情回调""" + print data, reqID + + # ---------------------------------------------------------------------- + def onGetDepth(self, data, reqID): + """查询深度回调""" + print data, reqID + + # ---------------------------------------------------------------------- + def onGetTrades(self, data, reqID): + """查询历史成交""" + print data, reqID + + # ---------------------------------------------------------------------- + def onGetKline(self, data, reqID): + """查询K线回报""" + print data, reqID + + ############################################### + # 交易接口 + ############################################### + + # ---------------------------------------------------------------------- + def getUserInfo(self): + """查询K线""" + function = FUNCTION_USERINFO + params = {} + callback = self.onGetUserInfo + return self.sendRequest(function, params, callback) + + # ---------------------------------------------------------------------- + def createOrder(self, symbol, type_, price, amount): + """发送委托""" + function = FUNCTION_CREATEORDER + params = { + 'symbol': symbol, + 'type': type_, + 'price': price, + 'amount': amount + } + callback = self.onCreateOrder + return self.sendRequest(function, params, callback) + + # ---------------------------------------------------------------------- + def cancelOrder(self, symbol, orderId): + """撤单""" + function = FUNCTION_CANCELORDER + params = { + 'symbol': symbol, + 'order_id': orderId + } + callback = self.onCancelOrder + return self.sendRequest(function, params, callback) + + # ---------------------------------------------------------------------- + def getOrdersInfo(self, symbol, orderId): + """查询委托""" + function = FUNCTION_ORDERSINFO + params = { + 'symbol': symbol, + 'order_id': orderId + } + callback = self.onGetOrdersInfo + return self.sendRequest(function, params, callback) + + # ---------------------------------------------------------------------- + def getOrdersInfoHistory(self, symbol, status, currentPage, pageLength): + """撤单""" + function = FUNCTION_ORDERSINFOHISTORY + params = { + 'symbol': symbol, + 'status': status, + 'current_page': currentPage, + 'page_length': pageLength + } + callback = self.onGetOrdersInfoHistory + return self.sendRequest(function, params, callback) + + # ---------------------------------------------------------------------- + def onGetUserInfo(self, data, reqID): + """查询K线回报""" + print data, reqID + + # ---------------------------------------------------------------------- + def onCreateOrder(self, data, reqID): + """委托回报""" + print data, reqID + + # ---------------------------------------------------------------------- + def onCancelOrder(self, data, reqID): + """撤单回报""" + print data, reqID + + # ---------------------------------------------------------------------- + def onGetOrdersInfo(self, data, reqID): + """查询委托回报""" + print data, reqID + + # ---------------------------------------------------------------------- + def onGetOrdersInfoHistory(self, data, reqID): + """撤单回报""" + print data, reqID +