text: # encoding: UTF-8
  
  import json
  import csv
  import os
  from collections import OrderedDict
  
  from PyQt4 import QtGui, QtCore
  
  from eventEngine import *
  from vtFunction import *
  from vtGateway import *
  
  
  #----------------------------------------------------------------------
  def loadFont():
      """载入字体设置"""
      fileName = 'VT_setting.json'
      path = os.path.abspath(os.path.dirname(__file__)) 
      fileName = os.path.join(path, fileName)  
      
      try:
          f = file(fileName)
          setting = json.load(f)
          family = setting['fontFamily']
          size = setting['fontSize']
          font = QtGui.QFont(family, size)
      except:
          font = QtGui.QFont(u'微软雅黑', 12)
      return font
  
  BASIC_FONT = loadFont()
  
  
  ########################################################################
  class BasicCell(QtGui.QTableWidgetItem):
      """基础的单元格"""
  
      #----------------------------------------------------------------------
      def __init__(self, text=None, mainEngine=None):
          """Constructor"""
          super(BasicCell, self).__init__()
          self.data = None
          if text:
              self.setContent(text)
      
      #----------------------------------------------------------------------
      def setContent(self, text):
          """设置内容"""
          if text == '0' or text == '0.0':
              self.setText('')
          else:
              self.setText(text)
  
  
  ########################################################################
  class NumCell(QtGui.QTableWidgetItem):
      """用来显示数字的单元格"""
  
      #----------------------------------------------------------------------
      def __init__(self, text=None, mainEngine=None):
          """Constructor"""
          super(NumCell, self).__init__()
          self.data = None
          if text:
              self.setContent(text)
      
      #----------------------------------------------------------------------
      def setContent(self, text):
          """设置内容"""
          # 考虑到NumCell主要用来显示OrderID和TradeID之类的整数字段，
          # 这里的数据转化方式使用int类型。但是由于部分交易接口的委托
          # 号和成交号可能不是纯数字的形式，因此补充了一个try...except
          try:
              num = int(text)
              self.setData(QtCore.Qt.DisplayRole, num)
          except ValueError:
              self.setText(text)
              
  
  ########################################################################
  class DirectionCell(QtGui.QTableWidgetItem):
      """用来显示买卖方向的单元格"""
  
      #----------------------------------------------------------------------
      def __init__(self, text=None, mainEngine=None):
          """Constructor"""
          super(DirectionCell, self).__init__()
          self.data = None
          if text:
              self.setContent(text)
          
      #----------------------------------------------------------------------
      def setContent(self, text):
          """设置内容"""
          if text == DIRECTION_LONG or text == DIRECTION_NET:
              self.setForeground(QtGui.QColor('red'))
          elif text == DIRECTION_SHORT:
              self.setForeground(QtGui.QColor('green'))
          self.setText(text)
  
  
  ########################################################################
  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)
  
  
  ########################################################################
  class BidCell(QtGui.QTableWidgetItem):
      """买价单元格"""
  
      #----------------------------------------------------------------------
      def __init__(self, text=None, mainEngine=None):
          """Constructor"""
          super(BidCell, self).__init__()
          self.data = None
  
          self.setForeground(QtGui.QColor('black'))
          self.setBackground(QtGui.QColor(255,174,201))
          
          if text:
              self.setContent(text)
      
      #----------------------------------------------------------------------
      def setContent(self, text):
          """设置内容"""
          self.setText(text)
  
  
  ########################################################################
  class AskCell(QtGui.QTableWidgetItem):
      """买价单元格"""
  
      #----------------------------------------------------------------------
      def __init__(self, text=None, mainEngine=None):
          """Constructor"""
          super(AskCell, self).__init__()
          self.data = None
  
          self.setForeground(QtGui.QColor('black'))
          self.setBackground(QtGui.QColor(160,255,160))
          
          if text:
              self.setContent(text)
      
      #----------------------------------------------------------------------
      def setContent(self, text):
          """设置内容"""
          self.setText(text)
  
  
  ########################################################################
  class BasicMonitor(QtGui.QTableWidget):
      """
      基础监控
      
      headerDict中的值对应的字典格式如下
      {'chinese': u'中文名', 'cellType': BasicCell}
      
      """
      signal = QtCore.pyqtSignal(type(Event()))
  
      #----------------------------------------------------------------------
      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)
  
      #----------------------------------------------------------------------
      def registerEvent(self):
          """注册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)     
                  d = {}
                  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
              # 否则如果已经存在，则直接更新相关单元格
              else:
                  d = self.dataDict[key]
                  for header in self.headerList:
                      content = safeUnicode(data.__getattribute__(header))
                      cell = d[header]
                      cell.setContent(content)
                      
                      if self.saveData:            # 如果设置了保存数据对象，则进行对象保存
                          cell.data = data                    
          # 否则采用增量更新模式
          else:
              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                
  
                  self.setItem(0, n, cell)                        
                  
          # 调整列宽
          self.resizeColumns()
          
          # 重新打开排序
          if self.sorting:
              self.setSortingEnabled(True)
      
      #----------------------------------------------------------------------
      def resizeColumns(self):
          """调整各列的大小"""
          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)')
  
          try:
              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 = []
                          for column in range(self.columnCount()):
                              item = self.item(row, column)
                              if item is not None:
                                  rowdata.append(
                                      unicode(item.text()).encode('gbk'))
                              else:
                                  rowdata.append('')
                          writer.writerow(rowdata)     
          except IOError:
              pass
  
      #----------------------------------------------------------------------
      def initMenu(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())    
  
  
  ########################################################################
  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}
          d['vtSymbol'] = {'chinese':u'名称', 'cellType':NameCell}
          d['lastPrice'] = {'chinese':u'最新价', 'cellType':BasicCell}
          d['preClosePrice'] = {'chinese':u'昨收盘价', 'cellType':BasicCell}
          d['volume'] = {'chinese':u'成交量', 'cellType':BasicCell}
          d['openInterest'] = {'chinese':u'持仓量', 'cellType':BasicCell}
          d['openPrice'] = {'chinese':u'开盘价', 'cellType':BasicCell}
          d['highPrice'] = {'chinese':u'最高价', 'cellType':BasicCell}
          d['lowPrice'] = {'chinese':u'最低价', 'cellType':BasicCell}
          d['bidPrice1'] = {'chinese':u'买一价', 'cellType':BidCell}
          d['bidVolume1'] = {'chinese':u'买一量', 'cellType':BidCell}
          d['askPrice1'] = {'chinese':u'卖一价', 'cellType':AskCell}
          d['askVolume1'] = {'chinese':u'卖一量', 'cellType':AskCell}
          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.initTable()
          
          # 注册事件监听
          self.registerEvent()
  
  
  ########################################################################
  class LogMonitor(BasicMonitor):
      """日志监控"""
  
      #----------------------------------------------------------------------
      def __init__(self, mainEngine, eventEngine, parent=None):
          """Constructor"""
          super(LogMonitor, self).__init__(mainEngine, eventEngine, parent)
          
          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.initTable()
          self.registerEvent()
  
  
  ########################################################################
  class ErrorMonitor(BasicMonitor):
      """错误监控"""
  
      #----------------------------------------------------------------------
      def __init__(self, mainEngine, eventEngine, parent=None):
          """Constructor"""
          super(ErrorMonitor, self).__init__(mainEngine, eventEngine, parent)
          
          d = OrderedDict()       
          d['errorTime']  = {'chinese':u'错误时间', 'cellType':BasicCell}
          d['errorID'] = {'chinese':u'错误代码', 'cellType':BasicCell}
          d['errorMsg'] = {'chinese':u'错误信息', 'cellType':BasicCell}
          d['additionalInfo'] = {'chinese':u'补充信息', 'cellType':BasicCell}
          d['gatewayName'] = {'chinese':u'接口', 'cellType':BasicCell}
          self.setHeaderDict(d)
          
          self.setEventType(EVENT_ERROR)
          self.setFont(BASIC_FONT)
          self.initTable()
          self.registerEvent()
  
  
  ########################################################################
  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}
          d['symbol'] = {'chinese':u'合约代码', 'cellType':BasicCell}
          d['vtSymbol'] = {'chinese':u'名称', 'cellType':NameCell}
          d['direction'] = {'chinese':u'方向', 'cellType':DirectionCell}
          d['offset'] = {'chinese':u'开平', 'cellType':BasicCell}
          d['price'] = {'chinese':u'价格', 'cellType':BasicCell}
          d['volume'] = {'chinese':u'数量', 'cellType':BasicCell}
          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()
  
  
  ########################################################################
  class OrderMonitor(BasicMonitor):
      """委托监控"""
  
      #----------------------------------------------------------------------
      def __init__(self, mainEngine, eventEngine, parent=None):
          """Constructor"""
          super(OrderMonitor, self).__init__(mainEngine, eventEngine, parent)
  
          self.mainEngine = mainEngine
          
          d = OrderedDict()
          d['orderID'] = {'chinese':u'委托编号', 'cellType':NumCell}
          d['symbol'] = {'chinese':u'合约代码', 'cellType':BasicCell}
          d['vtSymbol'] = {'chinese':u'名称', 'cellType':NameCell}
          d['direction'] = {'chinese':u'方向', 'cellType':DirectionCell}
          d['offset'] = {'chinese':u'开平', 'cellType':BasicCell}
          d['price'] = {'chinese':u'价格', 'cellType':BasicCell}
          d['totalVolume'] = {'chinese':u'委托数量', 'cellType':BasicCell}
          d['tradedVolume'] = {'chinese':u'成交数量', 'cellType':BasicCell}
          d['status'] = {'chinese':u'状态', 'cellType':BasicCell}
          d['orderTime'] = {'chinese':u'委托时间', 'cellType':BasicCell}
          d['cancelTime'] = {'chinese':u'撤销时间', 'cellType':BasicCell}
          d['frontID'] = {'chinese':u'前置编号', 'cellType':BasicCell}
          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) 
      
      #----------------------------------------------------------------------
      def cancelOrder(self, cell):
          """根据单元格的数据撤单"""
          order = cell.data
          
          req = VtCancelOrderReq()
          req.symbol = order.symbol
          req.exchange = order.exchange
          req.frontID = order.frontID
          req.sessionID = order.sessionID
          req.orderID = order.orderID
          self.mainEngine.cancelOrder(req, order.gatewayName)
  
  
  ########################################################################
  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}
          d['direction'] = {'chinese':u'方向', 'cellType':DirectionCell}
          d['position'] = {'chinese':u'持仓量', 'cellType':BasicCell}
          d['ydPosition'] = {'chinese':u'昨持仓', 'cellType':BasicCell}
          d['frozen'] = {'chinese':u'冻结量', 'cellType':BasicCell}
          d['price'] = {'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):
      """账户监控"""
  
      #----------------------------------------------------------------------
      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}
          d['balance'] = {'chinese':u'净值', 'cellType':BasicCell}
          d['available'] = {'chinese':u'可用', 'cellType':BasicCell}
          d['commission'] = {'chinese':u'手续费', 'cellType':BasicCell}
          d['margin'] = {'chinese':u'保证金', 'cellType':BasicCell}
          d['closeProfit'] = {'chinese':u'平仓盈亏', 'cellType':BasicCell}
          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)
          self.initTable()
          self.registerEvent()
  
  
  ########################################################################
  class TradingWidget(QtGui.QFrame):
      """简单交易组件"""
      signal = QtCore.pyqtSignal(type(Event()))
      
      directionList = [DIRECTION_LONG,
                       DIRECTION_SHORT]
  
      offsetList = [OFFSET_OPEN,
                    OFFSET_CLOSE,
                    OFFSET_CLOSEYESTERDAY,
                    OFFSET_CLOSETODAY]
      
      priceTypeList = [PRICETYPE_LIMITPRICE,
                       PRICETYPE_MARKETPRICE,
                       PRICETYPE_FAK,
                       PRICETYPE_FOK]
      
      exchangeList = [EXCHANGE_NONE,
                      EXCHANGE_CFFEX,
                      EXCHANGE_SHFE,
                      EXCHANGE_DCE,
                      EXCHANGE_CZCE,
                      EXCHANGE_SSE,
                      EXCHANGE_SZSE,
                      EXCHANGE_SGE,
                      EXCHANGE_HKEX,
                      EXCHANGE_SMART,
                      EXCHANGE_ICE,
                      EXCHANGE_CME,
                      EXCHANGE_NYMEX,
                      EXCHANGE_GLOBEX,
                      EXCHANGE_IDEALPRO]
      
      currencyList = [CURRENCY_NONE,
                      CURRENCY_CNY,
                      CURRENCY_USD]
      
      productClassList = [PRODUCT_NONE,
                          PRODUCT_EQUITY,
                          PRODUCT_FUTURES,
                          PRODUCT_OPTION,
                          PRODUCT_FOREX]
      
      gatewayList = ['']
  
      #----------------------------------------------------------------------
      def __init__(self, mainEngine, eventEngine, parent=None):
          """Constructor"""
          super(TradingWidget, self).__init__(parent)
          self.mainEngine = mainEngine
          self.eventEngine = eventEngine
          
          self.symbol = ''
          
          # 添加交易接口
          self.gatewayList.extend(mainEngine.gatewayDict.keys())
  
          self.initUi()
          self.connectSignal()
  
      #----------------------------------------------------------------------
      def initUi(self):
          """初始化界面"""
          self.setWindowTitle(u'交易')
          self.setMaximumWidth(400)
          self.setFrameShape(self.Box)    # 设置边框
          self.setLineWidth(1)           
  
          # 左边部分
          labelSymbol = QtGui.QLabel(u'代码')
          labelName =  QtGui.QLabel(u'名称')
          labelDirection = QtGui.QLabel(u'方向类型')
          labelOffset = QtGui.QLabel(u'开平')
          labelPrice = QtGui.QLabel(u'价格')
          labelVolume = QtGui.QLabel(u'数量')
          labelPriceType = QtGui.QLabel(u'价格类型')
          labelExchange = QtGui.QLabel(u'交易所') 
          labelCurrency = QtGui.QLabel(u'货币')
          labelProductClass = QtGui.QLabel(u'产品类型')
          labelGateway = QtGui.QLabel(u'交易接口')
  
          self.lineSymbol = QtGui.QLineEdit()
          self.lineName = QtGui.QLineEdit()
  
          self.comboDirection = QtGui.QComboBox()
          self.comboDirection.addItems(self.directionList)
  
          self.comboOffset = QtGui.QComboBox()
          self.comboOffset.addItems(self.offsetList)
  
          self.spinPrice = QtGui.QDoubleSpinBox()
          self.spinPrice.setDecimals(4)
          self.spinPrice.setMinimum(0)
          self.spinPrice.setMaximum(100000)
  
          self.spinVolume = QtGui.QSpinBox()
          self.spinVolume.setMinimum(0)
          self.spinVolume.setMaximum(1000000)
  
          self.comboPriceType = QtGui.QComboBox()
          self.comboPriceType.addItems(self.priceTypeList)
          
          self.comboExchange = QtGui.QComboBox()
          self.comboExchange.addItems(self.exchangeList)      
          
          self.comboCurrency = QtGui.QComboBox()
          self.comboCurrency.addItems(self.currencyList)
          
          self.comboProductClass = QtGui.QComboBox()
          self.comboProductClass.addItems(self.productClassList)     
          
          self.comboGateway = QtGui.QComboBox()
          self.comboGateway.addItems(self.gatewayList)          
  
          gridleft = QtGui.QGridLayout()
          gridleft.addWidget(labelSymbol, 0, 0)
          gridleft.addWidget(labelName, 1, 0)
          gridleft.addWidget(labelDirection, 2, 0)
          gridleft.addWidget(labelOffset, 3, 0)
          gridleft.addWidget(labelPrice, 4, 0)
          gridleft.addWidget(labelVolume, 5, 0)
          gridleft.addWidget(labelPriceType, 6, 0)
          gridleft.addWidget(labelExchange, 7, 0)
          gridleft.addWidget(labelCurrency, 8, 0)
          gridleft.addWidget(labelProductClass, 9, 0)   
          gridleft.addWidget(labelGateway, 10, 0)
          
          gridleft.addWidget(self.lineSymbol, 0, 1)
          gridleft.addWidget(self.lineName, 1, 1)
          gridleft.addWidget(self.comboDirection, 2, 1)
          gridleft.addWidget(self.comboOffset, 3, 1)
          gridleft.addWidget(self.spinPrice, 4, 1)
          gridleft.addWidget(self.spinVolume, 5, 1)
          gridleft.addWidget(self.comboPriceType, 6, 1)	
          gridleft.addWidget(self.comboExchange, 7, 1)
          gridleft.addWidget(self.comboCurrency, 8, 1)	
          gridleft.addWidget(self.comboProductClass, 9, 1) 
          gridleft.addWidget(self.comboGateway, 10, 1)
  
          # 右边部分
          labelBid1 = QtGui.QLabel(u'买一')
          labelBid2 = QtGui.QLabel(u'买二')
          labelBid3 = QtGui.QLabel(u'买三')
          labelBid4 = QtGui.QLabel(u'买四')
          labelBid5 = QtGui.QLabel(u'买五')
  
          labelAsk1 = QtGui.QLabel(u'卖一')
          labelAsk2 = QtGui.QLabel(u'卖二')
          labelAsk3 = QtGui.QLabel(u'卖三')
          labelAsk4 = QtGui.QLabel(u'卖四')
          labelAsk5 = QtGui.QLabel(u'卖五')
  
          self.labelBidPrice1 = QtGui.QLabel()
          self.labelBidPrice2 = QtGui.QLabel()
          self.labelBidPrice3 = QtGui.QLabel()
          self.labelBidPrice4 = QtGui.QLabel()
          self.labelBidPrice5 = QtGui.QLabel()
          self.labelBidVolume1 = QtGui.QLabel()
          self.labelBidVolume2 = QtGui.QLabel()
          self.labelBidVolume3 = QtGui.QLabel()
          self.labelBidVolume4 = QtGui.QLabel()
          self.labelBidVolume5 = QtGui.QLabel()	
  
          self.labelAskPrice1 = QtGui.QLabel()
          self.labelAskPrice2 = QtGui.QLabel()
          self.labelAskPrice3 = QtGui.QLabel()
          self.labelAskPrice4 = QtGui.QLabel()
          self.labelAskPrice5 = QtGui.QLabel()
          self.labelAskVolume1 = QtGui.QLabel()
          self.labelAskVolume2 = QtGui.QLabel()
          self.labelAskVolume3 = QtGui.QLabel()
          self.labelAskVolume4 = QtGui.QLabel()
          self.labelAskVolume5 = QtGui.QLabel()	
  
          labelLast = QtGui.QLabel(u'最新')
          self.labelLastPrice = QtGui.QLabel()
          self.labelReturn = QtGui.QLabel()
  
          self.labelLastPrice.setMinimumWidth(60)
          self.labelReturn.setMinimumWidth(60)
  
          gridRight = QtGui.QGridLayout()
          gridRight.addWidget(labelAsk5, 0, 0)
          gridRight.addWidget(labelAsk4, 1, 0)
          gridRight.addWidget(labelAsk3, 2, 0)
          gridRight.addWidget(labelAsk2, 3, 0)
          gridRight.addWidget(labelAsk1, 4, 0)
          gridRight.addWidget(labelLast, 5, 0)
          gridRight.addWidget(labelBid1, 6, 0)
          gridRight.addWidget(labelBid2, 7, 0)
          gridRight.addWidget(labelBid3, 8, 0)
          gridRight.addWidget(labelBid4, 9, 0)
          gridRight.addWidget(labelBid5, 10, 0)
  
          gridRight.addWidget(self.labelAskPrice5, 0, 1)
          gridRight.addWidget(self.labelAskPrice4, 1, 1)
          gridRight.addWidget(self.labelAskPrice3, 2, 1)
          gridRight.addWidget(self.labelAskPrice2, 3, 1)
          gridRight.addWidget(self.labelAskPrice1, 4, 1)
          gridRight.addWidget(self.labelLastPrice, 5, 1)
          gridRight.addWidget(self.labelBidPrice1, 6, 1)
          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.labelAskVolume5, 0, 2)
          gridRight.addWidget(self.labelAskVolume4, 1, 2)
          gridRight.addWidget(self.labelAskVolume3, 2, 2)
          gridRight.addWidget(self.labelAskVolume2, 3, 2)
          gridRight.addWidget(self.labelAskVolume1, 4, 2)
          gridRight.addWidget(self.labelReturn, 5, 2)
          gridRight.addWidget(self.labelBidVolume1, 6, 2)
          gridRight.addWidget(self.labelBidVolume2, 7, 2)
          gridRight.addWidget(self.labelBidVolume3, 8, 2)
          gridRight.addWidget(self.labelBidVolume4, 9, 2)
          gridRight.addWidget(self.labelBidVolume5, 10, 2)
  
          # 发单按钮
          buttonSendOrder = QtGui.QPushButton(u'发单')
          buttonCancelAll = QtGui.QPushButton(u'全撤')
          
          size = buttonSendOrder.sizeHint()
          buttonSendOrder.setMinimumHeight(size.height()*2)   # 把按钮高度设为默认两倍
          buttonCancelAll.setMinimumHeight(size.height()*2)
  
          # 整合布局
          hbox = QtGui.QHBoxLayout()
          hbox.addLayout(gridleft)
          hbox.addLayout(gridRight)
  
          vbox = QtGui.QVBoxLayout()
          vbox.addLayout(hbox)
          vbox.addWidget(buttonSendOrder)
          vbox.addWidget(buttonCancelAll)
          vbox.addStretch()
  
          self.setLayout(vbox)
  
          # 关联更新
          buttonSendOrder.clicked.connect(self.sendOrder)
          buttonCancelAll.clicked.connect(self.cancelAll)
          self.lineSymbol.returnPressed.connect(self.updateSymbol)
  
      #----------------------------------------------------------------------
      def updateSymbol(self):
          """合约变化"""
          # 读取组件数据
          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())
          
          # 查询合约
          if exchange:
              vtSymbol = '.'.join([symbol, exchange])
              contract = self.mainEngine.getContract(vtSymbol)
          else:
              vtSymbol = 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)
  
          # 清空行情显示
          self.labelBidPrice1.setText('')
          self.labelBidPrice2.setText('')
          self.labelBidPrice3.setText('')
          self.labelBidPrice4.setText('')
          self.labelBidPrice5.setText('')
          self.labelBidVolume1.setText('')
          self.labelBidVolume2.setText('')
          self.labelBidVolume3.setText('')
          self.labelBidVolume4.setText('')
          self.labelBidVolume5.setText('')	
          self.labelAskPrice1.setText('')
          self.labelAskPrice2.setText('')
          self.labelAskPrice3.setText('')
          self.labelAskPrice4.setText('')
          self.labelAskPrice5.setText('')
          self.labelAskVolume1.setText('')
          self.labelAskVolume2.setText('')
          self.labelAskVolume3.setText('')
          self.labelAskVolume4.setText('')
          self.labelAskVolume5.setText('')
          self.labelLastPrice.setText('')
          self.labelReturn.setText('')
  
          # 重新注册事件监听
          self.eventEngine.unregister(EVENT_TICK + self.symbol, self.signal.emit)
          self.eventEngine.register(EVENT_TICK + vtSymbol, self.signal.emit)
  
          # 订阅合约
          req = VtSubscribeReq()
          req.symbol = symbol
          req.exchange = exchange
          req.currency = currency
          req.productClass = productClass
          
          self.mainEngine.subscribe(req, gatewayName)
  
          # 更新组件当前交易的合约
          self.symbol = vtSymbol
  
      #----------------------------------------------------------------------
      def updateTick(self, event):
          """更新行情"""
          tick = event.dict_['data']
  
          if tick.vtSymbol == self.symbol:
              self.labelBidPrice1.setText(str(tick.bidPrice1))
              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.labelLastPrice.setText(str(tick.lastPrice))
              
              if tick.preClosePrice:
                  rt = (tick.lastPrice/tick.preClosePrice)-1
                  self.labelReturn.setText(('%.2f' %(rt*100))+'%')
              else:
                  self.labelReturn.setText('')
  
      #----------------------------------------------------------------------
      def connectSignal(self):
          """连接Signal"""
          self.signal.connect(self.updateTick)
  
      #----------------------------------------------------------------------
      def sendOrder(self):
          """发单"""
          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())        
  
          # 查询合约
          if exchange:
              vtSymbol = '.'.join([symbol, exchange])
              contract = self.mainEngine.getContract(vtSymbol)
          else:
              vtSymbol = symbol
              contract = self.mainEngine.getContract(symbol)
          
          if contract:
              gatewayName = contract.gatewayName
              exchange = contract.exchange    # 保证有交易所代码
              
          req = VtOrderReq()
          req.symbol = symbol
          req.exchange = exchange
          req.price = self.spinPrice.value()
          req.volume = self.spinVolume.value()
          req.direction = unicode(self.comboDirection.currentText())
          req.priceType = unicode(self.comboPriceType.currentText())
          req.offset = unicode(self.comboOffset.currentText())
          req.currency = currency
          req.productClass = productClass
          
          self.mainEngine.sendOrder(req, gatewayName)
              
      #----------------------------------------------------------------------
      def cancelAll(self):
          """一键撤销所有委托"""
          l = self.mainEngine.getAllWorkingOrders()
          for order in l:
              req = VtCancelOrderReq()
              req.symbol = order.symbol
              req.exchange = order.exchange
              req.frontID = order.frontID
              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))
          self.spinVolume.setValue(pos.position)
  
          if pos.direction == DIRECTION_LONG or pos.direction == DIRECTION_NET:
              self.comboDirection.setCurrentIndex(self.directionList.index(DIRECTION_SHORT))
          else:
              self.comboDirection.setCurrentIndex(self.directionList.index(DIRECTION_LONG))
  
          # 价格留待更新后由用户输入，防止有误操作
  
  
  ########################################################################
  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}
          d['vtSymbol'] = {'chinese':u'vt系统代码', 'cellType':BasicCell}
          d['name'] = {'chinese':u'名称', 'cellType':BasicCell}
          d['productClass'] = {'chinese':u'合约类型', 'cellType':BasicCell}
          d['size'] = {'chinese':u'大小', 'cellType':BasicCell}
          d['priceTick'] = {'chinese':u'最小价格变动', 'cellType':BasicCell}
          #d['strikePrice'] = {'chinese':u'期权行权价', 'cellType':BasicCell}
          #d['underlyingSymbol'] = {'chinese':u'期权标的物', 'cellType':BasicCell}
          #d['optionType'] = {'chinese':u'期权类型', 'cellType':BasicCell}     
          self.setHeaderDict(d)
          
          self.initUi()
          
      #----------------------------------------------------------------------
      def initUi(self):
          """初始化界面"""
          self.setWindowTitle(u'合约查询')
          self.setMinimumSize(800, 800)
          self.setFont(BASIC_FONT)
          self.initTable()
          self.addMenuAction()
      
      #----------------------------------------------------------------------
      def showAllContracts(self):
          """显示所有合约数据"""
          l = self.mainEngine.getAllContracts()
          d = {'.'.join([contract.exchange, contract.symbol]):contract for contract in l}
          l2 = d.keys()
          l2.sort(reverse=True)
  
          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']
                  cell = cellType(content)
                  
                  if self.font:
                      cell.setFont(self.font)  # 如果设置了特殊字体，则进行单元格设置
                      
                  self.setItem(row, n, cell)
              
              row = row + 1
      
      #----------------------------------------------------------------------
      def refresh(self):
          """刷新"""
          self.menu.close()   # 关闭菜单
          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()
      
      
  