Example #1
0
class Test:
    def __init__(self):
        self.Session = ''
        dllpath = os.path.join(
            os.path.split(os.path.realpath(__file__))[0], '..', 'dll')
        self.q = Quote(
            os.path.join(
                dllpath, 'ctp_quote.' +
                ('dll' if 'Windows' in platform.system() else 'so')))
        self.t = Trade(
            os.path.join(
                dllpath, 'ctp_trade.' +
                ('dll' if 'Windows' in platform.system() else 'so')))
        self.req = 0
        self.ordered = False
        self.needAuth = False
        self.RelogEnable = True

    def q_OnFrontConnected(self):
        print('connected')
        self.q.ReqUserLogin(BrokerID=self.broker,
                            UserID=self.investor,
                            Password=self.pwd)

    def q_OnRspUserLogin(self, rsp: ctp.CThostFtdcRspUserLoginField,
                         info: ctp.CThostFtdcRspInfoField, req: int,
                         last: bool):
        print(info)
        self.q.SubscribeMarketData('rb1812')

    def q_OnTick(self, tick: ctp.CThostFtdcMarketDataField):
        f = tick
        # print(tick)

        if not self.ordered:
            _thread.start_new_thread(self.Order, (f, ))
            self.ordered = True

    def Order(self, f: ctp.CThostFtdcMarketDataField):
        print("报单")
        self.req += 1
        self.t.ReqOrderInsert(
            BrokerID=self.broker,
            InvestorID=self.investor,
            InstrumentID=f.getInstrumentID(),
            OrderRef='{0:>12}'.format(self.req),
            UserID=self.investor,
            OrderPriceType=ctp.OrderPriceTypeType.LimitPrice,
            Direction=ctp.DirectionType.Buy,
            CombOffsetFlag=ctp.OffsetFlagType.Open.__char__(),
            CombHedgeFlag=ctp.HedgeFlagType.Speculation.__char__(),
            LimitPrice=f.getLastPrice() - 50,
            VolumeTotalOriginal=1,
            TimeCondition=ctp.TimeConditionType.GFD,
            # GTDDate=''
            VolumeCondition=ctp.VolumeConditionType.AV,
            MinVolume=1,
            ContingentCondition=ctp.ContingentConditionType.Immediately,
            StopPrice=0,
            ForceCloseReason=ctp.ForceCloseReasonType.NotForceClose,
            IsAutoSuspend=0,
            IsSwapOrder=0,
            UserForceClose=0)

    def OnFrontConnected(self):
        if not self.RelogEnable:
            return
        print('connected')
        if self.needAuth:
            self.t.ReqAuthenticate(self.broker, self.investor, '@haifeng',
                                   '8MTL59FK1QGLKQW2')
        else:
            self.t.ReqUserLogin(BrokerID=self.broker,
                                UserID=self.investor,
                                Password=self.pwd,
                                UserProductInfo='@haifeng')

    def OnFrontDisconnected(self, reason: int):
        print(reason)

    def OnRspAuthenticate(
            self, pRspAuthenticateField: ctp.CThostFtdcRspAuthenticateField,
            pRspInfo: ctp.CThostFtdcRspInfoField, nRequestID: int,
            bIsLast: bool):
        print('auth:{0}:{1}'.format(pRspInfo.getErrorID(),
                                    pRspInfo.getErrorMsg()))
        self.t.ReqUserLogin(BrokerID=self.broker,
                            UserID=self.investor,
                            Password=self.pwd,
                            UserProductInfo='@haifeng')

    def OnRspUserLogin(self, rsp: ctp.CThostFtdcRspUserLoginField,
                       info: ctp.CThostFtdcRspInfoField, req: int, last: bool):
        print(info.getErrorMsg())

        if info.getErrorID() == 0:
            self.Session = rsp.getSessionID()
            self.t.ReqSettlementInfoConfirm(BrokerID=self.broker,
                                            InvestorID=self.investor)
        else:
            self.RelogEnable = False

    def OnRspSettlementInfoConfirm(
            self,
            pSettlementInfoConfirm: ctp.CThostFtdcSettlementInfoConfirmField,
            pRspInfo: ctp.CThostFtdcRspInfoField, nRequestID: int,
            bIsLast: bool):
        # print(pSettlementInfoConfirm)
        _thread.start_new_thread(self.StartQuote, ())

    def StartQuote(self):
        self.q.CreateApi()
        spi = self.q.CreateSpi()
        self.q.RegisterSpi(spi)

        self.q.OnFrontConnected = self.q_OnFrontConnected
        self.q.OnRspUserLogin = self.q_OnRspUserLogin
        self.q.OnRtnDepthMarketData = self.q_OnTick

        self.q.RegCB()

        self.q.RegisterFront(self.frontAddr.split(',')[1])
        self.q.Init()
        # self.q.Join()

    def Qry(self):
        sleep(1.1)
        self.t.ReqQryInstrument()
        while True:
            sleep(1.1)
            self.t.ReqQryTradingAccount(self.broker, self.investor)
            sleep(1.1)
            self.t.ReqQryInvestorPosition(self.broker, self.investor)
            return

    def OnRtnInstrumentStatus(
            self, pInstrumentStatus: ctp.CThostFtdcInstrumentStatusField):
        print(pInstrumentStatus.getInstrumentStatus())

    def OnRspOrderInsert(self, pInputOrder: ctp.CThostFtdcInputOrderField,
                         pRspInfo: ctp.CThostFtdcRspInfoField, nRequestID: int,
                         bIsLast: bool):
        print(pRspInfo)
        print(pInputOrder)
        print(pRspInfo.getErrorMsg())

    def OnRtnOrder(self, pOrder: ctp.CThostFtdcOrderField):
        print(pOrder)
        if pOrder.getSessionID() == self.Session and pOrder.getOrderStatus(
        ) == ctp.OrderStatusType.NoTradeQueueing:
            print("撤单")
            self.t.ReqOrderAction(self.broker,
                                  self.investor,
                                  InstrumentID=pOrder.getInstrumentID(),
                                  OrderRef=pOrder.getOrderRef(),
                                  FrontID=pOrder.getFrontID(),
                                  SessionID=pOrder.getSessionID(),
                                  ActionFlag=ctp.ActionFlagType.Delete)

    def Run(self):
        # CreateApi时会用到log目录,需要在程序目录下创建**而非dll下**
        self.t.CreateApi()
        spi = self.t.CreateSpi()
        self.t.RegisterSpi(spi)

        self.t.OnFrontConnected = self.OnFrontConnected
        self.t.OnFrontDisconnected = self.OnFrontDisconnected
        self.t.OnRspUserLogin = self.OnRspUserLogin
        self.t.OnRspSettlementInfoConfirm = self.OnRspSettlementInfoConfirm
        self.t.OnRspAuthenticate = self.OnRspAuthenticate
        self.t.OnRtnInstrumentStatus = self.OnRtnInstrumentStatus
        self.t.OnRspOrderInsert = self.OnRspOrderInsert
        self.t.OnRtnOrder = self.OnRtnOrder
        # _thread.start_new_thread(self.Qry, ())
        self.t.RegCB()

        self.frontAddr = 'tcp://180.168.146.187:10000,tcp://180.168.146.187:10010'
        self.broker = '9999'
        self.investor = '008107'
        self.pwd = '1'
        self.t.RegisterFront(self.frontAddr.split(',')[0])
        self.t.SubscribePrivateTopic(nResumeType=2)  # quick
        self.t.SubscribePrivateTopic(nResumeType=2)
        self.t.Init()
Example #2
0
class CtpTrade():
    """"""

    def __init__(self, dll_relative_path: str = 'dll'):
        self.front_address = ''
        self.investor = ''
        self.password = ''
        self.broker = ''
        self.logined = False
        self.tradingday = ''

        self.instruments = {}
        self.orders = {}
        self.trades = {}
        self.account: TradingAccount = None
        self.positions = {}
        self.instrument_status = {}

        self._req = 0
        self._session = ''
        self._orderid_sysid = {}
        self._posi = []

        self.t = Trade(os.path.join(os.getcwd(), dll_relative_path, 'ctp_trade.' + ('dll' if 'Windows' in platform.system() else 'so')))

    def _OnFrontConnected(self):
        _thread.start_new_thread(self.OnConnected, (self,))

    def _OnFrontDisconnected(self, nReason):
        self.logined = False
        print(nReason)
        # 下午收盘后会不停断开再连接 4097错误
        if nReason == 4097 or nReason == 4098:
            _thread.start_new_thread(self._reconnect, ())
        else:
            _thread.start_new_thread(self.OnDisConnected, (self, nReason))

    def _reconnect(self):
        if sum([1 if stat == 'Continous' else 0 for exc, stat in self.instrument_status.items()]) == 0:
            print(time.strftime('%Y%m%d %H:%M:%S', time.localtime()))
            self.t.Release()
            time.sleep(600)
            self.ReqConnect(self.front_address)

    # def _OnRspUserLogout(self, pUserLogout: CThostFtdcUserLogoutField, pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool):
    #     pass

    def _OnRspUserLogin(self, pRspUserLogin: CThostFtdcRspUserLoginField(), pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool):
        """"""
        if pRspInfo.getErrorID() == 0:
            self.session = pRspUserLogin.getSessionID()
            self.tradingday = pRspUserLogin.getTradingDay()
            self.t.ReqSettlementInfoConfirm(self.broker, self.investor)
        elif self.logined:
            _thread.start_new_thread(self._relogin, ())
        else:
            info = InfoField()
            info.ErrorID = pRspInfo.getErrorID()
            info.ErrorMsg = pRspInfo.getErrorMsg()
            _thread.start_new_thread(self.OnUserLogin, (self, info))

    def _relogin(self):
        # 隔夜重连=>处理'初始化'错误
        time.sleep(60 * 10)
        self.t.ReqUserLogin(
            BrokerID=self.broker,
            UserID=self.investor,
            Password=self.password,
            UserProductInfo='@haifeng')

    def _OnRspSettlementInfoConfirm(
            self,
            pSettlementInfoConfirm: CThostFtdcSettlementInfoConfirmField,
            pRspInfo: CThostFtdcRspInfoField,
            nRequestID: int,
            bIsLast: bool):
        if not self.logined:
            time.sleep(0.5)
            """查询合约/持仓/权益"""
            _thread.start_new_thread(self._qry, ())  # 开启查询

    def _qry(self):
        """查询帐号相关信息"""
        # restart 模式, 待rtnorder 处理完毕后再进行查询,否则会造成position混乱
        ord_cnt = 0
        while True:
            time.sleep(0.5)
            if len(self.orders) == ord_cnt:
                break
            ord_cnt = len(self.orders)
        self.t.ReqQryInstrument()
        time.sleep(1.1)
        self.t.ReqQryInvestorPosition(self.broker, self.investor)
        time.sleep(1.1)
        self.t.ReqQryTradingAccount(self.broker, self.investor)
        time.sleep(1.1)

        self.logined = True
        info = InfoField()
        info.ErrorID = 0
        info.ErrorMsg = '正确'
        _thread.start_new_thread(self.OnUserLogin, (self, info))
        # 调用Release后程序异常退出,但不报错误:接口断开了仍然调用了查询指令
        while self.logined:
            """查询持仓与权益"""
            self.t.ReqQryInvestorPosition(self.broker, self.investor)
            time.sleep(1.1)
            if not self.logined:
                return
            self.t.ReqQryTradingAccount(self.broker, self.investor)
            time.sleep(1.1)

    def _OnRtnInstrumentStatus(self, pInstrumentStatus: CThostFtdcInstrumentStatusField):
        if pInstrumentStatus.getInstrumentID() == '':
            return
        status = InstrumentStatus.Continous
        if pInstrumentStatus.getInstrumentStatus() == InstrumentStatusType.Continous:
            status = InstrumentStatus.Continous
        elif pInstrumentStatus.getInstrumentStatus() == InstrumentStatusType.Closed:
            status = InstrumentStatus.Closed
        elif str(pInstrumentStatus.getInstrumentStatus()).startswith('Auction'):
            status = InstrumentStatus.Auction
        else:
            status = InstrumentStatus.NoTrading
        self.instrument_status[pInstrumentStatus.getInstrumentID()] = status
        self.OnInstrumentStatus(self, pInstrumentStatus.getInstrumentID(), status)
        # _thread.start_new_thread(self.OnInstrumentStatus, (self, pInstrumentStatus.getInstrumentID(), status))

    def _OnRspQryInstrument(self, pInstrument: CThostFtdcInstrumentField, pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool):
        """"""
        inst = InstrumentField()
        inst.InstrumentID = pInstrument.getInstrumentID()
        inst.ProductID = pInstrument.getProductID()
        inst.ExchangeID = pInstrument.getExchangeID()
        inst.VolumeMultiple = pInstrument.getVolumeMultiple()
        inst.PriceTick = pInstrument.getPriceTick()
        inst.MaxOrderVolume = pInstrument.getMaxLimitOrderVolume()
        self.instruments[inst.InstrumentID] = inst

    def _OnRspQryPosition(self, pInvestorPosition: CThostFtdcInvestorPositionField, pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool):
        """"""
        if pInvestorPosition.getInstrumentID() != '':  # 偶尔出现NULL的数据导致数据转换错误
            self._posi.append(pInvestorPosition)  # Struct(**f.__dict__)) #dict -> object

        if bIsLast:
            # 先排序再group才有效
            self._posi = sorted(self._posi, key=lambda c: '{0}_{1}'.format(c.getInstrumentID(), DirectType.Buy if c.getPosiDirection() == PosiDirectionType.Long else DirectType.Sell))
            # direction需从posidiction转换为dictiontype
            for key, group in itertools.groupby(self._posi, lambda c: '{0}_{1}'.format(c.getInstrumentID(), 'Buy' if c.getPosiDirection() == PosiDirectionType.Long else 'Sell')):
                pf = self.positions.get(key)
                if not pf:
                    pf = PositionField()
                    self.positions[key] = pf
                pf.Position = 0
                pf.TdPosition = 0
                pf.YdPosition = 0
                pf.CloseProfit = 0
                pf.PositionProfit = 0
                pf.Commission = 0
                pf.Margin = 0
                pf.Price = 0
                cost = 0.0
                for g in group:
                    if not pf.InstrumentID:
                        pf.InstrumentID = g.getInstrumentID()
                        pf.Direction = DirectType.Buy if g.getPosiDirection() == PosiDirectionType.Long else DirectType.Sell
                    pf.Position += g.getPosition()
                    pf.TdPosition += g.getTodayPosition()
                    pf.YdPosition = pf.Position - pf.TdPosition
                    pf.CloseProfit += g.getCloseProfit()
                    pf.PositionProfit += g.getPositionProfit()
                    pf.Commission += g.getCommission()
                    pf.Margin += g.getUseMargin()
                    cost += g.OpenCost
                # pf.Position <= 0 ? 0 : (g.Sum(n => n.PositionCost) / DicInstrumentField[pf.InstrumentID].VolumeMultiple / pf.Position);
                vm = self.instruments[pf.InstrumentID].VolumeMultiple
                pf.Price = 0 if pf.Position <= 0 else cost / vm / pf.Position
            self._posi.clear()

    def _OnRspQryAccount(self, pTradingAccount: CThostFtdcTradingAccountField, pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool):
        """"""
        if not self.account:
            self.account = TradingAccount()
        self.account.Available = pTradingAccount.getAvailable()
        self.account.CloseProfit = pTradingAccount.getCloseProfit()
        self.account.Commission = pTradingAccount.getCommission()
        self.account.CurrMargin = pTradingAccount.getCurrMargin()
        self.account.FrozenCash = pTradingAccount.getFrozenCash()
        self.account.PositionProfit = pTradingAccount.getPositionProfit()
        self.account.PreBalance = pTradingAccount.getPreBalance() + pTradingAccount.getDeposit() + pTradingAccount.getWithdraw()
        self.account.Fund = self.account.PreBalance + pTradingAccount.getCloseProfit() + pTradingAccount.getPositionProfit() - pTradingAccount.getCommission()
        self.account.Risk = 0 if self.account.Fund == 0 else self.account.CurrMargin / self.account.Fund

    def _OnRtnOrder(self, pOrder: CThostFtdcOrderField):
        """"""
        id = '{0}|{1}|{2}'.format(pOrder.getSessionID(), pOrder.getFrontID(), pOrder.getOrderRef())
        of = self.orders.get(id)
        if not of:
            of = OrderField()
            if pOrder.getOrderRef().isdigit():
                of.Custom = int(pOrder.getOrderRef()) % 1000000
            of.InstrumentID = pOrder.getInstrumentID()
            of.InsertTime = pOrder.getInsertTime()
            of.Direction = DirectType.Buy if DirectionType(
                pOrder.getDirection()
            ) == DirectionType.Buy else DirectType.Sell
            ot = OffsetFlagType(ord(pOrder.getCombOffsetFlag()[0]))
            of.Offset = OffsetType.Open if ot == OffsetFlagType.Open else (
                OffsetType.CloseToday
                if ot == OffsetFlagType.CloseToday else OffsetType.Close)
            of.Status = OrderStatus.Normal
            of.StatusMsg = pOrder.getStatusMsg()
            of.IsLocal = pOrder.getSessionID() == self.session
            of.LimitPrice = pOrder.getLimitPrice()
            of.OrderID = id
            of.Volume = pOrder.getVolumeTotalOriginal()
            of.VolumeLeft = of.Volume
            self.orders[id] = of
            _thread.start_new_thread(self.OnOrder, (self, of))
        elif pOrder.getOrderStatus() == OrderStatusType.Canceled:
            of.Status = OrderStatus.Canceled
            of.StatusMsg = pOrder.getStatusMsg()

            if of.StatusMsg.find('被拒绝') >= 0:
                info = InfoField()
                info.ErrorID = -1
                info.ErrorMsg = of.StatusMsg
                _thread.start_new_thread(self.OnErrOrder, (self, of, info))
            else:
                _thread.start_new_thread(self.OnCancel, (self, of))
        else:
            if pOrder.getOrderSysID():
                of.SysID = pOrder.getOrderSysID()
                self._orderid_sysid[pOrder.getOrderSysID()] = id  # 记录sysid与orderid关联,方便Trade时查找处理

    def _OnRtnTrade(self, f):
        """"""
        tf = TradeField()
        tf.Direction = DirectType.Buy if f.getDirection() == DirectionType.Buy else DirectType.Sell
        tf.ExchangeID = f.getExchangeID()
        tf.InstrumentID = f.getInstrumentID()
        tf.Offset = OffsetType.Open if f.getOffsetFlag() == OffsetFlagType.Open else OffsetType.Close if f.getOffsetFlag(
        ) == OffsetFlagType.Close else OffsetType.CloseToday
        tf.Price = f.getPrice()
        tf.SysID = f.getOrderSysID()
        tf.TradeID = f.getTradeID()
        tf.TradeTime = f.getTradeTime()
        tf.TradingDay = f.getTradingDay()
        tf.Volume = f.getVolume()

        self.trades[tf.TradeID] = tf

        id = self._orderid_sysid[tf.SysID]
        of = self.orders[id]
        tf.OrderID = id  # tradeid 与 orderid 关联
        of.TradeTime = tf.TradeTime
        of.AvgPrice = (of.AvgPrice * (of.Volume - of.VolumeLeft) + tf.Price *
                       tf.Volume) / (of.Volume - of.VolumeLeft + tf.Volume)
        of.TradeVolume = tf.Volume
        of.VolumeLeft -= tf.Volume
        if of.VolumeLeft == 0:
            of.Status = OrderStatus.Filled
            of.StatusMsg = '全部成交'
        else:
            of.Status = OrderStatus.Partial
            of.StatusMsg = '部分成交'
        # 更新持仓 *****
        if tf.Offset == OffsetType.Open:
            key = '{0}_{1}'.format(tf.InstrumentID, tf.Direction)
            pf = self.positions.get(key)
            if not pf:
                pf = PositionField()
                self.positions[key] = pf
            pf.InstrumentID = tf.InstrumentID
            pf.Direction = tf.Direction
            pf.Price = (pf.Price * pf.Position + tf.Price * tf.Volume) / (pf.Position + tf.Volume)
            pf.TdPosition += tf.Volume
            pf.Position += tf.Volume
        else:
            key = '{0}_{1}'.format(tf.InstrumentID, DirectType.Sell if tf.Direction == DirectType.Buy else DirectType.Buy)
            pf = self.positions.get(key)
            if pf:  # 有可能出现无持仓的情况
                if tf.Offset == OffsetType.CloseToday:
                    pf.TdPosition -= tf.Volume
                else:
                    tdclose = min(pf.TdPosition, tf.Volume)
                    if pf.TdPosition > 0:
                        pf.TdPosition -= tdclose
                    pf.YdPosition -= max(0, tf.Volume - tdclose)
                pf.Position -= tf.Volume
        _thread.start_new_thread(self._onRtn, (of, tf))

    def _onRtn(self, of, tf):
        self.OnOrder(self, of)
        self.OnTrade(self, tf)

    def _OnRspOrder(self, pInputOrder: CThostFtdcInputOrderField, pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool):
        """"""
        info = InfoField()
        info.ErrorID = pRspInfo.getErrorID()
        info.ErrorMsg = pRspInfo.getErrorMsg()

        id = '{0}|{1}|{2}'.format(self.session, '0', pInputOrder.getOrderRef())
        of = self.orders.get(id)
        if not of:
            of = OrderField()
            l = int(pInputOrder.getOrderRef())
            of.Custom = l % 1000000
            of.InstrumentID = pInputOrder.getInstrumentID()
            of.InsertTime = time.strftime('%H:%M:%S', time.localtime())
            # 对direction需特别处理(具体见ctp_struct)
            of.Direction = DirectType.Buy if DirectionType(pInputOrder.getDirection()) == DirectionType.Buy else DirectType.Sell
            ot = OffsetFlagType(ord(pInputOrder.getCombOffsetFlag()[0]))
            of.Offset = OffsetType.Open if ot == OffsetFlagType.Open else (OffsetType.CloseToday if ot == OffsetFlagType.CloseToday else OffsetType.Close)
            # of.Status = OrderStatus.Normal
            # of.StatusMsg = f.getStatusMsg()
            of.IsLocal = True
            of.LimitPrice = pInputOrder.getLimitPrice()
            of.OrderID = id
            of.Volume = pInputOrder.getVolumeTotalOriginal()
            of.VolumeLeft = of.Volume
            self.orders[id] = of

        of.Status = OrderStatus.Error
        of.StatusMsg = '{0}:{1}'.format(info.ErrorID, info.ErrorMsg)
        _thread.start_new_thread(self.OnErrOrder, (self, of, info))

    def _OnErrOrder(self, pInputOrder: CThostFtdcInputOrderField, pRspInfo: CThostFtdcRspInfoField):
        """"""
        id = '{0}|{1}|{2}'.format(self.session, '0', pInputOrder.getOrderRef())
        of = self.orders.get(id)

        info = InfoField()
        info.ErrorID = pRspInfo.getErrorID()
        info.ErrorMsg = pRspInfo.getErrorMsg()

        if of and of.IsLocal:
            of.Status = OrderStatus.Error
            of.StatusMsg = '{0}:{1}'.format(pRspInfo.getErrorID(), pRspInfo.getErrorMsg())
            _thread.start_new_thread(self.OnErrOrder, (self, of, info))

    def _OnRspOrderAction(self, pInputOrderAction: CThostFtdcInputOrderActionField, pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool):
        id = "{0}|{1}|{2}".format(pInputOrderAction.getSessionID(), pInputOrderAction.getFrontID(), pInputOrderAction.getOrderRef())
        if self.logined and id in self.orders:
            info = InfoField()
            info.ErrorID = pRspInfo.ErrorID
            info.ErrorMsg = pRspInfo.ErrorMsg
            _thread.start_new_thread(self.OnErrCancel, (self, self.orders[id], info))

    def ReqConnect(self, front: str):
        """
        连接交易前置
            :param self:
            :param front:str:
        """
        self.t.CreateApi()
        spi = self.t.CreateSpi()
        self.t.RegisterSpi(spi)

        self.t.OnFrontConnected = self._OnFrontConnected
        self.t.OnRspUserLogin = self._OnRspUserLogin
        self.t.OnFrontDisconnected = self._OnFrontDisconnected
        # self.t.OnRspUserLogout = self._OnRspUserLogout
        self.t.OnRspSettlementInfoConfirm = self._OnRspSettlementInfoConfirm
        self.t.OnRtnOrder = self._OnRtnOrder
        self.t.OnRtnTrade = self._OnRtnTrade
        self.t.OnRspOrderInsert = self._OnRspOrder
        self.t.OnErrRtnOrderInsert = self._OnErrOrder
        self.t.OnRspOrderAction = self._OnRspOrderAction
        self.t.OnRtnInstrumentStatus = self._OnRtnInstrumentStatus
        self.t.OnRspQryInstrument = self._OnRspQryInstrument
        self.t.OnRspQryTradingAccount = self._OnRspQryAccount
        self.t.OnRspQryInvestorPosition = self._OnRspQryPosition

        self.front_address = front
        self.t.RegCB()
        self.t.RegisterFront(front)
        self.t.SubscribePrivateTopic(0)  # restart 同步处理order trade
        self.t.SubscribePublicTopic(0)
        self.t.Init()
        # self.t.Join()

    def ReqUserLogin(self, user: str, pwd: str, broker: str):
        """
        登录
            :param self:
            :param user:str:
            :param pwd:str:
            :param broker:str:
        """
        self.broker = broker
        self.investor = user
        self.password = pwd
        self.t.ReqUserLogin(BrokerID=broker, UserID=user, Password=pwd)

    def ReqOrderInsert(self, pInstrument: str, pDirection: DirectType, pOffset: OffsetType, pPrice: float = 0.0, pVolume: int = 1, pType: OrderType = OrderType.Limit, pCustom: int = 0):
        """
        委托
            :param self:
            :param pInstrument:str:
            :param pDirection:DirectType:
            :param pOffset:OffsetType:
            :param pPrice:float=0.0:
            :param pVolume:int=1:
            :param pType:OrderType=OrderType.Limit:
        """
        OrderPriceType = OrderPriceTypeType.AnyPrice
        TimeCondition = TimeConditionType.IOC
        LimitPrice = 0.0
        VolumeCondition = VolumeConditionType.AV

        if pType == OrderType.Market:  # 市价
            OrderPriceType = OrderPriceTypeType.AnyPrice
            TimeCondition = TimeConditionType.IOC
            LimitPrice = 0.0
            VolumeCondition = VolumeConditionType.AV
        elif pType == OrderType.Limit:  # 限价
            OrderPriceType = OrderPriceTypeType.LimitPrice
            TimeCondition = TimeConditionType.GFD
            LimitPrice = pPrice
            VolumeCondition = VolumeConditionType.AV
        elif pType == OrderType.FAK:  # FAK
            OrderPriceType = OrderPriceTypeType.LimitPrice
            TimeCondition = TimeConditionType.IOC
            LimitPrice = pPrice
            VolumeCondition = VolumeConditionType.AV
        elif pType == OrderType.FOK:  # FOK
            OrderPriceType = OrderPriceTypeType.LimitPrice
            TimeCondition = TimeConditionType.IOC
            LimitPrice = pPrice
            VolumeCondition = VolumeConditionType.CV  # 全部数量

        self._req += 1
        self.t.ReqOrderInsert(
            BrokerID=self.broker,
            InvestorID=self.investor,
            InstrumentID=pInstrument,
            OrderRef="%06d%06d" % (self._req, pCustom % 1000000),
            UserID=self.investor,
            # 此处ctp_enum与at_struct名称冲突
            Direction=DirectionType.Buy
            if pDirection == DirectType.Buy else DirectionType.Sell,
            CombOffsetFlag=chr(OffsetFlagType.Open if pOffset == OffsetType.Open else (OffsetFlagType.CloseToday if pOffset == OffsetType.CloseToday else OffsetFlagType.Close)),
            CombHedgeFlag=HedgeFlagType.Speculation.__char__(),
            IsAutoSuspend=0,
            ForceCloseReason=ForceCloseReasonType.NotForceClose,
            IsSwapOrder=0,
            ContingentCondition=ContingentConditionType.Immediately,
            VolumeCondition=VolumeCondition,
            MinVolume=1,
            VolumeTotalOriginal=pVolume,
            OrderPriceType=OrderPriceType,
            TimeCondition=TimeCondition,
            LimitPrice=LimitPrice,
        )

    def ReqOrderAction(self, OrderID: str):
        """
        撤单
            :param self:
            :param OrderID:str:
        """
        of = self.orders[OrderID]

        if not of:
            return -1
        else:
            pOrderId = of.OrderID
            return self.t.ReqOrderAction(
                self.broker,
                self.investor,
                OrderRef=pOrderId.split('|')[2],
                FrontID=int(pOrderId.split('|')[1]),
                SessionID=int(pOrderId.split('|')[0]),
                InstrumentID=of.InstrumentID,
                ActionFlag=ActionFlagType.Delete)

    def ReqUserLogout(self):
        """
        退出接口
            :param self:
        """
        self.logined = False
        time.sleep(3)
        self.t.ReqUserLogout(BrokerID=self.broker, UserID=self.investor)
        self.t.RegisterSpi(None)
        self.t.Release()
        _thread.start_new_thread(self.OnDisConnected, (self, 0))

    def OnConnected(self, obj):
        """
        接口连接
            :param self:
            :param obj:
        """
        print('=== OnConnected ==='.format(''))

    def OnDisConnected(self, obj, reason: int):
        """
        接口断开
            :param self:
            :param obj:
            :param reason:int:
        """
        print('=== OnDisConnected === \n{0}'.format(reason))

    def OnUserLogin(self, obj, info: InfoField):
        """
        登录响应
            :param self:
            :param obj:
            :param info:InfoField:
        """
        print('=== OnUserLogin === \n{0}'.format(info))

    def OnOrder(self, obj, f: OrderField):
        """
        委托响应
            :param self:
            :param obj:
            :param f:OrderField:
        """
        print('=== OnOrder === \n{0}'.format(f.__dict__))

    def OnTrade(self, obj, f: TradeField):
        """
        成交响应
            :param self:
            :param obj:
            :param f:TradeField:
        """
        print('=== OnTrade === \n{0}'.format(f.__dict__))

    def OnCancel(self, obj, f: OrderField):
        """
        撤单响应
            :param self:
            :param obj:
            :param f:OrderField:
        """
        print('=== OnCancel === \n{0}'.format(f.__dict__))

    def OnErrCancel(self, obj, f: OrderField, info: InfoField):
        """
        撤单失败
            :param self:
            :param obj:
            :param f:OrderField:
            :param info:InfoField:
        """
        print('=== OnErrCancel ===\n{0}'.format(f.__dict__))
        print(info)

    def OnErrOrder(self, obj, f: OrderField, info: InfoField):
        """
        委托错误
            :param self:
            :param obj:
            :param f:OrderField:
            :param info:InfoField:
        """
        print('=== OnErrOrder ===\n{0}'.format(f.__dict__))
        print(info)

    def OnInstrumentStatus(self, obj, inst: str, status: InstrumentStatus):
        """
        交易状态
            :param self:
            :param obj:
            :param inst:str:
            :param status:InstrumentStatus:
        """
        print('{}:{}'.format(inst, str(status).strip().split('.')[1]))