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)
cellGatewayName = BasicCell(error.gatewayName)
self.setItem(0, 0, cellLogTime)
self.setItem(0, 1, cellLogContent)
self.setItem(0, 2, cellGatewayName)
self.setItem(0, 0, cellGatewayName)
self.setItem(0, 1, cellLogTime)
self.setItem(0, 2, cellLogContent)
########################################################################
class TradeMonitor(BasicMonitor):

View File

@ -199,18 +199,14 @@ class CoinbaseWebsocketApi(object):
def run(self):
"""运行"""
while self.active:
stream = self.ws.recv()
data = json.loads(stream)
self.onData(data)
#try:
#stream = self.ws.recv()
#data = json.loads(stream)
#self.onData(data)
#except:
#msg = traceback.format_exc()
#self.onError(msg)
#self.reconnect()
try:
stream = self.ws.recv()
data = json.loads(stream)
self.onData(data)
except:
msg = traceback.format_exc()
self.onError(msg)
self.reconnect()
#----------------------------------------------------------------------
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):
""""""
setting = OrderedDict()
setting['templateName'] = StopAlgo.templateName
setting['templateName'] = self.templateName
setting['vtSymbol'] = str(self.lineVtSymbol.text())
setting['direction'] = text_type(self.comboDirection.currentText())
setting['offset'] = text_type(self.comboOffset.currentText())

View File

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

View File

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

View File

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

View File

@ -415,6 +415,7 @@ class StActiveButton(QtWidgets.QPushButton):
########################################################################
class StAlgoManager(QtWidgets.QTableWidget):
"""价差算法管理组件"""
signalPos = QtCore.pyqtSignal(type(Event()))
#----------------------------------------------------------------------
def __init__(self, stEngine, parent=None):
@ -422,16 +423,20 @@ class StAlgoManager(QtWidgets.QTableWidget):
super(StAlgoManager, self).__init__(parent)
self.algoEngine = stEngine.algoEngine
self.eventEngine = stEngine.eventEngine
self.buttonActiveDict = {} # spreadName: buttonActive
self.posCellDict = {} # spreadName: cell
self.initUi()
self.registerEvent()
#----------------------------------------------------------------------
def initUi(self):
"""初始化表格"""
headers = [u'价差',
u'算法',
u'净持仓'
'BuyPrice',
'SellPrice',
'CoverPrice',
@ -462,6 +467,7 @@ class StAlgoManager(QtWidgets.QTableWidget):
for row, d in enumerate(l):
cellSpreadName = QtWidgets.QTableWidgetItem(d['spreadName'])
cellAlgoName = QtWidgets.QTableWidgetItem(d['algoName'])
cellNetPos = QtWidgets.QTableWidgetItem('0')
spinBuyPrice = StBuyPriceSpinBox(algoEngine, d['spreadName'], d['buyPrice'])
spinSellPrice = StSellPriceSpinBox(algoEngine, d['spreadName'], d['sellPrice'])
spinShortPrice = StShortPriceSpinBox(algoEngine, d['spreadName'], d['shortPrice'])
@ -473,14 +479,15 @@ class StAlgoManager(QtWidgets.QTableWidget):
self.setItem(row, 0, cellSpreadName)
self.setItem(row, 1, cellAlgoName)
self.setCellWidget(row, 2, spinBuyPrice)
self.setCellWidget(row, 3, spinSellPrice)
self.setCellWidget(row, 4, spinCoverPrice)
self.setCellWidget(row, 5, spinShortPrice)
self.setCellWidget(row, 6, spinMaxOrderSize)
self.setCellWidget(row, 7, spinMaxPosSize)
self.setCellWidget(row, 8, comboMode)
self.setCellWidget(row, 9, buttonActive)
self.setItem(row, 2, cellNetPos)
self.setCellWidget(row, 3, spinBuyPrice)
self.setCellWidget(row, 4, spinSellPrice)
self.setCellWidget(row, 5, spinCoverPrice)
self.setCellWidget(row, 6, spinShortPrice)
self.setCellWidget(row, 7, spinMaxOrderSize)
self.setCellWidget(row, 8, spinMaxPosSize)
self.setCellWidget(row, 9, comboMode)
self.setCellWidget(row, 10, buttonActive)
buttonActive.signalActive.connect(spinBuyPrice.algoActiveChanged)
buttonActive.signalActive.connect(spinSellPrice.algoActiveChanged)
@ -491,12 +498,28 @@ class StAlgoManager(QtWidgets.QTableWidget):
buttonActive.signalActive.connect(comboMode.algoActiveChanged)
self.buttonActiveDict[d['spreadName']] = buttonActive
self.posCellDict[d['spreadName']] = cellNetPos
#----------------------------------------------------------------------
def stopAll(self):
"""停止所有算法"""
for button in self.buttonActiveDict.values():
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.wsApi.connect(apiKey, apiSecret, symbols)
# 初始化并启动查询
#self.initQuery()
#----------------------------------------------------------------------
def subscribe(self, subscribeReq):
"""订阅行情"""

View File

@ -488,7 +488,11 @@ class CcxtApi(object):
tick.lowPrice = float(data['low'])
tick.lastPrice = float(data['close'])
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.time = tick.datetime.strftime('%H:%M:%S')
@ -509,8 +513,11 @@ class CcxtApi(object):
for n, ask in enumerate(data['asks'][:5]):
tick.__setattr__('askPrice%s' %(n+1), float(ask[0]))
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.time = tick.datetime.strftime('%H:%M:%S')

View File

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