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()) SetITapTradeAPIDataPath(str(path)) SetITapTradeAPILogLevel(APILOGLEVEL_NONE) # Create API object info = TapTradeAPIApplicationInfo() info.AuthCode = auth_code info.KeyOperationLogPath = str(path) self.api, iResult = CreateITapTradeAPI(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, False) # Start connection login_auth = TapAPITradeLoginAuth() login_auth.UserNo = username login_auth.Password = password login_auth.ISModifyPassword = APIYNFLAG_NO self.api.Login(login_auth)
class TradeApi(ITapTradeAPINotify): """ Implementation of TAP trade api. """ def __init__(self, gateway: TapGateway): """""" super().__init__() self.gateway = gateway self.gateway_name = gateway.gateway_name self.api = None self.account_no = "" # required when sending order request self.cancel_reqs = { } # waiting cancel order requests before OrderNo received # for mapping relationship between TAP OrderNo and ClientOrderNo self.sys_local_map = {} self.local_sys_map = {} self.sys_server_map = {} def OnConnect(self): """ Callback when connection is established with TAP server. """ self.gateway.write_log("交易服务器连接成功") def OnRspLogin(self, errorCode: int, info: TapAPITradeLoginRspInfo): """ 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, code: int): """ Callback when API is ready for sending requests or queries. """ self.api.QryCommodity() def OnRspQryCommodity( self, sessionID: int, errorCode: int, isLast: str, info: TapAPICommodityInfo, ): """ Callback of commodity query with size and pricetick data. """ if errorCode != TAPIERROR_SUCCEED: self.gateway.write_log("查询交易品种信息失败") return commodity_info = CommodityInfo(name=info.CommodityEngName, size=int(info.ContractSize), pricetick=info.CommodityTickSize) commodity_infos[info.CommodityNo] = commodity_info if isLast == "Y": self.gateway.write_log("查询交易品种信息成功") self.api.QryContract(None) def OnRspQryContract(self, sessionID: int, errorCode: int, isLast: str, info: TapAPITradeContractInfo): """ Callback of contract query with detailed contract data. """ if errorCode != TAPIERROR_SUCCEED: self.gateway.write_log("查询交易合约信息失败") return exchange = EXCHANGE_TAP2VT.get(info.ExchangeNo, None) commodity_info = commodity_infos.get(info.CommodityNo, None) if not info or not exchange or not commodity_info: return if info.CommodityType == "F": symbol = info.CommodityNo + info.ContractNo1 if commodity_info.name: name = f"{commodity_info.name} {info.ContractNo1}" else: name = symbol contract = ContractData(symbol=symbol, exchange=exchange, name=name, product=Product.FUTURES, size=commodity_info.size, pricetick=commodity_info.pricetick, net_position=True, gateway_name=self.gateway.gateway_name) self.gateway.on_contract(contract) contract_info = ContractInfo( name=contract.name, exchange_no=info.ExchangeNo, contract_no=info.ContractNo1, commodity_type=info.CommodityType, commodity_no=info.CommodityNo, ) contract_infos[(contract.symbol, contract.exchange)] = contract_info if isLast == "Y": self.gateway.write_log("查询交易合约信息成功") self.query_account() def OnRspQryAccount(self, sessionID: int, errorCode: int, isLast: str, info: TapAPIAccountInfo): """ Callback of account number query. """ if errorCode != TAPIERROR_SUCCEED: self.gateway.write_log(f"查询账号信息失败") return req = TapAPIFundReq() req.AccountNo = info.AccountNo self.api.QryFund(req) def OnRspQryFund(self, sessionID: int, errorCode: int, isLast: str, info: TapAPIFundData): """Callback of account fund query""" if errorCode != TAPIERROR_SUCCEED: self.gateway.write_log(f"查询资金信息失败") return self.update_account(info) if isLast == "Y": self.gateway.write_log("查询资金信息成功") self.query_position() def OnRtnFund(self, info: TapAPIFundData): """ Callback of account fund update. """ self.update_account(info) def OnRspQryPositionSummary(self, sessionID: int, errorCode: int, isLast: str, info: TapAPIPositionSummary): """ Callback of position summary query. Position summary reflects the sum of positions on each contract. """ if errorCode != TAPIERROR_SUCCEED: self.gateway.write_log(f"查询持仓信息失败") return if info: self.update_position(info) if isLast == "Y": self.gateway.write_log(f"查询持仓信息成功") self.query_order() def OnRtnPositionSummary(self, info: TapAPIPositionSummary): """ Callback of position summary update. """ self.update_position(info) def OnRspQryOrder(self, sessionID: int, errorCode: int, isLast: str, info: TapAPIOrderInfo): """ Callback of today's order query. """ if errorCode != TAPIERROR_SUCCEED: self.gateway.write_log(f"查询委托信息失败") return if info: self.update_order(info) if isLast == "Y": self.gateway.write_log(f"查询委托信息成功") self.query_trade() def OnRtnOrder(self, info: TapAPIOrderInfoNotice): """ Callback of order update. """ if info.ErrorCode != TAPIERROR_SUCCEED: self.gateway.write_log(f"委托下单失败:{error_to_str(info.ErrorCode)}") if info.OrderInfo: self.update_order(info.OrderInfo) def OnRspQryFill(self, sessionID: int, errorCode: int, isLast: str, info: TapAPIFillInfo): """ Callback of today's order fill (trade) query. """ if errorCode != TAPIERROR_SUCCEED: self.gateway.write_log(f"查询成交信息失败") return if info: self.update_trade(info) if isLast == "Y": self.gateway.write_log(f"查询成交信息成功") def OnRtnFill(self, info: TapAPIFillInfo): """ Callback of trade update. """ self.update_trade(info) def OnRspOrderAction(self, sessionID: int, errorCode: int, info: TapAPIOrderActionRsp): """ Callback of order action (cancel/amend) request. """ if errorCode != TAPIERROR_SUCCEED: self.gateway.write_log(f"委托操作失败:{error_to_str(errorCode)}") return def update_account(self, info: TapAPIFundData): """ Convert TAP fund data structure into AccountData event and push it. """ self.account_no = info.AccountNo account = AccountData(accountid=info.AccountNo, balance=info.Balance, frozen=info.Balance - info.Available, gateway_name=self.gateway_name) self.gateway.on_account(account) def update_position(self, info: TapAPIPositionSummary): """ Convert TAP position summary structure into PositionData event and push it. """ position = PositionData(symbol=info.CommodityNo + info.ContractNo, exchange=EXCHANGE_TAP2VT.get( info.ExchangeNo, None), direction=DIRECTION_TAP2VT[info.MatchSide], volume=info.PositionQty, price=info.PositionPrice, gateway_name=self.gateway_name) self.gateway.on_position(position) def update_order(self, info: TapAPIOrderInfo): """ Convert TAP order data structure into OrderData event and push it. """ self.local_sys_map[info.ClientOrderNo] = info.OrderNo self.sys_local_map[info.OrderNo] = info.ClientOrderNo self.sys_server_map[info.OrderNo] = info.ServerFlag order = OrderData(symbol=info.CommodityNo + info.ContractNo, exchange=EXCHANGE_TAP2VT.get(info.ExchangeNo, None), orderid=info.ClientOrderNo, type=ORDERTYPE_TAP2VT.get(info.OrderType, info.OrderType), direction=DIRECTION_TAP2VT[info.OrderSide], price=info.OrderPrice, volume=info.OrderQty, traded=info.OrderMatchQty, status=STATUS_TAP2VT.get(info.OrderState, Status.SUBMITTING), time=info.OrderInsertTime, gateway_name=self.gateway_name) self.gateway.on_order(order) # Send waiting cancel request to server if info.ClientOrderNo in self.cancel_reqs: req = self.cancel_reqs.pop(info.ClientOrderNo) self.cancel_order(req) def update_trade(self, info: TapAPIFillInfo): """ Convert TAP fill data structure into TradeData event and push it. """ orderid = self.sys_local_map[info.OrderNo] trade = TradeData(symbol=info.CommodityNo + info.ContractNo, exchange=EXCHANGE_TAP2VT.get(info.ExchangeNo, None), orderid=orderid, tradeid=info.MatchNo, direction=DIRECTION_TAP2VT[info.MatchSide], price=info.MatchPrice, volume=info.MatchQty, time=info.MatchDateTime, gateway_name=self.gateway_name) self.gateway.on_trade(trade) 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()) SetITapTradeAPIDataPath(str(path)) SetITapTradeAPILogLevel(APILOGLEVEL_NONE) # Create API object info = TapTradeAPIApplicationInfo() info.AuthCode = auth_code info.KeyOperationLogPath = str(path) self.api, iResult = CreateITapTradeAPI(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, False) # Start connection login_auth = TapAPITradeLoginAuth() login_auth.UserNo = username login_auth.Password = password login_auth.ISModifyPassword = APIYNFLAG_NO self.api.Login(login_auth) def send_order(self, req: OrderRequest): """ Send new order to TAP server. """ contract_info = contract_infos.get((req.symbol, req.exchange), None) if not contract_info: self.write_log(f"找不到匹配的合约:{req.symbol}和{req.exchange.value}") return "" if req.type not in ORDERTYPE_VT2TAP: self.write_log(f"不支持的委托类型: {req.type.value}") return "" order_req = TapAPINewOrder() order_req.ExchangeNo = contract_info.exchange_no order_req.CommodityNo = contract_info.commodity_no order_req.CommodityType = contract_info.commodity_type order_req.ContractNo = contract_info.contract_no order_req.OrderType = ORDERTYPE_VT2TAP[req.type] order_req.OrderSide = DIRECTION_VT2TAP[req.direction] order_req.OrderPrice = req.price order_req.OrderQty = int(req.volume) order_req.AccountNo = self.account_no retv, session_id, order_id = self.api.InsertOrder(order_req) order = req.create_order_data(order_id, self.gateway_name) self.gateway.on_order(order) return order.vt_orderid def cancel_order(self, req: CancelRequest): """ Cancel an existing order. If LocalOrderNo/OrderNo map is not ready yet (from query or update callback), the cancel request will be put into cancel_reqs dict waiting. """ order_no = self.local_sys_map.get(req.orderid, "") if not order_no: self.cancel_reqs[req.orderid] = req return server_flag = self.sys_server_map[order_no] cancel_req = TapAPIOrderCancelReq() cancel_req.OrderNo = order_no cancel_req.ServerFlag = server_flag self.api.CancelOrder(cancel_req) def query_account(self): """ Query account number data (and account fund data will be auto queried in callback). """ req = TapAPIAccQryReq() self.api.QryAccount(req) def query_position(self): """ Query position summary. """ req = TapAPIPositionQryReq() self.api.QryPositionSummary(req) def query_order(self): """ Query today order data. """ req = TapAPIOrderQryReq() self.api.QryOrder(req) def query_trade(self): """ Query today trade data. """ req = TapAPIFillQryReq() self.api.QryFill(req) def close(self): """ Release TAP API resources. """ if self.api: self.api.SetAPINotify(None) FreeITapTradeAPI(self.api) self.api = None