From 79a9ac2bfb33f81c1c32b351b41fc0bf712787f7 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Fri, 23 Jun 2017 16:27:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90=E4=BB=B7?= =?UTF-8?q?=E5=B7=AE=E4=BA=A4=E6=98=93=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/spreadTrading/st.ico | Bin 45118 -> 66622 bytes vnpy/trader/app/spreadTrading/stAlgo.py | 122 +++++- vnpy/trader/app/spreadTrading/stBase.py | 2 + vnpy/trader/app/spreadTrading/stEngine.py | 171 ++++++++- vnpy/trader/app/spreadTrading/uiStWidget.py | 405 ++++++++++++++++++-- 5 files changed, 654 insertions(+), 46 deletions(-) diff --git a/vnpy/trader/app/spreadTrading/st.ico b/vnpy/trader/app/spreadTrading/st.ico index a66c245e0dc6c55842f923177515889ca5b9ce4e..4d0ad1991d3d17f3d649562dad09da2e23142166 100644 GIT binary patch literal 66622 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 diff --git a/vnpy/trader/app/spreadTrading/stAlgo.py b/vnpy/trader/app/spreadTrading/stAlgo.py index e3903407..3cb24c70 100644 --- a/vnpy/trader/app/spreadTrading/stAlgo.py +++ b/vnpy/trader/app/spreadTrading/stAlgo.py @@ -12,9 +12,9 @@ from vnpy.trader.vtConstant import (EMPTY_INT, EMPTY_FLOAT, ######################################################################## class StAlgoTemplate(object): """价差算法交易模板""" - MODE_LONGSHORT = 1 - MODE_LONGONLY = 2 - MODE_SHORTONLY = 3 + MODE_LONGSHORT = u'双向' + MODE_LONGONLY = u'做多' + MODE_SHORTONLY = u'做空' SPREAD_LONG = 1 SPREAD_SHORT = 2 @@ -65,7 +65,7 @@ class StAlgoTemplate(object): raise NotImplementedError #---------------------------------------------------------------------- - def start(self, mode=MODE_LONGSHORT): + def start(self): """""" raise NotImplementedError @@ -74,7 +74,79 @@ class StAlgoTemplate(object): """""" raise NotImplementedError + #---------------------------------------------------------------------- + def setBuyPrice(self, buyPrice): + """设置买开的价格""" + self.buyPrice = buyPrice + + #---------------------------------------------------------------------- + def setSellPrice(self, sellPrice): + """设置卖平的价格""" + self.sellPrice = sellPrice + + #---------------------------------------------------------------------- + def setShortPrice(self, shortPrice): + """设置卖开的价格""" + self.shortPrice = shortPrice + + #---------------------------------------------------------------------- + def setCoverPrice(self, coverPrice): + """设置买平的价格""" + self.coverPrice = coverPrice + + #---------------------------------------------------------------------- + def setMode(self, mode): + """设置算法交易方向""" + self.mode = mode + + #---------------------------------------------------------------------- + def setMaxOrderSize(self, maxOrderSize): + """设置最大单笔委托数量""" + self.maxOrderSize = maxOrderSize + + #---------------------------------------------------------------------- + def setMaxPosSize(self, maxPosSize): + """设置最大持仓数量""" + self.maxPosSize = maxPosSize + + #---------------------------------------------------------------------- + def putEvent(self): + """发出算法更新事件""" + self.algoEngine.putAlgoEvent(self) + + #---------------------------------------------------------------------- + def writeLog(self, content): + """输出算法日志""" + content = ':'.join([self.spreadName, content]) + self.algoEngine.writeLog(content) + #---------------------------------------------------------------------- + def getAlgoParams(self): + """获取算法参数""" + d = { + "spreadName": self.spreadName, + "algoName": self.algoName, + "buyPrice": self.buyPrice, + "sellPrice": self.sellPrice, + "shortPrice": self.shortPrice, + "coverPrice": self.coverPrice, + "maxOrderSize": self.maxOrderSize, + "maxPosSize": self.maxPosSize, + "mode": self.mode + } + return d + + #---------------------------------------------------------------------- + def setAlgoParams(self, d): + """设置算法参数""" + self.buyPrice = d.get('buyPrice', EMPTY_FLOAT) + self.sellPrice = d.get('sellPrice', EMPTY_FLOAT) + self.shortPrice = d.get('shortPrice', EMPTY_FLOAT) + self.coverPrice = d.get('coverPrice', EMPTY_FLOAT) + self.maxOrderSize = d.get('maxOrderSize', EMPTY_INT) + self.maxPosSize = d.get('maxPosSize', EMPTY_INT) + self.mode = d.get('mode', self.MODE_LONGSHORT) + ######################################################################## class SniperAlgo(StAlgoTemplate): @@ -82,9 +154,9 @@ class SniperAlgo(StAlgoTemplate): FINISHED_STATUS = [STATUS_ALLTRADED, STATUS_CANCELLED, STATUS_REJECTED] #---------------------------------------------------------------------- - def __init__(self, algoEngine): + def __init__(self, algoEngine, spread): """Constructor""" - super(SniperAlgo, self).__init__(algoEngine) + super(SniperAlgo, self).__init__(algoEngine, spread) self.algoName = u'Sniper' self.quoteInterval = 2 # 主动腿报价撤单再发前等待的时间 @@ -125,11 +197,13 @@ class SniperAlgo(StAlgoTemplate): spread.netPos < self.maxPosSize and spread.askPrice <= self.buyPrice): self.quoteActiveLeg(self.SPREAD_LONG) + self.writeLog(u'买入开仓') # 卖出 elif (spread.netPos > 0 and spread.bidPrice >= self.sellPrice): self.quoteActiveLeg(self.SPREAD_SHORT) + self.writeLog(u'卖出平仓') # 允许做空 if self.mode == self.MODE_LONGSHORT or self.mode == self.MODE_SHORTONLY: @@ -138,11 +212,13 @@ class SniperAlgo(StAlgoTemplate): spread.netPos > -self.maxPosSize and spread.bidPrice >= self.shortPrice): self.quoteActiveLeg(self.SPREAD_SHORT) + self.writeLog(u'卖出开仓') # 平空 elif (spread.netPos < 0 and spread.askPrice <= self.coverPrice): self.quoteActiveLeg(self.SPREAD_LONG) + self.writeLog(u'买入平仓') #---------------------------------------------------------------------- def updateSpreadPos(self, spread): @@ -180,10 +256,14 @@ class SniperAlgo(StAlgoTemplate): # 检查若是被动腿,且已经没有未完成委托,则执行对冲 if not orderList and vtSymbol in self.passiveVtSymbols: self.hedgePassiveLeg(vtSymbol) + self.writeLog(u'发出新的被动腿%s对冲单' %vtSymbol) #---------------------------------------------------------------------- def updateTimer(self): """计时更新""" + if not self.active: + return + self.quoteCount += 1 self.hedgeCount += 1 @@ -200,10 +280,14 @@ class SniperAlgo(StAlgoTemplate): self.hedgeCount = 0 #---------------------------------------------------------------------- - def start(self, mode=MODE_LONGSHORT): + def start(self): """启动""" - self.mode = mode self.active = True + + self.quoteCount = 0 + self.hedgeCount = 0 + + return self.active #---------------------------------------------------------------------- def stop(self): @@ -212,6 +296,8 @@ class SniperAlgo(StAlgoTemplate): self.hedgingTaskDict.clear() self.cancelAllOrders() + + return self.active #---------------------------------------------------------------------- def sendLegOrder(self, leg, legVolume): @@ -310,6 +396,9 @@ class SniperAlgo(StAlgoTemplate): self.hedgingTaskDict[leg.vtSymbol] = newHedgingTask else: self.hedgingTaskDict[leg.vtSymbol] += newHedgingTask + + # 输出日志 + self.writeLog(u'主动腿%s成交,方向%s,数量%s' %(trade.vtSymbol, trade.direction, trade.volume)) #---------------------------------------------------------------------- def newPassiveLegTrade(self, trade): @@ -328,6 +417,9 @@ class SniperAlgo(StAlgoTemplate): if not self.hedgingTaskDict[trade.vtSymbol]: del self.hedgingTaskDict[trade.vtSymbol] + # 输出日志 + self.writeLog(u'被动腿%s成交,方向%s,数量%s' %(trade.vtSymbol, trade.direction, trade.volume)) + #---------------------------------------------------------------------- def cancelLegOrder(self, vtSymbol): """撤销某条腿的委托""" @@ -339,15 +431,27 @@ class SniperAlgo(StAlgoTemplate): for vtOrderID in orderList: self.algoEngine.cancelOrder(vtOrderID) + self.writeLog(u'撤单%s的所有委托' %vtSymbol) + #---------------------------------------------------------------------- def cancelAllOrders(self): """撤销全部委托""" for orderList in self.legOrderDict.values(): for vtOrderID in orderList: self.algoEngine.cancelOrder(vtOrderID) + + self.writeLog(u'全部撤单') #---------------------------------------------------------------------- def cancelAllPassiveLegOrders(self): """撤销全部被动腿委托""" + cancelPassive = False + for vtSymbol in self.passiveVtSymbols: - self.cancelLegOrder(vtSymbol) \ No newline at end of file + if self.legOrderDict[vtSymbol]: + self.cancelLegOrder(vtSymbol) + cancelPassive = True + + # 只有确实发出撤单委托时,才输出信息 + if cancelPassive: + self.writeLog(u'被动腿全撤') diff --git a/vnpy/trader/app/spreadTrading/stBase.py b/vnpy/trader/app/spreadTrading/stBase.py index 64f0f00f..71f25f15 100644 --- a/vnpy/trader/app/spreadTrading/stBase.py +++ b/vnpy/trader/app/spreadTrading/stBase.py @@ -13,6 +13,8 @@ from vnpy.trader.vtConstant import (EMPTY_INT, EMPTY_FLOAT, EVENT_SPREADTRADING_TICK = 'eSpreadTradingTick.' EVENT_SPREADTRADING_POS = 'eSpreadTradingPos.' EVENT_SPREADTRADING_LOG = 'eSpreadTradingLog' +EVENT_SPREADTRADING_ALGO = 'eSpreadTradingAlgo.' +EVENT_SPREADTRADING_ALGOLOG = 'eSpreadTradingAlgoLog' diff --git a/vnpy/trader/app/spreadTrading/stEngine.py b/vnpy/trader/app/spreadTrading/stEngine.py index c93bb3cd..71e89c31 100644 --- a/vnpy/trader/app/spreadTrading/stEngine.py +++ b/vnpy/trader/app/spreadTrading/stEngine.py @@ -2,10 +2,10 @@ import json import traceback -from copy import copy +import shelve from vnpy.event import Event -from vnpy.trader.vtFunction import getJsonPath +from vnpy.trader.vtFunction import getJsonPath, getTempPath from vnpy.trader.vtEvent import (EVENT_TICK, EVENT_TRADE, EVENT_POSITION, EVENT_TIMER, EVENT_ORDER) from vnpy.trader.vtObject import (VtSubscribeReq, VtOrderReq, @@ -14,7 +14,9 @@ from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT, OFFSET_OPEN, OFFSET_CLOSE) from .stBase import (StLeg, StSpread, EVENT_SPREADTRADING_TICK, - EVENT_SPREADTRADING_POS, EVENT_SPREADTRADING_LOG) + EVENT_SPREADTRADING_POS, EVENT_SPREADTRADING_LOG, + EVENT_SPREADTRADING_ALGO, EVENT_SPREADTRADING_ALGOLOG) +from .stAlgo import SniperAlgo ######################################################################## @@ -121,6 +123,9 @@ class StDataEngine(object): # 初始化价差 spread.initSpread() + self.putSpreadTickEvent(spread) + self.putSpreadPosEvent(spread) + # 返回结果 result = True msg = u'%s价差创建成功' %spread.name @@ -145,7 +150,12 @@ class StDataEngine(object): spread = self.vtSymbolSpreadDict[tick.vtSymbol] spread.calculatePrice() - # 推送价差行情更新 + # 发出事件 + self.putSpreadTickEvent(spread) + + #---------------------------------------------------------------------- + def putSpreadTickEvent(self, spread): + """发出价差行情更新事件""" event1 = Event(EVENT_SPREADTRADING_TICK+spread.name) event1.dict_['data'] = spread self.eventEngine.put(event1) @@ -215,13 +225,19 @@ class StDataEngine(object): spread.calculatePos() # 推送价差持仓更新 + self.putSpreadPosEvent(spread) + + #---------------------------------------------------------------------- + def putSpreadPosEvent(self, spread): + """发出价差持仓事件""" event1 = Event(EVENT_SPREADTRADING_POS+spread.name) event1.dict_['data'] = spread self.eventEngine.put(event1) - + event2 = Event(EVENT_SPREADTRADING_POS) event2.dict_['data'] = spread - self.eventEngine.put(event2) + self.eventEngine.put(event2) + #---------------------------------------------------------------------- def registerEvent(self): @@ -236,6 +252,7 @@ class StDataEngine(object): contract = self.mainEngine.getContract(vtSymbol) if not contract: self.writeLog(u'订阅行情失败,找不到该合约%s' %vtSymbol) + return req = VtSubscribeReq() req.symbol = contract.symbol @@ -254,18 +271,21 @@ class StDataEngine(object): self.eventEngine.put(event) #---------------------------------------------------------------------- - def stop(self): - """停止""" - pass + def getAllSpreads(self): + """获取所有的价差""" + return self.spreadDict.values() ######################################################################## class StAlgoEngine(object): """价差算法交易引擎""" + algoFileName = 'SpreadTradingAlgo.vt' + algoFilePath = getTempPath(algoFileName) #---------------------------------------------------------------------- - def __init__(self, mainEngine, eventEngine): + def __init__(self, dataEngine, mainEngine, eventEngine): """Constructor""" + self.dataEngine = dataEngine self.mainEngine = mainEngine self.eventEngine = eventEngine @@ -387,6 +407,122 @@ class StAlgoEngine(object): vtOrderID = self.sendOrder(vtSymbol, DIRECTION_LONG, OFFSET_CLOSE, price, volume, payup) return [vtOrderID] + #---------------------------------------------------------------------- + def putAlgoEvent(self, algo): + """发出算法状态更新事件""" + event = Event(EVENT_SPREADTRADING_ALGO+algo.name) + self.eventEngine.put(event) + + #---------------------------------------------------------------------- + def writeLog(self, content): + """输出日志""" + log = VtLogData() + log.logContent = content + + event = Event(EVENT_SPREADTRADING_ALGOLOG) + event.dict_['data'] = log + + self.eventEngine.put(event) + + #---------------------------------------------------------------------- + def saveSetting(self): + """保存算法配置""" + setting = {} + for algo in self.algoDict.values(): + setting[algo.spreadName] = algo.getAlgoParams() + + f = shelve.open(self.algoFilePath) + f['setting'] = setting + f.close() + + #---------------------------------------------------------------------- + def loadSetting(self): + """加载算法配置""" + # 创建算法对象 + l = self.dataEngine.getAllSpreads() + for spread in l: + self.algoDict[spread.name] = SniperAlgo(self, spread) + + # 加载配置 + f = shelve.open(self.algoFilePath) + setting = f.get('setting', None) + f.close() + + if not setting: + return + + for algo in self.algoDict.values(): + if algo.spreadName in setting: + d = setting[algo.spreadName] + algo.setAlgoParams(d) + + #---------------------------------------------------------------------- + def stopAll(self): + """停止全部算法""" + for algo in self.algoDict.values(): + algo.stop() + + #---------------------------------------------------------------------- + def startAlgo(self, spreadName): + """启动算法""" + algo = self.algoDict[spreadName] + algoActive = algo.start() + return algoActive + + #---------------------------------------------------------------------- + def stopAlgo(self, spreadName): + """停止算法""" + algo = self.algoDict[spreadName] + algoActive = algo.stop() + return algoActive + + #---------------------------------------------------------------------- + def getAllAlgoParams(self): + """获取所有算法的参数""" + return [algo.getAlgoParams() for algo in self.algoDict.values()] + + #---------------------------------------------------------------------- + def setAlgoBuyPrice(self, spreadName, buyPrice): + """设置算法买开价格""" + algo = self.algoDict[spreadName] + algo.setBuyPrice(buyPrice) + + #---------------------------------------------------------------------- + def setAlgoSellPrice(self, spreadName, sellPrice): + """设置算法卖平价格""" + algo = self.algoDict[spreadName] + algo.setSellPrice(sellPrice) + + #---------------------------------------------------------------------- + def setAlgoShortPrice(self, spreadName, shortPrice): + """设置算法卖开价格""" + algo = self.algoDict[spreadName] + algo.setShortPrice(shortPrice) + + #---------------------------------------------------------------------- + def setAlgoCoverPrice(self, spreadName, coverPrice): + """设置算法买平价格""" + algo = self.algoDict[spreadName] + algo.setCoverPrice(coverPrice) + + #---------------------------------------------------------------------- + def setAlgoMode(self, spreadName, mode): + """设置算法工作模式""" + algo = self.algoDict[spreadName] + algo.setMode(mode) + + #---------------------------------------------------------------------- + def setAlgoMaxOrderSize(self, spreadName, maxOrderSize): + """设置算法单笔委托限制""" + algo = self.algoDict[spreadName] + algo.setMaxOrderSize(maxOrderSize) + + #---------------------------------------------------------------------- + def setAlgoMaxPosSize(self, spreadName, maxPosSize): + """设置算法持仓限制""" + algo = self.algoDict[spreadName] + algo.setMaxPosSize(maxPosSize) + ######################################################################## class StEngine(object): @@ -399,12 +535,21 @@ class StEngine(object): self.eventEngine = eventEngine self.dataEngine = StDataEngine(mainEngine, eventEngine) - self.algoEngine = StAlgoEngine(mainEngine, eventEngine) + self.algoEngine = StAlgoEngine(self.dataEngine, mainEngine, eventEngine) #---------------------------------------------------------------------- - def loadSetting(self): - """""" + def init(self): + """初始化""" self.dataEngine.loadSetting() + self.algoEngine.loadSetting() + + #---------------------------------------------------------------------- + def stop(self): + """停止""" + self.dataEngine.saveSetting() + + self.algoEngine.stopAll() + self.algoEngine.saveSetting() diff --git a/vnpy/trader/app/spreadTrading/uiStWidget.py b/vnpy/trader/app/spreadTrading/uiStWidget.py index 9244fc4d..76fd714e 100644 --- a/vnpy/trader/app/spreadTrading/uiStWidget.py +++ b/vnpy/trader/app/spreadTrading/uiStWidget.py @@ -2,14 +2,20 @@ from collections import OrderedDict -from vnpy.trader.uiQt import QtWidgets +from vnpy.event import Event +from vnpy.trader.uiQt import QtWidgets, QtCore from vnpy.trader.uiBasicWidget import (BasicMonitor, BasicCell, PnlCell, AskCell, BidCell, BASIC_FONT) from .stBase import (EVENT_SPREADTRADING_TICK, EVENT_SPREADTRADING_POS, - EVENT_SPREADTRADING_LOG) + EVENT_SPREADTRADING_LOG, EVENT_SPREADTRADING_ALGO, + EVENT_SPREADTRADING_ALGOLOG) +from .stAlgo import StAlgoTemplate +STYLESHEET_START = 'background-color: rgb(111,255,244); color: black' +STYLESHEET_STOP = 'background-color: rgb(255,201,111); color: black' + ######################################################################## class StTickMonitor(BasicMonitor): @@ -64,25 +70,365 @@ class StPosMonitor(BasicMonitor): ######################################################################## -class StLogMonitor(BasicMonitor): +class StLogMonitor(QtWidgets.QTextEdit): + """价差日志监控""" + signal = QtCore.pyqtSignal(type(Event())) + + #---------------------------------------------------------------------- + def __init__(self, mainEngine, eventEngine, parent=None): + """Constructor""" + super(StLogMonitor, self).__init__(parent) + + self.eventEngine = eventEngine + + self.registerEvent() + + #---------------------------------------------------------------------- + def processLogEvent(self, event): + """处理日志事件""" + log = event.dict_['data'] + content = '%s:%s' %(log.logTime, log.logContent) + self.append(content) + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.signal.connect(self.processLogEvent) + + self.eventEngine.register(EVENT_SPREADTRADING_LOG, self.signal.emit) + + +######################################################################## +class StAlgoLogMonitor(BasicMonitor): """价差日志监控""" #---------------------------------------------------------------------- def __init__(self, mainEngine, eventEngine, parent=None): """Constructor""" - super(StLogMonitor, self).__init__(mainEngine, eventEngine, parent) + super(StAlgoLogMonitor, self).__init__(mainEngine, eventEngine, parent) d = OrderedDict() d['logTime'] = {'chinese':u'时间', 'cellType':BasicCell} - d['logContent'] = {'chinese':u'日志', 'cellType':BasicCell} + d['logContent'] = {'chinese':u'信息', 'cellType':BasicCell} self.setHeaderDict(d) - self.setEventType(EVENT_SPREADTRADING_LOG) + self.setEventType(EVENT_SPREADTRADING_ALGOLOG) self.setFont(BASIC_FONT) self.initTable() - self.registerEvent() + self.registerEvent() + +######################################################################## +class StBuyPriceSpinBox(QtWidgets.QDoubleSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, price, parent=None): + """Constructor""" + super(StBuyPriceSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setDecimals(4) + self.setRange(-10000, 10000) + self.setValue(price) + + self.valueChanged.connect(self.setPrice) + + #---------------------------------------------------------------------- + def setPrice(self, value): + """设置价格""" + self.algoEngine.setAlgoBuyPrice(self.spreadName, value) + + +######################################################################## +class StSellPriceSpinBox(QtWidgets.QDoubleSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, price, parent=None): + """Constructor""" + super(StSellPriceSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setDecimals(4) + self.setRange(-10000, 10000) + self.setValue(price) + + self.valueChanged.connect(self.setPrice) + + #---------------------------------------------------------------------- + def setPrice(self, value): + """设置价格""" + self.algoEngine.setAlgoSellPrice(self.spreadName, value) + + +######################################################################## +class StShortPriceSpinBox(QtWidgets.QDoubleSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, price, parent=None): + """Constructor""" + super(StShortPriceSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setDecimals(4) + self.setRange(-10000, 10000) + self.setValue(price) + + self.valueChanged.connect(self.setPrice) + + #---------------------------------------------------------------------- + def setPrice(self, value): + """设置价格""" + self.algoEngine.setAlgoShortPrice(self.spreadName, value) + + +######################################################################## +class StCoverPriceSpinBox(QtWidgets.QDoubleSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, price, parent=None): + """Constructor""" + super(StCoverPriceSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setDecimals(4) + self.setRange(-10000, 10000) + self.setValue(price) + + self.valueChanged.connect(self.setPrice) + + #---------------------------------------------------------------------- + def setPrice(self, value): + """设置价格""" + self.algoEngine.setAlgoCoverPrice(self.spreadName, value) + + +######################################################################## +class StMaxPosSizeSpinBox(QtWidgets.QSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, size, parent=None): + """Constructor""" + super(StMaxPosSizeSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setRange(-10000, 10000) + self.setValue(size) + + self.valueChanged.connect(self.setSize) + + #---------------------------------------------------------------------- + def setSize(self, size): + """设置价格""" + self.algoEngine.setAlgoMaxPosSize(self.spreadName, size) + + +######################################################################## +class StMaxOrderSizeSpinBox(QtWidgets.QSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, size, parent=None): + """Constructor""" + super(StMaxOrderSizeSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setRange(-10000, 10000) + self.setValue(size) + + self.valueChanged.connect(self.setSize) + + #---------------------------------------------------------------------- + def setSize(self, size): + """设置价格""" + self.algoEngine.setAlgoMaxOrderSize(self.spreadName, size) + + +######################################################################## +class StModeComboBox(QtWidgets.QComboBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, mode, parent=None): + """Constructor""" + super(StModeComboBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + l = [StAlgoTemplate.MODE_LONGSHORT, + StAlgoTemplate.MODE_LONGONLY, + StAlgoTemplate.MODE_SHORTONLY] + self.addItems(l) + self.setCurrentIndex(l.index(mode)) + + self.currentIndexChanged.connect(self.setMode) + + #---------------------------------------------------------------------- + def setMode(self): + """设置模式""" + mode = unicode(self.currentText()) + self.algoEngine.setAlgoMode(self.spreadName, mode) + + #---------------------------------------------------------------------- + def algoActiveChanged(self, active): + """算法运行状态改变""" + # 只允许算法停止时修改运行模式 + if active: + self.setEnabled(False) + else: + self.setEnabled(True) + + +######################################################################## +class StActiveButton(QtWidgets.QPushButton): + """""" + signalActive = QtCore.pyqtSignal(bool) + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, parent=None): + """Constructor""" + super(StActiveButton, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.active = False + self.setStopped() + + self.clicked.connect(self.buttonClicked) + + #---------------------------------------------------------------------- + def buttonClicked(self): + """改变运行模式""" + if self.active: + algoActive = self.algoEngine.stopAlgo(self.spreadName) + + if not algoActive: + self.setStopped() + else: + algoActive = self.algoEngine.startAlgo(self.spreadName) + + if algoActive: + self.setStarted() + + #---------------------------------------------------------------------- + def setStarted(self): + """算法启动""" + self.setText(u'运行中') + self.setStyleSheet(STYLESHEET_START) + + self.active = True + self.signalActive.emit(self.active) + + #---------------------------------------------------------------------- + def setStopped(self): + """算法停止""" + self.setText(u'已停止') + self.setStyleSheet(STYLESHEET_STOP) + + self.active = False + self.signalActive.emit(self.active) + + +######################################################################## +class StAlgoManager(QtWidgets.QTableWidget): + """""" + + #---------------------------------------------------------------------- + def __init__(self, stEngine, parent=None): + """Constructor""" + super(StAlgoManager, self).__init__(parent) + + self.algoEngine = stEngine.algoEngine + + self.initUi() + + #---------------------------------------------------------------------- + def initUi(self): + """初始化表格""" + headers = [u'价差', + u'算法', + 'BuyPrice', + 'SellPrice', + 'CoverPrice', + 'ShortPrice', + u'委托上限', + u'持仓上限', + u'模式', + u'状态'] + self.setColumnCount(len(headers)) + self.setHorizontalHeaderLabels(headers) + self.horizontalHeader().setResizeMode(QtWidgets.QHeaderView.Stretch) + + self.verticalHeader().setVisible(False) + self.setEditTriggers(self.NoEditTriggers) + + #---------------------------------------------------------------------- + def initCells(self): + """初始化单元格""" + algoEngine = self.algoEngine + + l = self.algoEngine.getAllAlgoParams() + self.setRowCount(len(l)) + + for row, d in enumerate(l): + cellSpreadName = QtWidgets.QTableWidgetItem(d['spreadName']) + cellAlgoName = QtWidgets.QTableWidgetItem(d['algoName']) + spinBuyPrice = StBuyPriceSpinBox(algoEngine, d['spreadName'], d['buyPrice']) + spinSellPrice = StSellPriceSpinBox(algoEngine, d['spreadName'], d['sellPrice']) + spinShortPrice = StShortPriceSpinBox(algoEngine, d['spreadName'], d['shortPrice']) + spinCoverPrice = StCoverPriceSpinBox(algoEngine, d['spreadName'], d['coverPrice']) + spinMaxOrderSize = StMaxOrderSizeSpinBox(algoEngine, d['spreadName'], d['maxOrderSize']) + spinMaxPosSize = StMaxPosSizeSpinBox(algoEngine, d['spreadName'], d['maxPosSize']) + comboMode = StModeComboBox(algoEngine, d['spreadName'], d['mode']) + buttonActive = StActiveButton(algoEngine, d['spreadName']) + + 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) + + buttonActive.signalActive.connect(comboMode.algoActiveChanged) + + +######################################################################## +class StGroup(QtWidgets.QGroupBox): + """集合显示""" + + #---------------------------------------------------------------------- + def __init__(self, widget, title, parent=None): + """Constructor""" + super(StGroup, self).__init__(parent) + + self.setTitle(title) + vbox = QtWidgets.QVBoxLayout() + vbox.addWidget(widget) + self.setLayout(vbox) + ######################################################################## class StManager(QtWidgets.QWidget): @@ -105,37 +451,48 @@ class StManager(QtWidgets.QWidget): self.setWindowTitle(u'价差交易') # 创建按钮 - buttonLoadSetting = QtWidgets.QPushButton(u'加载配置') - - buttonLoadSetting.clicked.connect(self.stEngine.loadSetting) + buttonInit = QtWidgets.QPushButton(u'初始化') + buttonInit.clicked.connect(self.init) # 创建组件 tickMonitor = StTickMonitor(self.mainEngine, self.eventEngine) posMonitor = StPosMonitor(self.mainEngine, self.eventEngine) logMonitor = StLogMonitor(self.mainEngine, self.eventEngine) + self.algoManager = StAlgoManager(self.stEngine) + algoLogMonitor = StAlgoLogMonitor(self.mainEngine, self.eventEngine) + + # 创建集合 + groupTick = StGroup(tickMonitor, u'价差行情') + groupPos = StGroup(posMonitor, u'价差持仓') + groupLog = StGroup(logMonitor, u'日志信息') + groupAlgo = StGroup(self.algoManager, u'价差算法') + groupAlgoLog = StGroup(algoLogMonitor, u'算法信息') # 设置布局 - hbox1 = QtWidgets.QHBoxLayout() - hbox1.addWidget(buttonLoadSetting) - hbox1.addStretch() + hbox = QtWidgets.QHBoxLayout() + hbox.addWidget(buttonInit) + hbox.addStretch() - hbox2 = QtWidgets.QHBoxLayout() - hbox2.addWidget(tickMonitor) - hbox2.addWidget(posMonitor) - - vbox = QtWidgets.QVBoxLayout() - vbox.addLayout(hbox1) - vbox.addLayout(hbox2) - vbox.addWidget(logMonitor) - - self.setLayout(vbox) + grid = QtWidgets.QGridLayout() + grid.addLayout(hbox, 0, 0, 1, 2) + grid.addWidget(groupTick, 1, 0) + grid.addWidget(groupPos, 1, 1) + grid.addWidget(groupAlgo, 2, 0, 1, 2) + grid.addWidget(groupLog, 3, 0) + grid.addWidget(groupAlgoLog, 3, 1) + + self.setLayout(grid) #---------------------------------------------------------------------- def show(self): """重载显示""" self.showMaximized() - + #---------------------------------------------------------------------- + def init(self): + """初始化""" + self.stEngine.init() + self.algoManager.initCells()