[Add]新增AlgoTrading算法交易模块
This commit is contained in:
parent
08e836b070
commit
8b1bc4e2ea
12
vnpy/trader/app/algoTrading/__init__.py
Normal file
12
vnpy/trader/app/algoTrading/__init__.py
Normal file
@ -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'
|
221
vnpy/trader/app/algoTrading/algoEngine.py
Normal file
221
vnpy/trader/app/algoTrading/algoEngine.py
Normal file
@ -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
|
||||
|
168
vnpy/trader/app/algoTrading/algoTemplate.py
Normal file
168
vnpy/trader/app/algoTrading/algoTemplate.py
Normal file
@ -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)
|
||||
|
||||
|
232
vnpy/trader/app/algoTrading/twapAlgo.py
Normal file
232
vnpy/trader/app/algoTrading/twapAlgo.py
Normal file
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
243
vnpy/trader/app/algoTrading/uiAlgoManager.py
Normal file
243
vnpy/trader/app/algoTrading/uiAlgoManager.py
Normal file
@ -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)
|
Loading…
Reference in New Issue
Block a user