def connect(self, username: str, password: str, host: str, port: int,
                auth_code: str):
        """
        Starting connection to TAP server.
        """
        # General API setting
        path = get_folder_path(self.gateway_name.lower())
        SetTapQuoteAPIDataPath(str(path))

        SetTapQuoteAPILogLevel(APILOGLEVEL_NONE)

        # Create API object
        info = TapAPIApplicationInfo()
        info.AuthCode = auth_code
        info.KeyOperationLogPath = str(path)

        self.api, iResult = CreateTapQuoteAPI(info)
        if not self.api:
            self.gateway.write_log("行情API初始化失败")
            return

        # Set server address and port
        self.api.SetAPINotify(self)
        self.api.SetHostAddress(host, port)

        # Start connection
        login_auth = TapAPIQuoteLoginAuth()
        login_auth.UserNo = username
        login_auth.Password = password
        login_auth.ISDDA = APIYNFLAG_NO
        login_auth.ISModifyPassword = APIYNFLAG_NO

        self.api.Login(login_auth)
class QuoteApi(ITapQuoteAPINotify):
    """
    Implementation of TAP quote api.
    """
    def __init__(self, gateway: TapGateway):
        """"""
        super().__init__()

        self.gateway = gateway
        self.gateway_name = gateway.gateway_name
        self.api = None

    def OnRspLogin(self, errorCode: int, info: TapAPIQuotLoginRspInfo):
        """
        Callback of login request.
        """
        if errorCode != TAPIERROR_SUCCEED:
            self.gateway.write_log(f"行情服务器登录失败:{error_to_str(errorCode)}")
        else:
            self.gateway.write_log("行情服务器登录成功")

    def OnAPIReady(self):
        """
        Callback when API is ready for sending requests or queries.
        """
        self.api.QryCommodity()

    def OnDisconnect(self, reasonCode: int):
        """
        Callback when connection to TAP server is lost.
        """
        self.gateway.write_log(f"行情服务器连接断开,原因:{reasonCode}")

    def OnRspSubscribeQuote(self, sessionID: int, errorCode: int, isLast: str,
                            info: TapAPIQuoteWhole):
        """
        Callback of subscribe market data request.
        """
        if errorCode != TAPIERROR_SUCCEED:
            self.gateway.write_log(f"订阅行情失败:{error_to_str(errorCode)}")
        else:
            self.update_tick(info)

    def OnRtnQuote(self, info: TapAPIQuoteWhole):
        """
        Callback of new data update.
        """
        self.update_tick(info)

    def update_tick(self, info: TapAPIQuoteWhole):
        """
        Convert TAP quote data structure into TickData event and push it.
        """
        symbol = info.Contract.Commodity.CommodityNo + info.Contract.ContractNo1
        exchange = EXCHANGE_TAP2VT[info.Contract.Commodity.ExchangeNo]

        contract_info = contract_infos.get((symbol, exchange), None)
        if not contract_info:
            self.gateway.write_log(f"行情合约信息无法匹配:{symbol}和{exchange}")
            return

        tick = TickData(
            symbol=symbol,
            exchange=exchange,
            datetime=parse_datetime(info.DateTimeStamp),
            name=contract_info.name,
            volume=info.QTotalQty,
            last_price=info.QLastPrice,
            last_volume=info.QLastQty,
            limit_up=info.QLimitUpPrice,
            limit_down=info.QLimitDownPrice,
            open_price=info.QOpeningPrice,
            high_price=info.QHighPrice,
            low_price=info.QLowPrice,
            pre_close=info.QPreClosingPrice,
            bid_price_1=info.QBidPrice[0],
            bid_price_2=info.QBidPrice[1],
            bid_price_3=info.QBidPrice[2],
            bid_price_4=info.QBidPrice[3],
            bid_price_5=info.QBidPrice[4],
            ask_price_1=info.QAskPrice[0],
            ask_price_2=info.QAskPrice[1],
            ask_price_3=info.QAskPrice[2],
            ask_price_4=info.QAskPrice[3],
            ask_price_5=info.QAskPrice[4],
            bid_volume_1=info.QBidQty[0],
            bid_volume_2=info.QBidQty[1],
            bid_volume_3=info.QBidQty[2],
            bid_volume_4=info.QBidQty[3],
            bid_volume_5=info.QBidQty[4],
            ask_volume_1=info.QAskQty[0],
            ask_volume_2=info.QAskQty[1],
            ask_volume_3=info.QAskQty[2],
            ask_volume_4=info.QAskQty[3],
            ask_volume_5=info.QAskQty[4],
            gateway_name=self.gateway_name,
        )
        self.gateway.on_tick(tick)

    def connect(self, username: str, password: str, host: str, port: int,
                auth_code: str):
        """
        Starting connection to TAP server.
        """
        # General API setting
        path = get_folder_path(self.gateway_name.lower())
        SetTapQuoteAPIDataPath(str(path))

        SetTapQuoteAPILogLevel(APILOGLEVEL_NONE)

        # Create API object
        info = TapAPIApplicationInfo()
        info.AuthCode = auth_code
        info.KeyOperationLogPath = str(path)

        self.api, iResult = CreateTapQuoteAPI(info)
        if not self.api:
            self.gateway.write_log("行情API初始化失败")
            return

        # Set server address and port
        self.api.SetAPINotify(self)
        self.api.SetHostAddress(host, port)

        # Start connection
        login_auth = TapAPIQuoteLoginAuth()
        login_auth.UserNo = username
        login_auth.Password = password
        login_auth.ISDDA = APIYNFLAG_NO
        login_auth.ISModifyPassword = APIYNFLAG_NO

        self.api.Login(login_auth)

    def close(self):
        """
        Release TAP API resources.
        """
        if self.api:
            self.api.SetAPINotify(None)
            FreeTapQuoteAPI(self.api)
            self.api = None

    def subscribe(self, req: SubscribeRequest):
        """
        Subscribe to new market data update.
        """
        contract_info = contract_infos.get((req.symbol, req.exchange), None)
        if not contract_info:
            self.gateway.write_log(
                f"找不到匹配的合约:{req.symbol}和{req.exchange.value}")
            return

        tap_contract = TapAPIContract()
        tap_contract.Commodity.ExchangeNo = EXCHANGE_VT2TAP[req.exchange]
        tap_contract.Commodity.CommodityType = contract_info.commodity_type
        tap_contract.Commodity.CommodityNo = contract_info.commodity_no
        tap_contract.ContractNo1 = contract_info.contract_no
        tap_contract.CallOrPutFlag1 = TAPI_CALLPUT_FLAG_NONE
        tap_contract.CallOrPutFlag2 = TAPI_CALLPUT_FLAG_NONE

        self.api.SubscribeQuote(tap_contract)