1. 增加vn.trader里OKCOIN比特币交易所的接入
2. 增加CTA模块回测中的部分业绩分析数据:盈亏比等 3. 修复之前vn.okcoin里的几个BUG
This commit is contained in:
parent
e405e760f4
commit
e7582dd01f
@ -15,9 +15,9 @@ api.connect(OKCOIN_USD, apiKey, secretKey, True)
|
|||||||
sleep(1)
|
sleep(1)
|
||||||
|
|
||||||
# 测试现货行情API
|
# 测试现货行情API
|
||||||
api.subscribeSpotTicker(SYMBOL_BTC)
|
#api.subscribeSpotTicker(SYMBOL_BTC)
|
||||||
#api.subscribeSpotTradeData(SYMBOL_BTC)
|
#api.subscribeSpotTradeData(SYMBOL_BTC)
|
||||||
#api.subscribeSpotDepth(SYMBOL_BTC, DEPTH_20)
|
api.subscribeSpotDepth(SYMBOL_BTC, DEPTH_20)
|
||||||
#api.subscribeSpotKline(SYMBOL_BTC, INTERVAL_1M)
|
#api.subscribeSpotKline(SYMBOL_BTC, INTERVAL_1M)
|
||||||
|
|
||||||
# 测试现货交易API
|
# 测试现货交易API
|
||||||
|
@ -41,7 +41,7 @@ INTERVAL_1W = 'week'
|
|||||||
|
|
||||||
# 交易代码,需要后缀货币名才能完整
|
# 交易代码,需要后缀货币名才能完整
|
||||||
TRADING_SYMBOL_BTC = 'btc_'
|
TRADING_SYMBOL_BTC = 'btc_'
|
||||||
TRADING_SYMBOL_LTS = 'ltc_'
|
TRADING_SYMBOL_LTC = 'ltc_'
|
||||||
|
|
||||||
# 委托类型
|
# 委托类型
|
||||||
TYPE_BUY = 'buy'
|
TYPE_BUY = 'buy'
|
||||||
@ -86,6 +86,7 @@ class OkCoinApi(object):
|
|||||||
self.apiKey = '' # 用户名
|
self.apiKey = '' # 用户名
|
||||||
self.secretKey = '' # 密码
|
self.secretKey = '' # 密码
|
||||||
self.host = '' # 服务器地址
|
self.host = '' # 服务器地址
|
||||||
|
|
||||||
self.currency = '' # 货币类型(usd或者cny)
|
self.currency = '' # 货币类型(usd或者cny)
|
||||||
|
|
||||||
self.ws = None # websocket应用对象
|
self.ws = None # websocket应用对象
|
||||||
@ -164,11 +165,7 @@ class OkCoinApi(object):
|
|||||||
|
|
||||||
self.thread = Thread(target=self.ws.run_forever)
|
self.thread = Thread(target=self.ws.run_forever)
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
|
|
||||||
#######################
|
|
||||||
## 现货相关
|
|
||||||
#######################
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def sendMarketDataRequest(self, channel):
|
def sendMarketDataRequest(self, channel):
|
||||||
"""发送行情请求"""
|
"""发送行情请求"""
|
||||||
@ -198,8 +195,12 @@ class OkCoinApi(object):
|
|||||||
|
|
||||||
# 使用json打包并发送
|
# 使用json打包并发送
|
||||||
j = json.dumps(d)
|
j = json.dumps(d)
|
||||||
self.ws.send(j)
|
self.ws.send(j)
|
||||||
|
|
||||||
|
#######################
|
||||||
|
## 现货相关
|
||||||
|
#######################
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def subscribeSpotTicker(self, symbol):
|
def subscribeSpotTicker(self, symbol):
|
||||||
"""订阅现货普通报价"""
|
"""订阅现货普通报价"""
|
||||||
@ -224,8 +225,8 @@ class OkCoinApi(object):
|
|||||||
def spotTrade(self, symbol, type_, price, amount):
|
def spotTrade(self, symbol, type_, price, amount):
|
||||||
"""现货委托"""
|
"""现货委托"""
|
||||||
params = {}
|
params = {}
|
||||||
params['symbol'] = str(symbol)
|
params['symbol'] = str(symbol+self.currency)
|
||||||
params['type'] = str(type_+self.currency)
|
params['type'] = str(type_)
|
||||||
params['price'] = str(price)
|
params['price'] = str(price)
|
||||||
params['amount'] = str(amount)
|
params['amount'] = str(amount)
|
||||||
|
|
||||||
@ -258,7 +259,7 @@ class OkCoinApi(object):
|
|||||||
params['symbol'] = str(symbol+self.currency)
|
params['symbol'] = str(symbol+self.currency)
|
||||||
params['order_id'] = str(orderid)
|
params['order_id'] = str(orderid)
|
||||||
|
|
||||||
channel = 'ok_spot%s_orderinfo'
|
channel = 'ok_spot%s_orderinfo' %(self.currency)
|
||||||
|
|
||||||
self.sendTradingRequest(channel, params)
|
self.sendTradingRequest(channel, params)
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
本文件中包含的是CTA模块的回测引擎,回测引擎的API和CTA引擎一致,
|
本文件中包含的是CTA模块的回测引擎,回测引擎的API和CTA引擎一致,
|
||||||
可以使用和实盘相同的代码进行回测。
|
可以使用和实盘相同的代码进行回测。
|
||||||
'''
|
'''
|
||||||
|
from __future__ import division
|
||||||
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
@ -504,6 +505,11 @@ class BacktestingEngine(object):
|
|||||||
capitalList = [] # 盈亏汇总的时间序列
|
capitalList = [] # 盈亏汇总的时间序列
|
||||||
drawdownList = [] # 回撤的时间序列
|
drawdownList = [] # 回撤的时间序列
|
||||||
|
|
||||||
|
winningResult = 0 # 盈利次数
|
||||||
|
losingResult = 0 # 亏损次数
|
||||||
|
totalWinning = 0 # 总盈利金额
|
||||||
|
totalLosing = 0 # 总亏损金额
|
||||||
|
|
||||||
for time, result in resultDict.items():
|
for time, result in resultDict.items():
|
||||||
capital += result.pnl
|
capital += result.pnl
|
||||||
maxCapital = max(capital, maxCapital)
|
maxCapital = max(capital, maxCapital)
|
||||||
@ -519,6 +525,19 @@ class BacktestingEngine(object):
|
|||||||
totalCommission += result.commission
|
totalCommission += result.commission
|
||||||
totalSlippage += result.slippage
|
totalSlippage += result.slippage
|
||||||
|
|
||||||
|
if result.pnl >= 0:
|
||||||
|
winningResult += 1
|
||||||
|
totalWinning += result.pnl
|
||||||
|
else:
|
||||||
|
losingResult += 1
|
||||||
|
totalLosing += result.pnl
|
||||||
|
|
||||||
|
# 计算盈亏相关数据
|
||||||
|
winningRate = winningResult/totalResult*100 # 胜率
|
||||||
|
averageWinning = totalWinning/winningResult # 平均每笔盈利
|
||||||
|
averageLosing = totalLosing/losingResult # 平均每笔亏损
|
||||||
|
profitLossRatio = -averageWinning/averageLosing # 盈亏比
|
||||||
|
|
||||||
# 返回回测结果
|
# 返回回测结果
|
||||||
d = {}
|
d = {}
|
||||||
d['capital'] = capital
|
d['capital'] = capital
|
||||||
@ -531,7 +550,12 @@ class BacktestingEngine(object):
|
|||||||
d['timeList'] = timeList
|
d['timeList'] = timeList
|
||||||
d['pnlList'] = pnlList
|
d['pnlList'] = pnlList
|
||||||
d['capitalList'] = capitalList
|
d['capitalList'] = capitalList
|
||||||
d['drawdownList'] = drawdownList
|
d['drawdownList'] = drawdownList
|
||||||
|
d['winningRate'] = winningRate
|
||||||
|
d['averageWinning'] = averageWinning
|
||||||
|
d['averageLosing'] = averageLosing
|
||||||
|
d['profitLossRatio'] = profitLossRatio
|
||||||
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
@ -551,6 +575,11 @@ class BacktestingEngine(object):
|
|||||||
self.output(u'平均每笔盈利:\t%s' %formatNumber(d['capital']/d['totalResult']))
|
self.output(u'平均每笔盈利:\t%s' %formatNumber(d['capital']/d['totalResult']))
|
||||||
self.output(u'平均每笔滑点:\t%s' %formatNumber(d['totalSlippage']/d['totalResult']))
|
self.output(u'平均每笔滑点:\t%s' %formatNumber(d['totalSlippage']/d['totalResult']))
|
||||||
self.output(u'平均每笔佣金:\t%s' %formatNumber(d['totalCommission']/d['totalResult']))
|
self.output(u'平均每笔佣金:\t%s' %formatNumber(d['totalCommission']/d['totalResult']))
|
||||||
|
|
||||||
|
self.output(u'胜率\t\t%s%%' %formatNumber(d['winningRate']))
|
||||||
|
self.output(u'平均每笔盈利\t%s' %formatNumber(d['averageWinning']))
|
||||||
|
self.output(u'平均每笔亏损\t%s' %formatNumber(d['averageLosing']))
|
||||||
|
self.output(u'盈亏比:\t%s' %formatNumber(d['profitLossRatio']))
|
||||||
|
|
||||||
# 绘图
|
# 绘图
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
@ -651,11 +680,11 @@ class TradingResult(object):
|
|||||||
self.exit = exit # 平仓价格
|
self.exit = exit # 平仓价格
|
||||||
self.volume = volume # 交易数量(+/-代表方向)
|
self.volume = volume # 交易数量(+/-代表方向)
|
||||||
|
|
||||||
self.turnover = (self.entry+self.exit)*size # 成交金额
|
self.turnover = (self.entry+self.exit)*size*abs(volume) # 成交金额
|
||||||
self.commission = self.turnover*rate # 手续费成本
|
self.commission = self.turnover*rate # 手续费成本
|
||||||
self.slippage = slippage*2*size # 滑点成本
|
self.slippage = slippage*2*size*abs(volume) # 滑点成本
|
||||||
self.pnl = ((self.exit - self.entry) * volume * size
|
self.pnl = ((self.exit - self.entry) * volume * size
|
||||||
- self.commission - self.slippage) # 净盈亏
|
- self.commission - self.slippage) # 净盈亏
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
|
@ -259,21 +259,21 @@ if __name__ == '__main__':
|
|||||||
# 设置使用的历史数据库
|
# 设置使用的历史数据库
|
||||||
engine.setDatabase(MINUTE_DB_NAME, 'IF0000')
|
engine.setDatabase(MINUTE_DB_NAME, 'IF0000')
|
||||||
|
|
||||||
## 在引擎中创建策略对象
|
# 在引擎中创建策略对象
|
||||||
#d = {'atrLength': 11}
|
d = {'atrLength': 11}
|
||||||
#engine.initStrategy(AtrRsiStrategy, d)
|
engine.initStrategy(AtrRsiStrategy, d)
|
||||||
|
|
||||||
## 开始跑回测
|
# 开始跑回测
|
||||||
#engine.runBacktesting()
|
engine.runBacktesting()
|
||||||
|
|
||||||
## 显示回测结果
|
# 显示回测结果
|
||||||
#engine.showBacktestingResult()
|
engine.showBacktestingResult()
|
||||||
|
|
||||||
# 跑优化
|
## 跑优化
|
||||||
setting = OptimizationSetting() # 新建一个优化任务设置对象
|
#setting = OptimizationSetting() # 新建一个优化任务设置对象
|
||||||
setting.setOptimizeTarget('capital') # 设置优化排序的目标是策略净盈利
|
#setting.setOptimizeTarget('capital') # 设置优化排序的目标是策略净盈利
|
||||||
setting.addParameter('atrLength', 11, 12, 1) # 增加第一个优化参数atrLength,起始11,结束12,步进1
|
#setting.addParameter('atrLength', 11, 12, 1) # 增加第一个优化参数atrLength,起始11,结束12,步进1
|
||||||
setting.addParameter('atrMa', 20, 30, 5) # 增加第二个优化参数atrMa,起始20,结束30,步进1
|
#setting.addParameter('atrMa', 20, 30, 5) # 增加第二个优化参数atrMa,起始20,结束30,步进1
|
||||||
engine.runOptimization(AtrRsiStrategy, setting) # 运行优化函数,自动输出结果
|
#engine.runOptimization(AtrRsiStrategy, setting) # 运行优化函数,自动输出结果
|
||||||
|
|
||||||
|
|
7
vn.trader/okcoinGateway/OKCOIN_connect.json
Normal file
7
vn.trader/okcoinGateway/OKCOIN_connect.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"host": "CNY",
|
||||||
|
"apiKey": "OKCOIN网站申请",
|
||||||
|
"secretKey": "OKCOIN网站申请",
|
||||||
|
"trace": false,
|
||||||
|
"leverage": 20
|
||||||
|
}
|
0
vn.trader/okcoinGateway/__init__.py
Normal file
0
vn.trader/okcoinGateway/__init__.py
Normal file
657
vn.trader/okcoinGateway/okcoinGateway.py
Normal file
657
vn.trader/okcoinGateway/okcoinGateway.py
Normal file
@ -0,0 +1,657 @@
|
|||||||
|
# encoding: UTF-8
|
||||||
|
|
||||||
|
'''
|
||||||
|
vn.okcoin的gateway接入
|
||||||
|
|
||||||
|
注意:
|
||||||
|
1. 该接口尚处于测试阶段,用于实盘请谨慎
|
||||||
|
2. 目前仅支持USD和CNY的现货交易,USD的期货合约交易暂不支持
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
from copy import copy
|
||||||
|
from threading import Condition
|
||||||
|
|
||||||
|
import vnokcoin
|
||||||
|
from vtGateway import *
|
||||||
|
|
||||||
|
# 价格类型映射
|
||||||
|
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'
|
||||||
|
|
||||||
|
# CNY
|
||||||
|
BTC_CNY_SPOT = 'BTC_CNY_SPOT'
|
||||||
|
LTC_CNY_SPOT = 'LTC_CNY_SPOT'
|
||||||
|
|
||||||
|
# 印射字典
|
||||||
|
spotSymbolMap = {}
|
||||||
|
spotSymbolMap['ltc_usd'] = LTC_USD_SPOT
|
||||||
|
spotSymbolMap['btc_usd'] = BTC_USD_SPOT
|
||||||
|
spotSymbolMap['ltc_cny'] = LTC_CNY_SPOT
|
||||||
|
spotSymbolMap['btc_cny'] = BTC_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_btc_depth_20'] = BTC_USD_SPOT
|
||||||
|
channelSymbolMap['ok_sub_spotusd_ltc_depth_20'] = LTC_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_btc_depth_20'] = BTC_CNY_SPOT
|
||||||
|
channelSymbolMap['ok_sub_spotcny_ltc_depth_20'] = LTC_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
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def connect(self):
|
||||||
|
"""连接"""
|
||||||
|
# 载入json文件
|
||||||
|
fileName = self.gatewayName + '_connect.json'
|
||||||
|
fileName = os.getcwd() + '/okcoinGateway/' + fileName
|
||||||
|
|
||||||
|
try:
|
||||||
|
f = file(fileName)
|
||||||
|
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.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):
|
||||||
|
"""关闭"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
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.cbDict = {}
|
||||||
|
self.tickDict = {}
|
||||||
|
self.orderDict = {}
|
||||||
|
|
||||||
|
self.lastOrderID = ''
|
||||||
|
self.orderCondition = Condition()
|
||||||
|
|
||||||
|
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):
|
||||||
|
"""接口断开"""
|
||||||
|
self.gateway.connected = True
|
||||||
|
self.writeLog(u'服务器连接断开')
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
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.subscribeSpotTrades()
|
||||||
|
self.subscribeSpotUserInfo()
|
||||||
|
|
||||||
|
self.subscribeSpotTicker(vnokcoin.SYMBOL_BTC)
|
||||||
|
self.subscribeSpotTicker(vnokcoin.SYMBOL_LTC)
|
||||||
|
|
||||||
|
self.subscribeSpotDepth(vnokcoin.SYMBOL_BTC, vnokcoin.DEPTH_20)
|
||||||
|
self.subscribeSpotDepth(vnokcoin.SYMBOL_LTC, 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_btc_depth_20'] = self.onDepth
|
||||||
|
self.cbDict['ok_sub_spotusd_ltc_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_btc_depth_20'] = self.onDepth
|
||||||
|
self.cbDict['ok_sub_spotcny_ltc_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'].replace(',', ''))
|
||||||
|
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'][0]
|
||||||
|
tick.askPrice2, tick.askVolume2 = rawData['asks'][1]
|
||||||
|
tick.askPrice3, tick.askVolume3 = rawData['asks'][2]
|
||||||
|
tick.askPrice4, tick.askVolume4 = rawData['asks'][3]
|
||||||
|
tick.askPrice5, tick.askVolume5 = rawData['asks'][4]
|
||||||
|
|
||||||
|
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', 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', 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'])
|
||||||
|
if orderID not in self.orderDict:
|
||||||
|
order = VtOrderData()
|
||||||
|
order.gatewayName = self.gatewayName
|
||||||
|
|
||||||
|
order.symbol = spotSymbolMap[rawData['symbol']]
|
||||||
|
order.vtSymbol = order.symbol
|
||||||
|
|
||||||
|
order.orderID = str(rawData['orderId'])
|
||||||
|
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 = str(rawData['orderId'])
|
||||||
|
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']:
|
||||||
|
orderID = str(d['order_id'])
|
||||||
|
|
||||||
|
if orderID not in self.orderDict:
|
||||||
|
order = VtOrderData()
|
||||||
|
order.gatewayName = self.gatewayName
|
||||||
|
|
||||||
|
order.symbol = spotSymbolMap[d['symbol']]
|
||||||
|
order.vtSymbol = order.symbol
|
||||||
|
|
||||||
|
order.orderID = str(d['order_id'])
|
||||||
|
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))
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
# 期货
|
||||||
|
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))
|
||||||
|
|
||||||
|
return contractList
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onSpotTrade(self, data):
|
||||||
|
"""委托回报"""
|
||||||
|
rawData = data['data']
|
||||||
|
self.lastOrderID = rawData['order_id']
|
||||||
|
|
||||||
|
# 收到委托号后,通知发送委托的线程返回委托号
|
||||||
|
self.orderCondition.acquire()
|
||||||
|
self.orderCondition.notify()
|
||||||
|
self.orderCondition.release()
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
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))
|
||||||
|
|
||||||
|
# 等待发单回调推送委托号信息
|
||||||
|
self.orderCondition.acquire()
|
||||||
|
self.orderCondition.wait()
|
||||||
|
self.orderCondition.release()
|
||||||
|
|
||||||
|
vtOrderID = '.'.join([self.gatewayName, self.lastOrderID])
|
||||||
|
self.lastOrderID = ''
|
||||||
|
return vtOrderID
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def spotCancel(self, req):
|
||||||
|
"""撤单"""
|
||||||
|
symbol = spotSymbolMapReverse[req.symbol][:4]
|
||||||
|
self.spotCancelOrder(symbol, req.orderID)
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
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
|
382
vn.trader/okcoinGateway/vnokcoin.py
Normal file
382
vn.trader/okcoinGateway/vnokcoin.py
Normal file
@ -0,0 +1,382 @@
|
|||||||
|
# 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'
|
||||||
|
|
||||||
|
# 行情深度
|
||||||
|
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_'
|
||||||
|
|
||||||
|
# 委托类型
|
||||||
|
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 sendMarketDataRequest(self, channel):
|
||||||
|
"""发送行情请求"""
|
||||||
|
# 生成请求
|
||||||
|
d = {}
|
||||||
|
d['event'] = 'addChannel'
|
||||||
|
d['binary'] = True
|
||||||
|
d['channel'] = channel
|
||||||
|
|
||||||
|
# 使用json打包并发送
|
||||||
|
j = json.dumps(d)
|
||||||
|
self.ws.send(j)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
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)
|
||||||
|
self.ws.send(j)
|
||||||
|
|
||||||
|
#######################
|
||||||
|
## 现货相关
|
||||||
|
#######################
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
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.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, {})
|
||||||
|
|
||||||
|
|
@ -89,6 +89,9 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
connectOandaAction = QtGui.QAction(u'连接OANDA', self)
|
connectOandaAction = QtGui.QAction(u'连接OANDA', self)
|
||||||
connectOandaAction.triggered.connect(self.connectOanda)
|
connectOandaAction.triggered.connect(self.connectOanda)
|
||||||
|
|
||||||
|
connectOkcoinAction = QtGui.QAction(u'连接OKCOIN', self)
|
||||||
|
connectOkcoinAction.triggered.connect(self.connectOkcoin)
|
||||||
|
|
||||||
connectDbAction = QtGui.QAction(u'连接数据库', self)
|
connectDbAction = QtGui.QAction(u'连接数据库', self)
|
||||||
connectDbAction.triggered.connect(self.mainEngine.dbConnect)
|
connectDbAction.triggered.connect(self.mainEngine.dbConnect)
|
||||||
|
|
||||||
@ -137,6 +140,8 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
sysMenu.addAction(connectIbAction)
|
sysMenu.addAction(connectIbAction)
|
||||||
if 'OANDA' in self.mainEngine.gatewayDict:
|
if 'OANDA' in self.mainEngine.gatewayDict:
|
||||||
sysMenu.addAction(connectOandaAction)
|
sysMenu.addAction(connectOandaAction)
|
||||||
|
if 'OKCOIN' in self.mainEngine.gatewayDict:
|
||||||
|
sysMenu.addAction(connectOkcoinAction)
|
||||||
sysMenu.addSeparator()
|
sysMenu.addSeparator()
|
||||||
if 'Wind' in self.mainEngine.gatewayDict:
|
if 'Wind' in self.mainEngine.gatewayDict:
|
||||||
sysMenu.addAction(connectWindAction)
|
sysMenu.addAction(connectWindAction)
|
||||||
@ -239,6 +244,11 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
"""连接OANDA"""
|
"""连接OANDA"""
|
||||||
self.mainEngine.connect('OANDA')
|
self.mainEngine.connect('OANDA')
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def connectOkcoin(self):
|
||||||
|
"""连接OKCOIN"""
|
||||||
|
self.mainEngine.connect('OKCOIN')
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def test(self):
|
def test(self):
|
||||||
"""测试按钮用的函数"""
|
"""测试按钮用的函数"""
|
||||||
|
@ -69,6 +69,7 @@ EXCHANGE_GLOBEX = 'GLOBEX' # CME电子交易平台
|
|||||||
EXCHANGE_IDEALPRO = 'IDEALPRO' # IB外汇ECN
|
EXCHANGE_IDEALPRO = 'IDEALPRO' # IB外汇ECN
|
||||||
|
|
||||||
EXCHANGE_OANDA = 'OANDA' # OANDA外汇做市商
|
EXCHANGE_OANDA = 'OANDA' # OANDA外汇做市商
|
||||||
|
EXCHANGE_OKCOIN = 'OKCOIN' # OKCOIN比特币交易所
|
||||||
|
|
||||||
# 货币类型
|
# 货币类型
|
||||||
CURRENCY_USD = 'USD' # 美元
|
CURRENCY_USD = 'USD' # 美元
|
||||||
|
@ -114,6 +114,13 @@ class MainEngine(object):
|
|||||||
self.gatewayDict['OANDA'].setQryEnabled(True)
|
self.gatewayDict['OANDA'].setQryEnabled(True)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print e
|
print e
|
||||||
|
|
||||||
|
try:
|
||||||
|
from okcoinGateway.okcoinGateway import OkcoinGateway
|
||||||
|
self.addGateway(OkcoinGateway, 'OKCOIN')
|
||||||
|
self.gatewayDict['OKCOIN'].setQryEnabled(True)
|
||||||
|
except Exception, e:
|
||||||
|
print e
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def addGateway(self, gateway, gatewayName=None):
|
def addGateway(self, gateway, gatewayName=None):
|
||||||
|
Loading…
Reference in New Issue
Block a user