[Del]移除OkCoin和火币的老接口
This commit is contained in:
parent
ec88ac1ce3
commit
1dcd2239bd
@ -1,18 +0,0 @@
|
||||
# vn.huobi
|
||||
|
||||
### 简介
|
||||
|
||||
火币的比特币交易接口,基于Rest API开发,实现了官方提供API的全部功能。
|
||||
|
||||
### 特点
|
||||
相比较于[火币官方](http://github.com/huobiapi/API_Docs/)给出的Python API实现,vn.huobi的一些特点:
|
||||
|
||||
1. 面向对象的API设计,接近CTP API的结构,对于国内用户而言更容易上手
|
||||
|
||||
2. 参考CTP API的设计,主动函数调用的结果通过异步(回调函数)的方式推送到程序中,适用于开发稳定可靠的实盘交易程序
|
||||
|
||||
### API版本
|
||||
日期:2015-12-02
|
||||
|
||||
链接:[http://github.com/huobiapi/API_Docs/wiki](http://github.com/huobiapi/API_Docs/wiki)
|
||||
|
@ -1,3 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
from vnhuobi import TradeApi, DataApi
|
@ -1,67 +0,0 @@
|
||||
# encoding: utf-8
|
||||
|
||||
from vnhuobi import *
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def testTrade():
|
||||
"""测试交易"""
|
||||
accessKey = ''
|
||||
secretKey = ''
|
||||
|
||||
# 创建API对象并初始化
|
||||
api = TradeApi()
|
||||
api.DEBUG = True
|
||||
api.init(accessKey, secretKey)
|
||||
|
||||
# 查询账户,测试通过
|
||||
api.getAccountInfo()
|
||||
|
||||
# 查询委托,测试通过
|
||||
#api.getOrders()
|
||||
|
||||
# 买入,测试通过
|
||||
#api.buy(7100, 0.0095)
|
||||
|
||||
# 卖出,测试通过
|
||||
#api.sell(7120, 0.0095)
|
||||
|
||||
# 撤单,测试通过
|
||||
#api.cancelOrder(3915047376L)
|
||||
|
||||
# 查询杠杆额度,测试通过
|
||||
#api.getLoanAvailable()
|
||||
|
||||
# 查询杠杆列表,测试通过
|
||||
#api.getLoans()
|
||||
|
||||
# 阻塞
|
||||
input()
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def testData():
|
||||
"""测试行情接口"""
|
||||
api = DataApi()
|
||||
|
||||
api.init(0.5)
|
||||
|
||||
# 订阅成交推送,测试通过
|
||||
#api.subscribeTick(SYMBOL_BTCCNY)
|
||||
|
||||
# 订阅报价推送,测试通过
|
||||
#api.subscribeQuote(SYMBOL_BTCCNY)
|
||||
|
||||
# 订阅深度推送,测试通过
|
||||
#api.subscribeDepth(SYMBOL_BTCCNY, 1)
|
||||
|
||||
# 查询K线数据,测试通过
|
||||
data = api.getKline(SYMBOL_BTCCNY, PERIOD_1MIN, 100)
|
||||
print data
|
||||
|
||||
input()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
#testTrade()
|
||||
|
||||
testData()
|
@ -1,652 +0,0 @@
|
||||
# encoding: utf-8
|
||||
|
||||
import urllib
|
||||
import hashlib
|
||||
|
||||
import json
|
||||
import requests
|
||||
from time import time, sleep
|
||||
from Queue import Queue, Empty
|
||||
from threading import Thread
|
||||
|
||||
|
||||
# 常量定义
|
||||
COINTYPE_BTC = 1
|
||||
COINTYPE_LTC = 2
|
||||
|
||||
ACCOUNTTYPE_CNY = 1
|
||||
ACCOUNTTYPE_USD = 2
|
||||
|
||||
LOANTYPE_CNY = 1
|
||||
LOANTYPE_BTC = 2
|
||||
LOANTYPE_LTC = 3
|
||||
LOANTYPE_USD = 4
|
||||
|
||||
MARKETTYPE_CNY = 'cny'
|
||||
MARKETTYPE_USD = 'usd'
|
||||
|
||||
SYMBOL_BTCCNY = 'BTC_CNY'
|
||||
SYMBOL_LTCCNY = 'LTC_CNY'
|
||||
SYMBOL_BTCUSD = 'BTC_USD'
|
||||
|
||||
PERIOD_1MIN = '001'
|
||||
PERIOD_5MIN = '005'
|
||||
PERIOD_15MIN = '015'
|
||||
PERIOD_30MIN = '030'
|
||||
PERIOD_60MIN = '060'
|
||||
PERIOD_DAILY = '100'
|
||||
PERIOD_WEEKLY = '200'
|
||||
PERIOD_MONTHLY = '300'
|
||||
PERIOD_ANNUALLY = '400'
|
||||
|
||||
# API相关定义
|
||||
HUOBI_TRADE_API = 'https://api.huobi.com/apiv3'
|
||||
|
||||
# 功能代码
|
||||
FUNCTIONCODE_GETACCOUNTINFO = 'get_account_info'
|
||||
FUNCTIONCODE_GETORDERS = 'get_orders'
|
||||
FUNCTIONCODE_ORDERINFO = 'order_info'
|
||||
FUNCTIONCODE_BUY = 'buy'
|
||||
FUNCTIONCODE_SELL = 'sell'
|
||||
FUNCTIONCODE_BUYMARKET = 'buy_market'
|
||||
FUNCTIONCODE_SELLMARKET = 'sell_market'
|
||||
FUNCTIONCODE_CANCELORDER = 'cancel_order'
|
||||
FUNCTIONCODE_GETNEWDEALORDERS = 'get_new_deal_orders'
|
||||
FUNCTIONCODE_GETORDERIDBYTRADEID = 'get_order_id_by_trade_id'
|
||||
FUNCTIONCODE_WITHDRAWCOIN = 'withdraw_coin'
|
||||
FUNCTIONCODE_CANCELWITHDRAWCOIN = 'cancel_withdraw_coin'
|
||||
FUNCTIONCODE_GETWITHDRAWCOINRESULT = 'get_withdraw_coin_result'
|
||||
FUNCTIONCODE_TRANSFER = 'transfer'
|
||||
FUNCTIONCODE_LOAN = 'loan'
|
||||
FUNCTIONCODE_REPAYMENT = 'repayment'
|
||||
FUNCTIONCODE_GETLOANAVAILABLE = 'get_loan_available'
|
||||
FUNCTIONCODE_GETLOANS = 'get_loans'
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def signature(params):
|
||||
"""生成签名"""
|
||||
params = sorted(params.iteritems(), key=lambda d:d[0], reverse=False)
|
||||
message = urllib.urlencode(params)
|
||||
|
||||
m = hashlib.md5()
|
||||
m.update(message)
|
||||
m.digest()
|
||||
|
||||
sig=m.hexdigest()
|
||||
return sig
|
||||
|
||||
|
||||
########################################################################
|
||||
class TradeApi(object):
|
||||
"""交易接口"""
|
||||
DEBUG = True
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self):
|
||||
"""Constructor"""
|
||||
self.accessKey = ''
|
||||
self.secretKey = ''
|
||||
|
||||
self.active = False # API工作状态
|
||||
self.reqID = 0 # 请求编号
|
||||
self.reqQueue = Queue() # 请求队列
|
||||
self.reqThread = Thread(target=self.processQueue) # 请求处理线程
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def processRequest(self, req):
|
||||
"""处理请求"""
|
||||
# 读取方法和参数
|
||||
method = req['method']
|
||||
params = req['params']
|
||||
optional = req['optional']
|
||||
|
||||
# 在参数中增加必须的字段
|
||||
params['created'] = long(time())
|
||||
params['access_key'] = self.accessKey
|
||||
params['secret_key'] = self.secretKey
|
||||
params['method'] = method
|
||||
|
||||
# 添加签名
|
||||
sign = signature(params)
|
||||
params['sign'] = sign
|
||||
del params['secret_key']
|
||||
|
||||
# 添加选填参数
|
||||
if optional:
|
||||
params.update(optional)
|
||||
|
||||
# 发送请求
|
||||
payload = urllib.urlencode(params)
|
||||
|
||||
r = requests.post(HUOBI_TRADE_API, 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 'code' in data and 'message' in data:
|
||||
error = u'错误信息:%s' %data['message']
|
||||
self.onError(error, req, reqID)
|
||||
# 请求成功
|
||||
else:
|
||||
if self.DEBUG:
|
||||
print callback.__name__
|
||||
callback(data, req, reqID)
|
||||
|
||||
except Empty:
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def sendRequest(self, method, params, callback, optional=None):
|
||||
"""发送请求"""
|
||||
# 请求编号加1
|
||||
self.reqID += 1
|
||||
|
||||
# 生成请求字典并放入队列中
|
||||
req = {}
|
||||
req['method'] = method
|
||||
req['params'] = params
|
||||
req['callback'] = callback
|
||||
req['optional'] = optional
|
||||
req['reqID'] = self.reqID
|
||||
self.reqQueue.put(req)
|
||||
|
||||
# 返回请求编号
|
||||
return self.reqID
|
||||
|
||||
####################################################
|
||||
## 主动函数
|
||||
####################################################
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def init(self, accessKey, secretKey):
|
||||
"""初始化"""
|
||||
self.accessKey = accessKey
|
||||
self.secretKey = secretKey
|
||||
|
||||
self.active = True
|
||||
self.reqThread.start()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def exit(self):
|
||||
"""退出"""
|
||||
self.active = False
|
||||
|
||||
if self.reqThread.isAlive():
|
||||
self.reqThread.join()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getAccountInfo(self, market='cny'):
|
||||
"""查询账户"""
|
||||
method = FUNCTIONCODE_GETACCOUNTINFO
|
||||
params = {}
|
||||
callback = self.onGetAccountInfo
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getOrders(self, coinType=COINTYPE_BTC, market='cny'):
|
||||
"""查询委托"""
|
||||
method = FUNCTIONCODE_GETORDERS
|
||||
params = {'coin_type': coinType}
|
||||
callback = self.onGetOrders
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def orderInfo(self, id_, coinType=COINTYPE_BTC, market='cny'):
|
||||
"""获取委托详情"""
|
||||
method = FUNCTIONCODE_ORDERINFO
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'id': id_
|
||||
}
|
||||
callback = self.onOrderInfo
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def buy(self, price, amount, coinType=COINTYPE_BTC,
|
||||
tradePassword='', tradeId = '', market='cny'):
|
||||
"""委托买入"""
|
||||
method = FUNCTIONCODE_BUY
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'price': price,
|
||||
'amount': amount
|
||||
}
|
||||
callback = self.onBuy
|
||||
optional = {
|
||||
'trade_password': tradePassword,
|
||||
'trade_id': tradeId,
|
||||
'market': market
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def sell(self, price, amount, coinType=COINTYPE_BTC,
|
||||
tradePassword='', tradeId = '', market='cny'):
|
||||
"""委托卖出"""
|
||||
method = FUNCTIONCODE_SELL
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'price': price,
|
||||
'amount': amount
|
||||
}
|
||||
callback = self.onSell
|
||||
optional = {
|
||||
'trade_password': tradePassword,
|
||||
'trade_id': tradeId,
|
||||
'market': market
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def buyMarket(self, amount, coinType=COINTYPE_BTC,
|
||||
tradePassword='', tradeId = '', market='cny'):
|
||||
"""市价买入"""
|
||||
method = FUNCTIONCODE_BUYMARKET
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'amount': amount
|
||||
}
|
||||
callback = self.onBuyMarket
|
||||
optional = {
|
||||
'trade_password': tradePassword,
|
||||
'trade_id': tradeId,
|
||||
'market': market
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def sellMarket(self, amount, coinType=COINTYPE_BTC,
|
||||
tradePassword='', tradeId = '', market='cny'):
|
||||
"""市价卖出"""
|
||||
method = FUNCTIONCODE_SELLMARKET
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'amount': amount
|
||||
}
|
||||
callback = self.onSellMarket
|
||||
optional = {
|
||||
'trade_password': tradePassword,
|
||||
'trade_id': tradeId,
|
||||
'market': market
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def cancelOrder(self, id_, coinType=COINTYPE_BTC, market='cny'):
|
||||
"""撤销委托"""
|
||||
method = FUNCTIONCODE_CANCELORDER
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'id': id_
|
||||
}
|
||||
callback = self.onCancelOrder
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getNewDealOrders(self, market='cny'):
|
||||
"""查询最新10条成交"""
|
||||
method = FUNCTIONCODE_GETNEWDEALORDERS
|
||||
params = {}
|
||||
callback = self.onGetNewDealOrders
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getOrderIdByTradeId(self, tradeId, coinType=COINTYPE_BTC,
|
||||
market='cny'):
|
||||
"""通过成交编号查询委托编号"""
|
||||
method = FUNCTIONCODE_GETORDERIDBYTRADEID
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'trade_id': tradeId
|
||||
}
|
||||
callback = self.onGetOrderIdByTradeId
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def withdrawCoin(self, withdrawAddress, withdrawAmount,
|
||||
coinType=COINTYPE_BTC, tradePassword='',
|
||||
market='cny', withdrawFee=0.0001):
|
||||
"""提币"""
|
||||
method = FUNCTIONCODE_WITHDRAWCOIN
|
||||
params = {
|
||||
'coin_type': coinType,
|
||||
'withdraw_address': withdrawAddress,
|
||||
'withdraw_amount': withdrawAmount
|
||||
}
|
||||
callback = self.onWithdrawCoin
|
||||
optional = {
|
||||
'market': market,
|
||||
'withdraw_fee': withdrawFee
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def cancelWithdrawCoin(self, id_, market='cny'):
|
||||
"""取消提币"""
|
||||
method = FUNCTIONCODE_CANCELWITHDRAWCOIN
|
||||
params = {'withdraw_coin_id': id_}
|
||||
callback = self.onCancelWithdrawCoin
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetWithdrawCoinResult(self, id_, market='cny'):
|
||||
"""查询提币结果"""
|
||||
method = FUNCTIONCODE_GETWITHDRAWCOINRESULT
|
||||
params = {'withdraw_coin_id': id_}
|
||||
callback = self.onGetWithdrawCoinResult
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def transfer(self, amountFrom, amountTo, amount,
|
||||
coinType=COINTYPE_BTC ):
|
||||
"""账户内转账"""
|
||||
method = FUNCTIONCODE_TRANSFER
|
||||
params = {
|
||||
'amount_from': amountFrom,
|
||||
'amount_to': amountTo,
|
||||
'amount': amount,
|
||||
'coin_type': coinType
|
||||
}
|
||||
callback = self.onTransfer
|
||||
optional = {}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def loan(self, amount, loan_type=LOANTYPE_CNY,
|
||||
market=MARKETTYPE_CNY):
|
||||
"""申请杠杆"""
|
||||
method = FUNCTIONCODE_LOAN
|
||||
params = {
|
||||
'amount': amount,
|
||||
'loan_type': loan_type
|
||||
}
|
||||
callback = self.onLoan
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def repayment(self, id_, amount, repayAll=0,
|
||||
market=MARKETTYPE_CNY):
|
||||
"""归还杠杆"""
|
||||
method = FUNCTIONCODE_REPAYMENT
|
||||
params = {
|
||||
'loan_id': id_,
|
||||
'amount': amount
|
||||
}
|
||||
callback = self.onRepayment
|
||||
optional = {
|
||||
'repay_all': repayAll,
|
||||
'market': market
|
||||
}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getLoanAvailable(self, market='cny'):
|
||||
"""查询杠杆额度"""
|
||||
method = FUNCTIONCODE_GETLOANAVAILABLE
|
||||
params = {}
|
||||
callback = self.onLoanAvailable
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getLoans(self, market='cny'):
|
||||
"""查询杠杆列表"""
|
||||
method = FUNCTIONCODE_GETLOANS
|
||||
params = {}
|
||||
callback = self.onGetLoans
|
||||
optional = {'market': market}
|
||||
return self.sendRequest(method, params, callback, optional)
|
||||
|
||||
####################################################
|
||||
## 回调函数
|
||||
####################################################
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onError(self, error, req, reqID):
|
||||
"""错误推送"""
|
||||
print error, reqID
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetAccountInfo(self, data, req, reqID):
|
||||
"""查询账户回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetOrders(self, data, req, reqID, fuck):
|
||||
"""查询委托回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onOrderInfo(self, data, req, reqID):
|
||||
"""委托详情回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBuy(self, data, req, reqID):
|
||||
"""买入回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSell(self, data, req, reqID):
|
||||
"""卖出回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBuyMarket(self, data, req, reqID):
|
||||
"""市价买入回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSellMarket(self, data, req, reqID):
|
||||
"""市价卖出回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onCancelOrder(self, data, req, reqID):
|
||||
"""撤单回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetNewDealOrders(self, data, req, reqID):
|
||||
"""查询最新成交回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetOrderIdByTradeId(self, data, req, reqID):
|
||||
"""通过成交编号查询委托编号回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onWithdrawCoin(self, data, req, reqID):
|
||||
"""提币回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onCancelWithdrawCoin(self, data, req, reqID):
|
||||
"""取消提币回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetWithdrawCoinResult(self, data, req, reqID):
|
||||
"""查询提币结果回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onTransfer(self, data, req, reqID):
|
||||
"""转账回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onLoan(self, data, req, reqID):
|
||||
"""申请杠杆回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onRepayment(self, data, req, reqID):
|
||||
"""归还杠杆回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onLoanAvailable(self, data, req, reqID):
|
||||
"""查询杠杆额度回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetLoans(self, data, req, reqID):
|
||||
"""查询杠杆列表"""
|
||||
print data
|
||||
|
||||
|
||||
########################################################################
|
||||
class DataApi(object):
|
||||
"""行情接口"""
|
||||
TICK_SYMBOL_URL = {
|
||||
SYMBOL_BTCCNY: 'http://api.huobi.com/staticmarket/detail_btc_json.js',
|
||||
SYMBOL_LTCCNY: 'http://api.huobi.com/staticmarket/detail_ltc_json.js',
|
||||
SYMBOL_BTCUSD: 'http://api.huobi.com/usdmarket/detail_btc_json.js'
|
||||
}
|
||||
|
||||
QUOTE_SYMBOL_URL = {
|
||||
SYMBOL_BTCCNY: 'http://api.huobi.com/staticmarket/ticker_btc_json.js',
|
||||
SYMBOL_LTCCNY: 'http://api.huobi.com/staticmarket/ticker_ltc_json.js',
|
||||
SYMBOL_BTCUSD: 'http://api.huobi.com/usdmarket/ticker_btc_json.js'
|
||||
}
|
||||
|
||||
DEPTH_SYMBOL_URL = {
|
||||
SYMBOL_BTCCNY: 'http://api.huobi.com/staticmarket/depth_btc_json.js',
|
||||
SYMBOL_LTCCNY: 'http://api.huobi.com/staticmarket/depth_ltc_json.js',
|
||||
SYMBOL_BTCUSD: 'http://api.huobi.com/usdmarket/depth_btc_json.js'
|
||||
}
|
||||
|
||||
KLINE_SYMBOL_URL = {
|
||||
SYMBOL_BTCCNY: 'http://api.huobi.com/staticmarket/btc_kline_[period]_json.js',
|
||||
SYMBOL_LTCCNY: 'http://api.huobi.com/staticmarket/btc_kline_[period]_json.js',
|
||||
SYMBOL_BTCUSD: 'http://api.huobi.com/usdmarket/btc_kline_[period]_json.js'
|
||||
}
|
||||
|
||||
DEBUG = True
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self):
|
||||
"""Constructor"""
|
||||
self.active = False
|
||||
|
||||
self.taskInterval = 0 # 每轮请求延时
|
||||
self.taskList = [] # 订阅的任务列表
|
||||
self.taskThread = Thread(target=self.run) # 处理任务的线程
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def init(self, interval, debug):
|
||||
"""初始化"""
|
||||
self.taskInterval = interval
|
||||
self.DEBUG = debug
|
||||
|
||||
self.active = True
|
||||
self.taskThread.start()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def exit(self):
|
||||
"""退出"""
|
||||
self.active = False
|
||||
|
||||
if self.taskThread.isAlive():
|
||||
self.taskThread.join()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def run(self):
|
||||
"""连续运行"""
|
||||
while self.active:
|
||||
for url, callback in self.taskList:
|
||||
try:
|
||||
r = requests.get(url)
|
||||
if r.status_code == 200:
|
||||
data = r.json()
|
||||
if self.DEBUG:
|
||||
print callback.__name__
|
||||
callback(data)
|
||||
except Exception, e:
|
||||
print e
|
||||
|
||||
sleep(self.taskInterval)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeTick(self, symbol):
|
||||
"""订阅实时成交数据"""
|
||||
url = self.TICK_SYMBOL_URL[symbol]
|
||||
task = (url, self.onTick)
|
||||
self.taskList.append(task)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeQuote(self, symbol):
|
||||
"""订阅实时报价数据"""
|
||||
url = self.QUOTE_SYMBOL_URL[symbol]
|
||||
task = (url, self.onQuote)
|
||||
self.taskList.append(task)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeDepth(self, symbol, level=0):
|
||||
"""订阅深度数据"""
|
||||
url = self.DEPTH_SYMBOL_URL[symbol]
|
||||
|
||||
if level:
|
||||
url = url.replace('json', str(level))
|
||||
|
||||
task = (url, self.onDepth)
|
||||
self.taskList.append(task)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onTick(self, data):
|
||||
"""实时成交推送"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onQuote(self, data):
|
||||
"""实时报价推送"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onDepth(self, data):
|
||||
"""实时深度推送"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def getKline(self, symbol, period, length=0):
|
||||
"""查询K线数据"""
|
||||
url = self.KLINE_SYMBOL_URL[symbol]
|
||||
url = url.replace('[period]', period)
|
||||
|
||||
if length:
|
||||
url = url + '?length=' + str(length)
|
||||
|
||||
try:
|
||||
r = requests.get(url)
|
||||
if r.status_code == 200:
|
||||
data = r.json()
|
||||
return data
|
||||
except Exception, e:
|
||||
print e
|
||||
return None
|
@ -1,36 +0,0 @@
|
||||
# vn.okcoin
|
||||
|
||||
贡献者:量衍投资
|
||||
|
||||
### 简介
|
||||
OkCoin的比特币交易接口,基于Websocket API开发,实现了以下功能:
|
||||
|
||||
1. 发送、撤销委托
|
||||
|
||||
2. 查询委托、持仓、资金、成交历史
|
||||
|
||||
3. 实时行情、成交、资金更新的推送
|
||||
|
||||
### 特点
|
||||
相比较于[OkCoin官方](http://github.com/OKCoin/websocket/tree/master/python)给出的Python API实现,vn.okcoin的一些特点:
|
||||
|
||||
1. 同时支持OkCoin的中国站和国际站交易,根据用户连接的站点会在内部自动切换结算货币(CNY、USD)
|
||||
|
||||
2. 采用面向对象的接口设计模式,接近国内CTP接口的风格,并对主动函数的调用参数做了大幅简化
|
||||
|
||||
3. 数据解包和签名生成两个热点函数使用了更加高效的实现方式
|
||||
|
||||
### 参数命名
|
||||
函数的参数命名针对金融领域用户的习惯做了一些修改,具体对应如下:
|
||||
|
||||
* expiry:原生命名的contract_type
|
||||
* order: 原生命名的match_price
|
||||
* leverage:原生命名的lever_rate
|
||||
* page:原生命名的current_page
|
||||
* length:原生命名的page_length
|
||||
|
||||
### API版本
|
||||
日期:2016-06-29
|
||||
|
||||
链接:[http://www.okcoin.com/about/ws_getStarted.do](http://www.okcoin.com/about/ws_getStarted.do)
|
||||
|
@ -1,3 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
from vnokcoin import OkCoinApi
|
@ -1,47 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
from vnokcoin import *
|
||||
|
||||
# 在OkCoin网站申请这两个Key,分别对应用户名和密码
|
||||
apiKey = ''
|
||||
secretKey = ''
|
||||
|
||||
# 创建API对象
|
||||
api = OkCoinApi()
|
||||
|
||||
# 连接服务器,并等待1秒
|
||||
api.connect(OKCOIN_USD, apiKey, secretKey, True)
|
||||
|
||||
sleep(1)
|
||||
|
||||
# 测试现货行情API
|
||||
#api.subscribeSpotTicker(SYMBOL_BTC)
|
||||
#api.subscribeSpotTradeData(SYMBOL_BTC)
|
||||
api.subscribeSpotDepth(SYMBOL_BTC, DEPTH_20)
|
||||
#api.subscribeSpotKline(SYMBOL_BTC, INTERVAL_1M)
|
||||
|
||||
# 测试现货交易API
|
||||
#api.subscribeSpotTrades()
|
||||
#api.subscribeSpotUserInfo()
|
||||
#api.spotUserInfo()
|
||||
#api.spotTrade(symbol, type_, price, amount)
|
||||
#api.spotCancelOrder(symbol, orderid)
|
||||
#api.spotOrderInfo(symbol, orderid)
|
||||
|
||||
# 测试期货行情API
|
||||
#api.subscribeFutureTicker(SYMBOL_BTC, FUTURE_EXPIRY_THIS_WEEK)
|
||||
#api.subscribeFutureTradeData(SYMBOL_BTC, FUTURE_EXPIRY_THIS_WEEK)
|
||||
#api.subscribeFutureDepth(SYMBOL_BTC, FUTURE_EXPIRY_THIS_WEEK, DEPTH_20)
|
||||
#api.subscribeFutureKline(SYMBOL_BTC, FUTURE_EXPIRY_THIS_WEEK, INTERVAL_1M)
|
||||
#api.subscribeFutureIndex(SYMBOL_BTC)
|
||||
|
||||
# 测试期货交易API
|
||||
#api.subscribeFutureTrades()
|
||||
#api.subscribeFutureUserInfo()
|
||||
#api.subscribeFuturePositions()
|
||||
#api.futureUserInfo()
|
||||
#api.futureTrade(symbol, expiry, type_, price, amount, order, leverage)
|
||||
#api.futureCancelOrder(symbol, expiry, orderid)
|
||||
#api.futureOrderInfo(symbol, expiry, orderid, status, page, length)
|
||||
|
||||
raw_input()
|
@ -1,417 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
import hashlib
|
||||
import zlib
|
||||
import json
|
||||
from time import sleep
|
||||
from threading import Thread
|
||||
|
||||
import websocket
|
||||
|
||||
|
||||
# OKCOIN网站
|
||||
OKCOIN_CNY = 'wss://real.okcoin.cn:10440/websocket/okcoinapi'
|
||||
OKCOIN_USD = 'wss://real.okcoin.com:10440/websocket/okcoinapi'
|
||||
|
||||
# 账户货币代码
|
||||
CURRENCY_CNY = 'cny'
|
||||
CURRENCY_USD = 'usd'
|
||||
|
||||
# 电子货币代码
|
||||
SYMBOL_BTC = 'btc'
|
||||
SYMBOL_LTC = 'ltc'
|
||||
SYMBOL_ETH = 'eth'
|
||||
|
||||
# 行情深度
|
||||
DEPTH_20 = 20
|
||||
DEPTH_60 = 60
|
||||
|
||||
# K线时间区间
|
||||
INTERVAL_1M = '1min'
|
||||
INTERVAL_3M = '3min'
|
||||
INTERVAL_5M = '5min'
|
||||
INTERVAL_15M = '15min'
|
||||
INTERVAL_30M = '30min'
|
||||
INTERVAL_1H = '1hour'
|
||||
INTERVAL_2H = '2hour'
|
||||
INTERVAL_4H = '4hour'
|
||||
INTERVAL_6H = '6hour'
|
||||
INTERVAL_1D = 'day'
|
||||
INTERVAL_3D = '3day'
|
||||
INTERVAL_1W = 'week'
|
||||
|
||||
# 交易代码,需要后缀货币名才能完整
|
||||
TRADING_SYMBOL_BTC = 'btc_'
|
||||
TRADING_SYMBOL_LTC = 'ltc_'
|
||||
TRADING_SYMBOL_ETH = 'eth_'
|
||||
|
||||
# 委托类型
|
||||
TYPE_BUY = 'buy'
|
||||
TYPE_SELL = 'sell'
|
||||
TYPE_BUY_MARKET = 'buy_market'
|
||||
TYPE_SELL_MARKET = 'sell_market'
|
||||
|
||||
# 期货合约到期类型
|
||||
FUTURE_EXPIRY_THIS_WEEK = 'this_week'
|
||||
FUTURE_EXPIRY_NEXT_WEEK = 'next_week'
|
||||
FUTURE_EXPIRY_QUARTER = 'quarter'
|
||||
|
||||
# 期货委托类型
|
||||
FUTURE_TYPE_LONG = 1
|
||||
FUTURE_TYPE_SHORT = 2
|
||||
FUTURE_TYPE_SELL = 3
|
||||
FUTURE_TYPE_COVER = 4
|
||||
|
||||
# 期货是否用现价
|
||||
FUTURE_ORDER_MARKET = 1
|
||||
FUTURE_ORDER_LIMIT = 0
|
||||
|
||||
# 期货杠杆
|
||||
FUTURE_LEVERAGE_10 = 10
|
||||
FUTURE_LEVERAGE_20 = 20
|
||||
|
||||
# 委托状态
|
||||
ORDER_STATUS_NOTTRADED = 0
|
||||
ORDER_STATUS_PARTTRADED = 1
|
||||
ORDER_STATUS_ALLTRADED = 2
|
||||
ORDER_STATUS_CANCELLED = -1
|
||||
ORDER_STATUS_CANCELLING = 4
|
||||
|
||||
|
||||
########################################################################
|
||||
class OkCoinApi(object):
|
||||
"""基于Websocket的API对象"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self):
|
||||
"""Constructor"""
|
||||
self.apiKey = '' # 用户名
|
||||
self.secretKey = '' # 密码
|
||||
self.host = '' # 服务器地址
|
||||
|
||||
self.currency = '' # 货币类型(usd或者cny)
|
||||
|
||||
self.ws = None # websocket应用对象
|
||||
self.thread = None # 工作线程
|
||||
|
||||
#######################
|
||||
## 通用函数
|
||||
#######################
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def readData(self, evt):
|
||||
"""解压缩推送收到的数据"""
|
||||
# 创建解压器
|
||||
decompress = zlib.decompressobj(-zlib.MAX_WBITS)
|
||||
|
||||
# 将原始数据解压成字符串
|
||||
inflated = decompress.decompress(evt) + decompress.flush()
|
||||
|
||||
# 通过json解析字符串
|
||||
data = json.loads(inflated)
|
||||
|
||||
return data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def generateSign(self, params):
|
||||
"""生成签名"""
|
||||
l = []
|
||||
for key in sorted(params.keys()):
|
||||
l.append('%s=%s' %(key, params[key]))
|
||||
l.append('secret_key=%s' %self.secretKey)
|
||||
sign = '&'.join(l)
|
||||
return hashlib.md5(sign.encode('utf-8')).hexdigest().upper()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onMessage(self, ws, evt):
|
||||
"""信息推送"""
|
||||
print 'onMessage'
|
||||
data = self.readData(evt)
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onError(self, ws, evt):
|
||||
"""错误推送"""
|
||||
print 'onError'
|
||||
print evt
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onClose(self, ws):
|
||||
"""接口断开"""
|
||||
print 'onClose'
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onOpen(self, ws):
|
||||
"""接口打开"""
|
||||
print 'onOpen'
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def connect(self, host, apiKey, secretKey, trace=False):
|
||||
"""连接服务器"""
|
||||
self.host = host
|
||||
self.apiKey = apiKey
|
||||
self.secretKey = secretKey
|
||||
|
||||
if self.host == OKCOIN_CNY:
|
||||
self.currency = CURRENCY_CNY
|
||||
else:
|
||||
self.currency = CURRENCY_USD
|
||||
|
||||
websocket.enableTrace(trace)
|
||||
|
||||
self.ws = websocket.WebSocketApp(host,
|
||||
on_message=self.onMessage,
|
||||
on_error=self.onError,
|
||||
on_close=self.onClose,
|
||||
on_open=self.onOpen)
|
||||
|
||||
self.thread = Thread(target=self.ws.run_forever)
|
||||
self.thread.start()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def reconnect(self):
|
||||
"""重新连接"""
|
||||
# 首先关闭之前的连接
|
||||
self.close()
|
||||
|
||||
# 再执行重连任务
|
||||
self.ws = websocket.WebSocketApp(self.host,
|
||||
on_message=self.onMessage,
|
||||
on_error=self.onError,
|
||||
on_close=self.onClose,
|
||||
on_open=self.onOpen)
|
||||
|
||||
self.thread = Thread(target=self.ws.run_forever)
|
||||
self.thread.start()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def close(self):
|
||||
"""关闭接口"""
|
||||
if self.thread and self.thread.isAlive():
|
||||
self.ws.close()
|
||||
self.thread.join()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def sendMarketDataRequest(self, channel):
|
||||
"""发送行情请求"""
|
||||
# 生成请求
|
||||
d = {}
|
||||
d['event'] = 'addChannel'
|
||||
d['binary'] = True
|
||||
d['channel'] = channel
|
||||
|
||||
# 使用json打包并发送
|
||||
j = json.dumps(d)
|
||||
|
||||
# 若触发异常则重连
|
||||
try:
|
||||
self.ws.send(j)
|
||||
except websocket.WebSocketConnectionClosedException:
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def sendTradingRequest(self, channel, params):
|
||||
"""发送交易请求"""
|
||||
# 在参数字典中加上api_key和签名字段
|
||||
params['api_key'] = self.apiKey
|
||||
params['sign'] = self.generateSign(params)
|
||||
|
||||
# 生成请求
|
||||
d = {}
|
||||
d['event'] = 'addChannel'
|
||||
d['binary'] = True
|
||||
d['channel'] = channel
|
||||
d['parameters'] = params
|
||||
|
||||
# 使用json打包并发送
|
||||
j = json.dumps(d)
|
||||
|
||||
# 若触发异常则重连
|
||||
try:
|
||||
self.ws.send(j)
|
||||
except websocket.WebSocketConnectionClosedException:
|
||||
pass
|
||||
|
||||
#######################
|
||||
## 现货相关
|
||||
#######################
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeSpotTicker(self, symbol):
|
||||
"""订阅现货普通报价"""
|
||||
self.sendMarketDataRequest('ok_sub_spot%s_%s_ticker' %(self.currency, symbol))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeSpotDepth(self, symbol, depth):
|
||||
"""订阅现货深度报价"""
|
||||
self.sendMarketDataRequest('ok_sub_spot%s_%s_depth_%s' %(self.currency, symbol, depth))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeSpotTradeData(self, symbol):
|
||||
"""订阅现货成交记录"""
|
||||
self.sendMarketDataRequest('ok_sub_spot%s_%s_trades' %(self.currency, symbol))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeSpotKline(self, symbol, interval):
|
||||
"""订阅现货K线"""
|
||||
self.sendMarketDataRequest('ok_sub_spot%s_%s_kline_%s' %(self.currency, symbol, interval))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def spotTrade(self, symbol, type_, price, amount):
|
||||
"""现货委托"""
|
||||
params = {}
|
||||
params['symbol'] = str(symbol+self.currency)
|
||||
params['type'] = str(type_)
|
||||
params['price'] = str(price)
|
||||
params['amount'] = str(amount)
|
||||
|
||||
channel = 'ok_spot%s_trade' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, params)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def spotCancelOrder(self, symbol, orderid):
|
||||
"""现货撤单"""
|
||||
params = {}
|
||||
params['symbol'] = str(symbol+self.currency)
|
||||
params['order_id'] = str(orderid)
|
||||
|
||||
channel = 'ok_spot%s_cancel_order' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, params)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def spotUserInfo(self):
|
||||
"""查询现货账户"""
|
||||
channel = 'ok_spot%s_userinfo' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, {})
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def spotOrderInfo(self, symbol, orderid):
|
||||
"""查询现货委托信息"""
|
||||
params = {}
|
||||
params['symbol'] = str(symbol+self.currency)
|
||||
params['order_id'] = str(orderid)
|
||||
|
||||
channel = 'ok_spot%s_orderinfo' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, params)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeSpotTrades(self):
|
||||
"""订阅现货成交信息"""
|
||||
channel = 'ok_sub_spot%s_trades' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, {})
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeSpotUserInfo(self):
|
||||
"""订阅现货账户信息"""
|
||||
channel = 'ok_sub_spot%s_userinfo' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, {})
|
||||
|
||||
#######################
|
||||
## 期货相关
|
||||
#######################
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeFutureTicker(self, symbol, expiry):
|
||||
"""订阅期货普通报价"""
|
||||
self.sendMarketDataRequest('ok_sub_future%s_%s_ticker_%s' %(self.currency, symbol, expiry))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeFutureDepth(self, symbol, expiry, depth):
|
||||
"""订阅期货深度报价"""
|
||||
self.sendMarketDataRequest('ok_sub_future%s_%s_depth_%s_%s' %(self.currency, symbol,
|
||||
expiry, depth))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeFutureTradeData(self, symbol, expiry):
|
||||
"""订阅期货成交记录"""
|
||||
self.sendMarketDataRequest('ok_sub_future%s_%s_trade_%s' %(self.currency, symbol, expiry))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeFutureKline(self, symbol, expiry, interval):
|
||||
"""订阅期货K线"""
|
||||
self.sendMarketDataRequest('ok_sub_future%s_%s_kline_%s_%s' %(self.currency, symbol,
|
||||
expiry, interval))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeFutureIndex(self, symbol):
|
||||
"""订阅期货指数"""
|
||||
self.sendMarketDataRequest('ok_sub_future%s_%s_index' %(self.currency, symbol))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def futureTrade(self, symbol, expiry, type_, price, amount, order, leverage):
|
||||
"""期货委托"""
|
||||
params = {}
|
||||
params['symbol'] = str(symbol+self.currency)
|
||||
params['type'] = str(type_)
|
||||
params['price'] = str(price)
|
||||
params['amount'] = str(amount)
|
||||
params['contract_type'] = str(expiry)
|
||||
params['match_price'] = str(order)
|
||||
params['lever_rate'] = str(leverage)
|
||||
|
||||
channel = 'ok_future%s_trade' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, params)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def futureCancelOrder(self, symbol, expiry, orderid):
|
||||
"""期货撤单"""
|
||||
params = {}
|
||||
params['symbol'] = str(symbol+self.currency)
|
||||
params['order_id'] = str(orderid)
|
||||
params['contract_type'] = str(expiry)
|
||||
|
||||
channel = 'ok_future%s_cancel_order' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, params)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def futureUserInfo(self):
|
||||
"""查询期货账户"""
|
||||
channel = 'ok_future%s_userinfo' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, {})
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def futureOrderInfo(self, symbol, expiry, orderid, status, page, length):
|
||||
"""查询期货委托信息"""
|
||||
params = {}
|
||||
params['symbol'] = str(symbol+self.currency)
|
||||
params['order_id'] = str(orderid)
|
||||
params['contract_type'] = expiry
|
||||
params['status'] = status
|
||||
params['current_page'] = page
|
||||
params['page_length'] = length
|
||||
|
||||
channel = 'ok_future%s_orderinfo' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, params)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeFutureTrades(self):
|
||||
"""订阅期货成交信息"""
|
||||
channel = 'ok_sub_future%s_trades' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, {})
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeFutureUserInfo(self):
|
||||
"""订阅期货账户信息"""
|
||||
channel = 'ok_sub_future%s_userinfo' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, {})
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribeFuturePositions(self):
|
||||
"""订阅期货持仓信息"""
|
||||
channel = 'ok_sub_future%s_positions' %(self.currency)
|
||||
|
||||
self.sendTradingRequest(channel, {})
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"accessKey": "火币网站申请",
|
||||
"secretKey": "火币网站申请",
|
||||
"interval": 0.5,
|
||||
"market": "cny",
|
||||
"debug": false
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
from vnpy.trader import vtConstant
|
||||
from huobiGateway import HuobiGateway
|
||||
|
||||
gatewayClass = HuobiGateway
|
||||
gatewayName = 'HUOBI'
|
||||
gatewayDisplayName = u'火币'
|
||||
gatewayType = vtConstant.GATEWAYTYPE_BTC
|
||||
gatewayQryEnabled = True
|
||||
|
@ -1,667 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
'''
|
||||
vn.huobi的gateway接入
|
||||
'''
|
||||
|
||||
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
from copy import copy
|
||||
from threading import Condition
|
||||
from Queue import Queue
|
||||
from threading import Thread
|
||||
|
||||
from vnpy.api.huobi import vnhuobi
|
||||
from vnpy.trader.vtGateway import *
|
||||
from vnpy.trader.vtFunction import getJsonPath
|
||||
|
||||
SYMBOL_BTCCNY = 'BTCCNY'
|
||||
SYMBOL_LTCCNY = 'LTCCNY'
|
||||
SYMBOL_BTCUSD = 'BTCUSD'
|
||||
|
||||
SYMBOL_MAP = {}
|
||||
SYMBOL_MAP[(vnhuobi.COINTYPE_BTC, 'cny')] = SYMBOL_BTCCNY
|
||||
SYMBOL_MAP[(vnhuobi.COINTYPE_LTC, 'cny')] = SYMBOL_LTCCNY
|
||||
SYMBOL_MAP[(vnhuobi.COINTYPE_BTC, 'usd')] = SYMBOL_BTCUSD
|
||||
SYMBOL_MAP_REVERSE = {v: k for k, v in SYMBOL_MAP.items()}
|
||||
|
||||
MDSYMBOL_MAP = {}
|
||||
MDSYMBOL_MAP['btccny'] = SYMBOL_BTCCNY
|
||||
MDSYMBOL_MAP['ltccny'] = SYMBOL_LTCCNY
|
||||
MDSYMBOL_MAP['btcusd'] = SYMBOL_BTCUSD
|
||||
|
||||
DIRECTION_MAP = {}
|
||||
DIRECTION_MAP[1] = DIRECTION_LONG
|
||||
DIRECTION_MAP[2] = DIRECTION_SHORT
|
||||
|
||||
STATUS_MAP = {}
|
||||
STATUS_MAP[0] = STATUS_NOTTRADED
|
||||
STATUS_MAP[1] = STATUS_PARTTRADED
|
||||
STATUS_MAP[2] = STATUS_ALLTRADED
|
||||
STATUS_MAP[3] = STATUS_CANCELLED
|
||||
STATUS_MAP[5] = STATUS_UNKNOWN
|
||||
STATUS_MAP[7] = STATUS_UNKNOWN
|
||||
|
||||
|
||||
|
||||
########################################################################
|
||||
class HuobiGateway(VtGateway):
|
||||
"""火币接口"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, eventEngine, gatewayName='HUOBI'):
|
||||
"""Constructor"""
|
||||
super(HuobiGateway, self).__init__(eventEngine, gatewayName)
|
||||
|
||||
self.market = 'cny'
|
||||
|
||||
self.tradeApi = HuobiTradeApi(self)
|
||||
self.dataApi = HuobiDataApi(self)
|
||||
|
||||
self.fileName = self.gatewayName + '_connect.json'
|
||||
self.filePath = getJsonPath(self.fileName, __file__)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def connect(self):
|
||||
"""连接"""
|
||||
# 载入json文件
|
||||
try:
|
||||
f = file(self.filePath)
|
||||
except IOError:
|
||||
log = VtLogData()
|
||||
log.gatewayName = self.gatewayName
|
||||
log.logContent = u'读取连接配置出错,请检查'
|
||||
self.onLog(log)
|
||||
return
|
||||
|
||||
# 解析json文件
|
||||
setting = json.load(f)
|
||||
try:
|
||||
accessKey = str(setting['accessKey'])
|
||||
secretKey = str(setting['secretKey'])
|
||||
interval = setting['interval']
|
||||
market = setting['market']
|
||||
debug = setting['debug']
|
||||
except KeyError:
|
||||
log = VtLogData()
|
||||
log.gatewayName = self.gatewayName
|
||||
log.logContent = u'连接配置缺少字段,请检查'
|
||||
self.onLog(log)
|
||||
return
|
||||
|
||||
# 初始化接口
|
||||
self.tradeApi.connect(accessKey, secretKey, market, debug)
|
||||
self.writeLog(u'交易接口初始化成功')
|
||||
|
||||
self.dataApi.connect(interval, market, debug)
|
||||
self.writeLog(u'行情接口初始化成功')
|
||||
|
||||
# 启动查询
|
||||
self.initQuery()
|
||||
self.startQuery()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def writeLog(self, content):
|
||||
"""发出日志"""
|
||||
log = VtLogData()
|
||||
log.gatewayName = self.gatewayName
|
||||
log.logContent = content
|
||||
self.onLog(log)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribe(self, subscribeReq):
|
||||
"""订阅行情,自动订阅全部行情,无需实现"""
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def sendOrder(self, orderReq):
|
||||
"""发单"""
|
||||
self.tradeApi.sendOrder(orderReq)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def cancelOrder(self, cancelOrderReq):
|
||||
"""撤单"""
|
||||
self.tradeApi.cancel(cancelOrderReq)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def qryAccount(self):
|
||||
"""查询账户资金"""
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def qryPosition(self):
|
||||
"""查询持仓"""
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def close(self):
|
||||
"""关闭"""
|
||||
self.tradeApi.exit()
|
||||
self.dataApi.exit()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def initQuery(self):
|
||||
"""初始化连续查询"""
|
||||
if self.qryEnabled:
|
||||
self.qryFunctionList = [self.tradeApi.queryWorkingOrders, self.tradeApi.queryAccount]
|
||||
self.startQuery()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def query(self, event):
|
||||
"""注册到事件处理引擎上的查询函数"""
|
||||
for function in self.qryFunctionList:
|
||||
function()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def startQuery(self):
|
||||
"""启动连续查询"""
|
||||
self.eventEngine.register(EVENT_TIMER, self.query)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def setQryEnabled(self, qryEnabled):
|
||||
"""设置是否要启动循环查询"""
|
||||
self.qryEnabled = qryEnabled
|
||||
|
||||
|
||||
########################################################################
|
||||
class HuobiTradeApi(vnhuobi.TradeApi):
|
||||
"""交易接口"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, gateway):
|
||||
"""Constructor"""
|
||||
super(HuobiTradeApi, self).__init__()
|
||||
|
||||
self.gateway = gateway
|
||||
self.gatewayName = gateway.gatewayName
|
||||
|
||||
self.localID = 0 # 本地委托号
|
||||
self.localSystemDict = {} # key:localID, value:systemID
|
||||
self.systemLocalDict = {} # key:systemID, value:localID
|
||||
self.workingOrderDict = {} # key:localID, value:order
|
||||
self.reqLocalDict = {} # key:reqID, value:localID
|
||||
self.cancelDict = {} # key:localID, value:cancelOrderReq
|
||||
|
||||
self.tradeID = 0 # 本地成交号
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onError(self, error, req, reqID):
|
||||
"""错误推送"""
|
||||
err = VtErrorData()
|
||||
err.gatewayName = self.gatewayName
|
||||
err.errorMsg = str(error)
|
||||
err.errorTime = datetime.now().strftime('%H:%M:%S')
|
||||
self.gateway.onError(err)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetAccountInfo(self, data, req, reqID):
|
||||
"""查询账户回调"""
|
||||
# 推送账户数据
|
||||
account = VtAccountData()
|
||||
account.gatewayName = self.gatewayName
|
||||
account.accountID = 'HUOBI'
|
||||
account.vtAccountID = '.'.join([account.accountID, self.gatewayName])
|
||||
account.balance = data['net_asset']
|
||||
self.gateway.onAccount(account)
|
||||
|
||||
# 推送持仓数据
|
||||
if self.market == 'cny':
|
||||
posCny = VtPositionData()
|
||||
posCny.gatewayName = self.gatewayName
|
||||
posCny.symbol = 'CNY'
|
||||
posCny.exchange = EXCHANGE_HUOBI
|
||||
posCny.vtSymbol = '.'.join([posCny.symbol, posCny.exchange])
|
||||
posCny.vtPositionName = posCny.vtSymbol
|
||||
posCny.position = data['available_cny_display']
|
||||
posCny.frozen = data['frozen_cny_display']
|
||||
self.gateway.onPosition(posCny)
|
||||
|
||||
posLtc = VtPositionData()
|
||||
posLtc.gatewayName = self.gatewayName
|
||||
posLtc.symbol = 'LTC'
|
||||
posLtc.exchange = EXCHANGE_HUOBI
|
||||
posLtc.vtSymbol = '.'.join([posLtc.symbol, posLtc.exchange])
|
||||
posLtc.vtPositionName = posLtc.vtSymbol
|
||||
posLtc.position = data['available_ltc_display']
|
||||
posLtc.frozen = data['frozen_ltc_display']
|
||||
self.gateway.onPosition(posLtc)
|
||||
else:
|
||||
posUsd = VtPositionData()
|
||||
posUsd.gatewayName = self.gatewayName
|
||||
posUsd.symbol = 'USD'
|
||||
posUsd.exchange = EXCHANGE_HUOBI
|
||||
posUsd.vtSymbol = '.'.join([posUsd.symbol, posUsd.exchange])
|
||||
posUsd.vtPositionName = posUsd.vtSymbol
|
||||
posUsd.position = data['available_usd_display']
|
||||
posUsd.frozen = data['frozen_usd_display']
|
||||
self.gateway.onPosition(posUsd)
|
||||
|
||||
posBtc = VtPositionData()
|
||||
posBtc.gatewayName = self.gatewayName
|
||||
posBtc.symbol = 'BTC'
|
||||
posBtc.exchange = EXCHANGE_HUOBI
|
||||
posBtc.vtSymbol = '.'.join([posBtc.symbol, posBtc.exchange])
|
||||
posBtc.vtPositionName = posBtc.vtSymbol
|
||||
posBtc.position = data['available_btc_display']
|
||||
posBtc.frozen = data['frozen_btc_display']
|
||||
self.gateway.onPosition(posBtc)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetOrders(self, data, req, reqID):
|
||||
"""查询委托回调"""
|
||||
for d in data:
|
||||
order = VtOrderData()
|
||||
order.gatewayName = self.gatewayName
|
||||
|
||||
# 合约代码
|
||||
params = req['params']
|
||||
coin = params['coin_type']
|
||||
order.symbol = SYMBOL_MAP[(coin, self.market)]
|
||||
order.exchange = EXCHANGE_HUOBI
|
||||
order.vtSymbol = '.'.join([order.symbol, order.exchange])
|
||||
|
||||
# 委托号
|
||||
systemID = d['id']
|
||||
self.localID += 1
|
||||
localID = str(self.localID)
|
||||
self.systemLocalDict[systemID] = localID
|
||||
self.localSystemDict[localID] = systemID
|
||||
order.orderID = localID
|
||||
order.vtOrderID = '.'.join([order.orderID, order.gatewayName])
|
||||
|
||||
# 其他信息
|
||||
order.direction = DIRECTION_MAP[d['type']]
|
||||
order.offset = OFFSET_NONE
|
||||
order.price = float(d['order_price'])
|
||||
order.totalVolume = float(d['order_amount'])
|
||||
order.tradedVolume = float(d['processed_amount'])
|
||||
order.orderTime = d['order_time']
|
||||
|
||||
# 委托状态
|
||||
if order.tradedVolume == 0:
|
||||
order.status = STATUS_NOTTRADED
|
||||
else:
|
||||
order.status = STATUS_PARTTRADED
|
||||
|
||||
# 缓存病推送
|
||||
self.workingOrderDict[localID] = order
|
||||
self.gateway.onOrder(order)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onOrderInfo(self, data, req, reqID):
|
||||
"""委托详情回调"""
|
||||
systemID = data['id']
|
||||
localID = self.systemLocalDict[systemID]
|
||||
order = self.workingOrderDict.get(localID, None)
|
||||
if not order:
|
||||
return
|
||||
|
||||
# 记录最新成交的金额
|
||||
newTradeVolume = float(data['processed_amount']) - order.tradedVolume
|
||||
if newTradeVolume:
|
||||
trade = VtTradeData()
|
||||
trade.gatewayName = self.gatewayName
|
||||
trade.symbol = order.symbol
|
||||
trade.vtSymbol = order.vtSymbol
|
||||
|
||||
self.tradeID += 1
|
||||
trade.tradeID = str(self.tradeID)
|
||||
trade.vtTradeID = '.'.join([trade.tradeID, trade.gatewayName])
|
||||
|
||||
trade.volume = newTradeVolume
|
||||
trade.price = data['processed_price']
|
||||
trade.direction = order.direction
|
||||
trade.offset = order.offset
|
||||
trade.exchange = order.exchange
|
||||
trade.tradeTime = datetime.now().strftime('%H:%M:%S')
|
||||
|
||||
self.gateway.onTrade(trade)
|
||||
|
||||
# 更新委托状态
|
||||
order.tradedVolume = float(data['processed_amount'])
|
||||
order.status = STATUS_MAP.get(data['status'], STATUS_UNKNOWN)
|
||||
|
||||
if newTradeVolume:
|
||||
self.gateway.onOrder(order)
|
||||
|
||||
if order.status == STATUS_ALLTRADED or order.status == STATUS_CANCELLED:
|
||||
del self.workingOrderDict[order.orderID]
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBuy(self, data, req, reqID):
|
||||
"""买入回调"""
|
||||
localID = self.reqLocalDict[reqID]
|
||||
systemID = data['id']
|
||||
self.localSystemDict[localID] = systemID
|
||||
self.systemLocalDict[systemID] = localID
|
||||
|
||||
# 撤单
|
||||
if localID in self.cancelDict:
|
||||
req = self.cancelDict[localID]
|
||||
self.cancel(req)
|
||||
del self.cancelDict[localID]
|
||||
|
||||
# 推送委托信息
|
||||
order = self.workingOrderDict[localID]
|
||||
if data['result'] == 'success':
|
||||
order.status = STATUS_NOTTRADED
|
||||
self.gateway.onOrder(order)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSell(self, data, req, reqID):
|
||||
"""卖出回调"""
|
||||
localID = self.reqLocalDict[reqID]
|
||||
systemID = data['id']
|
||||
self.localSystemDict[localID] = systemID
|
||||
self.systemLocalDict[systemID] = localID
|
||||
|
||||
# 撤单
|
||||
if localID in self.cancelDict:
|
||||
req = self.cancelDict[localID]
|
||||
self.cancel(req)
|
||||
del self.cancelDict[localID]
|
||||
|
||||
# 推送委托信息
|
||||
order = self.workingOrderDict[localID]
|
||||
if data['result'] == 'success':
|
||||
order.status = STATUS_NOTTRADED
|
||||
self.gateway.onOrder(order)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onBuyMarket(self, data, req, reqID):
|
||||
"""市价买入回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSellMarket(self, data, req, reqID):
|
||||
"""市价卖出回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onCancelOrder(self, data, req, reqID):
|
||||
"""撤单回调"""
|
||||
if data['result'] == 'success':
|
||||
systemID = req['params']['id']
|
||||
localID = self.systemLocalDict[systemID]
|
||||
|
||||
order = self.workingOrderDict[localID]
|
||||
order.status = STATUS_CANCELLED
|
||||
|
||||
del self.workingOrderDict[localID]
|
||||
self.gateway.onOrder(order)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetNewDealOrders(self, data, req, reqID):
|
||||
"""查询最新成交回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetOrderIdByTradeId(self, data, req, reqID):
|
||||
"""通过成交编号查询委托编号回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onWithdrawCoin(self, data, req, reqID):
|
||||
"""提币回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onCancelWithdrawCoin(self, data, req, reqID):
|
||||
"""取消提币回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetWithdrawCoinResult(self, data, req, reqID):
|
||||
"""查询提币结果回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onTransfer(self, data, req, reqID):
|
||||
"""转账回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onLoan(self, data, req, reqID):
|
||||
"""申请杠杆回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onRepayment(self, data, req, reqID):
|
||||
"""归还杠杆回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onLoanAvailable(self, data, req, reqID):
|
||||
"""查询杠杆额度回调"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onGetLoans(self, data, req, reqID):
|
||||
"""查询杠杆列表"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def connect(self, accessKey, secretKey, market, debug=False):
|
||||
"""连接服务器"""
|
||||
self.market = market
|
||||
self.DEBUG = debug
|
||||
|
||||
self.init(accessKey, secretKey)
|
||||
|
||||
# 查询未成交委托
|
||||
self.getOrders(vnhuobi.COINTYPE_BTC, self.market)
|
||||
|
||||
if self.market == vnhuobi.MARKETTYPE_CNY:
|
||||
# 只有人民币市场才有莱特币
|
||||
self.getOrders(vnhuobi.COINTYPE_LTC, self.market)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def queryWorkingOrders(self):
|
||||
"""查询活动委托状态"""
|
||||
for order in self.workingOrderDict.values():
|
||||
# 如果尚未返回委托号,则无法查询
|
||||
if order.orderID in self.localSystemDict:
|
||||
systemID = self.localSystemDict[order.orderID]
|
||||
coin, market = SYMBOL_MAP_REVERSE[order.symbol]
|
||||
self.orderInfo(systemID, coin, market)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def queryAccount(self):
|
||||
"""查询活动委托状态"""
|
||||
self.getAccountInfo(self.market)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def sendOrder(self, req):
|
||||
"""发送委托"""
|
||||
# 检查是否填入了价格,禁止市价委托
|
||||
if req.priceType != PRICETYPE_LIMITPRICE:
|
||||
err = VtErrorData()
|
||||
err.gatewayName = self.gatewayName
|
||||
err.errorMsg = u'火币接口仅支持限价单'
|
||||
err.errorTime = datetime.now().strftime('%H:%M:%S')
|
||||
self.gateway.onError(err)
|
||||
return None
|
||||
|
||||
# 发送限价委托
|
||||
coin, market = SYMBOL_MAP_REVERSE[req.symbol]
|
||||
|
||||
if req.direction == DIRECTION_LONG:
|
||||
reqID = self.buy(req.price, req.volume, coinType=coin, market=self.market)
|
||||
else:
|
||||
reqID = self.sell(req.price, req.volume, coinType=coin, market=self.market)
|
||||
|
||||
self.localID += 1
|
||||
localID = str(self.localID)
|
||||
self.reqLocalDict[reqID] = localID
|
||||
|
||||
# 推送委托信息
|
||||
order = VtOrderData()
|
||||
order.gatewayName = self.gatewayName
|
||||
|
||||
order.symbol = req.symbol
|
||||
order.exchange = EXCHANGE_HUOBI
|
||||
order.vtSymbol = '.'.join([order.symbol, order.exchange])
|
||||
|
||||
order.orderID = localID
|
||||
order.vtOrderID = '.'.join([order.orderID, order.gatewayName])
|
||||
|
||||
order.direction = req.direction
|
||||
order.offset = OFFSET_UNKNOWN
|
||||
order.price = req.price
|
||||
order.volume = req.volume
|
||||
order.orderTime = datetime.now().strftime('%H:%M:%S')
|
||||
order.status = STATUS_UNKNOWN
|
||||
|
||||
self.workingOrderDict[localID] = order
|
||||
self.gateway.onOrder(order)
|
||||
|
||||
# 返回委托号
|
||||
return order.vtOrderID
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def cancel(self, req):
|
||||
"""撤单"""
|
||||
localID = req.orderID
|
||||
if localID in self.localSystemDict:
|
||||
systemID = self.localSystemDict[localID]
|
||||
coin, market = SYMBOL_MAP_REVERSE[req.symbol]
|
||||
self.cancelOrder(systemID, coin, self.market)
|
||||
else:
|
||||
self.cancelDict[localID] = req
|
||||
|
||||
|
||||
########################################################################
|
||||
class HuobiDataApi(vnhuobi.DataApi):
|
||||
"""行情接口"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, gateway):
|
||||
"""Constructor"""
|
||||
super(HuobiDataApi, self).__init__()
|
||||
|
||||
self.market = 'cny'
|
||||
|
||||
self.gateway = gateway
|
||||
self.gatewayName = gateway.gatewayName
|
||||
|
||||
self.tickDict = {} # key:symbol, value:tick
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onTick(self, data):
|
||||
"""实时成交推送"""
|
||||
print data
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onQuote(self, data):
|
||||
"""实时报价推送"""
|
||||
ticker = data['ticker']
|
||||
symbol = MDSYMBOL_MAP[ticker['symbol']]
|
||||
|
||||
if symbol not in self.tickDict:
|
||||
tick = VtTickData()
|
||||
tick.gatewayName = self.gatewayName
|
||||
|
||||
tick.symbol = symbol
|
||||
tick.exchange = EXCHANGE_HUOBI
|
||||
tick.vtSymbol = '.'.join([tick.symbol, tick.exchange])
|
||||
self.tickDict[symbol] = tick
|
||||
else:
|
||||
tick = self.tickDict[symbol]
|
||||
|
||||
tick.highPrice = ticker['high']
|
||||
tick.lowPrice = ticker['low']
|
||||
tick.lastPrice = ticker['last']
|
||||
tick.volume = ticker['vol']
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onDepth(self, data):
|
||||
"""实时深度推送"""
|
||||
symbol = MDSYMBOL_MAP[data['symbol']]
|
||||
if symbol not in self.tickDict:
|
||||
tick = VtTickData()
|
||||
tick.gatewayName = self.gatewayName
|
||||
|
||||
tick.symbol = symbol
|
||||
tick.exchange = EXCHANGE_HUOBI
|
||||
tick.vtSymbol = '.'.join([tick.symbol, tick.exchange])
|
||||
self.tickDict[symbol] = tick
|
||||
else:
|
||||
tick = self.tickDict[symbol]
|
||||
|
||||
tick.bidPrice1, tick.bidVolume1 = data['bids'][0]
|
||||
tick.bidPrice2, tick.bidVolume2 = data['bids'][1]
|
||||
tick.bidPrice3, tick.bidVolume3 = data['bids'][2]
|
||||
tick.bidPrice4, tick.bidVolume4 = data['bids'][3]
|
||||
tick.bidPrice5, tick.bidVolume5 = data['bids'][4]
|
||||
|
||||
tick.askPrice1, tick.askVolume1 = data['asks'][0]
|
||||
tick.askPrice2, tick.askVolume2 = data['asks'][1]
|
||||
tick.askPrice3, tick.askVolume3 = data['asks'][2]
|
||||
tick.askPrice4, tick.askVolume4 = data['asks'][3]
|
||||
tick.askPrice5, tick.askVolume5 = data['asks'][4]
|
||||
|
||||
now = datetime.now()
|
||||
tick.time = now.strftime('%H:%M:%S')
|
||||
tick.date = now.strftime('%Y%m%d')
|
||||
|
||||
self.gateway.onTick(tick)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def connect(self, interval, market, debug=False):
|
||||
"""连接服务器"""
|
||||
self.market = market
|
||||
|
||||
self.init(interval, debug)
|
||||
|
||||
# 订阅行情并推送合约信息
|
||||
if self.market == vnhuobi.MARKETTYPE_CNY:
|
||||
self.subscribeQuote(vnhuobi.SYMBOL_BTCCNY)
|
||||
self.subscribeQuote(vnhuobi.SYMBOL_LTCCNY)
|
||||
|
||||
self.subscribeDepth(vnhuobi.SYMBOL_BTCCNY, 5)
|
||||
self.subscribeDepth(vnhuobi.SYMBOL_LTCCNY, 5)
|
||||
|
||||
contract = VtContractData()
|
||||
contract.gatewayName = self.gatewayName
|
||||
contract.symbol = SYMBOL_BTCCNY
|
||||
contract.exchange = EXCHANGE_HUOBI
|
||||
contract.vtSymbol = '.'.join([contract.symbol, contract.exchange])
|
||||
contract.name = u'人民币现货BTC'
|
||||
contract.size = 1
|
||||
contract.priceTick = 0.01
|
||||
contract.productClass = PRODUCT_SPOT
|
||||
self.gateway.onContract(contract)
|
||||
|
||||
contract = VtContractData()
|
||||
contract.gatewayName = self.gatewayName
|
||||
contract.symbol = SYMBOL_LTCCNY
|
||||
contract.exchange = EXCHANGE_HUOBI
|
||||
contract.vtSymbol = '.'.join([contract.symbol, contract.exchange])
|
||||
contract.name = u'人民币现货LTC'
|
||||
contract.size = 1
|
||||
contract.priceTick = 0.01
|
||||
contract.productClass = PRODUCT_SPOT
|
||||
self.gateway.onContract(contract)
|
||||
else:
|
||||
self.subscribeQuote(vnhuobi.SYMBOL_BTCUSD)
|
||||
|
||||
self.subscribeDepth(vnhuobi.SYMBOL_BTCUSD)
|
||||
|
||||
contract = VtContractData()
|
||||
contract.gatewayName = self.gatewayName
|
||||
contract.symbol = SYMBOL_BTCUSD
|
||||
contract.exchange = EXCHANGE_HUOBI
|
||||
contract.vtSymbol = '.'.join([contract.symbol, contract.exchange])
|
||||
contract.name = u'美元现货BTC'
|
||||
contract.size = 1
|
||||
contract.priceTick = 0.01
|
||||
contract.productClass = PRODUCT_SPOT
|
||||
self.gateway.onContract(contract)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@ STATUS_MAP[-1] = STATUS_CANCELLED
|
||||
|
||||
########################################################################
|
||||
class LbankGateway(VtGateway):
|
||||
"""链行接口"""
|
||||
"""LBANK接口"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, eventEngine, gatewayName='LBANK'):
|
||||
@ -195,7 +195,7 @@ class LbankApi(LbankApi):
|
||||
tick.gatewayName = self.gatewayName
|
||||
|
||||
tick.symbol = symbol
|
||||
tick.exchange = EXCHANGE_LHANG
|
||||
tick.exchange = EXCHANGE_LBANK
|
||||
tick.vtSymbol = '.'.join([tick.symbol, tick.exchange])
|
||||
self.tickDict[symbol] = tick
|
||||
else:
|
||||
@ -217,7 +217,7 @@ class LbankApi(LbankApi):
|
||||
tick.gatewayName = self.gatewayName
|
||||
|
||||
tick.symbol = symbol
|
||||
tick.exchange = EXCHANGE_LHANG
|
||||
tick.exchange = EXCHANGE_LBANK
|
||||
tick.vtSymbol = '.'.join([tick.symbol, tick.exchange])
|
||||
self.tickDict[symbol] = tick
|
||||
else:
|
||||
@ -265,7 +265,7 @@ class LbankApi(LbankApi):
|
||||
posCny = VtPositionData()
|
||||
posCny.gatewayName = self.gatewayName
|
||||
posCny.symbol = 'CNY'
|
||||
posCny.exchange = EXCHANGE_LHANG
|
||||
posCny.exchange = EXCHANGE_LBANK
|
||||
posCny.vtSymbol = '.'.join([posCny.symbol, posCny.exchange])
|
||||
posCny.vtPositionName = posCny.vtSymbol
|
||||
posCny.frozen = d['freeze']['cny']
|
||||
@ -275,7 +275,7 @@ class LbankApi(LbankApi):
|
||||
posBtc = VtPositionData()
|
||||
posBtc.gatewayName = self.gatewayName
|
||||
posBtc.symbol = 'BTC'
|
||||
posBtc.exchange = EXCHANGE_LHANG
|
||||
posBtc.exchange = EXCHANGE_LBANK
|
||||
posBtc.vtSymbol = '.'.join([posBtc.symbol, posBtc.exchange])
|
||||
posBtc.vtPositionName = posBtc.vtSymbol
|
||||
posBtc.frozen = d['freeze']['btc']
|
||||
@ -285,7 +285,7 @@ class LbankApi(LbankApi):
|
||||
posZec = VtPositionData()
|
||||
posZec.gatewayName = self.gatewayName
|
||||
posZec.symbol = 'ZEC'
|
||||
posZec.exchange = EXCHANGE_LHANG
|
||||
posZec.exchange = EXCHANGE_LBANK
|
||||
posZec.vtSymbol = '.'.join([posZec.symbol, posZec.exchange])
|
||||
posZec.vtPositionName = posZec.vtSymbol
|
||||
posZec.frozen = d['freeze']['zec']
|
||||
@ -379,7 +379,7 @@ class LbankApi(LbankApi):
|
||||
order.gatewayName = self.gatewayName
|
||||
|
||||
order.symbol = SYMBOL_MAP[data['symbol']]
|
||||
order.exchange = EXCHANGE_LHANG
|
||||
order.exchange = EXCHANGE_LBANK
|
||||
order.vtSymbol = '.'.join([order.symbol, order.exchange])
|
||||
|
||||
systemID = d['order_id']
|
||||
@ -419,7 +419,7 @@ class LbankApi(LbankApi):
|
||||
contract = VtContractData()
|
||||
contract.gatewayName = self.gatewayName
|
||||
contract.symbol = SYMBOL_BTCCNY
|
||||
contract.exchange = EXCHANGE_LHANG
|
||||
contract.exchange = EXCHANGE_LBANK
|
||||
contract.vtSymbol = '.'.join([contract.symbol, contract.exchange])
|
||||
contract.name = u'人民币现货BTC'
|
||||
contract.size = 1
|
||||
@ -430,7 +430,7 @@ class LbankApi(LbankApi):
|
||||
contract = VtContractData()
|
||||
contract.gatewayName = self.gatewayName
|
||||
contract.symbol = SYMBOL_ZECCNY
|
||||
contract.exchange = EXCHANGE_LHANG
|
||||
contract.exchange = EXCHANGE_LBANK
|
||||
contract.vtSymbol = '.'.join([contract.symbol, contract.exchange])
|
||||
contract.name = u'人民币现货ZEC'
|
||||
contract.size = 1
|
||||
@ -441,12 +441,11 @@ class LbankApi(LbankApi):
|
||||
#----------------------------------------------------------------------
|
||||
def sendOrder(self, req):
|
||||
"""发单"""
|
||||
"""发送委托"""
|
||||
# 检查是否填入了价格,禁止市价委托
|
||||
if req.priceType != PRICETYPE_LIMITPRICE:
|
||||
err = VtErrorData()
|
||||
err.gatewayName = self.gatewayName
|
||||
err.errorMsg = u'链行接口仅支持限价单'
|
||||
err.errorMsg = u'LBANK接口仅支持限价单'
|
||||
err.errorTime = datetime.now().strftime('%H:%M:%S.%f')[:-3]
|
||||
self.gateway.onError(err)
|
||||
return None
|
||||
@ -470,7 +469,7 @@ class LbankApi(LbankApi):
|
||||
order.gatewayName = self.gatewayName
|
||||
|
||||
order.symbol = req.symbol
|
||||
order.exchange = EXCHANGE_LHANG
|
||||
order.exchange = EXCHANGE_LBANK
|
||||
order.vtSymbol = '.'.join([order.symbol, order.exchange])
|
||||
|
||||
order.orderID = localID
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"host": "CNY",
|
||||
"apiKey": "OKCOIN网站申请",
|
||||
"secretKey": "OKCOIN网站申请",
|
||||
"trace": false,
|
||||
"leverage": 20
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
from vnpy.trader import vtConstant
|
||||
from okcoinGateway import OkcoinGateway
|
||||
|
||||
gatewayClass = OkcoinGateway
|
||||
gatewayName = 'OKCOIN'
|
||||
gatewayDisplayName = u'币行'
|
||||
gatewayType = vtConstant.GATEWAYTYPE_BTC
|
||||
gatewayQryEnabled = True
|
||||
|
@ -1,734 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
'''
|
||||
vn.okcoin的gateway接入
|
||||
|
||||
注意:
|
||||
1. 前仅支持USD和CNY的现货交易,USD的期货合约交易暂不支持
|
||||
'''
|
||||
|
||||
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
from time import sleep
|
||||
from copy import copy
|
||||
from threading import Condition
|
||||
from Queue import Queue
|
||||
from threading import Thread
|
||||
from time import sleep
|
||||
|
||||
from vnpy.api.okcoin import vnokcoin
|
||||
from vnpy.trader.vtGateway import *
|
||||
from vnpy.trader.vtFunction import getJsonPath
|
||||
|
||||
# 价格类型映射
|
||||
priceTypeMap = {}
|
||||
priceTypeMap['buy'] = (DIRECTION_LONG, PRICETYPE_LIMITPRICE)
|
||||
priceTypeMap['buy_market'] = (DIRECTION_LONG, PRICETYPE_MARKETPRICE)
|
||||
priceTypeMap['sell'] = (DIRECTION_SHORT, PRICETYPE_LIMITPRICE)
|
||||
priceTypeMap['sell_market'] = (DIRECTION_SHORT, PRICETYPE_MARKETPRICE)
|
||||
priceTypeMapReverse = {v: k for k, v in priceTypeMap.items()}
|
||||
|
||||
# 方向类型映射
|
||||
directionMap = {}
|
||||
directionMapReverse = {v: k for k, v in directionMap.items()}
|
||||
|
||||
# 委托状态印射
|
||||
statusMap = {}
|
||||
statusMap[-1] = STATUS_CANCELLED
|
||||
statusMap[0] = STATUS_NOTTRADED
|
||||
statusMap[1] = STATUS_PARTTRADED
|
||||
statusMap[2] = STATUS_ALLTRADED
|
||||
statusMap[4] = STATUS_UNKNOWN
|
||||
|
||||
############################################
|
||||
## 交易合约代码
|
||||
############################################
|
||||
|
||||
# USD
|
||||
BTC_USD_SPOT = 'BTC_USD_SPOT'
|
||||
BTC_USD_THISWEEK = 'BTC_USD_THISWEEK'
|
||||
BTC_USD_NEXTWEEK = 'BTC_USD_NEXTWEEK'
|
||||
BTC_USD_QUARTER = 'BTC_USD_QUARTER'
|
||||
|
||||
LTC_USD_SPOT = 'LTC_USD_SPOT'
|
||||
LTC_USD_THISWEEK = 'LTC_USD_THISWEEK'
|
||||
LTC_USD_NEXTWEEK = 'LTC_USD_NEXTWEEK'
|
||||
LTC_USD_QUARTER = 'LTC_USD_QUARTER'
|
||||
|
||||
ETH_USD_SPOT = 'ETH_USD_SPOT'
|
||||
ETH_USD_THISWEEK = 'ETH_USD_THISWEEK'
|
||||
ETH_USD_NEXTWEEK = 'ETH_USD_NEXTWEEK'
|
||||
ETH_USD_QUARTER = 'ETH_USD_QUARTER'
|
||||
|
||||
# CNY
|
||||
BTC_CNY_SPOT = 'BTC_CNY_SPOT'
|
||||
LTC_CNY_SPOT = 'LTC_CNY_SPOT'
|
||||
ETH_CNY_SPOT = 'ETH_CNY_SPOT'
|
||||
|
||||
# 印射字典
|
||||
spotSymbolMap = {}
|
||||
spotSymbolMap['ltc_usd'] = LTC_USD_SPOT
|
||||
spotSymbolMap['btc_usd'] = BTC_USD_SPOT
|
||||
spotSymbolMap['ETH_usd'] = ETH_USD_SPOT
|
||||
spotSymbolMap['ltc_cny'] = LTC_CNY_SPOT
|
||||
spotSymbolMap['btc_cny'] = BTC_CNY_SPOT
|
||||
spotSymbolMap['eth_cny'] = ETH_CNY_SPOT
|
||||
spotSymbolMapReverse = {v: k for k, v in spotSymbolMap.items()}
|
||||
|
||||
|
||||
############################################
|
||||
## Channel和Symbol的印射
|
||||
############################################
|
||||
channelSymbolMap = {}
|
||||
|
||||
# USD
|
||||
channelSymbolMap['ok_sub_spotusd_btc_ticker'] = BTC_USD_SPOT
|
||||
channelSymbolMap['ok_sub_spotusd_ltc_ticker'] = LTC_USD_SPOT
|
||||
channelSymbolMap['ok_sub_spotusd_eth_ticker'] = ETH_USD_SPOT
|
||||
|
||||
channelSymbolMap['ok_sub_spotusd_btc_depth_20'] = BTC_USD_SPOT
|
||||
channelSymbolMap['ok_sub_spotusd_ltc_depth_20'] = LTC_USD_SPOT
|
||||
channelSymbolMap['ok_sub_spotusd_eth_depth_20'] = ETH_USD_SPOT
|
||||
|
||||
# CNY
|
||||
channelSymbolMap['ok_sub_spotcny_btc_ticker'] = BTC_CNY_SPOT
|
||||
channelSymbolMap['ok_sub_spotcny_ltc_ticker'] = LTC_CNY_SPOT
|
||||
channelSymbolMap['ok_sub_spotcny_eth_ticker'] = ETH_CNY_SPOT
|
||||
|
||||
channelSymbolMap['ok_sub_spotcny_btc_depth_20'] = BTC_CNY_SPOT
|
||||
channelSymbolMap['ok_sub_spotcny_ltc_depth_20'] = LTC_CNY_SPOT
|
||||
channelSymbolMap['ok_sub_spotcny_eth_depth_20'] = ETH_CNY_SPOT
|
||||
|
||||
|
||||
|
||||
|
||||
########################################################################
|
||||
class OkcoinGateway(VtGateway):
|
||||
"""OkCoin接口"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, eventEngine, gatewayName='OKCOIN'):
|
||||
"""Constructor"""
|
||||
super(OkcoinGateway, self).__init__(eventEngine, gatewayName)
|
||||
|
||||
self.api = Api(self)
|
||||
|
||||
self.leverage = 0
|
||||
self.connected = False
|
||||
|
||||
self.fileName = self.gatewayName + '_connect.json'
|
||||
self.filePath = getJsonPath(self.fileName, __file__)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def connect(self):
|
||||
"""连接"""
|
||||
# 载入json文件
|
||||
try:
|
||||
f = file(self.filePath)
|
||||
except IOError:
|
||||
log = VtLogData()
|
||||
log.gatewayName = self.gatewayName
|
||||
log.logContent = u'读取连接配置出错,请检查'
|
||||
self.onLog(log)
|
||||
return
|
||||
|
||||
# 解析json文件
|
||||
setting = json.load(f)
|
||||
try:
|
||||
host = str(setting['host'])
|
||||
apiKey = str(setting['apiKey'])
|
||||
secretKey = str(setting['secretKey'])
|
||||
trace = setting['trace']
|
||||
leverage = setting['leverage']
|
||||
except KeyError:
|
||||
log = VtLogData()
|
||||
log.gatewayName = self.gatewayName
|
||||
log.logContent = u'连接配置缺少字段,请检查'
|
||||
self.onLog(log)
|
||||
return
|
||||
|
||||
# 初始化接口
|
||||
self.leverage = leverage
|
||||
|
||||
if host == 'CNY':
|
||||
host = vnokcoin.OKCOIN_CNY
|
||||
else:
|
||||
host = vnokcoin.OKCOIN_USD
|
||||
|
||||
self.api.active = True
|
||||
self.api.connect(host, apiKey, secretKey, trace)
|
||||
|
||||
log = VtLogData()
|
||||
log.gatewayName = self.gatewayName
|
||||
log.logContent = u'接口初始化成功'
|
||||
self.onLog(log)
|
||||
|
||||
# 启动查询
|
||||
self.initQuery()
|
||||
self.startQuery()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def subscribe(self, subscribeReq):
|
||||
"""订阅行情"""
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def sendOrder(self, orderReq):
|
||||
"""发单"""
|
||||
return self.api.spotSendOrder(orderReq)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def cancelOrder(self, cancelOrderReq):
|
||||
"""撤单"""
|
||||
self.api.spotCancel(cancelOrderReq)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def qryAccount(self):
|
||||
"""查询账户资金"""
|
||||
self.api.spotUserInfo()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def qryPosition(self):
|
||||
"""查询持仓"""
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def close(self):
|
||||
"""关闭"""
|
||||
self.api.active = False
|
||||
self.api.close()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def initQuery(self):
|
||||
"""初始化连续查询"""
|
||||
if self.qryEnabled:
|
||||
# 需要循环的查询函数列表
|
||||
self.qryFunctionList = [self.qryAccount]
|
||||
|
||||
self.qryCount = 0 # 查询触发倒计时
|
||||
self.qryTrigger = 2 # 查询触发点
|
||||
self.qryNextFunction = 0 # 上次运行的查询函数索引
|
||||
|
||||
self.startQuery()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def query(self, event):
|
||||
"""注册到事件处理引擎上的查询函数"""
|
||||
self.qryCount += 1
|
||||
|
||||
if self.qryCount > self.qryTrigger:
|
||||
# 清空倒计时
|
||||
self.qryCount = 0
|
||||
|
||||
# 执行查询函数
|
||||
function = self.qryFunctionList[self.qryNextFunction]
|
||||
function()
|
||||
|
||||
# 计算下次查询函数的索引,如果超过了列表长度,则重新设为0
|
||||
self.qryNextFunction += 1
|
||||
if self.qryNextFunction == len(self.qryFunctionList):
|
||||
self.qryNextFunction = 0
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def startQuery(self):
|
||||
"""启动连续查询"""
|
||||
self.eventEngine.register(EVENT_TIMER, self.query)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def setQryEnabled(self, qryEnabled):
|
||||
"""设置是否要启动循环查询"""
|
||||
self.qryEnabled = qryEnabled
|
||||
|
||||
|
||||
|
||||
########################################################################
|
||||
class Api(vnokcoin.OkCoinApi):
|
||||
"""OkCoin的API实现"""
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def __init__(self, gateway):
|
||||
"""Constructor"""
|
||||
super(Api, self).__init__()
|
||||
|
||||
self.gateway = gateway # gateway对象
|
||||
self.gatewayName = gateway.gatewayName # gateway对象名称
|
||||
|
||||
self.active = False # 若为True则会在断线后自动重连
|
||||
|
||||
self.cbDict = {}
|
||||
self.tickDict = {}
|
||||
self.orderDict = {}
|
||||
|
||||
self.localNo = 0 # 本地委托号
|
||||
self.localNoQueue = Queue() # 未收到系统委托号的本地委托号队列
|
||||
self.localNoDict = {} # key为本地委托号,value为系统委托号
|
||||
self.orderIdDict = {} # key为系统委托号,value为本地委托号
|
||||
self.cancelDict = {} # key为本地委托号,value为撤单请求
|
||||
|
||||
self.initCallback()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onMessage(self, ws, evt):
|
||||
"""信息推送"""
|
||||
data = self.readData(evt)[0]
|
||||
channel = data['channel']
|
||||
callback = self.cbDict[channel]
|
||||
callback(data)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onError(self, ws, evt):
|
||||
"""错误推送"""
|
||||
error = VtErrorData()
|
||||
error.gatewayName = self.gatewayName
|
||||
error.errorMsg = str(evt)
|
||||
self.gateway.onError(error)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onClose(self, ws):
|
||||
"""接口断开"""
|
||||
# 如果尚未连上,则忽略该次断开提示
|
||||
if not self.gateway.connected:
|
||||
return
|
||||
|
||||
self.gateway.connected = False
|
||||
self.writeLog(u'服务器连接断开')
|
||||
|
||||
# 重新连接
|
||||
if self.active:
|
||||
|
||||
def reconnect():
|
||||
while not self.gateway.connected:
|
||||
self.writeLog(u'等待10秒后重新连接')
|
||||
sleep(10)
|
||||
if not self.gateway.connected:
|
||||
self.reconnect()
|
||||
|
||||
t = Thread(target=reconnect)
|
||||
t.start()
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onOpen(self, ws):
|
||||
"""连接成功"""
|
||||
self.gateway.connected = True
|
||||
self.writeLog(u'服务器连接成功')
|
||||
|
||||
# 连接后查询账户和委托数据
|
||||
self.spotUserInfo()
|
||||
|
||||
self.spotOrderInfo(vnokcoin.TRADING_SYMBOL_LTC, '-1')
|
||||
self.spotOrderInfo(vnokcoin.TRADING_SYMBOL_BTC, '-1')
|
||||
self.spotOrderInfo(vnokcoin.TRADING_SYMBOL_ETH, '-1')
|
||||
|
||||
# 连接后订阅现货的成交和账户数据
|
||||
self.subscribeSpotTrades()
|
||||
self.subscribeSpotUserInfo()
|
||||
|
||||
self.subscribeSpotTicker(vnokcoin.SYMBOL_BTC)
|
||||
self.subscribeSpotTicker(vnokcoin.SYMBOL_LTC)
|
||||
self.subscribeSpotTicker(vnokcoin.SYMBOL_ETH)
|
||||
|
||||
self.subscribeSpotDepth(vnokcoin.SYMBOL_BTC, vnokcoin.DEPTH_20)
|
||||
self.subscribeSpotDepth(vnokcoin.SYMBOL_LTC, vnokcoin.DEPTH_20)
|
||||
self.subscribeSpotDepth(vnokcoin.SYMBOL_ETH, vnokcoin.DEPTH_20)
|
||||
|
||||
# 如果连接的是USD网站则订阅期货相关回报数据
|
||||
if self.currency == vnokcoin.CURRENCY_USD:
|
||||
self.subscribeFutureTrades()
|
||||
self.subscribeFutureUserInfo()
|
||||
self.subscribeFuturePositions()
|
||||
|
||||
# 返回合约信息
|
||||
if self.currency == vnokcoin.CURRENCY_CNY:
|
||||
l = self.generateCnyContract()
|
||||
else:
|
||||
l = self.generateUsdContract()
|
||||
|
||||
for contract in l:
|
||||
contract.gatewayName = self.gatewayName
|
||||
self.gateway.onContract(contract)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def writeLog(self, content):
|
||||
"""快速记录日志"""
|
||||
log = VtLogData()
|
||||
log.gatewayName = self.gatewayName
|
||||
log.logContent = content
|
||||
self.gateway.onLog(log)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def initCallback(self):
|
||||
"""初始化回调函数"""
|
||||
# USD_SPOT
|
||||
self.cbDict['ok_sub_spotusd_btc_ticker'] = self.onTicker
|
||||
self.cbDict['ok_sub_spotusd_ltc_ticker'] = self.onTicker
|
||||
self.cbDict['ok_sub_spotusd_eth_ticker'] = self.onTicker
|
||||
|
||||
self.cbDict['ok_sub_spotusd_btc_depth_20'] = self.onDepth
|
||||
self.cbDict['ok_sub_spotusd_ltc_depth_20'] = self.onDepth
|
||||
self.cbDict['ok_sub_spotusd_eth_depth_20'] = self.onDepth
|
||||
|
||||
self.cbDict['ok_spotusd_userinfo'] = self.onSpotUserInfo
|
||||
self.cbDict['ok_spotusd_orderinfo'] = self.onSpotOrderInfo
|
||||
|
||||
self.cbDict['ok_sub_spotusd_userinfo'] = self.onSpotSubUserInfo
|
||||
self.cbDict['ok_sub_spotusd_trades'] = self.onSpotSubTrades
|
||||
|
||||
self.cbDict['ok_spotusd_trade'] = self.onSpotTrade
|
||||
self.cbDict['ok_spotusd_cancel_order'] = self.onSpotCancelOrder
|
||||
|
||||
# CNY_SPOT
|
||||
self.cbDict['ok_sub_spotcny_btc_ticker'] = self.onTicker
|
||||
self.cbDict['ok_sub_spotcny_ltc_ticker'] = self.onTicker
|
||||
self.cbDict['ok_sub_spotcny_eth_ticker'] = self.onTicker
|
||||
|
||||
self.cbDict['ok_sub_spotcny_btc_depth_20'] = self.onDepth
|
||||
self.cbDict['ok_sub_spotcny_ltc_depth_20'] = self.onDepth
|
||||
self.cbDict['ok_sub_spotcny_eth_depth_20'] = self.onDepth
|
||||
|
||||
self.cbDict['ok_spotcny_userinfo'] = self.onSpotUserInfo
|
||||
self.cbDict['ok_spotcny_orderinfo'] = self.onSpotOrderInfo
|
||||
|
||||
self.cbDict['ok_sub_spotcny_userinfo'] = self.onSpotSubUserInfo
|
||||
self.cbDict['ok_sub_spotcny_trades'] = self.onSpotSubTrades
|
||||
|
||||
self.cbDict['ok_spotcny_trade'] = self.onSpotTrade
|
||||
self.cbDict['ok_spotcny_cancel_order'] = self.onSpotCancelOrder
|
||||
|
||||
# USD_FUTURES
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onTicker(self, data):
|
||||
""""""
|
||||
if 'data' not in data:
|
||||
return
|
||||
|
||||
channel = data['channel']
|
||||
symbol = channelSymbolMap[channel]
|
||||
|
||||
if symbol not in self.tickDict:
|
||||
tick = VtTickData()
|
||||
tick.symbol = symbol
|
||||
tick.vtSymbol = symbol
|
||||
tick.gatewayName = self.gatewayName
|
||||
self.tickDict[symbol] = tick
|
||||
else:
|
||||
tick = self.tickDict[symbol]
|
||||
|
||||
rawData = data['data']
|
||||
tick.highPrice = float(rawData['high'])
|
||||
tick.lowPrice = float(rawData['low'])
|
||||
tick.lastPrice = float(rawData['last'])
|
||||
tick.volume = float(rawData['vol'])
|
||||
#tick.date, tick.time = generateDateTime(rawData['timestamp'])
|
||||
|
||||
newtick = copy(tick)
|
||||
self.gateway.onTick(newtick)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onDepth(self, data):
|
||||
""""""
|
||||
if 'data' not in data:
|
||||
return
|
||||
|
||||
channel = data['channel']
|
||||
symbol = channelSymbolMap[channel]
|
||||
|
||||
if symbol not in self.tickDict:
|
||||
tick = VtTickData()
|
||||
tick.symbol = symbol
|
||||
tick.vtSymbol = symbol
|
||||
tick.gatewayName = self.gatewayName
|
||||
self.tickDict[symbol] = tick
|
||||
else:
|
||||
tick = self.tickDict[symbol]
|
||||
|
||||
if 'data' not in data:
|
||||
return
|
||||
rawData = data['data']
|
||||
|
||||
tick.bidPrice1, tick.bidVolume1 = rawData['bids'][0]
|
||||
tick.bidPrice2, tick.bidVolume2 = rawData['bids'][1]
|
||||
tick.bidPrice3, tick.bidVolume3 = rawData['bids'][2]
|
||||
tick.bidPrice4, tick.bidVolume4 = rawData['bids'][3]
|
||||
tick.bidPrice5, tick.bidVolume5 = rawData['bids'][4]
|
||||
|
||||
tick.askPrice1, tick.askVolume1 = rawData['asks'][-1]
|
||||
tick.askPrice2, tick.askVolume2 = rawData['asks'][-2]
|
||||
tick.askPrice3, tick.askVolume3 = rawData['asks'][-3]
|
||||
tick.askPrice4, tick.askVolume4 = rawData['asks'][-4]
|
||||
tick.askPrice5, tick.askVolume5 = rawData['asks'][-5]
|
||||
|
||||
tick.date, tick.time = generateDateTime(rawData['timestamp'])
|
||||
|
||||
newtick = copy(tick)
|
||||
self.gateway.onTick(newtick)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSpotUserInfo(self, data):
|
||||
"""现货账户资金推送"""
|
||||
rawData = data['data']
|
||||
info = rawData['info']
|
||||
funds = rawData['info']['funds']
|
||||
|
||||
# 持仓信息
|
||||
for symbol in ['btc', 'ltc','eth', self.currency]:
|
||||
if symbol in funds['free']:
|
||||
pos = VtPositionData()
|
||||
pos.gatewayName = self.gatewayName
|
||||
|
||||
pos.symbol = symbol
|
||||
pos.vtSymbol = symbol
|
||||
pos.vtPositionName = symbol
|
||||
pos.direction = DIRECTION_NET
|
||||
|
||||
pos.frozen = float(funds['freezed'][symbol])
|
||||
pos.position = pos.frozen + float(funds['free'][symbol])
|
||||
|
||||
self.gateway.onPosition(pos)
|
||||
|
||||
# 账户资金
|
||||
account = VtAccountData()
|
||||
account.gatewayName = self.gatewayName
|
||||
account.accountID = self.gatewayName
|
||||
account.vtAccountID = account.accountID
|
||||
account.balance = float(funds['asset']['net'])
|
||||
self.gateway.onAccount(account)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSpotSubUserInfo(self, data):
|
||||
"""现货账户资金推送"""
|
||||
if 'data' not in data:
|
||||
return
|
||||
|
||||
rawData = data['data']
|
||||
info = rawData['info']
|
||||
|
||||
# 持仓信息
|
||||
for symbol in ['btc', 'ltc','eth', self.currency]:
|
||||
if symbol in info['free']:
|
||||
pos = VtPositionData()
|
||||
pos.gatewayName = self.gatewayName
|
||||
|
||||
pos.symbol = symbol
|
||||
pos.vtSymbol = symbol
|
||||
pos.vtPositionName = symbol
|
||||
pos.direction = DIRECTION_NET
|
||||
|
||||
pos.frozen = float(info['freezed'][symbol])
|
||||
pos.position = pos.frozen + float(info['free'][symbol])
|
||||
|
||||
self.gateway.onPosition(pos)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSpotSubTrades(self, data):
|
||||
"""成交和委托推送"""
|
||||
if 'data' not in data:
|
||||
return
|
||||
rawData = data['data']
|
||||
|
||||
# 本地和系统委托号
|
||||
orderId = str(rawData['orderId'])
|
||||
localNo = self.orderIdDict[orderId]
|
||||
|
||||
# 委托信息
|
||||
if orderId not in self.orderDict:
|
||||
order = VtOrderData()
|
||||
order.gatewayName = self.gatewayName
|
||||
|
||||
order.symbol = spotSymbolMap[rawData['symbol']]
|
||||
order.vtSymbol = order.symbol
|
||||
|
||||
order.orderID = localNo
|
||||
order.vtOrderID = '.'.join([self.gatewayName, order.orderID])
|
||||
|
||||
order.price = float(rawData['tradeUnitPrice'])
|
||||
order.totalVolume = float(rawData['tradeAmount'])
|
||||
order.direction, priceType = priceTypeMap[rawData['tradeType']]
|
||||
|
||||
self.orderDict[orderId] = order
|
||||
else:
|
||||
order = self.orderDict[orderId]
|
||||
|
||||
order.tradedVolume = float(rawData['completedTradeAmount'])
|
||||
order.status = statusMap[rawData['status']]
|
||||
|
||||
self.gateway.onOrder(copy(order))
|
||||
|
||||
# 成交信息
|
||||
if 'sigTradeAmount' in rawData and float(rawData['sigTradeAmount'])>0:
|
||||
trade = VtTradeData()
|
||||
trade.gatewayName = self.gatewayName
|
||||
|
||||
trade.symbol = spotSymbolMap[rawData['symbol']]
|
||||
trade.vtSymbol = order.symbol
|
||||
|
||||
trade.tradeID = str(rawData['id'])
|
||||
trade.vtTradeID = '.'.join([self.gatewayName, trade.tradeID])
|
||||
|
||||
trade.orderID = localNo
|
||||
trade.vtOrderID = '.'.join([self.gatewayName, trade.orderID])
|
||||
|
||||
trade.price = float(rawData['sigTradePrice'])
|
||||
trade.volume = float(rawData['sigTradeAmount'])
|
||||
|
||||
trade.direction, priceType = priceTypeMap[rawData['tradeType']]
|
||||
|
||||
trade.tradeTime = datetime.now().strftime('%H:%M:%S')
|
||||
|
||||
self.gateway.onTrade(trade)
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSpotOrderInfo(self, data):
|
||||
"""委托信息查询回调"""
|
||||
rawData = data['data']
|
||||
|
||||
for d in rawData['orders']:
|
||||
self.localNo += 1
|
||||
localNo = str(self.localNo)
|
||||
orderId = str(d['order_id'])
|
||||
|
||||
self.localNoDict[localNo] = orderId
|
||||
self.orderIdDict[orderId] = localNo
|
||||
|
||||
if orderId not in self.orderDict:
|
||||
order = VtOrderData()
|
||||
order.gatewayName = self.gatewayName
|
||||
|
||||
order.symbol = spotSymbolMap[d['symbol']]
|
||||
order.vtSymbol = order.symbol
|
||||
|
||||
order.orderID = localNo
|
||||
order.vtOrderID = '.'.join([self.gatewayName, order.orderID])
|
||||
|
||||
order.price = d['price']
|
||||
order.totalVolume = d['amount']
|
||||
order.direction, priceType = priceTypeMap[d['type']]
|
||||
|
||||
self.orderDict[orderId] = order
|
||||
else:
|
||||
order = self.orderDict[orderId]
|
||||
|
||||
order.tradedVolume = d['deal_amount']
|
||||
order.status = statusMap[d['status']]
|
||||
|
||||
self.gateway.onOrder(copy(order))
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def generateSpecificContract(self, contract, symbol):
|
||||
"""生成合约"""
|
||||
new = copy(contract)
|
||||
new.symbol = symbol
|
||||
new.vtSymbol = symbol
|
||||
new.name = symbol
|
||||
return new
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def generateCnyContract(self):
|
||||
"""生成CNY合约信息"""
|
||||
contractList = []
|
||||
|
||||
contract = VtContractData()
|
||||
contract.exchange = EXCHANGE_OKCOIN
|
||||
contract.productClass = PRODUCT_SPOT
|
||||
contract.size = 1
|
||||
contract.priceTick = 0.01
|
||||
|
||||
contractList.append(self.generateSpecificContract(contract, BTC_CNY_SPOT))
|
||||
contractList.append(self.generateSpecificContract(contract, LTC_CNY_SPOT))
|
||||
contractList.append(self.generateSpecificContract(contract, ETH_CNY_SPOT))
|
||||
|
||||
return contractList
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def generateUsdContract(self):
|
||||
"""生成USD合约信息"""
|
||||
contractList = []
|
||||
|
||||
# 现货
|
||||
contract = VtContractData()
|
||||
contract.exchange = EXCHANGE_OKCOIN
|
||||
contract.productClass = PRODUCT_SPOT
|
||||
contract.size = 1
|
||||
contract.priceTick = 0.01
|
||||
|
||||
contractList.append(self.generateSpecificContract(contract, BTC_USD_SPOT))
|
||||
contractList.append(self.generateSpecificContract(contract, LTC_USD_SPOT))
|
||||
contractList.append(self.generateSpecificContract(contract, ETH_USD_SPOT))
|
||||
|
||||
# 期货
|
||||
contract.productClass = PRODUCT_FUTURES
|
||||
|
||||
contractList.append(self.generateSpecificContract(contract, BTC_USD_THISWEEK))
|
||||
contractList.append(self.generateSpecificContract(contract, BTC_USD_NEXTWEEK))
|
||||
contractList.append(self.generateSpecificContract(contract, BTC_USD_QUARTER))
|
||||
contractList.append(self.generateSpecificContract(contract, LTC_USD_THISWEEK))
|
||||
contractList.append(self.generateSpecificContract(contract, LTC_USD_NEXTWEEK))
|
||||
contractList.append(self.generateSpecificContract(contract, LTC_USD_QUARTER))
|
||||
contractList.append(self.generateSpecificContract(contract, ETH_USD_THISWEEK))
|
||||
contractList.append(self.generateSpecificContract(contract, ETH_USD_NEXTWEEK))
|
||||
contractList.append(self.generateSpecificContract(contract, ETH_USD_QUARTER))
|
||||
|
||||
return contractList
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSpotTrade(self, data):
|
||||
"""委托回报"""
|
||||
rawData = data['data']
|
||||
orderId = rawData['order_id']
|
||||
|
||||
# 尽管websocket接口的委托号返回是异步的,但经过测试是
|
||||
# 符合先发现回的规律,因此这里通过queue获取之前发送的
|
||||
# 本地委托号,并把它和推送的系统委托号进行映射
|
||||
localNo = self.localNoQueue.get_nowait()
|
||||
|
||||
self.localNoDict[localNo] = orderId
|
||||
self.orderIdDict[orderId] = localNo
|
||||
|
||||
# 检查是否有系统委托号返回前就发出的撤单请求,若有则进
|
||||
# 行撤单操作
|
||||
if localNo in self.cancelDict:
|
||||
req = self.cancelDict[localNo]
|
||||
self.spotCancel(req)
|
||||
del self.cancelDict[localNo]
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def onSpotCancelOrder(self, data):
|
||||
"""撤单回报"""
|
||||
pass
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def spotSendOrder(self, req):
|
||||
"""发单"""
|
||||
symbol = spotSymbolMapReverse[req.symbol][:4]
|
||||
type_ = priceTypeMapReverse[(req.direction, req.priceType)]
|
||||
self.spotTrade(symbol, type_, str(req.price), str(req.volume))
|
||||
|
||||
# 本地委托号加1,并将对应字符串保存到队列中,返回基于本地委托号的vtOrderID
|
||||
self.localNo += 1
|
||||
self.localNoQueue.put(str(self.localNo))
|
||||
vtOrderID = '.'.join([self.gatewayName, str(self.localNo)])
|
||||
return vtOrderID
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def spotCancel(self, req):
|
||||
"""撤单"""
|
||||
symbol = spotSymbolMapReverse[req.symbol][:4]
|
||||
localNo = req.orderID
|
||||
|
||||
if localNo in self.localNoDict:
|
||||
orderID = self.localNoDict[localNo]
|
||||
self.spotCancelOrder(symbol, orderID)
|
||||
else:
|
||||
# 如果在系统委托号返回前客户就发送了撤单请求,则保存
|
||||
# 在cancelDict字典中,等待返回后执行撤单任务
|
||||
self.cancelDict[localNo] = req
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
def generateDateTime(s):
|
||||
"""生成时间"""
|
||||
dt = datetime.fromtimestamp(float(s)/1e3)
|
||||
time = dt.strftime("%H:%M:%S.%f")
|
||||
date = dt.strftime("%Y%m%d")
|
||||
return date, time
|
@ -81,15 +81,15 @@ EXCHANGE_ICE = 'ICE' # ICE交易所
|
||||
EXCHANGE_LME = 'LME' # LME交易所
|
||||
|
||||
EXCHANGE_OANDA = 'OANDA' # OANDA外汇做市商
|
||||
EXCHANGE_OKCOIN = 'OKCOIN' # OKCOIN比特币交易所
|
||||
EXCHANGE_HUOBI = 'HUOBI' # 火币比特币交易所
|
||||
EXCHANGE_LHANG = 'LHANG' # 链行比特币交易所
|
||||
|
||||
EXCHANGE_KORBIT = 'KORBIT' # KORBIT 韩国交易所
|
||||
EXCHANGE_ZB = 'ZB' # ZB 中国比特币交易所 (比特币中国)
|
||||
EXCHANGE_OKEX = 'OKEX' # OKEX 中国比特币交易所 (okcoin)
|
||||
EXCHANGE_ZAIF = "ZAIF" # ZAIF 日本比特币交易所
|
||||
EXCHANGE_COINCHECK = "COINCHECK" # COINCHECK 日本比特币交易所
|
||||
EXCHANGE_OKCOIN = 'OKCOIN' # OKCOIN比特币交易所
|
||||
EXCHANGE_HUOBI = 'HUOBI' # 火币比特币交易所
|
||||
EXCHANGE_LBANK = 'LBANK' # LBANK比特币交易所
|
||||
EXCHANGE_KORBIT = 'KORBIT' # KORBIT韩国交易所
|
||||
EXCHANGE_ZB = 'ZB' # 比特币中国比特币交易所
|
||||
EXCHANGE_OKEX = 'OKEX' # OKEX比特币交易所
|
||||
EXCHANGE_ZAIF = "ZAIF" # ZAIF日本比特币交易所
|
||||
EXCHANGE_COINCHECK = "COINCHECK" # COINCHECK日本比特币交易所
|
||||
|
||||
# 货币类型
|
||||
CURRENCY_USD = 'USD' # 美元
|
||||
|
@ -77,15 +77,15 @@ EXCHANGE_ICE = 'ICE' # ICE交易所
|
||||
EXCHANGE_LME = 'LME' # LME交易所
|
||||
|
||||
EXCHANGE_OANDA = 'OANDA' # OANDA外汇做市商
|
||||
EXCHANGE_OKCOIN = 'OKCOIN' # OKCOIN比特币交易所
|
||||
EXCHANGE_HUOBI = 'HUOBI' # 火币比特币交易所
|
||||
EXCHANGE_LHANG = 'LHANG' # 链行比特币交易所
|
||||
|
||||
EXCHANGE_KORBIT = 'KORBIT' # KORBIT 韩国交易所
|
||||
EXCHANGE_ZB = 'ZB' # ZB 中国比特币交易所 (比特币中国)
|
||||
EXCHANGE_OKEX = 'OKEX' # OKEX 中国比特币交易所 (okcoin)
|
||||
EXCHANGE_ZAIF = "ZAIF" # ZAIF 日本比特币交易所 尚未实现
|
||||
EXCHANGE_COINCHECK = "COINCHECK" # COINCHECK 日本比特币交易所
|
||||
EXCHANGE_OKCOIN = 'OKCOIN' # OKCOIN比特币交易所
|
||||
EXCHANGE_HUOBI = 'HUOBI' # 火币比特币交易所
|
||||
EXCHANGE_LBANK = 'LBANK' # LBANK比特币交易所
|
||||
EXCHANGE_KORBIT = 'KORBIT' # KORBIT韩国交易所
|
||||
EXCHANGE_ZB = 'ZB' # 比特币中国比特币交易所
|
||||
EXCHANGE_OKEX = 'OKEX' # OKEX比特币交易所
|
||||
EXCHANGE_ZAIF = "ZAIF" # ZAIF日本比特币交易所
|
||||
EXCHANGE_COINCHECK = "COINCHECK" # COINCHECK日本比特币交易所
|
||||
|
||||
# 货币类型
|
||||
CURRENCY_USD = 'USD' # 美元
|
||||
|
Loading…
Reference in New Issue
Block a user