Merge branch 'dev' of https://github.com/vnpy/vnpy into dev

This commit is contained in:
vn.py 2018-08-05 22:44:07 +08:00
commit 5dd17111d7
11 changed files with 296 additions and 38 deletions

View File

@ -497,10 +497,11 @@ class LogMonitor(BasicMonitor):
cellLogContent = BasicCell(logContent) cellLogContent = BasicCell(logContent)
cellGatewayName = BasicCell(error.gatewayName) cellGatewayName = BasicCell(error.gatewayName)
self.setItem(0, 0, cellLogTime) self.setItem(0, 0, cellGatewayName)
self.setItem(0, 1, cellLogContent) self.setItem(0, 1, cellLogTime)
self.setItem(0, 2, cellGatewayName) self.setItem(0, 2, cellLogContent)
######################################################################## ########################################################################
class TradeMonitor(BasicMonitor): class TradeMonitor(BasicMonitor):

View File

@ -199,18 +199,14 @@ class CoinbaseWebsocketApi(object):
def run(self): def run(self):
"""运行""" """运行"""
while self.active: while self.active:
stream = self.ws.recv() try:
data = json.loads(stream) stream = self.ws.recv()
self.onData(data) data = json.loads(stream)
self.onData(data)
#try: except:
#stream = self.ws.recv() msg = traceback.format_exc()
#data = json.loads(stream) self.onError(msg)
#self.onData(data) self.reconnect()
#except:
#msg = traceback.format_exc()
#self.onError(msg)
#self.reconnect()
#---------------------------------------------------------------------- #----------------------------------------------------------------------
def close(self): def close(self):

View File

@ -0,0 +1,225 @@
# encoding: UTF-8
from __future__ import division
from collections import OrderedDict
from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT,
OFFSET_OPEN, OFFSET_CLOSE,
STATUS_ALLTRADED, STATUS_CANCELLED,
STATUS_REJECTED)
from vnpy.trader.uiQt import QtGui
from vnpy.trader.app.algoTrading.algoTemplate import AlgoTemplate
from vnpy.trader.app.algoTrading.uiAlgoWidget import AlgoWidget, QtWidgets
STATUS_FINISHED = set([STATUS_ALLTRADED, STATUS_CANCELLED, STATUS_REJECTED])
########################################################################
class ArbitrageAlgo(AlgoTemplate):
"""Arbitrage算法用于套利"""
templateName = u'Arbitrage 套利'
#----------------------------------------------------------------------
def __init__(self, engine, setting, algoName):
"""Constructor"""
super(ArbitrageAlgo, self).__init__(engine, setting, algoName)
# 配置参数
self.activeVtSymbol = str(setting['activeVtSymbol']) # 主动腿
self.passiveVtSymbol = str(setting['passiveVtSymbol']) # 被动腿
self.spread = float(setting['spread']) # 价差
self.volume = float(setting['volume']) # 数量
self.interval = int(setting['interval']) # 间隔
self.activeOrderID = '' # 主动委托号
self.passiveOrderID = '' # 被动委托号
self.netPos = 0 # 净持仓
self.count = 0 # 运行计数
# 初始化
self.subscribe(self.activeVtSymbol)
self.subscribe(self.passiveVtSymbol)
self.paramEvent()
self.varEvent()
#----------------------------------------------------------------------
def onTick(self, tick):
""""""
pass
#----------------------------------------------------------------------
def onTrade(self, trade):
""""""
# 更新净持仓数量
if trade.direction == DIRECTION_LONG:
self.netPos += trade.volume
else:
self.netPos -= trade.volume
# 如果是主动腿成交则需要执行对冲
if trade.vtSymbol == self.activeVtSymbol:
self.hedge()
self.varEvent()
#----------------------------------------------------------------------
def onOrder(self, order):
""""""
if order.vtSymbol == self.activeVtSymbol:
if order.status in STATUS_FINISHED:
self.activeOrderID = ''
elif order.vtSymbol == self.passiveVtSymbol:
if order.status in STATUS_FINISHED:
self.passiveOrderID = ''
self.varEvent()
#----------------------------------------------------------------------
def onTimer(self):
""""""
self.count += 1
if self.count < self.interval:
return
self.count = 0
# 撤单
if self.activeOrderID or self.passiveOrderID:
self.cancelAll()
return
# 如果有净仓位则执行对冲
if self.netPos:
self.hedge()
return
# 计算价差的bid/ask
activeTick = self.getTick(self.activeVtSymbol)
passiveTick = self.getTick(self.passiveVtSymbol)
spreadBidPrice = activeTick.bidPrice1 - passiveTick.askPrice1
spreadAskPrice = activeTick.askPrice1 - passiveTick.bidPrice1
spreadBidVolume = min(activeTick.bidVolume1, passiveTick.askVolume1)
spreadAskVolume = min(activeTick.askVolume1, passiveTick.bidVolume1)
if spreadBidPrice > self.spread:
self.activeOrderID = self.sell(self.activeVtSymbol, activeTick.bidPrice1, spreadBidVolume)
elif spreadAskPrice < - self.spread:
self.activeOrderID = self.buy(self.activeVtSymbol, activeTick.askPrice1, spreadAskVolume)
# 更新界面
self.varEvent()
#----------------------------------------------------------------------
def onStop(self):
""""""
self.writeLog(u'算法停止')
self.varEvent()
#----------------------------------------------------------------------
def varEvent(self):
"""更新变量"""
d = OrderedDict()
d[u'算法状态'] = self.active
d[u'运行计数'] = self.count
d[u'净持仓'] = self.netPos
d[u'主动腿委托号'] = self.activeOrderID
d[u'被动腿委托号'] = self.passiveOrderID
self.putVarEvent(d)
#----------------------------------------------------------------------
def paramEvent(self):
"""更新参数"""
d = OrderedDict()
d[u'主动腿代码'] = self.activeVtSymbol
d[u'被动腿代码'] = self.passiveVtSymbol
d[u'价差'] = self.spread
d[u'数量'] = self.volume
d[u'间隔'] = self.interval
self.putParamEvent(d)
#----------------------------------------------------------------------
def hedge(self):
""""""
tick = self.getTick(self.passiveVtSymbol)
volume = abs(self.netPos)
if self.netPos > 0:
self.passiveOrderID = self.sell(self.passiveVtSymbol,
tick.bidPrice5,
volume)
elif self.netPos < 0:
self.passiveOrderID = self.buy(self.activeVtSymbol,
tick.askPrice5,
volume)
########################################################################
class ArbitrageWidget(AlgoWidget):
""""""
#----------------------------------------------------------------------
def __init__(self, algoEngine, parent=None):
"""Constructor"""
super(ArbitrageWidget, self).__init__(algoEngine, parent)
self.templateName = ArbitrageAlgo.templateName
#----------------------------------------------------------------------
def initAlgoLayout(self):
""""""
self.lineActiveVtSymbol = QtWidgets.QLineEdit()
self.linePassiveVtSymbol = QtWidgets.QLineEdit()
validator = QtGui.QDoubleValidator()
validator.setBottom(0)
self.lineSpread = QtWidgets.QLineEdit()
self.lineSpread.setValidator(validator)
self.lineVolume = QtWidgets.QLineEdit()
self.lineVolume.setValidator(validator)
intValidator = QtGui.QIntValidator()
intValidator.setBottom(10)
self.lineInterval = QtWidgets.QLineEdit()
self.lineInterval.setValidator(intValidator)
Label = QtWidgets.QLabel
grid = QtWidgets.QGridLayout()
grid.addWidget(Label(u'主动腿代码'), 0, 0)
grid.addWidget(self.lineActiveVtSymbol, 0, 1)
grid.addWidget(Label(u'被动腿代码'), 1, 0)
grid.addWidget(self.linePassiveVtSymbol, 1, 1)
grid.addWidget(Label(u'套利价差'), 2, 0)
grid.addWidget(self.lineSpread, 2, 1)
grid.addWidget(Label(u'委托数量'), 3, 0)
grid.addWidget(self.lineVolume, 3, 1)
grid.addWidget(Label(u'运行间隔'), 4, 0)
grid.addWidget(self.lineInterval, 4, 1)
return grid
#----------------------------------------------------------------------
def getAlgoSetting(self):
""""""
setting = OrderedDict()
setting['templateName'] = self.templateName
setting['activeVtSymbol'] = str(self.lineActiveVtSymbol.text())
setting['passiveVtSymbol'] = str(self.linePassiveVtSymbol.text())
setting['spread'] = float(self.lineSpread.text())
setting['volume'] = float(self.lineVolume.text())
setting['interval'] = int(self.lineInterval.text())
return setting

View File

@ -188,7 +188,7 @@ class BlWidget(AlgoWidget):
def getAlgoSetting(self): def getAlgoSetting(self):
"""""" """"""
setting = OrderedDict() setting = OrderedDict()
setting['templateName'] = StopAlgo.templateName setting['templateName'] = self.templateName
setting['vtSymbol'] = str(self.lineVtSymbol.text()) setting['vtSymbol'] = str(self.lineVtSymbol.text())
setting['direction'] = text_type(self.comboDirection.currentText()) setting['direction'] = text_type(self.comboDirection.currentText())
setting['offset'] = text_type(self.comboOffset.currentText()) setting['offset'] = text_type(self.comboOffset.currentText())

View File

@ -34,7 +34,7 @@ class IcebergAlgo(AlgoTemplate):
self.price = float(setting['price']) # 价格 self.price = float(setting['price']) # 价格
self.volume = float(setting['volume']) # 数量 self.volume = float(setting['volume']) # 数量
self.display = float(setting['display']) # 挂出数量 self.display = float(setting['display']) # 挂出数量
self.interval = text_type(setting['interval']) # 间隔 self.interval = int(setting['interval']) # 间隔
self.offset = text_type(setting['offset']) # 开平 self.offset = text_type(setting['offset']) # 开平
self.count = 0 # 执行计数 self.count = 0 # 执行计数
@ -73,12 +73,18 @@ class IcebergAlgo(AlgoTemplate):
def onTimer(self): def onTimer(self):
"""""" """"""
self.count += 1 self.count += 1
if self.count < self.interval: if self.count < self.interval:
self.varEvent() self.varEvent()
return return
self.count = 0 self.count = 0
contract = self.getContract(self.vtSymbol)
if not contract:
self.writeLog(u'找不到合约%s' %self.vtSymbol)
return
if not self.vtOrderID: if not self.vtOrderID:
orderVolume = self.volume - self.tradedVolume orderVolume = self.volume - self.tradedVolume
orderVolume = min(orderVolume, self.display) orderVolume = min(orderVolume, self.display)
@ -193,7 +199,7 @@ class IcebergWidget(AlgoWidget):
def getAlgoSetting(self): def getAlgoSetting(self):
"""""" """"""
setting = OrderedDict() setting = OrderedDict()
setting['templateName'] = StopAlgo.templateName setting['templateName'] = self.templateName
setting['vtSymbol'] = str(self.lineVtSymbol.text()) setting['vtSymbol'] = str(self.lineVtSymbol.text())
setting['direction'] = text_type(self.comboDirection.currentText()) setting['direction'] = text_type(self.comboDirection.currentText())
setting['offset'] = text_type(self.comboOffset.currentText()) setting['offset'] = text_type(self.comboOffset.currentText())

View File

@ -178,7 +178,7 @@ class SniperWidget(AlgoWidget):
def getAlgoSetting(self): def getAlgoSetting(self):
"""""" """"""
setting = OrderedDict() setting = OrderedDict()
setting['templateName'] = StopAlgo.templateName setting['templateName'] = self.templateName
setting['vtSymbol'] = str(self.lineVtSymbol.text()) setting['vtSymbol'] = str(self.lineVtSymbol.text())
setting['direction'] = text_type(self.comboDirection.currentText()) setting['direction'] = text_type(self.comboDirection.currentText())
setting['offset'] = text_type(self.comboOffset.currentText()) setting['offset'] = text_type(self.comboOffset.currentText())

View File

@ -3,6 +3,7 @@
import json import json
import traceback import traceback
import shelve import shelve
from collections import OrderedDict
from vnpy.event import Event from vnpy.event import Event
from vnpy.trader.vtFunction import getJsonPath, getTempPath from vnpy.trader.vtFunction import getJsonPath, getTempPath
@ -289,8 +290,8 @@ class StAlgoEngine(object):
self.mainEngine = mainEngine self.mainEngine = mainEngine
self.eventEngine = eventEngine self.eventEngine = eventEngine
self.algoDict = {} # spreadName:algo self.algoDict = OrderedDict() # spreadName:algo
self.vtSymbolAlgoDict = {} # vtSymbol:algo self.vtSymbolAlgoDict = {} # vtSymbol:algo
self.registerEvent() self.registerEvent()

View File

@ -415,6 +415,7 @@ class StActiveButton(QtWidgets.QPushButton):
######################################################################## ########################################################################
class StAlgoManager(QtWidgets.QTableWidget): class StAlgoManager(QtWidgets.QTableWidget):
"""价差算法管理组件""" """价差算法管理组件"""
signalPos = QtCore.pyqtSignal(type(Event()))
#---------------------------------------------------------------------- #----------------------------------------------------------------------
def __init__(self, stEngine, parent=None): def __init__(self, stEngine, parent=None):
@ -422,16 +423,20 @@ class StAlgoManager(QtWidgets.QTableWidget):
super(StAlgoManager, self).__init__(parent) super(StAlgoManager, self).__init__(parent)
self.algoEngine = stEngine.algoEngine self.algoEngine = stEngine.algoEngine
self.eventEngine = stEngine.eventEngine
self.buttonActiveDict = {} # spreadName: buttonActive self.buttonActiveDict = {} # spreadName: buttonActive
self.posCellDict = {} # spreadName: cell
self.initUi() self.initUi()
self.registerEvent()
#---------------------------------------------------------------------- #----------------------------------------------------------------------
def initUi(self): def initUi(self):
"""初始化表格""" """初始化表格"""
headers = [u'价差', headers = [u'价差',
u'算法', u'算法',
u'净持仓'
'BuyPrice', 'BuyPrice',
'SellPrice', 'SellPrice',
'CoverPrice', 'CoverPrice',
@ -462,6 +467,7 @@ class StAlgoManager(QtWidgets.QTableWidget):
for row, d in enumerate(l): for row, d in enumerate(l):
cellSpreadName = QtWidgets.QTableWidgetItem(d['spreadName']) cellSpreadName = QtWidgets.QTableWidgetItem(d['spreadName'])
cellAlgoName = QtWidgets.QTableWidgetItem(d['algoName']) cellAlgoName = QtWidgets.QTableWidgetItem(d['algoName'])
cellNetPos = QtWidgets.QTableWidgetItem('0')
spinBuyPrice = StBuyPriceSpinBox(algoEngine, d['spreadName'], d['buyPrice']) spinBuyPrice = StBuyPriceSpinBox(algoEngine, d['spreadName'], d['buyPrice'])
spinSellPrice = StSellPriceSpinBox(algoEngine, d['spreadName'], d['sellPrice']) spinSellPrice = StSellPriceSpinBox(algoEngine, d['spreadName'], d['sellPrice'])
spinShortPrice = StShortPriceSpinBox(algoEngine, d['spreadName'], d['shortPrice']) spinShortPrice = StShortPriceSpinBox(algoEngine, d['spreadName'], d['shortPrice'])
@ -473,14 +479,15 @@ class StAlgoManager(QtWidgets.QTableWidget):
self.setItem(row, 0, cellSpreadName) self.setItem(row, 0, cellSpreadName)
self.setItem(row, 1, cellAlgoName) self.setItem(row, 1, cellAlgoName)
self.setCellWidget(row, 2, spinBuyPrice) self.setItem(row, 2, cellNetPos)
self.setCellWidget(row, 3, spinSellPrice) self.setCellWidget(row, 3, spinBuyPrice)
self.setCellWidget(row, 4, spinCoverPrice) self.setCellWidget(row, 4, spinSellPrice)
self.setCellWidget(row, 5, spinShortPrice) self.setCellWidget(row, 5, spinCoverPrice)
self.setCellWidget(row, 6, spinMaxOrderSize) self.setCellWidget(row, 6, spinShortPrice)
self.setCellWidget(row, 7, spinMaxPosSize) self.setCellWidget(row, 7, spinMaxOrderSize)
self.setCellWidget(row, 8, comboMode) self.setCellWidget(row, 8, spinMaxPosSize)
self.setCellWidget(row, 9, buttonActive) self.setCellWidget(row, 9, comboMode)
self.setCellWidget(row, 10, buttonActive)
buttonActive.signalActive.connect(spinBuyPrice.algoActiveChanged) buttonActive.signalActive.connect(spinBuyPrice.algoActiveChanged)
buttonActive.signalActive.connect(spinSellPrice.algoActiveChanged) buttonActive.signalActive.connect(spinSellPrice.algoActiveChanged)
@ -491,12 +498,28 @@ class StAlgoManager(QtWidgets.QTableWidget):
buttonActive.signalActive.connect(comboMode.algoActiveChanged) buttonActive.signalActive.connect(comboMode.algoActiveChanged)
self.buttonActiveDict[d['spreadName']] = buttonActive self.buttonActiveDict[d['spreadName']] = buttonActive
self.posCellDict[d['spreadName']] = cellNetPos
#---------------------------------------------------------------------- #----------------------------------------------------------------------
def stopAll(self): def stopAll(self):
"""停止所有算法""" """停止所有算法"""
for button in self.buttonActiveDict.values(): for button in self.buttonActiveDict.values():
button.stop() button.stop()
#----------------------------------------------------------------------
def processStPosEvent(self, event):
""""""
pos = event.dict_['data']
cell = self.posCellDict[pos.name]
cell.setText(str(pos.netPos))
#----------------------------------------------------------------------
def registerEvent(self):
""""""
self.signalPos.connect(self.processStPosEvent)
self.eventEngine.register(EVENT_SPREADTRADING_POS, self.signalPos.emit)
######################################################################## ########################################################################

View File

@ -87,9 +87,6 @@ class BitmexGateway(VtGateway):
self.restApi.connect(apiKey, apiSecret, sessionCount) self.restApi.connect(apiKey, apiSecret, sessionCount)
self.wsApi.connect(apiKey, apiSecret, symbols) self.wsApi.connect(apiKey, apiSecret, symbols)
# 初始化并启动查询
#self.initQuery()
#---------------------------------------------------------------------- #----------------------------------------------------------------------
def subscribe(self, subscribeReq): def subscribe(self, subscribeReq):
"""订阅行情""" """订阅行情"""

View File

@ -488,7 +488,11 @@ class CcxtApi(object):
tick.lowPrice = float(data['low']) tick.lowPrice = float(data['low'])
tick.lastPrice = float(data['close']) tick.lastPrice = float(data['close'])
tick.volume = float(data['quoteVolume']) tick.volume = float(data['quoteVolume'])
tick.datetime = datetime.fromtimestamp(data['timestamp']/1000)
if data['timestamp']:
tick.datetime = datetime.fromtimestamp(data['timestamp']/1000)
else:
tick.datetime = datetime.now()
tick.date = tick.datetime.strftime('%Y%m%d') tick.date = tick.datetime.strftime('%Y%m%d')
tick.time = tick.datetime.strftime('%H:%M:%S') tick.time = tick.datetime.strftime('%H:%M:%S')
@ -509,8 +513,11 @@ class CcxtApi(object):
for n, ask in enumerate(data['asks'][:5]): for n, ask in enumerate(data['asks'][:5]):
tick.__setattr__('askPrice%s' %(n+1), float(ask[0])) tick.__setattr__('askPrice%s' %(n+1), float(ask[0]))
tick.__setattr__('askVolume%s' %(n+1), float(ask[1])) tick.__setattr__('askVolume%s' %(n+1), float(ask[1]))
tick.datetime = datetime.fromtimestamp(data['timestamp']/1000) if data['timestamp']:
tick.datetime = datetime.fromtimestamp(data['timestamp']/1000)
else:
tick.datetime = datetime.now()
tick.date = tick.datetime.strftime('%Y%m%d') tick.date = tick.datetime.strftime('%Y%m%d')
tick.time = tick.datetime.strftime('%H:%M:%S') tick.time = tick.datetime.strftime('%H:%M:%S')

View File

@ -526,7 +526,8 @@ class WebsocketApi(FcoinWebsocketApi):
tick.lastPrice = ticker[0] tick.lastPrice = ticker[0]
tick.volume = ticker[9] tick.volume = ticker[9]
self.gateway.onTick(copy(tick)) if tick.askPrice1:
self.gateway.onTick(copy(tick))
#---------------------------------------------------------------------- #----------------------------------------------------------------------
def onDepth(self, d): def onDepth(self, d):
@ -565,7 +566,8 @@ class WebsocketApi(FcoinWebsocketApi):
tick.date = tick.datetime.strftime('%Y%m%d') tick.date = tick.datetime.strftime('%Y%m%d')
tick.time = tick.datetime.strftime('%H:%M:%S') tick.time = tick.datetime.strftime('%H:%M:%S')
self.gateway.onTick(copy(tick)) if tick.lastPrice:
self.gateway.onTick(copy(tick))
#---------------------------------------------------------------------- #----------------------------------------------------------------------