From 8b1bc4e2eabb075f07be02e957048457c80ffe97 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Tue, 5 Jun 2018 21:23:56 +0800 Subject: [PATCH] =?UTF-8?q?[Add]=E6=96=B0=E5=A2=9EAlgoTrading=E7=AE=97?= =?UTF-8?q?=E6=B3=95=E4=BA=A4=E6=98=93=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/algoTrading/__init__.py | 12 + vnpy/trader/app/algoTrading/algoEngine.py | 221 +++++++++++++++++ vnpy/trader/app/algoTrading/algoTemplate.py | 168 +++++++++++++ vnpy/trader/app/algoTrading/twapAlgo.py | 232 ++++++++++++++++++ vnpy/trader/app/algoTrading/uiAlgoManager.py | 243 +++++++++++++++++++ 5 files changed, 876 insertions(+) create mode 100644 vnpy/trader/app/algoTrading/__init__.py create mode 100644 vnpy/trader/app/algoTrading/algoEngine.py create mode 100644 vnpy/trader/app/algoTrading/algoTemplate.py create mode 100644 vnpy/trader/app/algoTrading/twapAlgo.py create mode 100644 vnpy/trader/app/algoTrading/uiAlgoManager.py diff --git a/vnpy/trader/app/algoTrading/__init__.py b/vnpy/trader/app/algoTrading/__init__.py new file mode 100644 index 00000000..5d8bab7c --- /dev/null +++ b/vnpy/trader/app/algoTrading/__init__.py @@ -0,0 +1,12 @@ +# encoding: UTF-8 + +import os + +from .algoEngine import AlgoEngine +from .uiAlgoManager import AlgoManager + +appName = 'AlgoTrading' +appDisplayName = u'算法交易' +appEngine = AlgoEngine +appWidget = AlgoManager +appIco = 'ct.ico' diff --git a/vnpy/trader/app/algoTrading/algoEngine.py b/vnpy/trader/app/algoTrading/algoEngine.py new file mode 100644 index 00000000..e6ac3617 --- /dev/null +++ b/vnpy/trader/app/algoTrading/algoEngine.py @@ -0,0 +1,221 @@ +# encoding: UTF-8 + +''' +''' + +from __future__ import division + +from vnpy.event import Event +from vnpy.trader.vtEvent import EVENT_TIMER, EVENT_TICK, EVENT_ORDER, EVENT_TRADE +from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT, PRICETYPE_LIMITPRICE, + OFFSET_OPEN, OFFSET_CLOSE, + OFFSET_CLOSETODAY, OFFSET_CLOSEYESTERDAY) +from vnpy.trader.vtObject import VtSubscribeReq, VtOrderReq, VtCancelOrderReq, VtLogData + +from .twapAlgo import TwapAlgo + + +EVENT_ALGO_LOG = 'eAlgoLog' # 算法日志事件 +EVENT_ALGO_PARAM = 'eAlgoParam' # 算法参数事件 +EVENT_ALGO_VAR = 'eAlgoVar' # 算法变量事件 + + +ALGO_DICT = { + TwapAlgo.name: TwapAlgo +} + + + +######################################################################## +class AlgoEngine(object): + """算法交易引擎""" + + #---------------------------------------------------------------------- + def __init__(self, mainEngine, eventEngine): + """""" + self.mainEngine = mainEngine + self.eventEngine = eventEngine + + self.algoDict = {} # algoName:algo + self.orderAlgoDict = {} # vtOrderID:algo + self.symbolAlgoDict = {} # vtSymbol:algo set + + self.registerEvent() + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.eventEngine.register(EVENT_TICK, self.processTickEvent) + self.eventEngine.register(EVENT_TIMER, self.processTimerEvent) + self.eventEngine.register(EVENT_ORDER, self.processOrderEvent) + self.eventEngine.register(EVENT_TRADE, self.processTradeEvent) + + #---------------------------------------------------------------------- + def stop(self): + """停止""" + pass + + #---------------------------------------------------------------------- + def processTickEvent(self, event): + """行情事件""" + tick = event.dict_['data'] + + l = self.symbolAlgoDict.get(tick.vtSymbol, None) + if l: + for algo in l: + algo.updateTick(tick) + + #---------------------------------------------------------------------- + def processOrderEvent(self, event): + """委托事件""" + order = event.dict_['data'] + + algo = self.orderAlgoDict.get(order.vtOrderID, None) + if algo: + algo.updateOrder(order) + + #---------------------------------------------------------------------- + def processTradeEvent(self, event): + """成交事件""" + trade = event.dict_['data'] + + algo = self.orderAlgoDict.get(trade.vtOrderID, None) + if algo: + algo.updateTrade(trade) + + #---------------------------------------------------------------------- + def processTimerEvent(self, event): + """定时事件""" + for algo in self.algoDict.values(): + algo.updateTimer() + + #---------------------------------------------------------------------- + def addAlgo(self, name, algoSetting): + """新增算法""" + algoClass = ALGO_DICT[name] + algo = algoClass.new(self, algoSetting) + self.algoDict[algo.algoName] = algo + return algo.algoName + + #---------------------------------------------------------------------- + def stopAlgo(self, algoName): + """停止算法""" + self.algoDict[algoName].stop() + del self.algoDict[algoName] + + #---------------------------------------------------------------------- + def stopAll(self): + """全部停止""" + l = self.algoDict.keys() + for algoName in l: + self.stopAlgo(algoName) + + #---------------------------------------------------------------------- + def subscribe(self, algo, vtSymbol): + """""" + contract = self.mainEngine.getContract(vtSymbol) + if not contract: + self.writeLog(u'%s订阅行情失败,找不到合约%s' %(algo.algoName, vtSymbol)) + return + + # 如果vtSymbol已存在于字典,说明已经订阅过 + if vtSymbol in self.symbolAlgoDict: + s = self.symbolAlgoDict[vtSymbol] + s.add(algo) + return + # 否则需要添加到字典中并执行订阅 + else: + s = set() + self.symbolAlgoDict[vtSymbol] = s + s.add(algo) + + req = VtSubscribeReq() + req.symbol = contract.symbol + req.exchange = contract.exchange + self.mainEngine.subscribe(req, contract.gatewayName) + + #---------------------------------------------------------------------- + def sendOrder(self, algo, vtSymbol, direction, price, volume): + """发单""" + contract = self.mainEngine.getContract(vtSymbol) + if not contract: + self.writeLog(u'%s委托下单失败,找不到合约:%s' %(algo.algoName, vtSymbol)) + + req = VtOrderReq() + req.vtSymbol = vtSymbol + req.symbol = contract.symbol + req.exchange = contract.exchange + req.direction = direction + req.priceType = PRICETYPE_LIMITPRICE + req.offset = OFFSET_CLOSETODAY + req.price = price + req.volume = volume + vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) + + return vtOrderID + + #---------------------------------------------------------------------- + def buy(self, algo, vtSymbol, price, volume): + """买入""" + return self.sendOrder(algo, vtSymbol, DIRECTION_LONG, price, volume) + + #---------------------------------------------------------------------- + def sell(self, algo, vtSymbol, price, volume): + """卖出""" + return self.sendOrder(algo, vtSymbol, DIRECTION_SHORT, price, volume) + + #---------------------------------------------------------------------- + def cancelOrder(self, algo, vtOrderID): + """撤单""" + order = self.mainEngine.getOrder(vtOrderID) + if not order: + self.writeLog(u'%s委托撤单失败,找不到委托:%s' %(algo.algoName, vtOrderID)) + return + + req = VtCancelOrderReq() + req.symbol = order.symbol + req.exchange = order.exchange + req.orderID = order.orderID + req.frontID = order.frontID + req.sessionID = order.sessionID + self.mainEngine.cancelOrder(req, order.gatewayName) + + #---------------------------------------------------------------------- + def writeLog(self, content, algo=None): + """输出日志""" + log = VtLogData() + log.logContent = content + + if algo: + log.gatewayName = algo.algoName + + event = Event(EVENT_ALGO_LOG) + event.dict_['data'] = log + self.eventEngine.put(event) + + #---------------------------------------------------------------------- + def putVarEvent(self, algo, d): + """更新变量""" + d['algoName'] = algo.algoName + event = Event(EVENT_ALGO_VAR) + event.dict_['data'] = d + self.eventEngine.put(event) + + #---------------------------------------------------------------------- + def putParamEvent(self, algo, d): + """更新参数""" + d['algoName'] = algo.algoName + event = Event(EVENT_ALGO_PARAM) + event.dict_['data'] = d + self.eventEngine.put(event) + + #---------------------------------------------------------------------- + def getTick(self, algo, vtSymbol): + """查询行情""" + tick = self.mainEngine.getTick(vtSymbol) + if not tick: + self.writeLog(u'%s查询行情失败,找不到报价:%s' %(algo.algoName, vtSymbol)) + return + + return tick + diff --git a/vnpy/trader/app/algoTrading/algoTemplate.py b/vnpy/trader/app/algoTrading/algoTemplate.py new file mode 100644 index 00000000..9866669f --- /dev/null +++ b/vnpy/trader/app/algoTrading/algoTemplate.py @@ -0,0 +1,168 @@ +# encoding: UTF-8 + +from __future__ import division + +from vnpy.trader.vtConstant import STATUS_NOTTRADED, STATUS_PARTTRADED, STATUS_UNKNOWN + + +# 活动委托状态 +STATUS_ACTIVE = [STATUS_NOTTRADED, STATUS_PARTTRADED, STATUS_UNKNOWN] + + +######################################################################## +class AlgoTemplate(object): + """算法模板""" + name = 'AlgoTemplate' + count = 0 + + @classmethod + #---------------------------------------------------------------------- + def new(cls, engine, setting): + """创建新对象""" + cls.count += 1 + algoName = '%s_%s' %(cls.name, cls.count) + + algo = cls(engine, setting, algoName) + return algo + + #---------------------------------------------------------------------- + def __init__(self, engine, setting, algoName): + """Constructor""" + self.engine = engine + self.active = True + self.algoName = algoName + self.activeOrderDict = {} # vtOrderID:order + + #---------------------------------------------------------------------- + def updateTick(self, tick): + """""" + if not self.active: + return + + self.onTick(tick) + + #---------------------------------------------------------------------- + def updateTrade(self, trade): + """""" + if not self.active: + return + + self.onTrade(trade) + + #---------------------------------------------------------------------- + def updateOrder(self, order): + """""" + if not self.active: + return + + # 活动委托需要缓存 + if order.status in STATUS_ACTIVE: + self.activeOrderDict[order.vtOrderID] = order + # 结束委托需要移除 + elif order.vtOrderID in self.activeOrderDict: + del self.activeOrderDict[order.vtOrderID] + + self.onOrder(order) + + #---------------------------------------------------------------------- + def updateTimer(self): + """""" + if not self.active: + return + + self.onTimer() + + #---------------------------------------------------------------------- + def stop(self): + """""" + self.active = False + self.cancelAll() + + self.onStop() + + #---------------------------------------------------------------------- + def onTick(self, tick): + """""" + pass + + #---------------------------------------------------------------------- + def onTrade(self, trade): + """""" + pass + + #---------------------------------------------------------------------- + def onOrder(self, order): + """""" + pass + + #---------------------------------------------------------------------- + def onTimer(self): + """""" + pass + + #---------------------------------------------------------------------- + def onStop(self): + """""" + pass + + #---------------------------------------------------------------------- + def subscribe(self, vtSymbol): + """""" + self.engine.subscribe(self, vtSymbol) + + #---------------------------------------------------------------------- + def buy(self, vtSymbol, price, volume): + """""" + return self.engine.buy(self, vtSymbol, price, volume) + + #---------------------------------------------------------------------- + def sell(self, vtSymbol, price, volume): + """""" + return self.engine.sell(self, vtSymbol, price, volume) + + #---------------------------------------------------------------------- + def cancelOrder(self, vtOrderID): + """""" + self.engine.cancelOrder(self, vtOrderID) + + #---------------------------------------------------------------------- + def cancelAll(self): + """""" + if not self.activeOrderDict: + return False + + for order in self.activeOrderDict.values(): + self.cancelOrder(order.vtOrderID) + return True + + #---------------------------------------------------------------------- + def getTick(self, vtSymbol): + """""" + return self.engine.getTick(self, vtSymbol) + + #---------------------------------------------------------------------- + def roundValue(self, value, change): + """标准化价格或者数量""" + if not change: + return value + + n = value / change + v = round(n, 0) * change + return v + + #---------------------------------------------------------------------- + def putVarEvent(self, d): + """更新变量""" + self.engine.putVarEvent(self, d) + + #---------------------------------------------------------------------- + def putParamEvent(self, d): + """更新参数""" + self.engine.putParamEvent(self, d) + + #---------------------------------------------------------------------- + def writeLog(self, content): + """输出日志""" + self.engine.writeLog(content, self) + + \ No newline at end of file diff --git a/vnpy/trader/app/algoTrading/twapAlgo.py b/vnpy/trader/app/algoTrading/twapAlgo.py new file mode 100644 index 00000000..f7723ddc --- /dev/null +++ b/vnpy/trader/app/algoTrading/twapAlgo.py @@ -0,0 +1,232 @@ +# encoding: UTF-8 + +from __future__ import division +from collections import OrderedDict + +from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT) +from vnpy.trader.uiQt import QtWidgets + +from algoTemplate import AlgoTemplate + + +######################################################################## +class TwapAlgo(AlgoTemplate): + """TWAP算法""" + + name = 'TWAP' + + #---------------------------------------------------------------------- + def __init__(self, engine, setting, algoName): + """Constructor""" + super(TwapAlgo, self).__init__(engine, setting, algoName) + + # 参数 + self.vtSymbol = setting['vtSymbol'] # 合约代码 + self.direction = setting['direction'] # 买卖 + self.price = setting['price'] # 目标价格 + self.totalVolume = setting['volume'] # 总数量 + self.time = setting['time'] # 执行时间 + self.interval = setting['interval'] # 执行间隔 + self.minVolume = setting['minVolume'] # 最小委托数量 + + # 变量 + self.orderSize = self.totalVolume / (self.time / self.interval) + self.orderSize = self.roundValue(self.orderSize, self.minVolume) + if self.minVolume >= 1: + self.orderSize = int(self.orderSize) + + self.timerCount = 0 + self.timerTotal = 0 + self.tradedVolume = 0 + + self.subscribe(self.vtSymbol) + self.paramEvent() + self.varEvent() + + #---------------------------------------------------------------------- + def onTick(self, tick): + """""" + pass + + #---------------------------------------------------------------------- + def onTrade(self, trade): + """""" + self.tradedVolume += trade.volume + + if self.tradedVolume >= self.totalVolume: + self.stop() + else: + self.varEvent() + + #---------------------------------------------------------------------- + def onOrder(self, order): + """""" + pass + + #---------------------------------------------------------------------- + def onTimer(self): + """""" + self.timerCount += 1 + self.timerTotal += 1 + + # 总时间结束,停止算法 + if self.timerTotal >= self.time: + self.stop() + return + + # 每到间隔发一次委托 + if self.timerCount >= self.interval: + self.timerCount = 0 + + tick = self.getTick(self.vtSymbol) + if not tick: + return + + size = min(self.orderSize, self.totalVolume-self.tradedVolume) + + # 买入 + if self.direction == DIRECTION_LONG: + # 市场买1价小于目标买价 + if tick.bidPrice1 < self.price: + self.buy(self.vtSymbol, self.price, size) + self.writeLog(u'委托买入%s,数量%,价格%s' %(self.vtSymbol, self.orderSize, self.price)) + # 卖出 + if self.direction == DIRECTION_SHORT: + # 市场卖1价大于目标价 + if tick.askPrice1 > self.price: + self.sell(self.vtSymbol, self.price, size) + self.writeLog(u'委托卖出%s,数量%s,价格%s' %(self.vtSymbol, self.orderSize, self.price)) + + # 委托后等待到间隔一半的时间撤单 + elif self.timerCount == round(self.interval/2, 0): + result = self.cancelAll() + if result: + self.writeLog(u'撤销之前的委托') + + self.varEvent() + + #---------------------------------------------------------------------- + def onStop(self): + """""" + self.writeLog(u'运行时间已到,停止算法') + self.varEvent() + + #---------------------------------------------------------------------- + def varEvent(self): + """更新变量""" + d = OrderedDict() + d[u'算法状态'] = self.active + d[u'成交数量'] = self.tradedVolume + d[u'单笔委托'] = self.orderSize + d[u'本轮读秒'] = self.timerCount + d[u'累计读秒'] = self.timerTotal + d['active'] = self.active + self.putVarEvent(d) + + #---------------------------------------------------------------------- + def paramEvent(self): + """更新参数""" + d = OrderedDict() + d[u'代码'] = self.vtSymbol + d[u'方向'] = self.direction + d[u'目标价格'] = self.price + d[u'总数量'] = self.totalVolume + d[u'总时间(秒)'] = self.time + d[u'间隔(秒)'] = self.interval + self.putParamEvent(d) + + + +######################################################################## +class TwapWidget(QtWidgets.QWidget): + """""" + name = TwapAlgo.name + + #---------------------------------------------------------------------- + def __init__(self, algoEngine): + """Constructor""" + super(TwapWidget, self).__init__() + + self.algoEngine = algoEngine + + self.initUi() + + #---------------------------------------------------------------------- + def initUi(self): + """""" + self.lineSymbol = QtWidgets.QLineEdit() + + self.comboDirection = QtWidgets.QComboBox() + self.comboDirection.addItem(DIRECTION_LONG) + self.comboDirection.addItem(DIRECTION_SHORT) + self.comboDirection.setCurrentIndex(0) + + self.spinPrice = QtWidgets.QDoubleSpinBox() + self.spinPrice.setMinimum(0) + self.spinPrice.setMaximum(1000000000) + self.spinPrice.setDecimals(8) + + self.spinVolume = QtWidgets.QDoubleSpinBox() + self.spinVolume.setMinimum(0) + self.spinVolume.setMaximum(1000000000) + self.spinVolume.setDecimals(6) + + self.spinTime = QtWidgets.QSpinBox() + self.spinTime.setMinimum(30) + self.spinTime.setMaximum(86400) + + self.spinInterval = QtWidgets.QSpinBox() + self.spinInterval.setMinimum(10) + self.spinInterval.setMaximum(3600) + + self.spinMinVolume = QtWidgets.QDoubleSpinBox() + self.spinMinVolume.setMinimum(0) + self.spinMinVolume.setMaximum(10000) + self.spinMinVolume.setDecimals(6) + self.spinMinVolume.setValue(1) + + buttonStart = QtWidgets.QPushButton(u'启动') + buttonStart.clicked.connect(self.addAlgo) + buttonStart.setMinimumHeight(100) + + Label = QtWidgets.QLabel + + grid = QtWidgets.QGridLayout() + grid.addWidget(Label(u'交易代码'), 0, 0) + grid.addWidget(self.lineSymbol, 0, 1) + grid.addWidget(Label(u'方向'), 1, 0) + grid.addWidget(self.comboDirection, 1, 1) + grid.addWidget(Label(u'目标价格'), 2, 0) + grid.addWidget(self.spinPrice, 2, 1) + grid.addWidget(Label(u'总数量'), 3, 0) + grid.addWidget(self.spinVolume, 3, 1) + grid.addWidget(Label(u'总时间(秒)'), 4, 0) + grid.addWidget(self.spinTime, 4, 1) + grid.addWidget(Label(u'间隔(秒)'), 5, 0) + grid.addWidget(self.spinInterval, 5, 1) + grid.addWidget(Label(u'数量取整'), 6, 0) + grid.addWidget(self.spinMinVolume, 6, 1) + grid.addWidget(buttonStart, 7, 0, 1, 2) + + self.setLayout(grid) + + #---------------------------------------------------------------------- + def addAlgo(self): + """""" + setting = { + 'vtSymbol': str(self.lineSymbol.text()), + 'direction': str(self.comboDirection.currentText()), + 'price': float(self.spinPrice.value()), + 'volume': float(self.spinVolume.value()), + 'time': int(self.spinTime.value()), + 'interval': int(self.spinInterval.value()), + 'minVolume': float(self.spinMinVolume.value()) + } + + self.algoEngine.addAlgo(TwapAlgo.name, setting) + + + + + + \ No newline at end of file diff --git a/vnpy/trader/app/algoTrading/uiAlgoManager.py b/vnpy/trader/app/algoTrading/uiAlgoManager.py new file mode 100644 index 00000000..1c0baea3 --- /dev/null +++ b/vnpy/trader/app/algoTrading/uiAlgoManager.py @@ -0,0 +1,243 @@ +# encoding: UTF-8 + +from vnpy.event import Event +from vnpy.trader.uiQt import QtCore, QtWidgets + +from .algoEngine import EVENT_ALGO_LOG, EVENT_ALGO_PARAM, EVENT_ALGO_VAR +from .twapAlgo import TwapWidget + + +######################################################################## +class StopButton(QtWidgets.QPushButton): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, algoName=''): + """Constructor""" + super(StopButton, self).__init__() + + self.algoEngine = algoEngine + self.algoName = algoName + + self.setStyleSheet("color:black;background-color:yellow") + + if algoName: + self.setText(u'停止') + self.clicked.connect(self.stopAlgo) + else: + self.setText(u'全部停止') + self.clicked.connect(self.stopAll) + + #---------------------------------------------------------------------- + def stopAlgo(self): + """""" + self.algoEngine.stopAlgo(self.algoName) + self.disable() + + #---------------------------------------------------------------------- + def stopAll(self): + """""" + self.algoEngine.stopAll() + + #---------------------------------------------------------------------- + def disable(self): + """""" + self.setEnabled(False) + self.setStyleSheet("color:black;background-color:grey") + + + +AlgoCell = QtWidgets.QTableWidgetItem + + +######################################################################## +class AlgoStatusMonitor(QtWidgets.QTableWidget): + """""" + signalParam = QtCore.Signal(type(Event())) + signalVar = QtCore.Signal(type(Event())) + + #---------------------------------------------------------------------- + def __init__(self, algoEngine): + """Constructor""" + super(AlgoStatusMonitor, self).__init__() + + self.algoEngine = algoEngine + self.eventEngine = algoEngine.eventEngine + + self.cellDict = {} + + self.initUi() + self.registerEvent() + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + labels = [u'', + u'名称', + u'参数', + u'变量'] + + self.setColumnCount(len(labels)) + self.setHorizontalHeaderLabels(labels) + self.setRowCount(0) + self.verticalHeader().setVisible(False) + self.setEditTriggers(self.NoEditTriggers) + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.signalParam.connect(self.processParamEvent) + self.signalVar.connect(self.processVarEvent) + + self.eventEngine.register(EVENT_ALGO_PARAM, self.signalParam.emit) + self.eventEngine.register(EVENT_ALGO_VAR, self.signalVar.emit) + + #---------------------------------------------------------------------- + def addAlgo(self, algoName): + """新增算法""" + self.insertRow(0) + + buttonStop = StopButton(self.algoEngine, algoName) + cellName = AlgoCell(algoName) + cellParam = AlgoCell() + cellVar = AlgoCell() + + self.setCellWidget(0, 0, buttonStop) + self.setItem(0, 1, cellName) + self.setItem(0, 2, cellParam) + self.setItem(0, 3, cellVar) + + self.cellDict[algoName] = { + 'param': cellParam, + 'var': cellVar, + 'button': buttonStop + } + + #---------------------------------------------------------------------- + def processParamEvent(self, event): + """""" + d = event.dict_['data'] + + algoName = d.pop('algoName') + if algoName not in self.cellDict: + self.addAlgo(algoName) + + l = [] + for k, v in d.items(): + msg = u'%s:%s' %(k, v) + l.append(msg) + text = ','.join(l) + + cell = self.cellDict[algoName]['param'] + cell.setText(text) + + self.resizeColumnsToContents() + + #---------------------------------------------------------------------- + def processVarEvent(self, event): + """""" + d = event.dict_['data'] + + algoName = d.pop('algoName') + if algoName not in self.cellDict: + self.addAlgo(algoName) + + if 'active' in d: + active = d.pop('active') + if not active: + button = self.cellDict[algoName]['button'] + button.disable() + + l = [] + for k, v in d.items(): + msg = u'%s:%s' %(k, v) + l.append(msg) + text = ','.join(l) + + cell = self.cellDict[algoName]['var'] + cell.setText(text) + + self.resizeColumnsToContents() + + +######################################################################## +class AlgoLogMonitor(QtWidgets.QTextEdit): + """""" + signal = QtCore.Signal(type(Event())) + + #---------------------------------------------------------------------- + def __init__(self, algoEngine): + """Constructor""" + super(AlgoLogMonitor, self).__init__() + + self.eventEngine = algoEngine.eventEngine + + self.registerEvent() + + #---------------------------------------------------------------------- + def registerEvent(self): + """""" + self.signal.connect(self.processEvent) + + self.eventEngine.register(EVENT_ALGO_LOG, self.signal.emit) + + #---------------------------------------------------------------------- + def processEvent(self, event): + """""" + log = event.dict_['data'] + if not log.gatewayName: + log.gatewayName = u'算法引擎' + msg = u'%s\t%s:%s' %(log.logTime, log.gatewayName, log.logContent) + self.append(msg) + + + +######################################################################## +class AlgoManager(QtWidgets.QWidget): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, eventEngine): + """Constructor""" + super(AlgoManager, self).__init__() + + self.algoEngine = algoEngine + self.eventEngine = eventEngine + + self.initUi() + self.addAlgoWidget(TwapWidget) + + #---------------------------------------------------------------------- + def initUi(self): + """""" + self.setWindowTitle(u'算法交易') + + self.statusMonitor = AlgoStatusMonitor(self.algoEngine) + self.logMonitor = AlgoLogMonitor(self.algoEngine) + self.tab = QtWidgets.QTabWidget() + self.buttonStop = StopButton(self.algoEngine) + + self.tab.setMaximumWidth(400) + self.buttonStop.setMaximumWidth(400) + self.buttonStop.setFixedHeight(100) + + vbox1 = QtWidgets.QVBoxLayout() + vbox1.addWidget(self.tab) + vbox1.addStretch() + vbox1.addWidget(self.buttonStop) + + vbox2 = QtWidgets.QVBoxLayout() + vbox2.addWidget(self.statusMonitor) + vbox2.addWidget(self.logMonitor) + + hbox = QtWidgets.QHBoxLayout() + hbox.addLayout(vbox1) + hbox.addLayout(vbox2) + + self.setLayout(hbox) + + #---------------------------------------------------------------------- + def addAlgoWidget(self, widgetClass): + """""" + w = widgetClass(self.algoEngine) + self.tab.addTab(w, w.name) \ No newline at end of file