From 584990a7edf6e0afabc054955dcdeaa3721f0b2c Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Mon, 11 Jun 2018 23:26:53 +0800 Subject: [PATCH] =?UTF-8?q?[Add]=E6=96=B0=E5=A2=9E=E5=81=9C=E6=AD=A2?= =?UTF-8?q?=E5=8D=95=E7=AE=97=E6=B3=95StopAlgo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/algoTrading/algoEngine.py | 10 +- vnpy/trader/app/algoTrading/dmaAlgo.py | 17 +- vnpy/trader/app/algoTrading/stopAlgo.py | 206 +++++++++++++++++++ vnpy/trader/app/algoTrading/twapAlgo.py | 1 + vnpy/trader/app/algoTrading/uiAlgoManager.py | 3 + 5 files changed, 224 insertions(+), 13 deletions(-) create mode 100644 vnpy/trader/app/algoTrading/stopAlgo.py diff --git a/vnpy/trader/app/algoTrading/algoEngine.py b/vnpy/trader/app/algoTrading/algoEngine.py index de3bcb34..f83c475b 100644 --- a/vnpy/trader/app/algoTrading/algoEngine.py +++ b/vnpy/trader/app/algoTrading/algoEngine.py @@ -15,6 +15,7 @@ from vnpy.trader.vtObject import VtSubscribeReq, VtOrderReq, VtCancelOrderReq, V from .twapAlgo import TwapAlgo from .dmaAlgo import DmaAlgo +from .stopAlgo import StopAlgo EVENT_ALGO_LOG = 'eAlgoLog' # 算法日志事件 EVENT_ALGO_PARAM = 'eAlgoParam' # 算法参数事件 @@ -29,7 +30,9 @@ HISTORY_COLLECTION_NAME = 'AlgoHistory' # 算法历史集合名 ALGO_DICT = { - TwapAlgo.templateName: TwapAlgo + TwapAlgo.templateName: TwapAlgo, + DmaAlgo.templateName: DmaAlgo, + StopAlgo.templateName: StopAlgo } @@ -113,8 +116,9 @@ class AlgoEngine(object): #---------------------------------------------------------------------- def stopAlgo(self, algoName): """停止算法""" - self.algoDict[algoName].stop() - del self.algoDict[algoName] + if algoName in self.algoDict: + self.algoDict[algoName].stop() + del self.algoDict[algoName] #---------------------------------------------------------------------- def stopAll(self): diff --git a/vnpy/trader/app/algoTrading/dmaAlgo.py b/vnpy/trader/app/algoTrading/dmaAlgo.py index 753794f3..fdb42a82 100644 --- a/vnpy/trader/app/algoTrading/dmaAlgo.py +++ b/vnpy/trader/app/algoTrading/dmaAlgo.py @@ -31,10 +31,10 @@ class DmaAlgo(AlgoTemplate): # 参数,强制类型转换,保证从CSV加载的配置正确 self.vtSymbol = str(setting['vtSymbol']) # 合约代码 self.direction = unicode(setting['direction']) # 买卖 - self.offset = float(setting['offset']) # 开平 - self.priceType = float(setting['priceType']) # 价格类型 + self.offset = unicode(setting['offset']) # 开平 + self.priceType = unicode(setting['priceType']) # 价格类型 self.price = float(setting['price']) # 价格 - self.totalVolume = int(setting['totalVolume']) # 数量 + self.totalVolume = float(setting['totalVolume']) # 数量 self.vtOrderID = '' # 委托号 self.tradedVolume = 0 # 成交数量 @@ -74,7 +74,7 @@ class DmaAlgo(AlgoTemplate): if self.orderStatus in STATUS_FINISHED: self.stop() - self.paramEvent() + self.varEvent() #---------------------------------------------------------------------- def onTimer(self): @@ -84,12 +84,8 @@ class DmaAlgo(AlgoTemplate): #---------------------------------------------------------------------- def onStop(self): """""" - if self.orderStatus not in STATUS_FINISHED: - self.cancelAll() - - # 处理这里的逻辑,区分用户停止和到期停止 - - self.writeLog(u'委托已%s,停止算法' %self.status) + self.writeLog(u'停止算法') + self.varEvent() #---------------------------------------------------------------------- def varEvent(self): @@ -99,6 +95,7 @@ class DmaAlgo(AlgoTemplate): d[u'委托号'] = self.vtOrderID d[u'成交数量'] = self.tradedVolume d[u'委托状态'] = self.orderStatus + d['active'] = self.active self.putVarEvent(d) #---------------------------------------------------------------------- diff --git a/vnpy/trader/app/algoTrading/stopAlgo.py b/vnpy/trader/app/algoTrading/stopAlgo.py new file mode 100644 index 00000000..3b2e662f --- /dev/null +++ b/vnpy/trader/app/algoTrading/stopAlgo.py @@ -0,0 +1,206 @@ +# encoding: UTF-8 + +from __future__ import division +from collections import OrderedDict + +from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT, + OFFSET_OPEN, OFFSET_CLOSE) +from vnpy.trader.uiQt import QtWidgets + +from .algoTemplate import AlgoTemplate +from .uiAlgoWidget import AlgoWidget, QtWidgets + + + +######################################################################## +class StopAlgo(AlgoTemplate): + """停止单算法,也可以用于止损单""" + + templateName = 'STOP' + + #---------------------------------------------------------------------- + def __init__(self, engine, setting, algoName): + """Constructor""" + super(StopAlgo, self).__init__(engine, setting, algoName) + + # 参数,强制类型转换,保证从CSV加载的配置正确 + self.vtSymbol = str(setting['vtSymbol']) # 合约代码 + self.direction = unicode(setting['direction']) # 买卖 + self.stopPrice = float(setting['stopPrice']) # 触发价格 + self.totalVolume = float(setting['totalVolume']) # 数量 + self.offset = unicode(setting['offset']) # 开平 + self.priceAdd = float(setting['priceAdd']) # 下单时的超价 + + self.vtOrderID = '' # 委托号 + self.tradedVolume = 0 # 成交数量 + self.orderStatus = '' # 委托状态 + + self.subscribe(self.vtSymbol) + self.paramEvent() + self.varEvent() + + #---------------------------------------------------------------------- + def onTick(self, tick): + """""" + # 如果已经发出委托,则忽略行情事件 + if self.vtOrderID: + return + + # 如果到达止损位,才触发委托 + if (self.direction == DIRECTION_LONG and + tick.lastPrice >= self.price): + # 计算超价委托价格 + price = self.stopPrice + self.priceAdd + + # 避免价格超过涨停价 + if tick.upperLimit: + price = min(price, tick.upperLimit) + + func = self.buy + else: + price = self.stopPrice - self.priceAdd + + if tick.lowerLimit: + price = max(price, tick.lowerLimit) + + func = self.sell + + self.vtOrderID = func(self.vtSymbol, price, self.volume, offset=self.offset) + + msg = u'停止单已触发,代码:%s,方向:%s, 价格:%s,数量:%s,开平:%s' %(self.vtSymbol, + self.direction, + self.stopPrice, + self.totalVolume, + self.offset) + self.writeLog(msg) + + # 更新变量 + self.varEvent() + + #---------------------------------------------------------------------- + def onTrade(self, trade): + """""" + pass + + #---------------------------------------------------------------------- + def onOrder(self, order): + """""" + self.tradedVolume = order.tradedVolume + self.orderStatus = order.status + + if self.orderStatus in STATUS_FINISHED: + self.stop() + + self.varEvent() + + #---------------------------------------------------------------------- + def onTimer(self): + """""" + pass + + #---------------------------------------------------------------------- + def onStop(self): + """""" + self.writeLog(u'停止算法') + self.varEvent() + + #---------------------------------------------------------------------- + def varEvent(self): + """更新变量""" + d = OrderedDict() + d[u'算法状态'] = self.active + d[u'委托号'] = self.vtOrderID + d[u'成交数量'] = self.tradedVolume + d[u'委托状态'] = self.orderStatus + d['active'] = self.active + self.putVarEvent(d) + + #---------------------------------------------------------------------- + def paramEvent(self): + """更新参数""" + d = OrderedDict() + d[u'代码'] = self.vtSymbol + d[u'方向'] = self.direction + d[u'触发价格'] = self.stopPrice + d[u'数量'] = self.totalVolume + d[u'开平'] = self.offset + self.putParamEvent(d) + + +######################################################################## +class StopWidget(AlgoWidget): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, parent=None): + """Constructor""" + super(StopWidget, self).__init__(algoEngine, parent) + + self.templateName = StopAlgo.templateName + + #---------------------------------------------------------------------- + def initAlgoLayout(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.comboOffset = QtWidgets.QComboBox() + self.comboOffset.addItems(['', OFFSET_OPEN, OFFSET_CLOSE]) + self.comboOffset.setCurrentIndex(0) + + self.spinPriceAdd = QtWidgets.QDoubleSpinBox() + self.spinPriceAdd.setMinimum(0) + self.spinPriceAdd.setMaximum(1000000000) + self.spinPriceAdd.setDecimals(8) + + 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.comboOffset, 4, 1) + grid.addWidget(Label(u'超价'), 5, 0) + grid.addWidget(self.spinPriceAdd, 5, 1) + + return grid + + #---------------------------------------------------------------------- + def getAlgoSetting(self): + """""" + setting = OrderedDict() + setting['templateName'] = StopAlgo.templateName + setting['vtSymbol'] = str(self.lineSymbol.text()) + setting['direction'] = unicode(self.comboDirection.currentText()) + setting['stopPrice'] = float(self.spinPrice.value()) + setting['totalVolume'] = float(self.spinVolume.value()) + setting['offset'] = unicode(self.comboOffset.currentText()) + setting['priceAdd'] = float(self.spinPriceAdd.value()) + + return setting + + \ No newline at end of file diff --git a/vnpy/trader/app/algoTrading/twapAlgo.py b/vnpy/trader/app/algoTrading/twapAlgo.py index d38d29af..d3727136 100644 --- a/vnpy/trader/app/algoTrading/twapAlgo.py +++ b/vnpy/trader/app/algoTrading/twapAlgo.py @@ -152,6 +152,7 @@ class TwapAlgo(AlgoTemplate): d[u'单笔委托'] = self.orderSize d[u'本轮读秒'] = self.timerCount d[u'累计读秒'] = self.timerTotal + d['active'] = self.active self.putVarEvent(d) #---------------------------------------------------------------------- diff --git a/vnpy/trader/app/algoTrading/uiAlgoManager.py b/vnpy/trader/app/algoTrading/uiAlgoManager.py index 8d8f8ac4..895e3fa0 100644 --- a/vnpy/trader/app/algoTrading/uiAlgoManager.py +++ b/vnpy/trader/app/algoTrading/uiAlgoManager.py @@ -9,8 +9,10 @@ from vnpy.trader.uiQt import QtCore, QtWidgets from .algoEngine import (EVENT_ALGO_LOG, EVENT_ALGO_PARAM, EVENT_ALGO_VAR, EVENT_ALGO_SETTING) + from .twapAlgo import TwapWidget from .dmaAlgo import DmaWidget +from .stopAlgo import StopWidget ######################################################################## @@ -388,6 +390,7 @@ class AlgoManager(QtWidgets.QWidget): self.initUi() self.addAlgoWidget(TwapWidget) self.addAlgoWidget(DmaWidget) + self.addAlgoWidget(StopWidget) self.algoEngine.loadAlgoSetting() # 界面初始化后,再加载算法配置