2017-02-06 13:54:35 +00:00
|
|
|
|
# encoding: UTF-8
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
行情记录模块相关的GUI控制组件
|
|
|
|
|
'''
|
2017-02-08 07:40:28 +00:00
|
|
|
|
import re
|
|
|
|
|
import sys
|
|
|
|
|
|
2017-02-06 13:54:35 +00:00
|
|
|
|
from PyQt4.QtGui import QTreeView
|
|
|
|
|
|
2017-02-07 11:32:55 +00:00
|
|
|
|
from dataRecorder.drEngine import DrEngine
|
2017-02-06 13:54:35 +00:00
|
|
|
|
from eventEngine import *
|
2017-02-08 03:41:28 +00:00
|
|
|
|
from uiBasicWidget import QtGui, QtCore
|
2017-02-06 13:54:35 +00:00
|
|
|
|
|
2017-02-08 07:40:28 +00:00
|
|
|
|
reload(sys)
|
|
|
|
|
sys.setdefaultencoding("utf8")
|
|
|
|
|
|
2017-02-06 13:54:35 +00:00
|
|
|
|
|
2017-02-07 11:32:55 +00:00
|
|
|
|
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
|
|
|
|
|
|
2017-02-08 03:41:28 +00:00
|
|
|
|
def setData(self, column, value):
|
|
|
|
|
if column < 0 or column >= len(self.itemData):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
self.itemData[column] = value
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
2017-02-07 11:32:55 +00:00
|
|
|
|
|
|
|
|
|
class TreeModel(QtCore.QAbstractItemModel):
|
|
|
|
|
def __init__(self, parent=None):
|
|
|
|
|
super(TreeModel, self).__init__(parent)
|
2017-02-08 07:40:28 +00:00
|
|
|
|
self.rootItem = TreeItem([u"合约", u"Tick", u"Bar", u"主力", u"交易所", u"接口"])
|
2017-02-07 11:32:55 +00:00
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
2017-02-08 03:41:28 +00:00
|
|
|
|
def setData(self, index, value, role=None):
|
2017-02-08 07:40:28 +00:00
|
|
|
|
if index.column() in [1, 2, 3] and role == QtCore.Qt.CheckStateRole:
|
2017-02-08 03:41:28 +00:00
|
|
|
|
item = index.internalPointer()
|
|
|
|
|
if item is None:
|
|
|
|
|
return False
|
|
|
|
|
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:
|
|
|
|
|
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
|
2017-02-07 11:32:55 +00:00
|
|
|
|
|
|
|
|
|
def data(self, index, role):
|
|
|
|
|
if not index.isValid():
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
item = index.internalPointer()
|
|
|
|
|
|
2017-02-08 07:40:28 +00:00
|
|
|
|
if role == QtCore.Qt.CheckStateRole and (
|
|
|
|
|
index.column() in [1, 2] or index.column() == 3 and item.parentItem != self.rootItem):
|
2017-02-07 11:32:55 +00:00
|
|
|
|
return QtCore.Qt.Checked if item.data(index.column()) == True else QtCore.Qt.Unchecked
|
|
|
|
|
|
2017-02-08 07:40:28 +00:00
|
|
|
|
if role != QtCore.Qt.DisplayRole or index.column() == 3 and item.parentItem == self.rootItem:
|
2017-02-07 11:32:55 +00:00
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
return item.data(index.column())
|
|
|
|
|
|
|
|
|
|
def flags(self, index):
|
|
|
|
|
if not index.isValid():
|
|
|
|
|
return QtCore.Qt.NoItemFlags
|
|
|
|
|
|
2017-02-08 07:40:28 +00:00
|
|
|
|
if index.column() in [0, 4, 5]:
|
2017-02-07 11:32:55 +00:00
|
|
|
|
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
|
|
|
|
|
|
2017-02-08 03:41:28 +00:00
|
|
|
|
item = index.internalPointer()
|
|
|
|
|
if index.column() == 3 and item.parentItem == self.rootItem:
|
2017-02-08 07:40:28 +00:00
|
|
|
|
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
|
2017-02-08 03:41:28 +00:00
|
|
|
|
|
2017-02-07 11:32:55 +00:00
|
|
|
|
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable
|
|
|
|
|
|
|
|
|
|
def headerData(self, section, orientation, role):
|
|
|
|
|
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
|
|
|
|
|
return self.rootItem.data(section)
|
|
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def index(self, row, column, parent):
|
|
|
|
|
if not self.hasIndex(row, column, parent):
|
|
|
|
|
return QtCore.QModelIndex()
|
|
|
|
|
|
2017-02-08 03:41:28 +00:00
|
|
|
|
if parent is None or not parent.isValid():
|
2017-02-07 11:32:55 +00:00
|
|
|
|
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()
|
|
|
|
|
|
2017-02-08 03:41:28 +00:00
|
|
|
|
def hasIndex(self, row, column, parentIndex=None, *args, **kwargs):
|
2017-02-08 07:40:28 +00:00
|
|
|
|
if row < 0 or column > self.rootItem.columnCount():
|
2017-02-08 03:41:28 +00:00
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
2017-02-07 11:32:55 +00:00
|
|
|
|
|
2017-02-06 13:54:35 +00:00
|
|
|
|
class DrEditWidget(QtGui.QWidget):
|
2017-02-07 11:32:55 +00:00
|
|
|
|
"""行情数据记录引擎管理组件"""
|
|
|
|
|
signal = QtCore.pyqtSignal(type(Event()))
|
|
|
|
|
|
2017-02-08 15:05:33 +00:00
|
|
|
|
def __init__(self, drWidget, mainEngine, eventEngine, parent=None):
|
2017-02-07 11:32:55 +00:00
|
|
|
|
"""Constructor"""
|
|
|
|
|
super(DrEditWidget, self).__init__(parent)
|
2017-02-08 15:05:33 +00:00
|
|
|
|
self.drWidget = drWidget
|
2017-02-08 07:40:28 +00:00
|
|
|
|
self.mainEngine = mainEngine
|
2017-02-07 11:32:55 +00:00
|
|
|
|
self.eventEngine = eventEngine
|
2017-02-08 15:05:33 +00:00
|
|
|
|
self.hasChanged = False
|
2017-02-07 11:32:55 +00:00
|
|
|
|
|
|
|
|
|
# 保存合约详细信息的字典
|
|
|
|
|
self.contractDict = {}
|
|
|
|
|
|
|
|
|
|
self.initUi()
|
|
|
|
|
self.updateSetting()
|
2017-02-08 03:41:28 +00:00
|
|
|
|
self.loadData()
|
2017-02-07 11:32:55 +00:00
|
|
|
|
self.registerEvent()
|
|
|
|
|
|
2017-02-08 15:05:33 +00:00
|
|
|
|
def closeEvent(self, QCloseEvent):
|
|
|
|
|
if self.hasChanged:
|
|
|
|
|
self.drWidget.restart()
|
|
|
|
|
|
2017-02-07 11:32:55 +00:00
|
|
|
|
def initUi(self):
|
|
|
|
|
|
|
|
|
|
vbox = QtGui.QVBoxLayout()
|
|
|
|
|
|
|
|
|
|
vline = QtGui.QHBoxLayout()
|
|
|
|
|
vline.setSpacing(2)
|
|
|
|
|
btnTickAll = QtGui.QPushButton(u"全部记录tick", self)
|
|
|
|
|
btnBarAll = QtGui.QPushButton(u'全部记录bar', self)
|
2017-02-08 09:55:38 +00:00
|
|
|
|
btnSaveAll = QtGui.QPushButton(u'保存设置', self)
|
2017-02-08 03:41:28 +00:00
|
|
|
|
btnTickAll.clicked.connect(self.selectAllTick)
|
|
|
|
|
btnBarAll.clicked.connect(self.selectAllBar)
|
2017-02-08 09:55:38 +00:00
|
|
|
|
btnSaveAll.clicked.connect(self.saveSetting)
|
2017-02-08 03:41:28 +00:00
|
|
|
|
|
2017-02-07 11:32:55 +00:00
|
|
|
|
vline.addWidget(btnTickAll)
|
|
|
|
|
vline.addWidget(btnBarAll)
|
2017-02-08 09:55:38 +00:00
|
|
|
|
vline.addWidget(btnSaveAll)
|
2017-02-08 03:41:28 +00:00
|
|
|
|
|
2017-02-07 11:32:55 +00:00
|
|
|
|
vbox.addLayout(vline)
|
2017-02-08 03:41:28 +00:00
|
|
|
|
|
|
|
|
|
self.qTreeView = QTreeView()
|
|
|
|
|
self.model = TreeModel()
|
|
|
|
|
self.qTreeView.setModel(self.model)
|
|
|
|
|
|
2017-02-07 11:32:55 +00:00
|
|
|
|
vbox.addWidget(self.qTreeView)
|
|
|
|
|
self.setLayout(vbox)
|
|
|
|
|
|
2017-02-08 07:40:28 +00:00
|
|
|
|
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
|
|
|
|
|
|
2017-02-08 03:41:28 +00:00
|
|
|
|
def loadData(self):
|
|
|
|
|
child = []
|
2017-02-08 07:40:28 +00:00
|
|
|
|
|
|
|
|
|
contractDict = {}
|
2017-02-08 09:55:38 +00:00
|
|
|
|
contracts = self.mainEngine.getAllContracts()
|
|
|
|
|
for contract in contracts:
|
|
|
|
|
contractName = self.getContractChineseName(contract.name)
|
|
|
|
|
if contractDict.has_key(contractName):
|
|
|
|
|
parentItem = contractDict[contractName]
|
|
|
|
|
item = TreeItem([contract.symbol, False, False, False, contract.exchange, "CTP"], parentItem)
|
|
|
|
|
parentItem.appendChild(item)
|
|
|
|
|
else:
|
|
|
|
|
item = TreeItem([contractName, False, False, False, contract.exchange, "CTP"], self.model.rootItem)
|
|
|
|
|
contractDict[contractName] = item
|
|
|
|
|
child.append(item)
|
|
|
|
|
subItem = TreeItem([contract.symbol, False, False, False, contract.exchange, "CTP"], 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)
|
2017-02-08 03:41:28 +00:00
|
|
|
|
self.model.setDataSource(child)
|
|
|
|
|
self.qTreeView.expandAll()
|
|
|
|
|
|
2017-02-08 09:55:38 +00:00
|
|
|
|
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):
|
2017-02-08 15:05:33 +00:00
|
|
|
|
self.hasChanged = True
|
2017-02-08 09:55:38 +00:00
|
|
|
|
self.close()
|
|
|
|
|
|
2017-02-08 03:41:28 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2017-02-07 11:32:55 +00:00
|
|
|
|
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)
|
2017-02-08 15:05:33 +00:00
|
|
|
|
self.eventEngine.register(EVENT_CONTRACT, self.signal.emit)
|
2017-02-07 11:32:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
app = QtGui.QApplication(sys.argv)
|
|
|
|
|
|
2017-02-08 15:05:33 +00:00
|
|
|
|
view = DrEditWidget(None, DrEngine, EventEngine)
|
2017-02-08 07:40:28 +00:00
|
|
|
|
view.setFixedSize(650, 500)
|
2017-02-08 03:41:28 +00:00
|
|
|
|
view.show()
|
2017-02-07 11:32:55 +00:00
|
|
|
|
sys.exit(app.exec_())
|