# encoding: UTF-8

'''
Wind Python API的gateway接入
'''

from copy import copy

w = None

try:
    from WindPy import w
except ImportError:
    print u'请先安装WindPy接口'

from vnpy.trader.vtGateway import *

# 交易所类型映射
exchangeMap = {}
exchangeMap[EXCHANGE_SSE] = 'SH'
exchangeMap[EXCHANGE_SZSE] = 'SZ'
exchangeMap[EXCHANGE_CFFEX] = 'CFE'
exchangeMap[EXCHANGE_SHFE] = 'SHF'
exchangeMap[EXCHANGE_DCE] = 'DCE'
exchangeMap[EXCHANGE_CZCE] = 'CZC'
exchangeMap[EXCHANGE_UNKNOWN] = ''
exchangeMapReverse = {v:k for k,v in exchangeMap.items()}

# Wind接口相关事件
EVENT_WIND_CONNECTREQ = 'eWindConnectReq'   # Wind接口请求连接事件


########################################################################
class WindGateway(VtGateway):
    """Wind接口"""
    # 订阅wsq时传入的字段列表
    wsqParamMap = {}
    wsqParamMap['rt_last'] = 'lastPrice'
    wsqParamMap['rt_last_vol'] = 'volume'
    wsqParamMap['rt_oi'] = 'openInterest'

    wsqParamMap['rt_open'] = 'openPrice'
    wsqParamMap['rt_high'] = 'highPrice'
    wsqParamMap['rt_low'] = 'lowPrice'
    wsqParamMap['rt_pre_close'] = 'preClosePrice'
                    
    wsqParamMap['rt_high_limit'] = 'upperLimit'
    wsqParamMap['rt_low_limit'] = 'lowerLimit'

    wsqParamMap['rt_bid1'] = 'bidPrice1'
    wsqParamMap['rt_bid2'] = 'bidPrice2'
    wsqParamMap['rt_bid3'] = 'bidPrice3'
    wsqParamMap['rt_bid4'] = 'bidPrice4'
    wsqParamMap['rt_bid5'] = 'bidPrice5'
                    
    wsqParamMap['rt_ask1'] = 'askPrice1'
    wsqParamMap['rt_ask2'] = 'askPrice2'
    wsqParamMap['rt_ask3'] = 'askPrice3'
    wsqParamMap['rt_ask4'] = 'askPrice4'
    wsqParamMap['rt_ask5'] = 'askPrice5'     
                    
    wsqParamMap['rt_bsize1'] = 'bidVolume1'
    wsqParamMap['rt_bsize2'] = 'bidVolume2'
    wsqParamMap['rt_bsize3'] = 'bidVolume3'
    wsqParamMap['rt_bsize4'] = 'bidVolume4'
    wsqParamMap['rt_bsize5'] = 'bidVolume5'
                    
    wsqParamMap['rt_asize1'] = 'askVolume1'
    wsqParamMap['rt_asize2'] = 'askVolume2'
    wsqParamMap['rt_asize3'] = 'askVolume3'
    wsqParamMap['rt_asize4'] = 'askVolume4'
    wsqParamMap['rt_asize5'] = 'askVolume5'
    
    wsqParam = ','.join(wsqParamMap.keys())

    #----------------------------------------------------------------------
    def __init__(self, eventEngine, gatewayName='Wind'):
        """Constructor"""
        super(WindGateway, self).__init__(eventEngine, gatewayName)
        
        self.w = w                  # Wind API对象
        self.connected = False      # 连接状态
        
        # Wind的wsq更新采用的是增量更新模式，每次推送只会更新发生变化的字段
        # 而vt中的tick是完整更新，因此需要本地维护一个所有字段的快照
        self.tickDict = {}
        
        # 订阅请求缓存
        self.subscribeBufferDict = {}
        
        self.registerEvent()
        
    #----------------------------------------------------------------------
    def connect(self):
        """连接"""
        # 由于w.start方法会阻塞较长时间
        # 因此设计为异步模式，交给事件处理线程去处理
        # 另外w.start和WingIDE的debug模块有冲突，会导致异常退出
        event = Event(type_=EVENT_WIND_CONNECTREQ)
        self.eventEngine.put(event)
        
    #----------------------------------------------------------------------
    def subscribe(self, subscribeReq):
        """订阅行情"""
        windSymbol = '.'.join([subscribeReq.symbol, exchangeMap[subscribeReq.exchange]])
        
        # 若已经连接则直接订阅
        if self.connected:    
            data = self.w.wsq(windSymbol, self.wsqParam, func=self.wsqCallBack)
        # 否则缓存在字典中
        else:
            self.subscribeBufferDict[windSymbol] = subscribeReq
            
    #----------------------------------------------------------------------
    def sendOrder(self, orderReq):
        """发单"""
        log = VtLogData()
        log.gatewayName = self.gatewayName        
        log.logContent = u'Wind接口未实现发单功能'
        self.onLog(log) 
    
    #----------------------------------------------------------------------
    def cancelOrder(self, cancelOrderReq):
        """撤单"""
        log = VtLogData()
        log.gatewayName = self.gatewayName        
        log.logContent = u'Wind接口未实现撤单功能'
        self.onLog(log) 
    
    #----------------------------------------------------------------------
    def getAccount(self):
        """查询账户资金"""
        log = VtLogData()
        log.gatewayName = self.gatewayName        
        log.logContent = u'Wind接口未实现查询账户功能'
        self.onLog(log) 
    
    #----------------------------------------------------------------------
    def getPosition(self):
        """查询持仓"""
        log = VtLogData()
        log.gatewayName = self.gatewayName        
        log.logContent = u'Wind接口未实现查询持仓功能'
        self.onLog(log) 
    
    #----------------------------------------------------------------------
    def close(self):
        if self.w:
            self.w.stop()
     
    #----------------------------------------------------------------------
    def registerEvent(self):
        """注册事件监听"""
        self.eventEngine.register(EVENT_WIND_CONNECTREQ, self.wConnect)
        
    #----------------------------------------------------------------------
    def wsqCallBack(self, data):
        """收到wsq推送"""
        windSymbol = data.Codes[0]
        if windSymbol in self.tickDict:
            tick = self.tickDict[windSymbol]
        else:
            tick = VtTickData()
            tick.gatewayName = self.gatewayName
            symbolSplit = windSymbol.split('.')
            tick.symbol = symbolSplit[0]
            tick.exchange = exchangeMapReverse[symbolSplit[1]]  
            tick.vtSymbol = '.'.join([tick.symbol, tick.exchange])
            self.tickDict[windSymbol] = tick

        dt = data.Times[0]
        tick.time = dt.strftime('%H:%M:%S.%f')
        tick.date = dt.strftime('%Y%m%d')
        
        # 采用遍历的形式读取数值
        fields = data.Fields
        values = data.Data
        d = tick.__dict__
        for n, field in enumerate(fields):
            field = field.lower()
            key = self.wsqParamMap[field]
            value = values[n][0]
            d[key] = value
        
        newtick = copy(tick)
        self.onTick(newtick)
    
    #----------------------------------------------------------------------
    def wConnect(self, event):
        """利用事件处理线程去异步连接Wind接口"""
        result = self.w.start()
        
        log = VtLogData()
        log.gatewayName = self.gatewayName        
        
        if not result.ErrorCode:
            log.logContent = u'Wind接口连接成功'
            
            self.connected = True
            
            # 发出缓存的订阅请求
            for req in self.subscribeBufferDict.values():
                self.subscribe(req)
            self.subscribeBufferDict.clear()
        else:
            log.logContent = u'Wind接口连接失败，错误代码%d' %result.ErrorCode
        self.onLog(log) 