text: # encoding: UTF-8
  
  from __future__ import absolute_import
  from vnpy.event import Event
  
  from vnpy.trader.vtConstant import DIRECTION_LONG, DIRECTION_SHORT, OFFSET_OPEN, OFFSET_CLOSE, PRICETYPE_LIMITPRICE
  from vnpy.trader.vtObject import VtOrderReq
  from vnpy.trader.vtEvent import EVENT_TICK, EVENT_TRADE
  from vnpy.trader.uiBasicWidget import WorkingOrderMonitor, PositionMonitor
  
  from .uiOmBase import *
  
  
  
  ########################################################################
  class ChainMonitor(QtWidgets.QTableWidget):
      """期权链监控"""
      headers = [
          u'代码',
          u'买价',
          u'买量',
          u'买隐波',
          u'卖价',
          u'卖量',
          u'卖隐波',
          u'净仓',
          u'行权价',
          u'净仓',
          u'买价',
          u'买量',
          u'买隐波',
          u'卖价',
          u'卖量',
          u'卖隐波',
          u'代码'
      ]
      
      signalTick = QtCore.pyqtSignal(type(Event()))
      signalPos = QtCore.pyqtSignal(type(Event()))
      signalTrade = QtCore.pyqtSignal(type(Event()))
  
      #----------------------------------------------------------------------
      def __init__(self, omEngine, eventEngine, parent=None):
          """Constructor"""
          super(ChainMonitor, self).__init__(parent)
          
          self.omEngine = omEngine
          self.eventEngine = eventEngine
          
          # 保存代码和持仓的字典
          self.bidPriceDict = {}
          self.bidVolumeDict = {}
          self.bidImpvDict = {}
          self.askPriceDict = {}
          self.askVolumeDict = {}
          self.askImpvDict = {}
          self.posDict = {}
          
          # 保存期权对象的字典
          portfolio = omEngine.portfolio
          
          self.instrumentDict = {}
          self.instrumentDict.update(portfolio.optionDict)
          self.instrumentDict.update(portfolio.underlyingDict)
          
          # 初始化
          self.initUi()
          self.registerEvent()
          
      #----------------------------------------------------------------------
      def initUi(self):
          """初始化界面"""
          portfolio = self.omEngine.portfolio
          
          # 初始化表格
          self.setColumnCount(len(self.headers))
          self.setHorizontalHeaderLabels(self.headers)
  
          rowCount = 0
          rowCount += len(portfolio.underlyingDict)
          rowCount += len(portfolio.chainDict)
          for chain in portfolio.chainDict.values():
              rowCount += len(chain.callDict)
          self.setRowCount(rowCount)
          
          self.verticalHeader().setVisible(False)
          self.setEditTriggers(self.NoEditTriggers)
          
          for i in range(self.columnCount()):
              self.horizontalHeader().setResizeMode(i, QtWidgets.QHeaderView.Stretch)
          self.horizontalHeader().setResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
          self.horizontalHeader().setResizeMode(self.columnCount()-1, QtWidgets.QHeaderView.ResizeToContents)
          
          # 初始化标的单元格
          row = 0
          
          for underlying in portfolio.underlyingDict.values():
              symbol = underlying.symbol
              
              cellSymbol = OmCell(symbol, COLOR_SYMBOL, COLOR_BLACK, underlying)
              cellBidPrice = OmCell(str(underlying.bidPrice1), COLOR_BID, COLOR_BLACK, underlying)
              cellBidVolume = OmCell(str(underlying.bidVolume1), COLOR_BID, COLOR_BLACK, underlying)
              cellAskPrice = OmCell(str(underlying.askPrice1), COLOR_ASK, COLOR_BLACK, underlying)
              cellAskVolume = OmCell(str(underlying.askVolume1), COLOR_ASK, COLOR_BLACK, underlying)
              cellPos = OmCell(str(underlying.netPos), COLOR_POS, COLOR_BLACK, underlying)
              
              self.setItem(row, 0, cellSymbol)
              self.setItem(row, 1, cellBidPrice)
              self.setItem(row, 2, cellBidVolume)
              self.setItem(row, 4, cellAskPrice)
              self.setItem(row, 5, cellAskVolume)
              self.setItem(row, 7, cellPos)
              
              self.bidPriceDict[symbol] = cellBidPrice
              self.bidVolumeDict[symbol] = cellBidVolume
              self.askPriceDict[symbol] = cellAskPrice
              self.askVolumeDict[symbol] = cellAskVolume
              self.posDict[symbol] = cellPos
              
              row += 1
              
          row += 1
              
          # 初始化期权单元格
          for chain in portfolio.chainDict.values():
              
              # call
              callRow = row
              
              for option in chain.callDict.values():    
                  cellSymbol = OmCell(option.symbol, COLOR_SYMBOL, COLOR_BLACK, option)
                  cellBidPrice = OmCell(str(option.bidPrice1), COLOR_BID, COLOR_BLACK, option)
                  cellBidVolume = OmCell(str(option.bidVolume1), COLOR_BID, COLOR_BLACK, option)
                  cellBidImpv = OmCell('%.1f' %(option.bidImpv*100), COLOR_BID, COLOR_BLACK, option)
                  cellAskPrice = OmCell(str(option.askPrice1), COLOR_ASK, COLOR_BLACK, option)
                  cellAskVolume = OmCell(str(option.askVolume1), COLOR_ASK, COLOR_BLACK, option)
                  cellAskImpv = OmCell('%.1f' %(option.askImpv*100), COLOR_ASK, COLOR_BLACK, option)
                  cellPos = OmCell(str(option.netPos), COLOR_POS, COLOR_BLACK, option)
                  cellStrike = OmCell(str(option.k), COLOR_STRIKE)
                  
                  self.setItem(callRow, 0, cellSymbol)
                  self.setItem(callRow, 1, cellBidPrice)
                  self.setItem(callRow, 2, cellBidVolume)
                  self.setItem(callRow, 3, cellBidImpv)
                  self.setItem(callRow, 4, cellAskPrice)
                  self.setItem(callRow, 5, cellAskVolume)
                  self.setItem(callRow, 6, cellAskImpv)
                  self.setItem(callRow, 7, cellPos)
                  self.setItem(callRow, 8, cellStrike)
                  
                  self.bidPriceDict[option.symbol] = cellBidPrice
                  self.bidVolumeDict[option.symbol] = cellBidVolume
                  self.bidImpvDict[option.symbol] = cellBidImpv
                  self.askPriceDict[option.symbol] = cellAskPrice
                  self.askVolumeDict[option.symbol] = cellAskVolume            
                  self.askImpvDict[option.symbol] = cellAskImpv
                  self.posDict[option.symbol] = cellPos
                  
                  callRow += 1
              
              # put
              putRow = row
              
              for option in chain.putDict.values():
                  cellSymbol = OmCell(option.symbol, COLOR_SYMBOL, COLOR_BLACK, option)
                  cellBidPrice = OmCell(str(option.bidPrice1), COLOR_BID, COLOR_BLACK, option)
                  cellBidVolume = OmCell(str(option.bidVolume1), COLOR_BID, COLOR_BLACK, option)
                  cellBidImpv = OmCell('%.1f' %(option.bidImpv*100), COLOR_BID, COLOR_BLACK, option)
                  cellAskPrice = OmCell(str(option.askPrice1), COLOR_ASK, COLOR_BLACK, option)
                  cellAskVolume = OmCell(str(option.askVolume1), COLOR_ASK, COLOR_BLACK, option)
                  cellAskImpv = OmCell('%.1f' %(option.askImpv*100), COLOR_ASK, COLOR_BLACK, option)
                  cellPos = OmCell(str(option.netPos), COLOR_POS, COLOR_BLACK, option)
                  
                  self.setItem(putRow, 9, cellPos)
                  self.setItem(putRow, 10, cellBidPrice)
                  self.setItem(putRow, 11, cellBidVolume)
                  self.setItem(putRow, 12, cellBidImpv)
                  self.setItem(putRow, 13, cellAskPrice)
                  self.setItem(putRow, 14, cellAskVolume)
                  self.setItem(putRow, 15, cellAskImpv)
                  self.setItem(putRow, 16, cellSymbol)
                  
                  self.bidPriceDict[option.symbol] = cellBidPrice
                  self.bidVolumeDict[option.symbol] = cellBidVolume
                  self.bidImpvDict[option.symbol] = cellBidImpv
                  self.askPriceDict[option.symbol] = cellAskPrice
                  self.askVolumeDict[option.symbol] = cellAskVolume            
                  self.askImpvDict[option.symbol] = cellAskImpv
                  self.posDict[option.symbol] = cellPos  
                  
                  putRow += 1
              
              row = putRow + 1
              
      #----------------------------------------------------------------------
      def registerEvent(self):
          """注册事件监听"""
          self.signalTick.connect(self.processTickEvent)
          self.signalTrade.connect(self.processTradeEvent)
          
          portfolio = self.omEngine.portfolio
          
          for underlying in portfolio.underlyingDict.values():
              self.eventEngine.register(EVENT_TICK + underlying.vtSymbol, self.signalTick.emit)
              self.eventEngine.register(EVENT_TRADE + underlying.vtSymbol, self.signalTrade.emit)
          
          for chain in portfolio.chainDict.values():
              for option in chain.optionDict.values():
                  self.eventEngine.register(EVENT_TICK + option.vtSymbol, self.signalTick.emit)
                  self.eventEngine.register(EVENT_TRADE + option.vtSymbol, self.signalTrade.emit)
      
      #----------------------------------------------------------------------
      def processTickEvent(self, event):
          """行情更新"""
          tick = event.dict_['data']
          symbol = tick.symbol
          
          if symbol in self.bidImpvDict:
              option = self.instrumentDict[symbol]
              self.bidImpvDict[symbol].setText('%.1f' %(option.bidImpv*100))
              self.askImpvDict[symbol].setText('%.1f' %(option.askImpv*100))
          
          self.bidPriceDict[symbol].setText(str(tick.bidPrice1))
          self.bidVolumeDict[symbol].setText(str(tick.bidVolume1))
          self.askPriceDict[symbol].setText(str(tick.askPrice1))
          self.askVolumeDict[symbol].setText(str(tick.askVolume1))
      
      #----------------------------------------------------------------------
      def processTradeEvent(self, event):
          """成交更新"""
          trade = event.dict_['data']
          
          symbol = trade.symbol
          instrument = self.instrumentDict[symbol]
          self.posDict[symbol].setText(str(instrument.netPos))
  
  
  ########################################################################
  class TradingWidget(QtWidgets.QWidget):
      """交易组件"""
  
      #----------------------------------------------------------------------
      def __init__(self, omEngine, parent=None):
          """Constructor"""
          super(TradingWidget, self).__init__(parent)
          
          self.omEngine = omEngine
          self.mainEngine = omEngine.mainEngine
          self.portfolio = omEngine.portfolio
          
          self.initUi()
          
      #----------------------------------------------------------------------
      def initUi(self):
          """初始化界面"""
          self.setFixedWidth(200)
          
          labelTradingWidget = QtWidgets.QLabel(u'期权交易')
          labelSymbol = QtWidgets.QLabel(u'代码')
          labelDirection = QtWidgets.QLabel(u'方向')
          labelPrice = QtWidgets.QLabel(u'价格')
          labelVolume = QtWidgets.QLabel(u'数量')
          
          self.lineSymbol = QtWidgets.QLineEdit()
          self.comboDirection = QtWidgets.QComboBox()
          self.comboDirection.addItems([DIRECTION_LONG, DIRECTION_SHORT])
          self.linePrice = QtWidgets.QLineEdit()
          self.lineVolume = QtWidgets.QLineEdit()
          self.buttonSendOrder = QtWidgets.QPushButton(u'发单')
          self.buttonSendOrder.clicked.connect(self.sendOrder)
          
          grid = QtWidgets.QGridLayout()
          grid.addWidget(labelTradingWidget, 0, 0, 1, 2)
          grid.addWidget(labelSymbol, 1, 0)
          grid.addWidget(labelDirection, 2, 0)
          grid.addWidget(labelPrice, 3, 0)
          grid.addWidget(labelVolume, 4, 0)
          grid.addWidget(self.lineSymbol, 1, 1)
          grid.addWidget(self.comboDirection, 2, 1)
          grid.addWidget(self.linePrice, 3, 1)
          grid.addWidget(self.lineVolume, 4, 1)
          grid.addWidget(self.buttonSendOrder, 5, 0, 1, 2)
          self.setLayout(grid)
  
      #----------------------------------------------------------------------
      def sendOrder(self):
          """发送委托"""
          try:
              symbol = str(self.lineSymbol.text())
              direction = str(self.comboDirection.currentText())
              price = float(self.linePrice.text())
              volume = int(self.lineVolume.text())
          except:
              return
          
          instrument = self.portfolio.instrumentDict.get(symbol, None)
          if not instrument:
              return
          
          # 做多
          if direction == DIRECTION_LONG:
              # 如果空头仓位大于等于买入量，则只需平
              if instrument.shortPos >= volume:
                  self.fastTrade(symbol, DIRECTION_LONG, OFFSET_CLOSE, price, volume)
              # 否则先平后开
              else:
                  openVolume = volume - instrument.shortPos
                  if instrument.shortPos:
                      self.fastTrade(symbol, DIRECTION_LONG, OFFSET_CLOSE, price, instrument.shortPos)
                  self.fastTrade(symbol, DIRECTION_LONG, OFFSET_OPEN, price, openVolume)
          # 做空
          else:
              if instrument.longPos >= volume:
                  self.fastTrade(symbol, DIRECTION_SHORT, OFFSET_CLOSE, price, volume)
              else:
                  openVolume = volume - instrument.longPos
                  if instrument.longPos:
                      self.fastTrade(symbol, DIRECTION_SHORT, OFFSET_CLOSE, price, instrument.longPos)
                  self.fastTrade(symbol ,DIRECTION_SHORT, OFFSET_OPEN, price, openVolume)
      
      #----------------------------------------------------------------------
      def fastTrade(self, symbol, direction, offset, price, volume):
          """封装下单函数"""
          contract = self.mainEngine.getContract(symbol)
          if not contract:
              return
          
          req = VtOrderReq()
          req.symbol = symbol
          req.exchange = contract.exchange
          req.direction = direction
          req.offset = offset
          req.price = price
          req.volume = volume
          req.priceType = PRICETYPE_LIMITPRICE
          self.mainEngine.sendOrder(req, contract.gatewayName)
      
      #----------------------------------------------------------------------
      def updateWidget(self, item):
          """双击监控组件单元格后自动更新组件"""
          instrument = item.data
          if not instrument:
              return
          
          self.lineSymbol.setText(instrument.symbol)
          
          # short
          if item.background is COLOR_BID:
              self.comboDirection.setCurrentIndex(1)
              self.linePrice.setText(str(instrument.bidPrice1))
              self.lineVolume.setText(str(instrument.bidVolume1))
          # long
          elif item.background is COLOR_ASK:
              self.comboDirection.setCurrentIndex(0)
              self.linePrice.setText(str(instrument.askPrice1))
              self.lineVolume.setText(str(instrument.askVolume1))
  
  
  ########################################################################
  class ManualTrader(QtWidgets.QWidget):
      """手动交易组件"""
  
      #----------------------------------------------------------------------
      def __init__(self, omEngine, parent=None):
          """Constructor"""
          super(ManualTrader, self).__init__(parent)
          
          self.omEngine = omEngine
          self.mainEngine = omEngine.mainEngine
          self.eventEngine = omEngine.eventEngine
          
          self.initUi()
          
      #----------------------------------------------------------------------
      def initUi(self):
          """初始化界面"""
          self.setWindowTitle(u'手动交易')
          
          posMonitor = PositionMonitor(self.mainEngine, self.eventEngine)
          for i in range(posMonitor.columnCount()):
              posMonitor.horizontalHeader().setResizeMode(QtWidgets.QHeaderView.Stretch)
          posMonitor.setSorting(False)
          
          orderMonitor = WorkingOrderMonitor(self.mainEngine, self.eventEngine)
          for i in range(orderMonitor.columnCount()):
              orderMonitor.horizontalHeader().setResizeMode(QtWidgets.QHeaderView.Stretch)
          orderMonitor.setSorting(False)
              
          tradingWidget = TradingWidget(self.omEngine)
          
          chainMonitor = ChainMonitor(self.omEngine, self.eventEngine)
          chainMonitor.itemDoubleClicked.connect(tradingWidget.updateWidget)
          
          vbox1 = QtWidgets.QVBoxLayout()
          vbox1.addWidget(orderMonitor)
          vbox1.addWidget(posMonitor)
          
          vbox2 = QtWidgets.QVBoxLayout()
          vbox2.addWidget(tradingWidget)
          vbox2.addStretch()
          
          hbox = QtWidgets.QHBoxLayout()
          hbox.addLayout(vbox1)
          hbox.addLayout(vbox2)
          
          vbox3 = QtWidgets.QVBoxLayout()
          vbox3.addWidget(chainMonitor)
          vbox3.addLayout(hbox)
          
          self.setLayout(vbox3)
      
      