Пример #1
0
    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)
Пример #2
0
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