From 799e47407deb96f0d24a4d3aba470707b5775f1a Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Mon, 11 Jun 2018 22:07:12 +0800 Subject: [PATCH] =?UTF-8?q?[Add]=E6=96=B0=E5=A2=9E=E7=9B=B4=E6=8E=A5?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E5=A7=94=E6=89=98=E7=9A=84DMA=E7=AE=97?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/algoTrading/algoEngine.py | 30 ++- vnpy/trader/app/algoTrading/algoTemplate.py | 8 +- vnpy/trader/app/algoTrading/dmaAlgo.py | 192 +++++++++++++++++++ vnpy/trader/app/algoTrading/twapAlgo.py | 1 - vnpy/trader/app/algoTrading/uiAlgoManager.py | 2 + 5 files changed, 219 insertions(+), 14 deletions(-) create mode 100644 vnpy/trader/app/algoTrading/dmaAlgo.py diff --git a/vnpy/trader/app/algoTrading/algoEngine.py b/vnpy/trader/app/algoTrading/algoEngine.py index 3c360cd8..ce20b3ad 100644 --- a/vnpy/trader/app/algoTrading/algoEngine.py +++ b/vnpy/trader/app/algoTrading/algoEngine.py @@ -7,13 +7,14 @@ 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, +from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT, + PRICETYPE_LIMITPRICE, PRICETYPE_MARKETPRICE, OFFSET_OPEN, OFFSET_CLOSE, OFFSET_CLOSETODAY, OFFSET_CLOSEYESTERDAY) from vnpy.trader.vtObject import VtSubscribeReq, VtOrderReq, VtCancelOrderReq, VtLogData from .twapAlgo import TwapAlgo - +from .dmaAlgo import DmaAlgo EVENT_ALGO_LOG = 'eAlgoLog' # 算法日志事件 EVENT_ALGO_PARAM = 'eAlgoParam' # 算法参数事件 @@ -143,7 +144,8 @@ class AlgoEngine(object): self.mainEngine.subscribe(req, contract.gatewayName) #---------------------------------------------------------------------- - def sendOrder(self, algo, vtSymbol, direction, price, volume): + def sendOrder(self, algo, vtSymbol, direction, price, volume, + priceType=None, offset=None): """发单""" contract = self.mainEngine.getContract(vtSymbol) if not contract: @@ -153,24 +155,34 @@ class AlgoEngine(object): req.vtSymbol = vtSymbol req.symbol = contract.symbol req.exchange = contract.exchange - req.direction = direction - req.priceType = PRICETYPE_LIMITPRICE + req.direction = direction req.offset = OFFSET_CLOSETODAY req.price = price req.volume = volume + + if priceType: + req.priceType = priceType + else: + req.priceType = PRICETYPE_LIMITPRICE + + if offset: + req.offset = offset + else: + req.offset = OFFSET_OPEN + vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) return vtOrderID #---------------------------------------------------------------------- - def buy(self, algo, vtSymbol, price, volume): + def buy(self, algo, vtSymbol, price, volume, priceType=None, offset=None): """买入""" - return self.sendOrder(algo, vtSymbol, DIRECTION_LONG, price, volume) + return self.sendOrder(algo, vtSymbol, DIRECTION_LONG, price, volume, priceType, offset) #---------------------------------------------------------------------- - def sell(self, algo, vtSymbol, price, volume): + def sell(self, algo, vtSymbol, price, volume, priceType=None, offset=None): """卖出""" - return self.sendOrder(algo, vtSymbol, DIRECTION_SHORT, price, volume) + return self.sendOrder(algo, vtSymbol, DIRECTION_SHORT, price, volume, priceType, offset) #---------------------------------------------------------------------- def cancelOrder(self, algo, vtOrderID): diff --git a/vnpy/trader/app/algoTrading/algoTemplate.py b/vnpy/trader/app/algoTrading/algoTemplate.py index 29e89a2a..6e2865c6 100644 --- a/vnpy/trader/app/algoTrading/algoTemplate.py +++ b/vnpy/trader/app/algoTrading/algoTemplate.py @@ -111,14 +111,14 @@ class AlgoTemplate(object): self.engine.subscribe(self, vtSymbol) #---------------------------------------------------------------------- - def buy(self, vtSymbol, price, volume): + def buy(self, vtSymbol, price, volume, priceType=None, offset=None): """""" - return self.engine.buy(self, vtSymbol, price, volume) + return self.engine.buy(self, vtSymbol, price, volume, priceType, offset) #---------------------------------------------------------------------- - def sell(self, vtSymbol, price, volume): + def sell(self, vtSymbol, price, volume, priceType=None, offset=None): """""" - return self.engine.sell(self, vtSymbol, price, volume) + return self.engine.sell(self, vtSymbol, price, volume, priceType, offset) #---------------------------------------------------------------------- def cancelOrder(self, vtOrderID): diff --git a/vnpy/trader/app/algoTrading/dmaAlgo.py b/vnpy/trader/app/algoTrading/dmaAlgo.py new file mode 100644 index 00000000..753794f3 --- /dev/null +++ b/vnpy/trader/app/algoTrading/dmaAlgo.py @@ -0,0 +1,192 @@ +# encoding: UTF-8 + +from __future__ import division +from collections import OrderedDict + +from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT, + OFFSET_OPEN, OFFSET_CLOSE, + PRICETYPE_LIMITPRICE, PRICETYPE_MARKETPRICE, + STATUS_REJECTED, STATUS_CANCELLED, STATUS_ALLTRADED) +from vnpy.trader.uiQt import QtWidgets + +from .algoTemplate import AlgoTemplate +from .uiAlgoWidget import AlgoWidget, QtWidgets + + + +STATUS_FINISHED = set([STATUS_ALLTRADED, STATUS_CANCELLED, STATUS_REJECTED]) + + +######################################################################## +class DmaAlgo(AlgoTemplate): + """DMA算法,直接发出限价或者市价委托""" + + templateName = 'DMA' + + #---------------------------------------------------------------------- + def __init__(self, engine, setting, algoName): + """Constructor""" + super(DmaAlgo, self).__init__(engine, setting, algoName) + + # 参数,强制类型转换,保证从CSV加载的配置正确 + self.vtSymbol = str(setting['vtSymbol']) # 合约代码 + self.direction = unicode(setting['direction']) # 买卖 + self.offset = float(setting['offset']) # 开平 + self.priceType = float(setting['priceType']) # 价格类型 + self.price = float(setting['price']) # 价格 + self.totalVolume = int(setting['totalVolume']) # 数量 + + self.vtOrderID = '' # 委托号 + self.tradedVolume = 0 # 成交数量 + self.orderStatus = '' # 委托状态 + + self.subscribe(self.vtSymbol) + self.paramEvent() + self.varEvent() + + #---------------------------------------------------------------------- + def onTick(self, tick): + """""" + # 发出委托 + if not self.vtOrderID: + if self.direction == DIRECTION_LONG: + func = self.buy + else: + func = self.sell + + self.vtOrderID = func(self.vtSymbol, self.price, self.volume, + self.priceType, self.offset) + + # 更新变量 + 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.paramEvent() + + #---------------------------------------------------------------------- + def onTimer(self): + """""" + pass + + #---------------------------------------------------------------------- + def onStop(self): + """""" + if self.orderStatus not in STATUS_FINISHED: + self.cancelAll() + + # 处理这里的逻辑,区分用户停止和到期停止 + + self.writeLog(u'委托已%s,停止算法' %self.status) + + #---------------------------------------------------------------------- + def varEvent(self): + """更新变量""" + d = OrderedDict() + d[u'算法状态'] = self.active + d[u'委托号'] = self.vtOrderID + d[u'成交数量'] = self.tradedVolume + d[u'委托状态'] = self.orderStatus + 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.priceType + d[u'开平'] = self.offset + self.putParamEvent(d) + + +######################################################################## +class DmaWidget(AlgoWidget): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, parent=None): + """Constructor""" + super(DmaWidget, self).__init__(algoEngine, parent) + + self.templateName = DmaAlgo.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.comboPriceType = QtWidgets.QComboBox() + self.comboPriceType.addItems([PRICETYPE_LIMITPRICE, PRICETYPE_MARKETPRICE]) + self.comboPriceType.setCurrentIndex(0) + + self.comboOffset = QtWidgets.QComboBox() + self.comboOffset.addItems(['', OFFSET_OPEN, OFFSET_CLOSE]) + self.comboOffset.setCurrentIndex(0) + + 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.comboPriceType, 4, 1) + grid.addWidget(Label(u'开平'), 5, 0) + grid.addWidget(self.comboOffset, 5, 1) + + return grid + + #---------------------------------------------------------------------- + def getAlgoSetting(self): + """""" + setting = OrderedDict() + setting['templateName'] = DmaAlgo.templateName + setting['vtSymbol'] = str(self.lineSymbol.text()) + setting['direction'] = unicode(self.comboDirection.currentText()) + setting['price'] = float(self.spinPrice.value()) + setting['totalVolume'] = float(self.spinVolume.value()) + setting['priceType'] = unicode(self.comboPriceType.currentText()) + setting['offset'] = unicode(self.comboOffset.currentText()) + + 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 d3727136..d38d29af 100644 --- a/vnpy/trader/app/algoTrading/twapAlgo.py +++ b/vnpy/trader/app/algoTrading/twapAlgo.py @@ -152,7 +152,6 @@ 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 811d1b08..1e07c1ec 100644 --- a/vnpy/trader/app/algoTrading/uiAlgoManager.py +++ b/vnpy/trader/app/algoTrading/uiAlgoManager.py @@ -10,6 +10,7 @@ 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 ######################################################################## @@ -384,6 +385,7 @@ class AlgoManager(QtWidgets.QWidget): self.initUi() self.addAlgoWidget(TwapWidget) + self.addAlgoWidget(DmaWidget) self.algoEngine.loadAlgoSetting() # 界面初始化后,再加载算法配置