Merge pull request #253 from ares89/master

在行情订阅中,增加了编辑订阅合约的功能
This commit is contained in:
vn.py 2017-03-08 22:50:08 +08:00 committed by GitHub
commit f2dba02243
8 changed files with 881 additions and 229 deletions

View File

@ -1,31 +1,91 @@
{
"working": false,
"tick":
[
["m1609", "XSPEED"],
["IF1606", "SGIT"],
["IH1606", "SGIT"],
["IH1606", "SGIT"],
["IC1606", "SGIT"],
["IC1606", "SGIT"],
["600036", "LTS", "SZSE"],
["EUR.USD", "IB", "IDEALPRO", "USD", "外汇"]
"working": true,
"tick": [
[
"au1706",
"CTP"
],
[
"a1705",
"CTP"
],
[
"m1705",
"CTP"
],
[
"bu1706",
"CTP"
],
[
"SR705",
"CTP"
],
[
"TA705",
"CTP"
],
[
"MA705",
"CTP"
],
[
"RM705",
"CTP"
],
[
"FG705",
"CTP"
],
[
"OI705",
"CTP"
]
],
"bar":
[
["IF1605", "SGIT"],
["IF1606", "SGIT"],
["IH1606", "SGIT"],
["IH1606", "SGIT"],
["IC1606", "SGIT"],
["IC1606", "SGIT"]
"bar": [
[
"au1706",
"CTP"
],
[
"a1705",
"CTP"
],
[
"m1705",
"CTP"
],
[
"bu1706",
"CTP"
],
[
"SR705",
"CTP"
],
[
"TA705",
"CTP"
],
[
"MA705",
"CTP"
],
[
"RM705",
"CTP"
],
[
"FG705",
"CTP"
],
[
"OI705",
"CTP"
]
],
"active":
{
"IF0000": "IF1605",
"active": {
"IF0000": "IF1605",
"IH0000": "IH1605",
"IC0000": "IC1605"
}

View File

@ -6,18 +6,15 @@
使用DR_setting.json来配置需要收集的合约以及主力合约代码
'''
import copy
import json
import os
import copy
from collections import OrderedDict
from datetime import datetime, timedelta
from Queue import Queue
from threading import Thread
from datetime import datetime
from eventEngine import *
from vtGateway import VtSubscribeReq, VtLogData
from drBase import *
from eventEngine import *
from vtFunction import todayDate
from vtGateway import VtSubscribeReq, VtLogData
########################################################################
@ -53,6 +50,17 @@ class DrEngine(object):
# 载入设置,订阅行情
self.loadSetting()
def saveSetting(self, setting):
"""保存设置"""
setting['working'] = self.working
with open(self.settingFileName, 'w') as f:
try:
str = json.dumps(setting, indent=2)
f.write(str)
except:
pass
return True
#----------------------------------------------------------------------
def loadSetting(self):
@ -61,8 +69,8 @@ class DrEngine(object):
drSetting = json.load(f)
# 如果working设为False则不启动行情记录功能
working = drSetting['working']
if not working:
self.working = drSetting['working']
if not self.working:
return
if 'tick' in drSetting:

View File

@ -0,0 +1,400 @@
# encoding: UTF-8
'''
行情记录模块相关的GUI控制组件
'''
import json
import re
import sys
from PyQt4.QtGui import QTreeView
from dataRecorder.drEngine import DrEngine
from eventEngine import *
from uiBasicWidget import QtGui, QtCore
from util.UiUtil import CheckBoxDelegate, ComboDelegate
reload(sys)
sys.setdefaultencoding("utf8")
class TreeItem(object):
def __init__(self, data, parent=None):
self.parentItem = parent
self.itemData = data
self.childItems = []
def appendChild(self, item):
self.childItems.append(item)
def extendChild(self, item):
self.childItems.extend(item)
def child(self, row):
return self.childItems[row]
def childCount(self):
return len(self.childItems)
def columnCount(self):
return len(self.itemData)
def data(self, column):
try:
return self.itemData[column]
except IndexError:
return None
def parent(self):
return self.parentItem
def row(self):
if self.parentItem:
return self.parentItem.childItems.index(self)
return 0
def setData(self, column, value):
if column < 0 or column >= len(self.itemData):
return False
self.itemData[column] = value
return True
class TreeModel(QtCore.QAbstractItemModel):
def __init__(self, parent=None):
super(TreeModel, self).__init__(parent)
self.rootItem = TreeItem([u"合约", u"Tick", u"Bar", u"主力", u"交易所", u"接口"])
def rootItem(self):
return self.rootItem
def setDataSource(self, data):
self.rootItem.extendChild(data)
def columnCount(self, parent):
if parent.isValid():
return parent.internalPointer().columnCount()
else:
return self.rootItem.columnCount()
def setData(self, index, value, role=None):
item = index.internalPointer()
if item is None:
return False
if index.column() == 5:
result = item.setData(index.column(), value)
if result:
self.dataChanged.emit(index, index)
# 如果第一条
if item.parentItem == self.rootItem:
for row in range(item.childCount()):
childIndex = self.index(row, index.column(), index)
self.setData(childIndex, value, QtCore.Qt.DisplayRole)
if index.column() in [1, 2, 3] and role == QtCore.Qt.CheckStateRole:
result = item.setData(index.column(), True if value == QtCore.Qt.Checked else False)
if result:
self.dataChanged.emit(index, index)
# 如果第一条
if item.parentItem == self.rootItem and index.column() in [1, 2]:
for row in range(item.childCount()):
childIndex = self.index(row, index.column(), index)
self.setData(childIndex, value, QtCore.Qt.CheckStateRole)
if value == QtCore.Qt.Checked and index.column() == 3:
for row in range(item.parentItem.childCount()):
if row != index.row():
siblingIndex = self.index(row, index.column(), index.parent())
self.setData(siblingIndex, QtCore.Qt.Unchecked, QtCore.Qt.CheckStateRole)
return True
def data(self, index, role):
if not index.isValid():
return None
item = index.internalPointer()
if role == QtCore.Qt.TextAlignmentRole:
return QtCore.Qt.AlignCenter
if role == QtCore.Qt.CheckStateRole and (
index.column() in [1, 2] or index.column() == 3 and item.parentItem != self.rootItem):
return QtCore.Qt.Checked if item.data(index.column()) == True else QtCore.Qt.Unchecked
if role != QtCore.Qt.DisplayRole or index.column() in [3, 4] and item.parentItem == self.rootItem:
return None
return item.data(index.column())
def flags(self, index):
if not index.isValid():
return QtCore.Qt.NoItemFlags
if index.column() in [0, 4]:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
if index.column() in [5]:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
item = index.internalPointer()
if index.column() == 3 and item.parentItem == self.rootItem:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEditable
def headerData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal:
if role == QtCore.Qt.DisplayRole:
return self.rootItem.data(section)
elif role == QtCore.Qt.TextAlignmentRole:
return QtCore.Qt.AlignCenter
return None
def index(self, row, column, parent):
if not self.hasIndex(row, column, parent):
return QtCore.QModelIndex()
if parent is None or not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
childItem = parentItem.child(row)
if childItem:
return self.createIndex(row, column, childItem)
else:
return QtCore.QModelIndex()
def parent(self, index):
if not index.isValid():
return QtCore.QModelIndex()
childItem = index.internalPointer()
parentItem = childItem.parent()
if parentItem == self.rootItem:
return QtCore.QModelIndex()
return self.createIndex(parentItem.row(), 0, parentItem)
def rowCount(self, parent):
if parent.column() > 0:
return 0
if not parent.isValid():
parentItem = self.rootItem
else:
parentItem = parent.internalPointer()
return parentItem.childCount()
def hasIndex(self, row, column, parentIndex=None, *args, **kwargs):
if row < 0 or column > self.rootItem.columnCount():
return False
return True
class DrEditWidget(QtGui.QWidget):
"""行情数据记录引擎管理组件"""
signal = QtCore.pyqtSignal(type(Event()))
def __init__(self, drWidget, mainEngine, eventEngine, parent=None):
"""Constructor"""
super(DrEditWidget, self).__init__(parent)
self.drWidget = drWidget
self.mainEngine = mainEngine
self.eventEngine = eventEngine
self.hasChanged = False
# 保存合约详细信息的字典
self.contractDict = {}
self.initUi()
self.updateSetting()
self.loadData()
self.registerEvent()
def closeEvent(self, QCloseEvent):
if self.hasChanged:
self.drWidget.restart()
def initUi(self):
vbox = QtGui.QVBoxLayout()
vline = QtGui.QHBoxLayout()
vline.setSpacing(2)
btnTickAll = QtGui.QPushButton(u"全部记录Tick", self)
btnBarAll = QtGui.QPushButton(u'全部记录Bar', self)
btnSaveAll = QtGui.QPushButton(u'保存设置(重启后生效)', self)
btnTickAll.clicked.connect(self.selectAllTick)
btnBarAll.clicked.connect(self.selectAllBar)
btnSaveAll.clicked.connect(self.saveSetting)
vline.addWidget(btnTickAll)
vline.addWidget(btnBarAll)
vline.addWidget(btnSaveAll)
vbox.addLayout(vline)
self.qTreeView = QTreeView()
self.model = TreeModel()
self.qTreeView.setModel(self.model)
self.qTreeView.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.qTreeView.setItemDelegateForColumn(1, CheckBoxDelegate(self))
self.qTreeView.setItemDelegateForColumn(2, CheckBoxDelegate(self))
self.qTreeView.setItemDelegateForColumn(3, CheckBoxDelegate(self))
self.qTreeView.setItemDelegateForColumn(5, ComboDelegate(self, ["CTP", "LTS", "XTP", "FEMAS", "XSPEED", "QDP",
"KSOTP", "KSGOLD", "SGIT"]))
vbox.addWidget(self.qTreeView)
self.setLayout(vbox)
def getContractChineseName(self, str):
line = str.strip().decode('utf-8', 'ignore') # 处理前进行相关的处理包括转换成Unicode等
p2 = re.compile(ur'[^\u4e00-\u9fa5]') # 中文的编码范围是:\u4e00到\u9fa5
zh = " ".join(p2.split(line)).strip()
zh = ",".join(zh.split())
outStr = zh # 经过相关处理后得到中文的文本
return outStr
def loadData(self):
child = []
tick = {}
bar = {}
active = []
with open(self.mainEngine.drEngine.settingFileName) as f:
drSetting = json.load(f)
if 'tick' in drSetting:
l = drSetting['tick']
for setting in l:
tick[setting[0]] = setting[1]
if 'bar' in drSetting:
l = drSetting['bar']
for setting in l:
bar[setting[0]] = setting[1]
if 'active' in drSetting:
d = drSetting['active']
for activeSymbol, symbol in d.items():
active.append(symbol)
contractDict = {}
contracts = self.mainEngine.getAllContracts()
for contract in contracts:
contractName = self.getContractChineseName(contract.name)
gateWayName = u"CTP"
hasTick = tick.has_key(contract.symbol)
hasBar = bar.has_key(contract.symbol)
hasActive = contract.symbol in active
if hasTick:
gateWayName = tick[contract.symbol]
elif hasBar:
gateWayName = bar[contract.symbol]
if contractDict.has_key(contractName):
parentItem = contractDict[contractName]
item = TreeItem([contract.symbol, hasTick, hasBar, hasActive, contract.exchange, gateWayName],
parentItem)
parentItem.appendChild(item)
else:
item = TreeItem([contractName, False, False, False, contract.exchange, gateWayName],
self.model.rootItem)
contractDict[contractName] = item
child.append(item)
subItem = TreeItem([contract.symbol, hasTick, hasBar, hasActive, contract.exchange, gateWayName], item)
item.appendChild(subItem)
# yumi = TreeItem([u"玉米", False, False, False, "SH", "CTP"], self.model.rootItem)
# yumi.appendChild(TreeItem([u"c1705", False, False, False, "SH", "CTP"], yumi))
# yumi.appendChild(TreeItem([u"c1703", False, False, False, "SH", "CTP"], yumi))
# yumi.appendChild(TreeItem([u"c1707", False, False, False, "SH", "CTP"], yumi))
# yumi.appendChild(TreeItem([u"c1709", False, False, False, "SH", "CTP"], yumi))
# dianfen = TreeItem([u"淀粉", False, False, False, "SH", "CTP"], self.model.rootItem)
# dianfen.appendChild(TreeItem([u"d1705", False, False, False, "SH", "CTP"], dianfen))
# dianfen.appendChild(TreeItem([u"d1703", False, False, False, "SH", "CTP"], dianfen))
# dianfen.appendChild(TreeItem([u"d1707", False, False, False, "SH", "CTP"], dianfen))
# dianfen.appendChild(TreeItem([u"d1709", False, False, False, "SH", "CTP"], dianfen))
#
# child.append(yumi)
# child.append(dianfen)
self.model.setDataSource(child)
self.qTreeView.expandAll()
def saveSetting(self):
setting = {}
setting["tick"] = []
setting["bar"] = []
setting["active"] = {}
queue = Queue()
queue.put(self.model.rootItem)
while queue.qsize() > 0:
item = queue.get()
for child in item.childItems:
queue.put(child)
if item.parentItem is not None and item.parentItem != self.model.rootItem:
name = item.data(0)
interface = item.data(5)
if item.data(1):
setting["tick"].append([name, interface])
if item.data(2):
setting["bar"].append([name, interface])
if item.data(3):
setting["active"][item.parentItem.data(0)] = name
if self.mainEngine.drEngine.saveSetting(setting):
self.hasChanged = True
self.close()
def selectAllTick(self):
self.selectAll(True, False, True)
def selectAllBar(self):
self.selectAll(False, True, True)
def selectAll(self, tick=False, bar=False, select=False):
column = None
if tick:
column = 1
if bar:
column = 2
for row in range(self.model.rootItem.childCount()):
childIndex = self.model.index(row, column, None)
self.model.setData(childIndex, QtCore.Qt.Unchecked if select == False else QtCore.Qt.Checked,
QtCore.Qt.CheckStateRole)
def updateSetting(self):
pass
def updateContract(self, event):
"""更新合约数据"""
contract = event.dict_['data']
self.contractDict[contract.vtSymbol] = contract
self.contractDict[contract.symbol] = contract # 使用常规代码(不包括交易所)可能导致重复
# ----------------------------------------------------------------------
def registerEvent(self):
"""注册事件监听"""
self.signal.connect(self.updateContract)
self.eventEngine.register(EVENT_CONTRACT, self.signal.emit)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
view = DrEditWidget(None, DrEngine, EventEngine)
view.setFixedSize(650, 500)
view.show()
sys.exit(app.exec_())

View File

@ -6,8 +6,9 @@
import json
from uiBasicWidget import QtGui, QtCore
from dataRecorder.uiDrEdit import DrEditWidget
from eventEngine import *
from uiBasicWidget import QtGui, QtCore
########################################################################
@ -38,22 +39,23 @@ class DrEngineManager(QtGui.QWidget):
signal = QtCore.pyqtSignal(type(Event()))
#----------------------------------------------------------------------
def __init__(self, drEngine, eventEngine, parent=None):
def __init__(self, mainEngine, eventEngine, parent=None):
"""Constructor"""
super(DrEngineManager, self).__init__(parent)
self.drEngine = drEngine
self.mainEngine = mainEngine
self.drEngine = mainEngine.drEngine
self.eventEngine = eventEngine
self.initUi()
self.updateSetting()
self.registerEvent()
self.registerEvent()
#----------------------------------------------------------------------
def initUi(self):
"""初始化界面"""
self.setWindowTitle(u'行情数据记录工具')
# 记录合约配置监控
tickLabel = QtGui.QLabel(u'Tick记录')
self.tickTable = QtGui.QTableWidget()
@ -63,14 +65,14 @@ class DrEngineManager(QtGui.QWidget):
self.tickTable.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
self.tickTable.setAlternatingRowColors(True)
self.tickTable.setHorizontalHeaderLabels([u'合约代码', u'接口'])
barLabel = QtGui.QLabel(u'Bar记录')
self.barTable = QtGui.QTableWidget()
self.barTable.setColumnCount(2)
self.barTable.verticalHeader().setVisible(False)
self.barTable.setEditTriggers(QtGui.QTableWidget.NoEditTriggers)
self.barTable.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
self.barTable.setAlternatingRowColors(True)
self.barTable.setAlternatingRowColors(True)
self.barTable.setHorizontalHeaderLabels([u'合约代码', u'接口'])
activeLabel = QtGui.QLabel(u'主力合约')
@ -79,77 +81,99 @@ class DrEngineManager(QtGui.QWidget):
self.activeTable.verticalHeader().setVisible(False)
self.activeTable.setEditTriggers(QtGui.QTableWidget.NoEditTriggers)
self.activeTable.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
self.activeTable.setAlternatingRowColors(True)
self.activeTable.setAlternatingRowColors(True)
self.activeTable.setHorizontalHeaderLabels([u'主力代码', u'合约代码'])
# 日志监控
self.logMonitor = QtGui.QTextEdit()
self.logMonitor.setReadOnly(True)
self.logMonitor.setMinimumHeight(600)
# 设置布局
grid = QtGui.QGridLayout()
grid.addWidget(tickLabel, 0, 0)
grid.addWidget(barLabel, 0, 1)
grid.addWidget(activeLabel, 0, 2)
grid.addWidget(self.tickTable, 1, 0)
grid.addWidget(self.barTable, 1, 1)
grid.addWidget(self.activeTable, 1, 2)
grid.addWidget(self.activeTable, 1, 2)
btnEdit = QtGui.QPushButton(u'编辑', self)
vbox = QtGui.QVBoxLayout()
vbox.addLayout(grid)
vline = QtGui.QHBoxLayout()
vline.addWidget(btnEdit)
vbox.addLayout(vline)
vbox.addWidget(self.logMonitor)
self.setLayout(vbox)
btnEdit.clicked.connect(self.openDr)
#----------------------------------------------------------------------
def updateLog(self, event):
"""更新日志"""
log = event.dict_['data']
content = '\t'.join([log.logTime, log.logContent])
self.logMonitor.append(content)
#----------------------------------------------------------------------
def registerEvent(self):
"""注册事件监听"""
self.signal.connect(self.updateLog)
self.eventEngine.register(EVENT_DATARECORDER_LOG, self.signal.emit)
#----------------------------------------------------------------------
def updateSetting(self):
"""显示引擎行情记录配置"""
self.tickTable.clearContents()
self.tickTable.setRowCount(0)
self.barTable.clearContents()
self.barTable.setRowCount(0)
self.activeTable.clearContents()
self.activeTable.setRowCount(0)
with open(self.drEngine.settingFileName) as f:
drSetting = json.load(f)
if 'tick' in drSetting:
l = drSetting['tick']
for setting in l:
self.tickTable.insertRow(0)
self.tickTable.setItem(0, 0, TableCell(setting[0]))
self.tickTable.setItem(0, 1, TableCell(setting[1]))
if 'bar' in drSetting:
l = drSetting['bar']
for setting in l:
self.barTable.insertRow(0)
self.barTable.setItem(0, 0, TableCell(setting[0]))
self.barTable.setItem(0, 1, TableCell(setting[1]))
self.barTable.setItem(0, 1, TableCell(setting[1]))
if 'active' in drSetting:
d = drSetting['active']
for activeSymbol, symbol in d.items():
self.activeTable.insertRow(0)
self.activeTable.setItem(0, 0, TableCell(activeSymbol))
self.activeTable.setItem(0, 1, TableCell(symbol))
# ----------------------------------------------------------------------
def openDr(self):
"""打开行情数据记录组件"""
self.mDrEditWidget = DrEditWidget(self,self.mainEngine, self.eventEngine)
self.mDrEditWidget.setWindowTitle(u"编辑订阅")
self.mDrEditWidget.setFixedSize(800,800)
self.mDrEditWidget.show()
def restart(self):
pass
# self.drEngine.stop()
# self.updateSetting()
# self.mainEngine.drEngine = DrEngine(self.mainEngine, self.mainEngine.eventEngine)

View File

@ -1,13 +1,11 @@
# encoding: UTF-8
import json
import csv
import os
from collections import OrderedDict
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import Qt
from eventEngine import *
from vtFunction import *
from vtGateway import *
@ -16,9 +14,9 @@ from vtGateway import *
def loadFont():
"""载入字体设置"""
fileName = 'VT_setting.json'
path = os.path.abspath(os.path.dirname(__file__))
fileName = os.path.join(path, fileName)
path = os.path.abspath(os.path.dirname(__file__))
fileName = os.path.join(path, fileName)
try:
f = file(fileName)
setting = json.load(f)
@ -43,7 +41,7 @@ class BasicCell(QtGui.QTableWidgetItem):
self.data = None
if text:
self.setContent(text)
#----------------------------------------------------------------------
def setContent(self, text):
"""设置内容"""
@ -53,6 +51,22 @@ class BasicCell(QtGui.QTableWidgetItem):
self.setText(text)
########################################################################
class CheckBoxCell(QtGui.QTableWidgetItem):
"""用来显示复选框的单元格"""
def __init__(self, isChecked=False, mainEngine=None):
"""Constructor"""
super(CheckBoxCell, self).__init__()
self.setFlags(QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
self.setStauts(isChecked)
def setStauts(self, isChecked=False):
if not isChecked:
self.setCheckState(Qt.Unchecked)
else:
self.setCheckState(Qt.Checked)
########################################################################
class NumCell(QtGui.QTableWidgetItem):
"""用来显示数字的单元格"""
@ -64,7 +78,7 @@ class NumCell(QtGui.QTableWidgetItem):
self.data = None
if text:
self.setContent(text)
#----------------------------------------------------------------------
def setContent(self, text):
"""设置内容"""
@ -76,7 +90,7 @@ class NumCell(QtGui.QTableWidgetItem):
self.setData(QtCore.Qt.DisplayRole, num)
except ValueError:
self.setText(text)
########################################################################
class DirectionCell(QtGui.QTableWidgetItem):
@ -89,7 +103,7 @@ class DirectionCell(QtGui.QTableWidgetItem):
self.data = None
if text:
self.setContent(text)
#----------------------------------------------------------------------
def setContent(self, text):
"""设置内容"""
@ -108,20 +122,20 @@ class NameCell(QtGui.QTableWidgetItem):
def __init__(self, text=None, mainEngine=None):
"""Constructor"""
super(NameCell, self).__init__()
self.mainEngine = mainEngine
self.data = None
if text:
self.setContent(text)
#----------------------------------------------------------------------
def setContent(self, text):
"""设置内容"""
if self.mainEngine:
# 首先尝试正常获取合约对象
contract = self.mainEngine.getContract(text)
# 如果能读取合约信息
if contract:
self.setText(contract.name)
@ -139,10 +153,10 @@ class BidCell(QtGui.QTableWidgetItem):
self.setForeground(QtGui.QColor('black'))
self.setBackground(QtGui.QColor(255,174,201))
if text:
self.setContent(text)
#----------------------------------------------------------------------
def setContent(self, text):
"""设置内容"""
@ -161,10 +175,10 @@ class AskCell(QtGui.QTableWidgetItem):
self.setForeground(QtGui.QColor('black'))
self.setBackground(QtGui.QColor(160,255,160))
if text:
self.setContent(text)
#----------------------------------------------------------------------
def setContent(self, text):
"""设置内容"""
@ -175,10 +189,10 @@ class AskCell(QtGui.QTableWidgetItem):
class BasicMonitor(QtGui.QTableWidget):
"""
基础监控
headerDict中的值对应的字典格式如下
{'chinese': u'中文名', 'cellType': BasicCell}
"""
signal = QtCore.pyqtSignal(type(Event()))
@ -186,79 +200,79 @@ class BasicMonitor(QtGui.QTableWidget):
def __init__(self, mainEngine=None, eventEngine=None, parent=None):
"""Constructor"""
super(BasicMonitor, self).__init__(parent)
self.mainEngine = mainEngine
self.eventEngine = eventEngine
# 保存表头标签用
self.headerDict = OrderedDict() # 有序字典key是英文名value是对应的配置字典
self.headerList = [] # 对应self.headerDict.keys()
# 保存相关数据用
self.dataDict = {} # 字典key是字段对应的数据value是保存相关单元格的字典
self.dataKey = '' # 字典键对应的数据字段
# 监控的事件类型
self.eventType = ''
# 字体
self.font = None
# 保存数据对象到单元格
self.saveData = False
# 默认不允许根据表头进行排序,需要的组件可以开启
self.sorting = False
# 初始化右键菜单
self.initMenu()
#----------------------------------------------------------------------
def setHeaderDict(self, headerDict):
"""设置表头有序字典"""
self.headerDict = headerDict
self.headerList = headerDict.keys()
#----------------------------------------------------------------------
def setDataKey(self, dataKey):
"""设置数据字典的键"""
self.dataKey = dataKey
#----------------------------------------------------------------------
def setEventType(self, eventType):
"""设置监控的事件类型"""
self.eventType = eventType
#----------------------------------------------------------------------
def setFont(self, font):
"""设置字体"""
self.font = font
#----------------------------------------------------------------------
def setSaveData(self, saveData):
"""设置是否要保存数据到单元格"""
self.saveData = saveData
#----------------------------------------------------------------------
def initTable(self):
"""初始化表格"""
# 设置表格的列数
col = len(self.headerDict)
self.setColumnCount(col)
# 设置列表头
labels = [d['chinese'] for d in self.headerDict.values()]
self.setHorizontalHeaderLabels(labels)
# 关闭左边的垂直表头
self.verticalHeader().setVisible(False)
# 设为不可编辑
self.setEditTriggers(self.NoEditTriggers)
# 设为行交替颜色
self.setAlternatingRowColors(True)
# 设置允许排序
self.setSortingEnabled(self.sorting)
@ -267,38 +281,38 @@ class BasicMonitor(QtGui.QTableWidget):
"""注册GUI更新相关的事件监听"""
self.signal.connect(self.updateEvent)
self.eventEngine.register(self.eventType, self.signal.emit)
#----------------------------------------------------------------------
def updateEvent(self, event):
"""收到事件更新"""
data = event.dict_['data']
self.updateData(data)
#----------------------------------------------------------------------
def updateData(self, data):
"""将数据更新到表格中"""
# 如果允许了排序功能,则插入数据前必须关闭,否则插入新的数据会变乱
if self.sorting:
self.setSortingEnabled(False)
# 如果设置了dataKey则采用存量更新模式
if self.dataKey:
key = data.__getattribute__(self.dataKey)
# 如果键在数据字典中不存在,则先插入新的一行,并创建对应单元格
if key not in self.dataDict:
self.insertRow(0)
self.insertRow(0)
d = {}
for n, header in enumerate(self.headerList):
for n, header in enumerate(self.headerList):
content = safeUnicode(data.__getattribute__(header))
cellType = self.headerDict[header]['cellType']
cell = cellType(content, self.mainEngine)
if self.font:
cell.setFont(self.font) # 如果设置了特殊字体,则进行单元格设置
if self.saveData: # 如果设置了保存数据对象,则进行对象保存
cell.data = data
self.setItem(0, n, cell)
d[header] = cell
self.dataDict[key] = d
@ -309,48 +323,48 @@ class BasicMonitor(QtGui.QTableWidget):
content = safeUnicode(data.__getattribute__(header))
cell = d[header]
cell.setContent(content)
if self.saveData: # 如果设置了保存数据对象,则进行对象保存
cell.data = data
cell.data = data
# 否则采用增量更新模式
else:
self.insertRow(0)
self.insertRow(0)
for n, header in enumerate(self.headerList):
content = safeUnicode(data.__getattribute__(header))
cellType = self.headerDict[header]['cellType']
cell = cellType(content, self.mainEngine)
if self.font:
cell.setFont(self.font)
if self.saveData:
cell.data = data
cell.data = data
self.setItem(0, n, cell)
self.setItem(0, n, cell)
# 调整列宽
self.resizeColumns()
# 重新打开排序
if self.sorting:
self.setSortingEnabled(True)
#----------------------------------------------------------------------
def resizeColumns(self):
"""调整各列的大小"""
self.horizontalHeader().resizeSections(QtGui.QHeaderView.ResizeToContents)
self.horizontalHeader().resizeSections(QtGui.QHeaderView.ResizeToContents)
#----------------------------------------------------------------------
def setSorting(self, sorting):
"""设置是否允许根据表头排序"""
self.sorting = sorting
#----------------------------------------------------------------------
def saveToCsv(self):
"""保存表格内容到CSV文件"""
# 先隐藏右键菜单
self.menu.close()
# 获取想要保存的文件名
path = QtGui.QFileDialog.getSaveFileName(self, '保存数据', '', 'CSV(*.csv)')
@ -358,11 +372,11 @@ class BasicMonitor(QtGui.QTableWidget):
if not path.isEmpty():
with open(unicode(path), 'wb') as f:
writer = csv.writer(f)
# 保存标签
headers = [header.encode('gbk') for header in self.headerList]
writer.writerow(headers)
# 保存每行内容
for row in range(self.rowCount()):
rowdata = []
@ -373,24 +387,24 @@ class BasicMonitor(QtGui.QTableWidget):
unicode(item.text()).encode('gbk'))
else:
rowdata.append('')
writer.writerow(rowdata)
writer.writerow(rowdata)
except IOError:
pass
#----------------------------------------------------------------------
def initMenu(self):
"""初始化右键菜单"""
self.menu = QtGui.QMenu(self)
self.menu = QtGui.QMenu(self)
saveAction = QtGui.QAction(u'保存内容', self)
saveAction.triggered.connect(self.saveToCsv)
self.menu.addAction(saveAction)
#----------------------------------------------------------------------
def contextMenuEvent(self, event):
"""右键点击事件"""
self.menu.popup(QtGui.QCursor.pos())
self.menu.popup(QtGui.QCursor.pos())
########################################################################
@ -401,7 +415,7 @@ class MarketMonitor(BasicMonitor):
def __init__(self, mainEngine, eventEngine, parent=None):
"""Constructor"""
super(MarketMonitor, self).__init__(mainEngine, eventEngine, parent)
# 设置表头有序字典
d = OrderedDict()
d['symbol'] = {'chinese':u'合约代码', 'cellType':BasicCell}
@ -420,22 +434,22 @@ class MarketMonitor(BasicMonitor):
d['time'] = {'chinese':u'时间', 'cellType':BasicCell}
d['gatewayName'] = {'chinese':u'接口', 'cellType':BasicCell}
self.setHeaderDict(d)
# 设置数据键
self.setDataKey('vtSymbol')
# 设置监控事件类型
self.setEventType(EVENT_TICK)
# 设置字体
self.setFont(BASIC_FONT)
# 设置允许排序
self.setSorting(True)
self.setSorting(False)
# 初始化表格
self.initTable()
# 注册事件监听
self.registerEvent()
@ -448,15 +462,15 @@ class LogMonitor(BasicMonitor):
def __init__(self, mainEngine, eventEngine, parent=None):
"""Constructor"""
super(LogMonitor, self).__init__(mainEngine, eventEngine, parent)
d = OrderedDict()
d = OrderedDict()
d['logTime'] = {'chinese':u'时间', 'cellType':BasicCell}
d['logContent'] = {'chinese':u'内容', 'cellType':BasicCell}
d['gatewayName'] = {'chinese':u'接口', 'cellType':BasicCell}
self.setHeaderDict(d)
self.setEventType(EVENT_LOG)
self.setFont(BASIC_FONT)
self.setFont(BASIC_FONT)
self.initTable()
self.registerEvent()
@ -469,14 +483,14 @@ class ErrorMonitor(BasicMonitor):
def __init__(self, mainEngine, eventEngine, parent=None):
"""Constructor"""
super(ErrorMonitor, self).__init__(mainEngine, eventEngine, parent)
d = OrderedDict()
d = OrderedDict()
d['errorTime'] = {'chinese':u'错误时间', 'cellType':BasicCell}
d['errorID'] = {'chinese':u'错误代码', 'cellType':BasicCell}
d['errorMsg'] = {'chinese':u'错误信息', 'cellType':BasicCell}
d['gatewayName'] = {'chinese':u'接口', 'cellType':BasicCell}
self.setHeaderDict(d)
self.setEventType(EVENT_ERROR)
self.setFont(BASIC_FONT)
self.initTable()
@ -491,7 +505,7 @@ class TradeMonitor(BasicMonitor):
def __init__(self, mainEngine, eventEngine, parent=None):
"""Constructor"""
super(TradeMonitor, self).__init__(mainEngine, eventEngine, parent)
d = OrderedDict()
d['tradeID'] = {'chinese':u'成交编号', 'cellType':NumCell}
d['orderID'] = {'chinese':u'委托编号', 'cellType':NumCell}
@ -504,11 +518,11 @@ class TradeMonitor(BasicMonitor):
d['tradeTime'] = {'chinese':u'成交时间', 'cellType':BasicCell}
d['gatewayName'] = {'chinese':u'接口', 'cellType':BasicCell}
self.setHeaderDict(d)
self.setEventType(EVENT_TRADE)
self.setFont(BASIC_FONT)
self.setSorting(True)
self.initTable()
self.registerEvent()
@ -523,7 +537,7 @@ class OrderMonitor(BasicMonitor):
super(OrderMonitor, self).__init__(mainEngine, eventEngine, parent)
self.mainEngine = mainEngine
d = OrderedDict()
d['orderID'] = {'chinese':u'委托编号', 'cellType':NumCell}
d['symbol'] = {'chinese':u'合约代码', 'cellType':BasicCell}
@ -540,28 +554,28 @@ class OrderMonitor(BasicMonitor):
d['sessionID'] = {'chinese':u'会话编号', 'cellType':BasicCell}
d['gatewayName'] = {'chinese':u'接口', 'cellType':BasicCell}
self.setHeaderDict(d)
self.setDataKey('vtOrderID')
self.setEventType(EVENT_ORDER)
self.setFont(BASIC_FONT)
self.setSaveData(True)
self.setSorting(True)
self.initTable()
self.registerEvent()
self.connectSignal()
#----------------------------------------------------------------------
def connectSignal(self):
"""连接信号"""
# 双击单元格撤单
self.itemDoubleClicked.connect(self.cancelOrder)
self.itemDoubleClicked.connect(self.cancelOrder)
#----------------------------------------------------------------------
def cancelOrder(self, cell):
"""根据单元格的数据撤单"""
order = cell.data
req = VtCancelOrderReq()
req.symbol = order.symbol
req.exchange = order.exchange
@ -578,7 +592,7 @@ class PositionMonitor(BasicMonitor):
def __init__(self, mainEngine, eventEngine, parent=None):
"""Constructor"""
super(PositionMonitor, self).__init__(mainEngine, eventEngine, parent)
d = OrderedDict()
d['symbol'] = {'chinese':u'合约代码', 'cellType':BasicCell}
d['vtSymbol'] = {'chinese':u'名称', 'cellType':NameCell}
@ -590,16 +604,16 @@ class PositionMonitor(BasicMonitor):
d['positionProfit'] = {'chinese':u'持仓盈亏', 'cellType':BasicCell}
d['gatewayName'] = {'chinese':u'接口', 'cellType':BasicCell}
self.setHeaderDict(d)
self.setDataKey('vtPositionName')
self.setEventType(EVENT_POSITION)
self.setFont(BASIC_FONT)
self.setSaveData(True)
self.initTable()
self.registerEvent()
########################################################################
class AccountMonitor(BasicMonitor):
"""账户监控"""
@ -608,7 +622,7 @@ class AccountMonitor(BasicMonitor):
def __init__(self, mainEngine, eventEngine, parent=None):
"""Constructor"""
super(AccountMonitor, self).__init__(mainEngine, eventEngine, parent)
d = OrderedDict()
d['accountID'] = {'chinese':u'账户', 'cellType':BasicCell}
d['preBalance'] = {'chinese':u'昨结', 'cellType':BasicCell}
@ -620,7 +634,7 @@ class AccountMonitor(BasicMonitor):
d['positionProfit'] = {'chinese':u'持仓盈亏', 'cellType':BasicCell}
d['gatewayName'] = {'chinese':u'接口', 'cellType':BasicCell}
self.setHeaderDict(d)
self.setDataKey('vtAccountID')
self.setEventType(EVENT_ACCOUNT)
self.setFont(BASIC_FONT)
@ -632,7 +646,7 @@ class AccountMonitor(BasicMonitor):
class TradingWidget(QtGui.QFrame):
"""简单交易组件"""
signal = QtCore.pyqtSignal(type(Event()))
directionList = [DIRECTION_LONG,
DIRECTION_SHORT]
@ -640,12 +654,12 @@ class TradingWidget(QtGui.QFrame):
OFFSET_CLOSE,
OFFSET_CLOSEYESTERDAY,
OFFSET_CLOSETODAY]
priceTypeList = [PRICETYPE_LIMITPRICE,
PRICETYPE_MARKETPRICE,
PRICETYPE_FAK,
PRICETYPE_FOK]
exchangeList = [EXCHANGE_NONE,
EXCHANGE_CFFEX,
EXCHANGE_SHFE,
@ -662,18 +676,18 @@ class TradingWidget(QtGui.QFrame):
EXCHANGE_NYMEX,
EXCHANGE_GLOBEX,
EXCHANGE_IDEALPRO]
currencyList = [CURRENCY_NONE,
CURRENCY_CNY,
CURRENCY_HKD,
CURRENCY_USD]
productClassList = [PRODUCT_NONE,
PRODUCT_EQUITY,
PRODUCT_FUTURES,
PRODUCT_OPTION,
PRODUCT_FOREX]
gatewayList = ['']
#----------------------------------------------------------------------
@ -682,9 +696,9 @@ class TradingWidget(QtGui.QFrame):
super(TradingWidget, self).__init__(parent)
self.mainEngine = mainEngine
self.eventEngine = eventEngine
self.symbol = ''
# 添加交易接口
self.gatewayList.extend(mainEngine.getAllGatewayNames())
@ -697,7 +711,7 @@ class TradingWidget(QtGui.QFrame):
self.setWindowTitle(u'交易')
self.setMaximumWidth(400)
self.setFrameShape(self.Box) # 设置边框
self.setLineWidth(1)
self.setLineWidth(1)
# 左边部分
labelSymbol = QtGui.QLabel(u'代码')
@ -708,7 +722,7 @@ class TradingWidget(QtGui.QFrame):
self.checkFixed = QtGui.QCheckBox(u'') # 价格固定选择框
labelVolume = QtGui.QLabel(u'数量')
labelPriceType = QtGui.QLabel(u'价格类型')
labelExchange = QtGui.QLabel(u'交易所')
labelExchange = QtGui.QLabel(u'交易所')
labelCurrency = QtGui.QLabel(u'货币')
labelProductClass = QtGui.QLabel(u'产品类型')
labelGateway = QtGui.QLabel(u'交易接口')
@ -733,18 +747,18 @@ class TradingWidget(QtGui.QFrame):
self.comboPriceType = QtGui.QComboBox()
self.comboPriceType.addItems(self.priceTypeList)
self.comboExchange = QtGui.QComboBox()
self.comboExchange.addItems(self.exchangeList)
self.comboExchange.addItems(self.exchangeList)
self.comboCurrency = QtGui.QComboBox()
self.comboCurrency.addItems(self.currencyList)
self.comboProductClass = QtGui.QComboBox()
self.comboProductClass.addItems(self.productClassList)
self.comboProductClass.addItems(self.productClassList)
self.comboGateway = QtGui.QComboBox()
self.comboGateway.addItems(self.gatewayList)
self.comboGateway.addItems(self.gatewayList)
gridleft = QtGui.QGridLayout()
gridleft.addWidget(labelSymbol, 0, 0)
@ -756,9 +770,9 @@ class TradingWidget(QtGui.QFrame):
gridleft.addWidget(labelPriceType, 6, 0)
gridleft.addWidget(labelExchange, 7, 0)
gridleft.addWidget(labelCurrency, 8, 0)
gridleft.addWidget(labelProductClass, 9, 0)
gridleft.addWidget(labelProductClass, 9, 0)
gridleft.addWidget(labelGateway, 10, 0)
gridleft.addWidget(self.lineSymbol, 0, 1, 1, -1)
gridleft.addWidget(self.lineName, 1, 1, 1, -1)
gridleft.addWidget(self.comboDirection, 2, 1, 1, -1)
@ -794,7 +808,7 @@ class TradingWidget(QtGui.QFrame):
self.labelBidVolume2 = QtGui.QLabel()
self.labelBidVolume3 = QtGui.QLabel()
self.labelBidVolume4 = QtGui.QLabel()
self.labelBidVolume5 = QtGui.QLabel()
self.labelBidVolume5 = QtGui.QLabel()
self.labelAskPrice1 = QtGui.QLabel()
self.labelAskPrice2 = QtGui.QLabel()
@ -805,7 +819,7 @@ class TradingWidget(QtGui.QFrame):
self.labelAskVolume2 = QtGui.QLabel()
self.labelAskVolume3 = QtGui.QLabel()
self.labelAskVolume4 = QtGui.QLabel()
self.labelAskVolume5 = QtGui.QLabel()
self.labelAskVolume5 = QtGui.QLabel()
labelLast = QtGui.QLabel(u'最新')
self.labelLastPrice = QtGui.QLabel()
@ -837,7 +851,7 @@ class TradingWidget(QtGui.QFrame):
gridRight.addWidget(self.labelBidPrice2, 7, 1)
gridRight.addWidget(self.labelBidPrice3, 8, 1)
gridRight.addWidget(self.labelBidPrice4, 9, 1)
gridRight.addWidget(self.labelBidPrice5, 10, 1)
gridRight.addWidget(self.labelBidPrice5, 10, 1)
gridRight.addWidget(self.labelAskVolume5, 0, 2)
gridRight.addWidget(self.labelAskVolume4, 1, 2)
@ -854,7 +868,7 @@ class TradingWidget(QtGui.QFrame):
# 发单按钮
buttonSendOrder = QtGui.QPushButton(u'发单')
buttonCancelAll = QtGui.QPushButton(u'全撤')
size = buttonSendOrder.sizeHint()
buttonSendOrder.setMinimumHeight(size.height()*2) # 把按钮高度设为默认两倍
buttonCancelAll.setMinimumHeight(size.height()*2)
@ -884,23 +898,23 @@ class TradingWidget(QtGui.QFrame):
symbol = str(self.lineSymbol.text())
exchange = unicode(self.comboExchange.currentText())
currency = unicode(self.comboCurrency.currentText())
productClass = unicode(self.comboProductClass.currentText())
productClass = unicode(self.comboProductClass.currentText())
gatewayName = unicode(self.comboGateway.currentText())
# 查询合约
if exchange:
vtSymbol = '.'.join([symbol, exchange])
contract = self.mainEngine.getContract(vtSymbol)
else:
vtSymbol = symbol
contract = self.mainEngine.getContract(symbol)
contract = self.mainEngine.getContract(symbol)
if contract:
vtSymbol = contract.vtSymbol
gatewayName = contract.gatewayName
self.lineName.setText(contract.name)
exchange = contract.exchange # 保证有交易所代码
# 清空价格数量
self.spinPrice.setValue(0)
self.spinVolume.setValue(0)
@ -915,7 +929,7 @@ class TradingWidget(QtGui.QFrame):
self.labelBidVolume2.setText('')
self.labelBidVolume3.setText('')
self.labelBidVolume4.setText('')
self.labelBidVolume5.setText('')
self.labelBidVolume5.setText('')
self.labelAskPrice1.setText('')
self.labelAskPrice2.setText('')
self.labelAskPrice3.setText('')
@ -960,30 +974,30 @@ class TradingWidget(QtGui.QFrame):
self.labelAskPrice1.setText(str(tick.askPrice1))
self.labelBidVolume1.setText(str(tick.bidVolume1))
self.labelAskVolume1.setText(str(tick.askVolume1))
if tick.bidPrice2:
self.labelBidPrice2.setText(str(tick.bidPrice2))
self.labelBidPrice3.setText(str(tick.bidPrice3))
self.labelBidPrice4.setText(str(tick.bidPrice4))
self.labelBidPrice5.setText(str(tick.bidPrice5))
self.labelAskPrice2.setText(str(tick.askPrice2))
self.labelAskPrice3.setText(str(tick.askPrice3))
self.labelAskPrice4.setText(str(tick.askPrice4))
self.labelAskPrice5.setText(str(tick.askPrice5))
self.labelBidVolume2.setText(str(tick.bidVolume2))
self.labelBidVolume3.setText(str(tick.bidVolume3))
self.labelBidVolume4.setText(str(tick.bidVolume4))
self.labelBidVolume5.setText(str(tick.bidVolume5))
self.labelAskVolume2.setText(str(tick.askVolume2))
self.labelAskVolume3.setText(str(tick.askVolume3))
self.labelAskVolume4.setText(str(tick.askVolume4))
self.labelAskVolume5.setText(str(tick.askVolume5))
self.labelAskVolume5.setText(str(tick.askVolume5))
self.labelLastPrice.setText(str(tick.lastPrice))
if tick.preClosePrice:
rt = (tick.lastPrice/tick.preClosePrice)-1
self.labelReturn.setText(('%.2f' %(rt*100))+'%')
@ -1001,8 +1015,8 @@ class TradingWidget(QtGui.QFrame):
symbol = str(self.lineSymbol.text())
exchange = unicode(self.comboExchange.currentText())
currency = unicode(self.comboCurrency.currentText())
productClass = unicode(self.comboProductClass.currentText())
gatewayName = unicode(self.comboGateway.currentText())
productClass = unicode(self.comboProductClass.currentText())
gatewayName = unicode(self.comboGateway.currentText())
# 查询合约
if exchange:
@ -1011,11 +1025,11 @@ class TradingWidget(QtGui.QFrame):
else:
vtSymbol = symbol
contract = self.mainEngine.getContract(symbol)
if contract:
gatewayName = contract.gatewayName
exchange = contract.exchange # 保证有交易所代码
req = VtOrderReq()
req.symbol = symbol
req.exchange = exchange
@ -1026,9 +1040,9 @@ class TradingWidget(QtGui.QFrame):
req.offset = unicode(self.comboOffset.currentText())
req.currency = currency
req.productClass = productClass
self.mainEngine.sendOrder(req, gatewayName)
#----------------------------------------------------------------------
def cancelAll(self):
"""一键撤销所有委托"""
@ -1041,18 +1055,18 @@ class TradingWidget(QtGui.QFrame):
req.sessionID = order.sessionID
req.orderID = order.orderID
self.mainEngine.cancelOrder(req, order.gatewayName)
#----------------------------------------------------------------------
def closePosition(self, cell):
"""根据持仓信息自动填写交易组件"""
# 读取持仓数据cell是一个表格中的单元格对象
pos = cell.data
symbol = pos.symbol
# 更新交易组件的显示合约
self.lineSymbol.setText(symbol)
self.updateSymbol()
# 自动填写信息
self.comboPriceType.setCurrentIndex(self.priceTypeList.index(PRICETYPE_LIMITPRICE))
self.comboOffset.setCurrentIndex(self.offsetList.index(OFFSET_CLOSE))
@ -1074,9 +1088,9 @@ class ContractMonitor(BasicMonitor):
def __init__(self, mainEngine, parent=None):
"""Constructor"""
super(ContractMonitor, self).__init__(parent=parent)
self.mainEngine = mainEngine
d = OrderedDict()
d['symbol'] = {'chinese':u'合约代码', 'cellType':BasicCell}
d['exchange'] = {'chinese':u'交易所', 'cellType':BasicCell}
@ -1087,11 +1101,11 @@ class ContractMonitor(BasicMonitor):
d['priceTick'] = {'chinese':u'最小价格变动', 'cellType':BasicCell}
#d['strikePrice'] = {'chinese':u'期权行权价', 'cellType':BasicCell}
#d['underlyingSymbol'] = {'chinese':u'期权标的物', 'cellType':BasicCell}
#d['optionType'] = {'chinese':u'期权类型', 'cellType':BasicCell}
#d['optionType'] = {'chinese':u'期权类型', 'cellType':BasicCell}
self.setHeaderDict(d)
self.initUi()
#----------------------------------------------------------------------
def initUi(self):
"""初始化界面"""
@ -1100,7 +1114,7 @@ class ContractMonitor(BasicMonitor):
self.setFont(BASIC_FONT)
self.initTable()
self.addMenuAction()
#----------------------------------------------------------------------
def showAllContracts(self):
"""显示所有合约数据"""
@ -1111,22 +1125,24 @@ class ContractMonitor(BasicMonitor):
self.setRowCount(len(l2))
row = 0
for key in l2:
contract = d[key]
for n, header in enumerate(self.headerList):
content = safeUnicode(contract.__getattribute__(header))
cellType = self.headerDict[header]['cellType']
content = None
if (hasattr(contract, header)):
content = safeUnicode(contract.__getattribute__(header))
cell = cellType(content)
if self.font:
cell.setFont(self.font) # 如果设置了特殊字体,则进行单元格设置
self.setItem(row, n, cell)
row = row + 1
#----------------------------------------------------------------------
def refresh(self):
"""刷新"""
@ -1134,19 +1150,19 @@ class ContractMonitor(BasicMonitor):
self.clearContents()
self.setRowCount(0)
self.showAllContracts()
#----------------------------------------------------------------------
def addMenuAction(self):
"""增加右键菜单内容"""
refreshAction = QtGui.QAction(u'刷新', self)
refreshAction.triggered.connect(self.refresh)
self.menu.addAction(refreshAction)
#----------------------------------------------------------------------
def show(self):
"""显示"""
super(ContractMonitor, self).show()
self.refresh()

View File

@ -2,10 +2,10 @@
import psutil
from uiBasicWidget import *
from ctaAlgo.uiCtaWidget import CtaEngineManager
from dataRecorder.uiDrWidget import DrEngineManager
from riskManager.uiRmWidget import RmEngineManager
from uiBasicWidget import *
########################################################################
class MainWindow(QtGui.QMainWindow):
@ -197,7 +197,7 @@ class MainWindow(QtGui.QMainWindow):
try:
self.widgetDict['drM'].showMaximized()
except KeyError:
self.widgetDict['drM'] = DrEngineManager(self.mainEngine.drEngine, self.eventEngine)
self.widgetDict['drM'] = DrEngineManager(self.mainEngine, self.eventEngine)
self.widgetDict['drM'].showMaximized()
#----------------------------------------------------------------------

144
vn.trader/util/UiUtil.py Normal file
View File

@ -0,0 +1,144 @@
from PyQt4 import QtCore
from PyQt4.QtGui import QStyle, QStyledItemDelegate, QStyleOptionButton, QApplication, QItemDelegate, QComboBox, \
QItemEditorCreatorBase
class CheckBoxDelegate(QStyledItemDelegate):
"""
A delegate that places a fully functioning QCheckBox in every
cell of the column to which it's applied
"""
def __init__(self, parent):
QItemDelegate.__init__(self, parent)
def createEditor(self, parent, option, index):
'''
Important, otherwise an editor is created if the user clicks in this cell.
** Need to hook up a signal to the model
'''
return None
def paint(self, painter, option, index):
'''
Paint a checkbox without the label.
'''
data = index.model().data(index, QtCore.Qt.CheckStateRole)
if not data in [QtCore.Qt.Unchecked, QtCore.Qt.Checked]:
return
checked = data == QtCore.Qt.Checked
check_box_style_option = QStyleOptionButton()
if index.flags() & QtCore.Qt.ItemIsEditable == QtCore.Qt.ItemIsEditable:
check_box_style_option.state |= QStyle.State_Enabled
else:
check_box_style_option.state |= QStyle.State_ReadOnly
if checked:
check_box_style_option.state |= QStyle.State_On
else:
check_box_style_option.state |= QStyle.State_Off
check_box_style_option.rect = self.getCheckBoxRect(option)
# this will not run - hasFlag does not exist
# if not index.model().hasFlag(index, QtCore.Qt.ItemIsEditable):
# check_box_style_option.state |= QStyle.State_ReadOnly
# check_box_style_option.state |= QStyle.State_Enabled
QApplication.style().drawControl(QStyle.CE_CheckBox, check_box_style_option, painter)
def editorEvent(self, event, model, option, index):
'''
Change the data in the model and the state of the checkbox
if the user presses the left mousebutton or presses
Key_Space or Key_Select and this cell is editable. Otherwise do nothing.
'''
# print 'Check Box editor Event detected : '
if index.flags() & QtCore.Qt.ItemIsEditable != QtCore.Qt.ItemIsEditable:
return False
# print 'Check Box edior Event detected : passed first check'
# Do not change the checkbox-state
if event.type() == QtCore.QEvent.MouseButtonRelease or event.type() == QtCore.QEvent.MouseButtonDblClick:
if event.button() != QtCore.Qt.LeftButton or not self.getCheckBoxRect(option).contains(event.pos()):
return False
if event.type() == QtCore.QEvent.MouseButtonDblClick:
return True
elif event.type() == QtCore.QEvent.KeyPress:
if event.key() != QtCore.Qt.Key_Space and event.key() != QtCore.Qt.Key_Select:
return False
else:
return False
# Change the checkbox-state
self.setModelData(None, model, index)
return True
def setModelData(self, editor, model, index):
'''
The user wanted to change the old state in the opposite.
'''
# print 'SetModelData'
newValue = not index.data().toBool()
# print 'New Value : {0}'.format(newValue)
model.setData(index, QtCore.Qt.Checked if newValue else QtCore.Qt.Unchecked, QtCore.Qt.CheckStateRole)
def getCheckBoxRect(self, option):
check_box_style_option = QStyleOptionButton()
check_box_rect = QApplication.style().subElementRect(QStyle.SE_CheckBoxIndicator, check_box_style_option, None)
check_box_point = QtCore.QPoint(option.rect.x() +
option.rect.width() / 2 -
check_box_rect.width() / 2,
option.rect.y() +
option.rect.height() / 2 -
check_box_rect.height() / 2)
return QtCore.QRect(check_box_point, check_box_rect.size())
class ComboDelegate(QItemDelegate):
def __init__(self, parent, dataList=[]):
QItemDelegate.__init__(self, parent)
self.dataList = dataList
def createEditor(self, parent, option, index):
combo = QComboBox(parent)
combo.addItems(self.dataList)
return combo
def setEditorData(self, editor, index):
text = index.data().toString()
index = editor.findText(text)
editor.setCurrentIndex(index)
def setModelData(self, editor, model, index):
model.setData(index, str(editor.itemText(editor.currentIndex())))
def updateEditorGeometry(self, editor, option, index):
print option, option.rect
editor.setGeometry(option.rect)
class GateWayListEditor(QComboBox):
def __init__(self, widget=None, dataList=[]):
super(GateWayListEditor, self).__init__(widget)
self.dataList = dataList
self.populateList()
def getGateWay(self):
gateWay = self.itemData(self.currentIndex(), QtCore.Qt.DisplayRole)
return gateWay
def setGateWay(self, gateWay):
self.setCurrentIndex(self.findData(gateWay, QtCore.Qt.DisplayRole))
def populateList(self):
for i, gateWayName in enumerate(self.dataList):
self.insertItem(i, gateWayName)
self.setItemData(i, gateWayName, QtCore.Qt.DisplayRole)
class GateWayListItemEditorCreator(QItemEditorCreatorBase):
def createWidget(self, parent):
return GateWayListEditor(parent, ["CTP", "LTS", "XTP", "FEMAS", "XSPEED", "QDP", "KSOTP", "KSGOLD", "SGIT"])

View File