From 7cceddb2278f0390a4b1873fb1eb601d91886556 Mon Sep 17 00:00:00 2001 From: msincenselee Date: Fri, 23 Nov 2018 17:03:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/uiBasicWidget.py | 12 +- vnpy/trader/uiMainWindow.py | 1 + vnpy/trader/uiMultiRpcMonitor.py | 149 ++++++++++++++++------ vnpy/trader/vtEngine.py | 2 +- vnpy/trader/vtObject.py | 212 ++++++++++++++++++++++++++++++- 5 files changed, 330 insertions(+), 46 deletions(-) diff --git a/vnpy/trader/uiBasicWidget.py b/vnpy/trader/uiBasicWidget.py index 6bcf59b1..0bcd4612 100644 --- a/vnpy/trader/uiBasicWidget.py +++ b/vnpy/trader/uiBasicWidget.py @@ -1182,14 +1182,18 @@ class TradingWidget(QtWidgets.QFrame): pos = cell.data symbol = pos.symbol + # 拆分 合约.交易所接口 symbol_split_list = symbol.split('.') - if len(symbol_split_list)==2: - exchange_name = symbol_split_list[-1] - if exchange_name in [EXCHANGE_OKEX,EXCHANGE_BINANCE,EXCHANGE_HUOBI,EXCHANGE_GATEIO]: - symbol = symbol_split_list[0] + if len(symbol_split_list)==2: + # 交易所 + exchange_name = symbol_split_list[-1] + + # 数字货币类交易所 + if exchange_name in [EXCHANGE_OKEX,EXCHANGE_BINANCE,EXCHANGE_HUOBI,EXCHANGE_GATEIO]: symbol_pair_list = symbol.split('_') if len(symbol_pair_list) ==1: + # 获取合约 if symbol.lower() == 'usdt': return symbol = symbol_pair_list[0] + '_' + 'usdt'+'.'+symbol_split_list[-1] diff --git a/vnpy/trader/uiMainWindow.py b/vnpy/trader/uiMainWindow.py index 8388a0ca..607e0518 100644 --- a/vnpy/trader/uiMainWindow.py +++ b/vnpy/trader/uiMainWindow.py @@ -298,6 +298,7 @@ class MainWindow(QtWidgets.QMainWindow): return def connect(): + r = False try: r = self.mainEngine.connect(gatewayName) except: diff --git a/vnpy/trader/uiMultiRpcMonitor.py b/vnpy/trader/uiMultiRpcMonitor.py index 54b1b123..b605fb32 100644 --- a/vnpy/trader/uiMultiRpcMonitor.py +++ b/vnpy/trader/uiMultiRpcMonitor.py @@ -1,21 +1,19 @@ # encoding: UTF-8 -''' -多RPC监控界面组件 -Author: IncenseLee - -设计思路: -1、单一RPC监控组件,包括: - 1)连接 - 2)服务端状态监控(是否运行,gw名称,连接状态;操作:停止服务端,停止gw连接,启动gw连接) - 3)服务端策略状态监控(策略名称,ValueMonitor,信号。操作:启动策略,停止策略,初始化策略,强制初始化策略,特殊操作。。) - 4)服务器端Warning\Error\Nofification\Critical Log -2、多RPC监控容器,包括: - 1)从本地VT_Setting读取服务端连接信息。进行初始化和连接。 - 2)订阅相应Event - -''' +#多RPC监控界面组件 +#Author: IncenseLee +# +#设计思路: +#1、单一RPC监控组件,包括: +# 1)连接 +# 2)服务端状态监控(是否运行,gw名称,连接状态;操作:停止服务端,停止gw连接,启动gw连接) +# 3)服务端策略状态监控(策略名称,ValueMonitor,信号。操作:启动策略,停止策略,初始化策略,强制初始化策略,特殊操作。。) +# 4)服务器端Warning\Error\Nofification\Critical Log +#2、多RPC监控容器,包括: +# 1)从本地VT_Setting读取服务端连接信息。进行初始化和连接。 +# 2)订阅相应Event +# import os import sys @@ -90,12 +88,15 @@ class StrategyMonitorWidget(QtWidgets.QGroupBox): btnStopStrategy.clicked.connect(self.stop_strategy) btnForceInitStrategy = QtWidgets.QPushButton(u'ForceInit') btnForceInitStrategy.clicked.connect(self.force_init_strategy) + btnDispatchOutStrategy = QtWidgets.QPushButton(u'Dispatch Out') + btnDispatchOutStrategy.clicked.connect(self.remove_strategy) hbox1 = QtWidgets.QHBoxLayout() hbox1.addWidget(btnInitStrategy) hbox1.addWidget(btnStartStrategy) hbox1.addWidget(btnStopStrategy) hbox1.addWidget(btnForceInitStrategy) + #hbox1.addWidget(btnDispatchOutStrategy) hbox1.addStretch() # 策略的运行数据表 @@ -128,6 +129,14 @@ class StrategyMonitorWidget(QtWidgets.QGroupBox): if self.mainEngine: self.mainEngine.initStrategy(self.name, force=True) + def remove_strategy(self): + if self.mainEngine and hasattr(self.mainEngine,'removeStrategy'): + print('call removeStrategy({})'.format(self.name)) + self.mainEngine.removeStrategy(self.name) + else: + print('cant not call removeStrategy',file=sys.stderr) + + class CtaEngineMonitorWidget(QtWidgets.QWidget): """RPC 服务端CTA引擎监控组件 {策略名称,ValueMonitor;操作:启动策略,停止策略,初始化策略,强制初始化策略,特殊操作。。)} @@ -146,23 +155,27 @@ class CtaEngineMonitorWidget(QtWidgets.QWidget): self.initUi() self.initVarMonitors = False + self.monitor_vbox = None def setMainEngine(self,mainEngine): self.mainEngine = mainEngine def initUi(self): - btnLoadStrategies = QtWidgets.QPushButton(u'Load All Strategies') + btnStartStrategies = QtWidgets.QPushButton(u'Start All Strategies') btnStopStrategies = QtWidgets.QPushButton(u'Stop All Strategies') + btnAddStrategy = QtWidgets.QPushButton(u'Add Strategy') + - btnLoadStrategies.clicked.connect(self.load_all_strategies) btnStartStrategies.clicked.connect(self.start_all_strategies) btnStopStrategies.clicked.connect(self.stop_all_strategies) + btnAddStrategy.clicked.connect(self.add_new_strategy) hbox1 = QtWidgets.QHBoxLayout() - hbox1.addWidget(btnLoadStrategies) + hbox1.addWidget(btnStartStrategies) hbox1.addWidget(btnStopStrategies) + #hbox1.addWidget(btnAddStrategy) hbox1.addStretch() self.vbox = QtWidgets.QVBoxLayout() @@ -171,15 +184,65 @@ class CtaEngineMonitorWidget(QtWidgets.QWidget): self.setLayout(self.vbox) - def load_all_strategies(self): - if self.mainEngine: - pass def start_all_strategies(self): - pass + """ + 启动调度服务器内所有运行中的策略 + :return: + """ + if self.mainEngine and hasattr(self.mainEngine, 'startStrategy'): + for strategy_name in self.strategy_monitors.keys(): + try: + self.mainEngine.startStrategy(strategy_name) + except Exception as ex: + print(u'调用启动{}策略时发生异常:{},{}'.format(strategy_name, str(ex), traceback.format_exc())) + continue def stop_all_strategies(self): - pass + """ + 停止调度服务器内所有运行中的策略 + :return: + """ + if self.mainEngine and hasattr(self.mainEngine,'stopStrategy'): + for strategy_name in self.strategy_monitors.keys(): + try: + self.mainEngine.stopStrategy(strategy_name) + except Exception as ex: + print(u'调用停止{}策略时发生异常:{},{}'.format(strategy_name,str(ex), traceback.format_exc())) + continue + + def add_new_strategy(self): + """ + 添加新的cta策略配置到运行中的调度服务器 + :return: + """ + value, ok = QtWidgets.QInputDialog.getMultiLineText(self, "输入CTA策略设置", "ditc结构", "{\n\n\n}") + if not ok: + return + + if len(value) == 0: + return + + cta_setting = None + try: + cta_setting = json.loads(value) + except Exception as ex: + print(u'{}{}'.format(str(ex),traceback.format_exc()),file=sys.stderr) + return + + if not isinstance(cta_setting, dict): + print(u'输入得不是dict结构',file=sys.stderr) + return + + if cta_setting.get('name',None) == None or cta_setting.get('className',None) == None: + print(u'输入设置里面缺少name/className', file=sys.stderr) + return + + if self.mainEngine and hasattr(self.mainEngine, 'addStrategy'): + print('call addStrategy({})'.format(cta_setting)) + self.mainEngine.addStrategy(cta_setting) + else: + print('cant not call addStrategy:{}'.format(cta_setting), file=sys.stderr) def updateStatus(self, status_dict): """更新状态数据""" @@ -188,16 +251,16 @@ class CtaEngineMonitorWidget(QtWidgets.QWidget): if not self.initVarMonitors: w = QtWidgets.QWidget() - vbox = QtWidgets.QVBoxLayout() - for k, v in status_dict.items(): + self.monitor_vbox = QtWidgets.QVBoxLayout() + + strategy_names = status_dict.keys() + sorted_strategy_names = sorted(strategy_names) + for k in sorted_strategy_names: monitor = StrategyMonitorWidget(name=k, mainEngine=self.mainEngine, parent=self) - #height = 65 - #monitor.setFixedHeight(height) - self.strategy_monitors[k] = monitor - vbox.addWidget(monitor) + self.monitor_vbox.addWidget(monitor) - w.setLayout(vbox) + w.setLayout(self.monitor_vbox) self.scrollArea.setWidget(w) self.initVarMonitors = True @@ -205,6 +268,13 @@ class CtaEngineMonitorWidget(QtWidgets.QWidget): if k in self.strategy_monitors: monitor = self.strategy_monitors[k] monitor.updateStatus(v) + else: + monitor = StrategyMonitorWidget(name=k, mainEngine=self.mainEngine, parent=self) + self.strategy_monitors[k] = monitor + if self.monitor_vbox is not None: + self.monitor_vbox.addWidget(monitor) + monitor.updateStatus(v) + class ServerInfoWidget(QtWidgets.QWidget): """服务器信息显示组件 @@ -250,12 +320,11 @@ class AccountMonitorWidget(QtWidgets.QWidget): ######################################################################## class RpcServerMonitor(QtWidgets.QWidget): - """RPC服务端监控容器组件 - 1)连接服务端,gw名称, - 2)连接状态;操作:停止服务端,停止gw连接,启动gw连接) - 3)CtaEngineMonitorWidget - 4)RpcEventLogMonitor Warning\Error\Nofification\Critical Log - """ + #RPC服务端监控容器组件 + #1)连接服务端,gw名称, + #2)连接状态;操作:停止服务端,停止gw连接,启动gw连接) + #3)CtaEngineMonitorWidget + #4)RpcEventLogMonitor Warning\Error\Nofification\Critical Log signal = QtCore.Signal(type(Event())) @@ -274,7 +343,7 @@ class RpcServerMonitor(QtWidgets.QWidget): self.rpc_client = None self.mainEngine = None - self.server_info_monitor= None + self.server_info_monitor = None self.initUi() # ---------------------------------------------------------------------- @@ -429,7 +498,6 @@ class RpcServerMonitor(QtWidgets.QWidget): self.updateCritical(event) return - def updateStatus(self,event): """更新Status""" status_dict = event.dict_['data'] @@ -553,16 +621,17 @@ class MultiRpcServerManager(QtWidgets.QMainWindow): except Exception as ex: traceback.print_exc() QtWidgets.QMessageBox.warning(self, 'Exception',u'Load vt_Setting.json Exception', QtWidgets.QMessageBox.Cancel, - QtWidgets.QMessageBox.NoButton, QtGui.QMessageBox.NoButton) + QtWidgets.QMessageBox.NoButton) return def closeEvent(self, event): """关闭窗口时的事件""" + self.mdi.closeAllSubWindows() + event.accept() sys.exit(0) - def main(): from vnpy.trader.uiQt import createQApp diff --git a/vnpy/trader/vtEngine.py b/vnpy/trader/vtEngine.py index d6554e3f..09dcf920 100644 --- a/vnpy/trader/vtEngine.py +++ b/vnpy/trader/vtEngine.py @@ -1,6 +1,6 @@ # encoding: UTF-8 -print('load vtEngine.py') +print(u'启动load vtEngine.py') import shelve from collections import OrderedDict diff --git a/vnpy/trader/vtObject.py b/vnpy/trader/vtObject.py index a94266b0..ba5ec3b0 100644 --- a/vnpy/trader/vtObject.py +++ b/vnpy/trader/vtObject.py @@ -6,7 +6,7 @@ from datetime import datetime from vnpy.trader.vtConstant import (EMPTY_STRING, EMPTY_UNICODE, EMPTY_FLOAT, EMPTY_INT) - +from vnpy.trader.language import constant ######################################################################## class VtBaseData(object): @@ -77,6 +77,35 @@ class VtTickData(VtBaseData): self.askVolume4 = EMPTY_FLOAT self.askVolume5 = EMPTY_FLOAT + #---------------------------------------------------------------------- + @staticmethod + def createFromGateway(gateway, symbol, exchange, + lastPrice, lastVolume, + highPrice, lowPrice, + openPrice=EMPTY_FLOAT, + openInterest=EMPTY_INT, + upperLimit=EMPTY_FLOAT, + lowerLimit=EMPTY_FLOAT): + tick = VtTickData() + tick.gatewayName = gateway.gatewayName + tick.symbol = symbol + tick.exchange = exchange + tick.vtSymbol = symbol + '.' + exchange + + tick.lastPrice = lastPrice + tick.lastVolume = lastVolume + tick.openInterest = openInterest + tick.datetime = datetime.now() + tick.date = tick.datetime.strftime('%Y%m%d') + tick.time = tick.datetime.strftime('%H:%M:%S') + + tick.openPrice = openPrice + tick.highPrice = highPrice + tick.lowPrice = lowPrice + tick.upperLimit = upperLimit + tick.lowerLimit = lowerLimit + return tick + ######################################################################## class VtBarData(VtBaseData): @@ -130,6 +159,48 @@ class VtTradeData(VtBaseData): self.volume = EMPTY_FLOAT # 成交数量 self.tradeTime = EMPTY_STRING # 成交时间 + #---------------------------------------------------------------------- + @staticmethod + def createFromGateway(gateway, symbol, exchange, tradeID, orderID, direction, tradePrice, tradeVolume): + trade = VtTradeData() + trade.gatewayName = gateway.gatewayName + trade.symbol = symbol + trade.exchange = exchange + trade.vtSymbol = symbol + '.' + exchange + + trade.orderID = orderID + trade.vtOrderID = trade.gatewayName + '.' + trade.tradeID + + trade.tradeID = tradeID + trade.vtTradeID = trade.gatewayName + '.' + tradeID + + trade.direction = direction + trade.price = tradePrice + trade.volume = tradeVolume + trade.tradeTime = datetime.now().strftime('%H:%M:%S') + return trade + + #---------------------------------------------------------------------- + @staticmethod + def createFromOrderData(order, + tradeID, + tradePrice, + tradeVolume): # type: (VtOrderData, str, float, float)->VtTradeData + trade = VtTradeData() + trade.gatewayName = order.gatewayName + trade.symbol = order.symbol + trade.vtSymbol = order.vtSymbol + + trade.orderID = order.orderID + trade.vtOrderID = order.vtOrderID + trade.tradeID = tradeID + trade.vtTradeID = trade.gatewayName + '.' + tradeID + trade.direction = order.direction + trade.price = tradePrice + trade.volume = tradeVolume + trade.tradeTime = datetime.now().strftime('%H:%M:%S') + return trade + ######################################################################## class VtOrderData(VtBaseData): @@ -164,6 +235,39 @@ class VtOrderData(VtBaseData): self.frontID = EMPTY_INT # 前置机编号 self.sessionID = EMPTY_INT # 连接编号 + #---------------------------------------------------------------------- + @staticmethod + def createFromGateway(gateway, # type: VtGateway + orderId, # type: str + symbol, # type: str + exchange, # type: str + price, # type: float + volume, # type: int + direction, # type: str + offset=EMPTY_UNICODE, # type: str + tradedVolume=EMPTY_INT, # type: int + status=constant.STATUS_UNKNOWN, # type: str + orderTime=EMPTY_UNICODE, # type: str + cancelTime=EMPTY_UNICODE, # type: str + ): # type: (...)->VtOrderData + vtOrder = VtOrderData() + vtOrder.gatewayName = gateway.gatewayName + vtOrder.symbol = symbol + vtOrder.exchange = exchange + vtOrder.vtSymbol = symbol + '.' + exchange + vtOrder.orderID = orderId + vtOrder.vtOrderID = gateway.gatewayName + '.' + orderId + + vtOrder.direction = direction + vtOrder.offset = offset + vtOrder.price = price + vtOrder.totalVolume = volume + vtOrder.tradedVolume = tradedVolume + vtOrder.status = status + vtOrder.orderTime = orderTime + vtOrder.cancelTime = cancelTime + return vtOrder + ######################################################################## class VtPositionData(VtBaseData): @@ -188,6 +292,33 @@ class VtPositionData(VtBaseData): self.ydPosition = EMPTY_INT # 昨持仓 self.positionProfit = EMPTY_FLOAT # 持仓盈亏 + #---------------------------------------------------------------------- + @staticmethod + def createFromGateway(gateway, # type: VtGateway + exchange, # type: str + symbol, # type: str + direction, # type: str + position, # type: int + frozen=EMPTY_INT, # type: int + price=EMPTY_FLOAT, # type: float + yestordayPosition=EMPTY_INT, # type: int + profit=EMPTY_FLOAT # type: float + ): # type: (...)->VtPositionData + vtPosition = VtPositionData() + vtPosition.gatewayName = gateway.gatewayName + vtPosition.symbol = symbol + vtPosition.exchange = exchange + vtPosition.vtSymbol = symbol + '.' + exchange + + vtPosition.direction = direction + vtPosition.position = position + vtPosition.frozen = frozen + vtPosition.price = price + vtPosition.vtPositionName = vtPosition.vtSymbol + '.' + direction + vtPosition.ydPosition = yestordayPosition + vtPosition.positionProfit = profit + return vtPosition + ######################################################################## class VtAccountData(VtBaseData): @@ -281,9 +412,56 @@ class VtContractData(VtBaseData): self.strikePrice = EMPTY_FLOAT # 期权行权价 self.underlyingSymbol = EMPTY_STRING # 标的物合约代码 self.optionType = EMPTY_UNICODE # 期权类型 + self.expiryDate = EMPTY_STRING # 到期日 # 数字货币有关 self.volumeTick = EMPTY_FLOAT #合约最小交易量 + # ---------------------------------------------------------------------- + @staticmethod + def createFromGateway(gateway, + exchange, + symbol, + productClass, + size, + priceTick, + name=None, + strikePrice=EMPTY_FLOAT, + underlyingSymbol=EMPTY_STRING, + optionType=EMPTY_UNICODE, + expiryDate=EMPTY_STRING + ): + d = VtContractData() + d.gatewayName = gateway.gatewayName + d.symbol = symbol + d.exchange = exchange + d.vtSymbol = symbol + '.' + exchange + d.productClass = productClass + d.size = size + d.priceTick = priceTick + if name is None: + d.name = d.symbol + d.strikePrice = strikePrice + d.underlyingSymbol = underlyingSymbol + d.optionType = optionType + d.expiryDate = expiryDate + return d + + +######################################################################## +class VtHistoryData(object): + """K线时间序列数据""" + + #---------------------------------------------------------------------- + def __init__(self): + """Constructor""" + self.vtSymbol = EMPTY_STRING # vt系统代码 + self.symbol = EMPTY_STRING # 代码 + self.exchange = EMPTY_STRING # 交易所 + + self.interval = EMPTY_UNICODE # K线时间周期 + self.queryID = EMPTY_STRING # 查询号 + self.barList = [] # VtBarData列表 + ######################################################################## class VtSubscribeReq(object): @@ -346,3 +524,35 @@ class VtCancelOrderReq(object): self.frontID = EMPTY_STRING # 前置机号 self.sessionID = EMPTY_STRING # 会话号 + +######################################################################## +class VtHistoryReq(object): + """查询历史数据时传入的对象类""" + + #---------------------------------------------------------------------- + def __init__(self): + """Constructor""" + self.symbol = EMPTY_STRING # 代码 + self.exchange = EMPTY_STRING # 交易所 + self.vtSymbol = EMPTY_STRING # VT合约代码 + + self.interval = EMPTY_UNICODE # K线周期 + self.start = None # 起始时间datetime对象 + self.end = None # 结束时间datetime对象 + + +######################################################################## +class VtSingleton(type): + """ + 单例,应用方式:静态变量 __metaclass__ = Singleton + """ + + _instances = {} + + #---------------------------------------------------------------------- + def __call__(cls, *args, **kwargs): + """调用""" + if cls not in cls._instances: + cls._instances[cls] = super(VtSingleton, cls).__call__(*args, **kwargs) + + return cls._instances[cls]