def __init__(self, userid, password, brokerid, RegisterFront, product_info, app_id, auth_code): # 创建 Trade 的类 self.t = Trade() # 建立好 帐户类 self.userid = userid self.password = password self.brokerid = brokerid self.product_info = product_info self.auth_code = auth_code self.app_id = app_id api = self.t.CreateApi() spi = self.t.CreateSpi() self.t.RegisterSpi(spi) self.t.OnFrontConnected = self.onFrontConnected # 交易服务器登陆相应 self.t.OnFrontDisconnected = self.onFrontDisconnected # 交易服务器断开连接的情况 self.t.OnRspAuthenticate = self.onRspAuthenticate # 申请码检验 self.t.OnRspUserLogin = self.onRspUserLogin # 用户登陆 self.t.OnRspUserLogout = self.onRspUserLogout # 用户登出 self.t.OnRspQryDepthMarketData = self.onRspQryDepthMarketData # 查询涨跌停 self.t.OnRtnInstrumentStatus = self.onRtnInstrumentStatus self.t.OnRspQryInstrument = self.onRspQryInstrument self.t.OnErrRtnOrderInsert = self.onErrRtnOrderInsert self.t.OnRtnOrder = self.onRtnOrder self.t.OnRtnTrade = self.onRtnTrade self.t.RegCB() self.t.RegisterFront(RegisterFront) self.t.Init() self.isLogin = False
def __init__(self, userid, password, brokerid, RegisterFront, product_info, app_id, auth_code): # 初始化账号 self.t = Trade() self.userid = userid self.password = password self.brokerid = brokerid self.product_info = product_info self.app_id = app_id self.auth_code = auth_code api = self.t.CreateApi() spi = self.t.CreateSpi() self.t.RegisterSpi(spi) self.t.OnFrontConnected = self.onFrontConnected # 交易服务器登陆相应 self.t.OnFrontDisconnected = self.onFrontDisconnected self.t.OnRspAuthenticate = self.onRspAuthenticate # 申请码检验 self.t.OnRspUserLogin = self.onRspUserLogin # 用户登陆 self.t.OnRspUserLogout = self.onRspUserLogout # 用户登出 self.t.OnRtnInstrumentStatus = self.onRtnInstrumentStatus self.t.OnRspQryInstrument = self.onRspQryInstrument # 查询全部交易合约 self.t.OnRspSettlementInfoConfirm = self.onRspSettlementInfoConfirm # 结算单确认,显示登陆日期 self.t.OnRspQryTradingAccount = self.onRspQryTradingAccount # 查询账户 self.t.OnRtnOrder = self.onRtnOrder # 报单 self.t.OnRtnTrade = self.onRtnTrade # 成交 # self.t.OnRspParkedOrderInsert = self.onRspParkedOrderInsert self.t.OnErrRtnOrderInsert = self.onErrRtnOrderInsert self.t.OnRspQryDepthMarketData = self.onRspQryDepthMarketData # 查询涨跌停 self.t.RegCB() self.t.RegisterFront(RegisterFront) self.t.Init() self.islogin = False
def __init__(self): self.Session = '' self.q = Quote() self.t = Trade() self.req = 0 self.ordered = False self.needAuth = False self.RelogEnable = True
def __init__(self, address, broker, investor, passwd): self.Session = '' dllpath = os.path.join( os.path.split(os.path.realpath(__file__))[0], '..', 'dll') self.t = Trade( os.path.join( dllpath, 'ctp_trade.' + ('dll' if 'Windows' in platform.system() else 'so'))) self.address = address self.broker = broker self.investor = investor self.pwd = passwd self.RelogEnable = True self.req = 0
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 __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')))
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()
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]))
class TdApi: def __init__(self, userid, password, brokerid, RegisterFront, product_info, app_id, auth_code): # 创建 Trade 的类 self.t = Trade() # 建立好 帐户类 self.userid = userid self.password = password self.brokerid = brokerid self.product_info = product_info self.auth_code = auth_code self.app_id = app_id api = self.t.CreateApi() spi = self.t.CreateSpi() self.t.RegisterSpi(spi) self.t.OnFrontConnected = self.onFrontConnected # 交易服务器登陆相应 self.t.OnFrontDisconnected = self.onFrontDisconnected # 交易服务器断开连接的情况 self.t.OnRspAuthenticate = self.onRspAuthenticate # 申请码检验 self.t.OnRspUserLogin = self.onRspUserLogin # 用户登陆 self.t.OnRspUserLogout = self.onRspUserLogout # 用户登出 self.t.OnRspQryDepthMarketData = self.onRspQryDepthMarketData # 查询涨跌停 self.t.OnRtnInstrumentStatus = self.onRtnInstrumentStatus self.t.OnRspQryInstrument = self.onRspQryInstrument self.t.OnErrRtnOrderInsert = self.onErrRtnOrderInsert self.t.OnRtnOrder = self.onRtnOrder self.t.OnRtnTrade = self.onRtnTrade self.t.RegCB() self.t.RegisterFront(RegisterFront) self.t.Init() self.isLogin = False def onFrontConnected(self): # 服务器连接成功能,进行注册码注册操作 downLogProgram('交易服务器连接成功') self.t.ReqAuthenticate(self.brokerid, self.userid, self.product_info, self.auth_code, self.app_id) def onFrontDisconnected(self, n): # 交易服务器断开连接 downLogProgram('交易服务器连接断开') self.isLogin = False def onRspAuthenticate( self, pRspAuthenticateField: CThostFtdcRspAuthenticateField, pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool): # 注册码成功后,进行登陆操作 self.t.ReqUserLogin(BrokerID=self.brokerid, UserID=self.userid, Password=self.password, UserProductInfo=self.product_info) def onRspUserLogin(self, data, error, n, last): """登陆回报""" if error.getErrorID() == 0: self.Investor = data.getUserID() self.BrokerID = data.getBrokerID() log = self.Investor + ' 交易服务器登陆成功' downLogProgram(log) self.isLogin = True # self.t.ReqQryDepthMarketData() # 执行是否切换合约的判断 else: log = '交易服务器登陆回报,错误代码:' + str(error.getErrorID()) + \ ', 错误信息:' + str(error.getErrorMsg()) downLogProgram(log) self.isLogin = False def onRspUserLogout(self, data, error, n, last): if error.getErrorID() == 0: log = '交易服务器登出成功' downLogProgram(log) else: log = '交易服务器登出回报,错误代码:' + str(error.getErrorID()) + \ ', 错误信息:' + str(error.getErrorMsg()) downLogProgram(log) def onRspQryDepthMarketData(self, data, error, n, last): #获取tick数据操作 # region 将 合约号 去除所有的数字,直接变成一个 icon 的操作 goodsIcon = filter(lambda x: x.isalpha(), data.getInstrumentID()) goodsIcon = ''.join(list(goodsIcon)) # endregion event = Event(type_=EVENT_INSTRUMENT) event.dict_['InstrumentID'] = data.getInstrumentID() # 合约号 event.dict_['ProductID'] = goodsIcon event.dict_['OpenInterest'] = data.getOpenInterest() # 持仓量 event.dict_['LastPrice'] = data.getLastPrice() # 获取收盘价 event.dict_['last'] = last # 是否为最后一笔 ee.put(event) def onRtnInstrumentStatus(self, data): pass def onRspQryInstrument(self, data, error, n, last): pass def onRtnOrder(self, data): # 常规报单事件 pass def onRtnTrade(self, data): """成交回报""" pass def onErrRtnOrderInsert(self, data, error): pass
class Trader: def __init__(self, address, broker, investor, passwd): self.Session = '' dllpath = os.path.join( os.path.split(os.path.realpath(__file__))[0], '..', 'dll') self.t = Trade( os.path.join( dllpath, 'ctp_trade.' + ('dll' if 'Windows' in platform.system() else 'so'))) self.address = address self.broker = broker self.investor = investor self.pwd = passwd self.RelogEnable = True self.req = 0 def OnFrontConnected(self): if not self.RelogEnable: return print('connected', "-------------enter OnFrontConnected -----------") self.t.ReqUserLogin(BrokerID=self.broker, UserID=self.investor, Password=self.pwd, UserProductInfo='@haifeng') 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(), "-------enter OnRspUserLogin--------") 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, "-------------enter OnRspSettlementInfoConfirm------------------") batchInsertOrder(self) # _thread.start_new_thread(self.StartQuote, ()) def OnRtnInstrumentStatus( self, pInstrumentStatus: ctp.CThostFtdcInstrumentStatusField): print(pInstrumentStatus.getInstrumentStatus(), "---------enter OnRtnInstrumentStatus-------------") # 报单录入应答 def OnRspOrderInsert(self, pInputOrder: ctp.CThostFtdcInputOrderField, pRspInfo: ctp.CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool): print("---------报单应答---------") print(pRspInfo) print(pInputOrder) print(pRspInfo.getErrorMsg()) #请求查询资金账户 def ReqQryTradingAccount(self): print("---------enter ReqQryTradingAccount----------") self.t.ReqQryTradingAccount(self.broker, self.investor) #资金回报 def OnRspQryTradingAccount( self, pTradingAccount: ctp.CThostFtdcTradingAccountField, pRspInfo: ctp.CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool): print("--------enter OnRspQryTradingAccount--------") print( 'OnRspQryTradingAccount:, pTradingAccount: CThostFtdcTradingAccountField, pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool' ) print(pTradingAccount) print(pRspInfo) print(nRequestID) print(bIsLast) # 持仓查询请求 def ReqQryInvestorPosition(self): print("-------ReqQryInvestorPosition----------") self.t.ReqQryInvestorPosition(self.broker, self.investor) #持仓回报 def OnRspQryInvestorPosition( self, pInvestorPosition: ctp.CThostFtdcInvestorPositionField, pRspInfo: ctp.CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool): print("----------OnRspQryInvestorPosition-----------") print( 'OnRspQryInvestorPosition:, pInvestorPosition: CThostFtdcInvestorPositionField, pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool' ) print(pInvestorPosition) print(pRspInfo) print(nRequestID) print(bIsLast) # 报单回报 def OnRtnOrder(self, pOrder: ctp.CThostFtdcOrderField): print("------OnRtnOrder----------") print(pOrder) # 合约 instrumentId = pOrder.getInstrumentID() # 订单状态 orderStatus = pOrder.getOrderStatus() # 成交数量 traderVolume = pOrder.getVolumeTraded() # 剩余数量 remainVolume = pOrder.getVolumeTotal() # 将每次返回的报单回报保存在traderDict traderDict[instrumentId] = pOrder # 如果全部成交完,从剩余中减去成交量 if orderStatus == ctp.OrderStatusType.AllTraded or orderStatus == ctp.OrderStatusType.PartTradedNotQueueing and orderStatus == ctp.OrderStatusType.Canceled: OrderDict[instrumentId].remain = int( OrderDict[instrumentId].remain) - traderVolume del traderDict[instrumentId] if len(traderDict.keys()) == 0: batchInsertOrder(self) def cancelAction(self, pOrder: ctp.CThostFtdcOrderField): print("撤单") if pOrder.getSessionID() == self.Session and pOrder.getOrderStatus( ) == ctp.OrderStatusType.NoTradeQueueing: self.t.ReqOrderAction(self.broker, self.investor, InstrumentID=pOrder.getInstrumentID(), OrderRef=pOrder.getOrderRef(), FrontID=pOrder.getFrontID(), SessionID=pOrder.getSessionID(), ActionFlag=ctp.ActionFlagType.Delete) # 报单 def Order(self, f: ctp.CThostFtdcMarketDataField, needVolume): print("报单", "-----enter Order------------") 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, LimitPrice=f.getLastPrice(), VolumeTotalOriginal=needVolume, 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 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.OnFrontConnected 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 self.t.OnRspQryInvestorPosition = self.OnRspQryInvestorPosition self.t.OnRspQryTradingAccount = self.OnRspQryTradingAccount # _thread.start_new_thread(self.Qry, ()) self.t.RegCB() self.t.RegisterFront(self.address) self.t.SubscribePrivateTopic(nResumeType=2) # quick self.t.SubscribePrivateTopic(nResumeType=2) self.t.Init()
class TdApi: def __init__(self, userid, password, brokerid, RegisterFront, product_info, app_id, auth_code): # 创建 Trade 的类 self.t = Trade() # 建立好 帐户类 self.userid = userid self.password = password self.brokerid = brokerid self.product_info = product_info self.auth_code = auth_code self.app_id = app_id api = self.t.CreateApi() spi = self.t.CreateSpi() self.t.RegisterSpi(spi) self.t.OnFrontConnected = self.onFrontConnected # 交易服务器登陆相应 self.t.OnFrontDisconnected = self.onFrontDisconnected # 交易服务器断开连接的情况 self.t.OnRspAuthenticate = self.onRspAuthenticate # 申请码检验 self.t.OnRspUserLogin = self.onRspUserLogin # 用户登陆 self.t.OnRspUserLogout = self.onRspUserLogout # 用户登出 self.t.OnRspQryDepthMarketData = self.onRspQryDepthMarketData # 查询涨跌停 self.t.OnRtnInstrumentStatus = self.onRtnInstrumentStatus self.t.OnRspQryInstrument = self.onRspQryInstrument self.t.OnErrRtnOrderInsert = self.onErrRtnOrderInsert self.t.OnRspSettlementInfoConfirm = self.onRspSettlementInfoConfirm # 结算单确认,显示登陆日期 self.t.OnRtnOrder = self.onRtnOrder self.t.OnRtnTrade = self.onRtnTrade self.t.RegCB() self.t.RegisterFront(RegisterFront) self.t.Init() self.isLogin = False def onFrontConnected(self): # 服务器连接成功能,进行注册码注册操作 downLogProgram('交易服务器连接成功') self.t.ReqAuthenticate(self.brokerid, self.userid, self.product_info, self.auth_code, self.app_id) def onFrontDisconnected(self, n): # 交易服务器断开连接 downLogProgram('交易服务器连接断开') self.isLogin = False def onRspAuthenticate( self, pRspAuthenticateField: CThostFtdcRspAuthenticateField, pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool): # 注册码成功后,进行登陆操作 downLogProgram('auth:{0}:{1}'.format(pRspInfo.getErrorID(), pRspInfo.getErrorMsg())) if pRspInfo.getErrorMsg() == '正确' or pRspInfo.getErrorMsg( ) == 'CTP:认证码错误,尽快获取正确的认证码。当前系统或者用户豁免终端认证,可以登录': self.t.ReqUserLogin(BrokerID=self.brokerid, UserID=self.userid, Password=self.password, UserProductInfo=self.product_info) elif pRspInfo.getErrorMsg() == 'CTP:前置不活跃': threading.Timer(60, self.t.ReqAuthenticate, [ self.brokerid, self.userid, self.product_info, self.auth_code, self.app_id ]).start() def onRspUserLogin(self, data, error, n, last): """登陆回报""" if error.getErrorID() == 0: self.Investor = data.getUserID() self.BrokerID = data.getBrokerID() log = self.Investor + ' 交易服务器登陆成功' downLogProgram(log) self.t.ReqSettlementInfoConfirm(self.BrokerID, self.Investor) # 对账单确认 else: log = '交易服务器登陆回报,错误代码:' + str(error.getErrorID()) + \ ', 错误信息:' + str(error.getErrorMsg()) downLogProgram(log) self.isLogin = False if error.getErrorMsg() == 'CTP:客户端未认证': # 过 60 秒后,重新登陆一次 threading.Timer(60, self.t.ReqUserLogin, [ '', self.brokerid, self.userid, self.password, self.product_info ]).start() def onRspUserLogout(self, data, error, n, last): if error.getErrorID() == 0: log = '交易服务器登出成功' downLogProgram(log) else: log = '交易服务器登出回报,错误代码:' + str(error.getErrorID()) + \ ', 错误信息:' + str(error.getErrorMsg()) downLogProgram(log) if error.getErrorMsg() == 'CTP:客户端未认证': # 过 60 秒后,重新登陆一次 threading.Timer(60, self.t.ReqUserLogin, [ '', self.brokerid, self.userid, self.password, self.product_info ]).start() def onRspQryDepthMarketData(self, data, error, n, last): #获取tick数据操作 # region 将 合约号 去除所有的数字,直接变成一个 icon 的操作 goodsIcon = filter(lambda x: x.isalpha(), data.getInstrumentID()) goodsIcon = ''.join(list(goodsIcon)) # endregion event = Event(type_=EVENT_INSTRUMENT) event.dict_['InstrumentID'] = data.getInstrumentID() # 合约号 event.dict_['ProductID'] = goodsIcon event.dict_['OpenInterest'] = data.getOpenInterest() # 持仓量 event.dict_['LastPrice'] = data.getLastPrice() # 获取收盘价 event.dict_['last'] = last # 是否为最后一笔 ee.put(event) def onRspSettlementInfoConfirm(self, data, error, n, last): """确认结算信息回报""" self.isLogin = True downLogProgram('账号:{}, 日期:{}, 时间:{} 交易账户已登陆成功'.format( data.getInvestorID(), data.getConfirmDate(), data.getConfirmTime())) def onRtnInstrumentStatus(self, data): pass def onRspQryInstrument(self, data, error, n, last): pass def onRtnOrder(self, data): # 常规报单事件 pass def onRtnTrade(self, data): """成交回报""" pass def onErrRtnOrderInsert(self, data, error): pass
class TdApi: def __init__(self, userid, password, brokerid, RegisterFront, product_info, app_id, auth_code): # 初始化账号 self.t = Trade() self.userid = userid self.password = password self.brokerid = brokerid self.product_info = product_info self.app_id = app_id self.auth_code = auth_code api = self.t.CreateApi() spi = self.t.CreateSpi() self.t.RegisterSpi(spi) self.t.OnFrontConnected = self.onFrontConnected # 交易服务器登陆相应 self.t.OnFrontDisconnected = self.onFrontDisconnected self.t.OnRspAuthenticate = self.onRspAuthenticate # 申请码检验 self.t.OnRspUserLogin = self.onRspUserLogin # 用户登陆 self.t.OnRspUserLogout = self.onRspUserLogout # 用户登出 self.t.OnRtnInstrumentStatus = self.onRtnInstrumentStatus self.t.OnRspQryInstrument = self.onRspQryInstrument # 查询全部交易合约 self.t.OnRspSettlementInfoConfirm = self.onRspSettlementInfoConfirm # 结算单确认,显示登陆日期 self.t.OnRspQryTradingAccount = self.onRspQryTradingAccount # 查询账户 self.t.OnRtnOrder = self.onRtnOrder # 报单 self.t.OnRtnTrade = self.onRtnTrade # 成交 # self.t.OnRspParkedOrderInsert = self.onRspParkedOrderInsert self.t.OnErrRtnOrderInsert = self.onErrRtnOrderInsert self.t.OnRspQryDepthMarketData = self.onRspQryDepthMarketData # 查询涨跌停 self.t.RegCB() self.t.RegisterFront(RegisterFront) self.t.Init() self.islogin = False def onFrontConnected(self): """服务器连接""" downLogProgram('交易服务器连接成功') self.t.ReqAuthenticate(self.brokerid, self.userid, self.product_info, self.auth_code, self.app_id) def onFrontDisconnected(self, n): downLogProgram('交易服务器连接断开') def onRspAuthenticate( self, pRspAuthenticateField: CThostFtdcRspAuthenticateField, pRspInfo: CThostFtdcRspInfoField, nRequestID: int, bIsLast: bool): downLogProgram('auth:{0}:{1}'.format(pRspInfo.getErrorID(), pRspInfo.getErrorMsg())) if pRspInfo.getErrorMsg() == '正确' or pRspInfo.getErrorMsg( ) == 'CTP:认证码错误,尽快获取正确的认证码。当前系统或者用户豁免终端认证,可以登录': self.t.ReqUserLogin(BrokerID=self.brokerid, UserID=self.userid, Password=self.password, UserProductInfo=self.product_info) elif pRspInfo.getErrorMsg() == 'CTP:前置不活跃': threading.Timer(60, self.t.ReqAuthenticate, [ self.brokerid, self.userid, self.product_info, self.auth_code, self.app_id ]).start() def onRspUserLogin(self, data, error, n, last): """登陆回报""" if error.getErrorID() == 0: self.Investor = data.getUserID() self.BrokerID = data.getBrokerID() log = self.Investor + '交易服务器登陆成功' self.islogin = True self.t.ReqSettlementInfoConfirm(self.BrokerID, self.Investor) # 对账单确认 self.t.ReqQryDepthMarketData() downLogProgram(log) else: log = '交易服务器登陆回报,错误代码:' + str(error.getErrorID()) + \ ', 错误信息:' + str(error.getErrorMsg()) downLogProgram(log) if error.getErrorMsg() == 'CTP:客户端未认证': # 过 60 秒后,重新登陆一次 threading.Timer(60, self.t.ReqUserLogin, [ '', self.brokerid, self.userid, self.password, self.product_info ]).start() def onRspUserLogout(self, data, error, n, last): if error.getErrorID() == 0: log = '交易服务器登出成功' self.islogin = False else: log = '交易服务器登出回报,错误代码:' + str(error.getErrorID()) + \ ', 错误信息:' + str(error.getErrorMsg()) downLogProgram(log) def onRtnInstrumentStatus(self, data): pass def onRspQryInstrument(self, data, error, n, last): pass def onRspSettlementInfoConfirm(self, data, error, n, last): """确认结算信息回报""" downLogProgram('账号:{}, 日期:{}, 时间:{}'.format(data.getInvestorID(), data.getConfirmDate(), data.getConfirmTime())) def getPosition(self): self.checkPosition = False downLogProgram("读取账号持仓情况") self.t.ReqQryInvestorPosition(self.brokerid, self.userid) def onRspQryTradingAccount(self, data, error, n, last): """资金账户查询回报""" if error.getErrorID() == 0: event = Event(type_=EVENT_ACCOUNT) event.dict_['BrokerID'] = data.getBrokerID() event.dict_['AccountID'] = data.getAccountID() event.dict_['PreDeposit'] = data.getPreDeposit() event.dict_['PreBalance'] = data.getPreBalance() event.dict_['PreMargin'] = data.getPreMargin() event.dict_['CurrMargin'] = data.getCurrMargin() event.dict_['Available'] = data.getAvailable() event.dict_['WithdrawQuota'] = data.getWithdrawQuota() ee.put(event) else: log = ('账户查询回报,错误代码:' + str(error.getErrorID()) + ', 错误信息:' + str(error.getErrorMsg())) downLogProgram(log) def getAccount(self): self.t.ReqQryTradingAccount(self.brokerid, self.userid) def onRtnOrder(self, data): # 常规报单事件 if time(7) <= datetime.now().time() <= time( 8, 15): # # 判断 连接 断开 与 连接 重连 的问题 return event = Event(type_=EVENT_ORDER) event.dict_ = data.__dict__.copy() ee.put(event) def onRtnTrade(self, data): """成交回报""" if time(7) <= datetime.now().time() <= time(8, 15): return event = Event(type_=EVENT_TRADE) event.dict_ = data.__dict__.copy() ee.put(event) # 预下单,没有用了 def onRspParkedOrderInsert(self, data=CThostFtdcParkedOrderField, pRspInfo=CThostFtdcRspInfoField, nRequestID=int, bIsLast=bool): event = Event(type_=EVENT_ORDERPARK) event.dict_['data'] = data._fields_ ee.put(event) def onErrRtnOrderInsert(self, data, error): """发单错误回报(交易所)""" if time(7) <= datetime.now().time() <= time(8, 15): return event = Event(type_=EVENT_ERROR) event.dict_['OrderRef'] = data.getOrderRef() event.dict_['InstrumentID'] = data.getInstrumentID() event.dict_['Direction'] = data.getDirection() event.dict_['CombOffsetFlag'] = data.getCombOffsetFlag() event.dict_['VolumeTotalOriginal'] = data.getVolumeTotalOriginal() event.dict_['LimitPrice'] = data.getLimitPrice() event.dict_['ErrorMsg'] = error.getErrorMsg() ee.put(event) # region 下单操作 def sendorder(self, instrumentid, orderRef, price, vol, direction, offset, OrderPriceType=TThostFtdcOrderPriceTypeType. THOST_FTDC_OPT_LimitPrice): goodsCode = getGoodsCode(instrumentid) if goodsCode.split('.')[1] == 'SHF': exChangeID = 'SHFE' elif goodsCode.split('.')[1] == 'DCE': exChangeID = 'DCE' elif goodsCode.split('.')[1] == 'CZC': exChangeID = 'CZCE' elif goodsCode.split('.')[1] == 'CFE': exChangeID = 'CFFEX' elif goodsCode.split('.')[1] == 'INE': exChangeID = 'INE' self.t.ReqOrderInsert( BrokerID=self.brokerid, InvestorID=self.userid, InstrumentID=instrumentid, OrderRef=orderRef, UserID=self.userid, OrderPriceType=OrderPriceType, Direction=direction, CombOffsetFlag=offset, CombHedgeFlag=chr( TThostFtdcHedgeFlagType.THOST_FTDC_HF_Speculation.value), LimitPrice=price, VolumeTotalOriginal=vol, TimeCondition=TThostFtdcTimeConditionType.THOST_FTDC_TC_GFD, VolumeCondition=TThostFtdcVolumeConditionType.THOST_FTDC_VC_AV, MinVolume=1, ForceCloseReason=TThostFtdcForceCloseReasonType. THOST_FTDC_FCC_NotForceClose, ContingentCondition=TThostFtdcContingentConditionType. THOST_FTDC_CC_Immediately, ExchangeID=exChangeID) return orderRef def buy(self, symbol, orderRef, price, vol): # 买开 direction = TThostFtdcDirectionType.THOST_FTDC_D_Buy offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Open.value) self.sendorder(symbol, orderRef, price, vol, direction, offset) def sell(self, symbol, orderRef, price, vol): # 买平 direction = TThostFtdcDirectionType.THOST_FTDC_D_Sell offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Close.value) self.sendorder(symbol, orderRef, price, vol, direction, offset) def sellMarket(self, symbol, orderRef, vol): # 买平市 direction = TThostFtdcDirectionType.THOST_FTDC_D_Sell offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Close.value) self.sendorder(symbol, orderRef, 0, vol, direction, offset, TThostFtdcOrderPriceTypeType.THOST_FTDC_OPT_AnyPrice) def sellToday(self, symbol, orderRef, price, vol): # 买平今 direction = TThostFtdcDirectionType.THOST_FTDC_D_Sell offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_CloseToday.value) self.sendorder(symbol, orderRef, price, vol, direction, offset) def sellMarketToday(self, symbol, orderRef, vol): # 买平市 direction = TThostFtdcDirectionType.THOST_FTDC_D_Sell offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_CloseToday.value) self.sendorder(symbol, orderRef, 0, vol, direction, offset, TThostFtdcOrderPriceTypeType.THOST_FTDC_OPT_AnyPrice) def short(self, symbol, orderRef, price, vol): # 卖开 direction = TThostFtdcDirectionType.THOST_FTDC_D_Sell offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Open.value) self.sendorder(symbol, orderRef, price, vol, direction, offset) def cover(self, symbol, orderRef, price, vol): # 卖平 direction = TThostFtdcDirectionType.THOST_FTDC_D_Buy offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Close.value) self.sendorder(symbol, orderRef, price, vol, direction, offset) def coverMarket(self, symbol, orderRef, vol): # 卖平市 direction = TThostFtdcDirectionType.THOST_FTDC_D_Buy offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Close.value) self.sendorder(symbol, orderRef, 0, vol, direction, offset, TThostFtdcOrderPriceTypeType.THOST_FTDC_OPT_AnyPrice) def coverToday(self, symbol, orderRef, price, vol): # 卖平今 direction = TThostFtdcDirectionType.THOST_FTDC_D_Buy offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_CloseToday.value) self.sendorder(symbol, orderRef, price, vol, direction, offset) def coverMarketToday(self, symbol, orderRef, vol): # 卖平市 direction = TThostFtdcDirectionType.THOST_FTDC_D_Buy offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_CloseToday.value) self.sendorder(symbol, orderRef, 0, vol, direction, offset, TThostFtdcOrderPriceTypeType.THOST_FTDC_OPT_AnyPrice) def cancelOrder(self, order): """撤单""" self.t.ReqOrderAction( BrokerID=self.brokerid, InvestorID=self.userid, OrderRef=order['OrderRef'], FrontID=int(order['FrontID']), SessionID=int(order['SessionID']), OrderSysID=order['OrderSysID'], ActionFlag=TThostFtdcActionFlagType.THOST_FTDC_AF_Delete, ExchangeID=order["ExchangeID"], InstrumentID=order['InstrumentID']) # endregion # region 预埋单 def sendorderPark(self, instrumentid, orderRef, price, vol, direction, offset, OrderPriceType=TThostFtdcOrderPriceTypeType. THOST_FTDC_OPT_LimitPrice): goodsCode = getGoodsCode(instrumentid) if goodsCode.split('.')[1] == 'SHF': exChangeID = 'SHFE' elif goodsCode.split('.')[1] == 'DCE': exChangeID = 'DCE' elif goodsCode.split('.')[1] == 'CZC': exChangeID = 'CZCE' elif goodsCode.split('.')[1] == 'CFE': exChangeID = 'CFFEX' elif goodsCode.split('.')[1] == 'INE': exChangeID = 'INE' self.t.ReqParkedOrderInsert( BrokerID=self.brokerid, InvestorID=self.userid, InstrumentID=instrumentid, OrderRef=orderRef, UserID=self.userid, OrderPriceType=OrderPriceType, Direction=direction, CombOffsetFlag=offset, CombHedgeFlag=chr( TThostFtdcHedgeFlagType.THOST_FTDC_HF_Speculation.value), LimitPrice=price, VolumeTotalOriginal=vol, TimeCondition=TThostFtdcTimeConditionType.THOST_FTDC_TC_GFD, VolumeCondition=TThostFtdcVolumeConditionType.THOST_FTDC_VC_AV, MinVolume=1, ForceCloseReason=TThostFtdcForceCloseReasonType. THOST_FTDC_FCC_NotForceClose, ContingentCondition=TThostFtdcContingentConditionType. THOST_FTDC_CC_Immediately, ExchangeID=exChangeID) return orderRef def buyPark(self, symbol, orderRef, price, vol): # 多开 direction = TThostFtdcDirectionType.THOST_FTDC_D_Buy offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Open.value) self.sendorderPark(symbol, orderRef, price, vol, direction, offset) def sellPark(self, symbol, orderRef, price, vol): # 多平 direction = TThostFtdcDirectionType.THOST_FTDC_D_Sell offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Close.value) self.sendorderPark(symbol, orderRef, price, vol, direction, offset) def sellMarketPark(self, symbol, orderRef, vol): # 多平 direction = TThostFtdcDirectionType.THOST_FTDC_D_Sell offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Close.value) self.sendorderPark( symbol, orderRef, 0, vol, direction, offset, TThostFtdcOrderPriceTypeType.THOST_FTDC_OPT_AnyPrice) def selltodayPark(self, symbol, orderRef, price, vol): # 平今多 direction = TThostFtdcDirectionType.THOST_FTDC_D_Sell offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_CloseToday.value) self.sendorderPark(symbol, orderRef, price, vol, direction, offset) def shortPark(self, symbol, orderRef, price, vol): # 卖开空开 direction = TThostFtdcDirectionType.THOST_FTDC_D_Sell offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Open.value) self.sendorderPark(symbol, orderRef, price, vol, direction, offset) def coverPark(self, symbol, orderRef, price, vol): # 空平 direction = TThostFtdcDirectionType.THOST_FTDC_D_Buy offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Close.value) self.sendorderPark(symbol, orderRef, price, vol, direction, offset) def coverMarketPark(self, symbol, orderRef, vol): # 空平 direction = TThostFtdcDirectionType.THOST_FTDC_D_Buy offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_Close.value) self.sendorderPark( symbol, orderRef, 0, vol, direction, offset, TThostFtdcOrderPriceTypeType.THOST_FTDC_OPT_AnyPrice) def covertodayPark(self, symbol, orderRef, price, vol): # 平今空 direction = TThostFtdcDirectionType.THOST_FTDC_D_Buy offset = chr(TThostFtdcOffsetFlagType.THOST_FTDC_OF_CloseToday.value) self.sendorderPark(symbol, orderRef, price, vol, direction, offset) def cancelOrderPark(self, order): # 预撤单 self.t.ReqParkedOrderAction( BrokerID=self.brokerid, InvestorID=self.userid, OrderRef=order['OrderRef'], FrontID=int(order['FrontID']), SessionID=int(order['SessionID']), OrderSysID=order['OrderSysID'], ActionFlag=TThostFtdcActionFlagType.THOST_FTDC_AF_Delete, ExchangeID=order["ExchangeID"], InstrumentID=order['InstrumentID']) def onRspQryDepthMarketData(self, data, error, n, last): #获取tick数据操作 icon = filter(lambda x: x.isalpha(), data.getInstrumentID()) icon = ''.join(list(icon)) event = Event(type_=EVENT_INSTRUMENT) event.dict_['InstrumentID'] = data.getInstrumentID() event.dict_['ProductID'] = icon event.dict_['OpenInterest'] = data.getOpenInterest() event.dict_['last'] = last # 主力合约的涨停版 if event.dict_['InstrumentID'] in listInstrument: # 可以避免多线程下数据的混乱 if dictInstrumentUpDownPrice.get(event.dict_['InstrumentID'], [0, 0]) == [0, 0]: dictInstrumentUpDownPrice[event.dict_['InstrumentID']] = [ data.getUpperLimitPrice(), data.getLowerLimitPrice() ] ee.put(event)