CTP |
您所在的位置:网站首页 › 交易类型代码 › CTP |
CTP-API开发系列之六:交易登录及查询流程
前情回顾全局配置参数交易初始化流程7步初始化交易api订阅私有流注意事项订阅公共流注意事项
交易认证登录流程OnFrontConnectedOnRspAuthenticate
交易数据查询流程新增查询分类合约的接口(v6.5.1版本)
日志截图下节预告
今天开始分享程序代码,主要以python语言为主。关于CTP-API的开发,前面进行了一些铺垫,不了解的朋友可以先看一下之前的文章,欢迎大家继续关注并订阅。 前情回顾CTP-API开发系列之一:各版本更新说明(持续更新) CTP-API开发系列之二:问题汇总(持续更新) CTP-API开发系列之三:柜台系统简介 CTP-API开发系列之四:接口对接准备 CTP-API开发系列之五:SimNow环境介绍 全局配置参数
1.创建交易api,参数"logs//trade_con//"指定flow目录,用于存放生成的.con文件,不传默认存放到当前路径。 注意:如果指定了路径,必须提前创建好文件夹2.设置交易托管系统(期货公司柜台系统)的网络通讯地址,可以注册一个或多个地址。 如果注册多个,会以最先建立TCP连接的地址作为当前连接地址进行连接,建立的连接如果中断,api会自动尝试重连。3.注册一个派生自 CThostFtdcTraderSpi 接口类的实例,该实例将完成事件处理。 4.订阅私有流。该方法要在Init 方法前调用。若不调用则不会收到私有流的数据。推荐使用THOSTTERTRESTART方式订阅私有流。 THOST_TERT_RESTART:从本交易日开始重传(推荐) THOST_TERT_RESUME:从上次收到的续传 THOST_TERT_QUICK:只传送登录后私有流的内容5.订阅公共流。该方法要在Init 方法前调用。若不调用,默认RESTART模式订阅。 THOST_TERT_RESTART:从本交易日开始重传 THOST_TERT_RESUME:从上次收到的续传 THOST_TERT_QUICK:只传送登录后私有流的内容 THOST_TERT_NONE:取消订阅公有流6.初始化运行环境,只有调用后,接口才开始发起前置的连接请求,也就是第2步设置的地址,连接建立成功后会回调 OnFrontConnected 函数,认证动作就是在该函数中进行。 7.等待一个接口实例线程的结束。 注:上述2,3,4,5步没有先后顺序之分,但必须在6,7步之前 订阅私有流注意事项1.订阅私有流主要涉及交易、行权、银期等操作的推送通知。比如在A设备报的单,这个单子的状态变化会主动推送到该投资者目前所有在线的设备上。涉及的常用函数有: /// 在该文件中 ThostFtdcTraderApi.h ,以OnRtn开头的函数 ///报单通知 virtual void OnRtnOrder(CThostFtdcOrderField *pOrder) {}; ///成交通知 virtual void OnRtnTrade(CThostFtdcTradeField *pTrade) {}; ///执行宣告通知 virtual void OnRtnExecOrder(CThostFtdcExecOrderField *pExecOrder) {}; ///期权自对冲通知 virtual void OnRtnOptionSelfClose(CThostFtdcOptionSelfCloseField *pOptionSelfClose) {}; ///期货发起银行资金转期货通知 virtual void OnRtnFromBankToFutureByFuture(CThostFtdcRspTransferField *pRspTransfer) {}; ///银行发起期货资金转银行通知 virtual void OnRtnFromFutureToBankByBank(CThostFtdcRspTransferField *pRspTransfer) {}; 订阅公共流注意事项1.公共流主要涉及合约交易状态通知: /// 在该文件中 ThostFtdcTraderApi.h ///合约交易状态通知 virtual void OnRtnInstrumentStatus(CThostFtdcInstrumentStatusField *pInstrumentStatus) {};2.合约的交易状态有以下几种: /// 在该文件中 ThostFtdcUserApiDataType.h / ///TFtdcInstrumentStatusType是一个合约交易状态类型 / ///开盘前 #define THOST_FTDC_IS_BeforeTrading '0' ///非交易 #define THOST_FTDC_IS_NoTrading '1' ///连续交易 #define THOST_FTDC_IS_Continous '2' ///集合竞价报单 #define THOST_FTDC_IS_AuctionOrdering '3' ///集合竞价价格平衡 #define THOST_FTDC_IS_AuctionBalance '4' ///集合竞价撮合 #define THOST_FTDC_IS_AuctionMatch '5' ///收盘 #define THOST_FTDC_IS_Closed '6'3.问题:如下图所示,流量飙升的几个时间点,几乎所有的合约都会推送(一个合约一个合约进行回调),这些时间点的流量压力以及自己程序的处理压力都会比较大,尤其对于中继服务的开发,应该避免这样的订阅方式,上述demo中我采用的是“取消订阅”。 前面提到过,在与柜台系统连接建立成功后会回调该函数,然后进行认证,调用ReqAuthenticate函数。所有涉及的配置字段请参考之前的文章 CTP-API开发系列之五:SimNow环境介绍,里面有介绍关键字段。 OnRspAuthenticate认证成功后(ErrorID == 0),填写登录相关信息,调用ReqUserLogin接口进行登录。 /// 在error.xml文件中 交易数据查询流程登录成功后,就需要进行一些列的基础数据查询操作,基本就是一请求一响应的模式,下面的函数都可以在 ThostFtdcTraderApi.h 头文件中找到定义,就不一一解释了,最后会把日志截图放上来。 def OnRspUserLogin(self, pRspUserLogin: 'CThostFtdcRspUserLoginField', pRspInfo: 'CThostFtdcRspInfoField', nRequestID: 'int', bIsLast: 'bool') -> "void": log.info("OnRspUserLogin: " + api_struct_serialize(pRspUserLogin)) qryinfofield = api.CThostFtdcQrySettlementInfoField() qryinfofield.BrokerID = BROKERID qryinfofield.InvestorID = USERID qryinfofield.TradingDay = pRspUserLogin.TradingDay self.tapi.ReqQrySettlementInfo(qryinfofield, 0) ## 请求查询投资者结算结果 log.info("send ReqQrySettlementInfo: " + api_struct_serialize(qryinfofield)) def OnRspQrySettlementInfo(self, pSettlementInfo: 'CThostFtdcSettlementInfoField', pRspInfo: 'CThostFtdcRspInfoField', nRequestID: 'int', bIsLast: 'bool') -> "void": log.info("OnRspQrySettlementInfo: " + api_struct_serialize(pSettlementInfo)) pSettlementInfoConfirm = api.CThostFtdcSettlementInfoConfirmField() pSettlementInfoConfirm.BrokerID = BROKERID pSettlementInfoConfirm.InvestorID = USERID self.tapi.ReqSettlementInfoConfirm(pSettlementInfoConfirm, 0) ## 投资者结算结果确认 log.info("send ReqSettlementInfoConfirm: " + api_struct_serialize(pSettlementInfoConfirm)) def OnRspSettlementInfoConfirm(self, pSettlementInfoConfirm: 'CThostFtdcSettlementInfoConfirmField', pRspInfo: 'CThostFtdcRspInfoField', nRequestID: 'int', bIsLast: 'bool') -> "void": log.info("OnRspSettlementInfoConfirm: " + api_struct_serialize(pSettlementInfoConfirm)) pQryTradingAccount = api.CThostFtdcQryTradingAccountField() pQryTradingAccount.BrokerID = BROKERID pQryTradingAccount.InvestorID = USERID self.tapi.ReqQryTradingAccount(pQryTradingAccount, 0) ## 请求查询资金账户 log.info("send ReqQryTradingAccount: " + api_struct_serialize(pQryTradingAccount)) def OnRspQryTradingAccount(self, pTradingAccount: 'CThostFtdcTradingAccountField', pRspInfo: 'CThostFtdcRspInfoField', nRequestID: 'int', bIsLast: 'bool') -> "void": log.info("OnRspQryTradingAccount: " + api_struct_serialize(pTradingAccount)) pQryOrder = api.CThostFtdcQryOrderField() pQryOrder.BrokerID = BROKERID pQryOrder.InvestorID = USERID self.tapi.ReqQryOrder(pQryOrder, 0) ## ///请求查询报单 log.info("send ReqQryOrder: " + api_struct_serialize(pQryOrder)) def OnRspQryOrder(self, pOrder: 'CThostFtdcOrderField', pRspInfo: 'CThostFtdcRspInfoField', nRequestID: 'int', bIsLast: 'bool') -> "void": log.info("OnRspQryOrder: " + api_struct_serialize(pOrder)) if bIsLast: pQryTrade = api.CThostFtdcQryTradeField() pQryTrade.BrokerID = BROKERID pQryTrade.InvestorID = USERID self.tapi.ReqQryTrade(pQryTrade, 0) ## ///请求查询成交 log.info("send pQryTrade: " + api_struct_serialize(pQryTrade)) def OnRspQryTrade(self, pTrade: 'CThostFtdcTradeField', pRspInfo: 'CThostFtdcRspInfoField', nRequestID: 'int', bIsLast: 'bool') -> "void": log.info("OnRspQryTrade: " + api_struct_serialize(pTrade)) if bIsLast: pQryInvestorPosition = api.CThostFtdcQryInvestorPositionField() pQryInvestorPosition.BrokerID = BROKERID pQryInvestorPosition.InvestorID = USERID self.tapi.ReqQryInvestorPosition(pQryInvestorPosition, 0) ## ///请求查询投资者持仓 log.info("send ReqQryInvestorPosition: " + api_struct_serialize(pQryInvestorPosition)) def OnRspQryInvestorPosition(self, pInvestorPosition: 'CThostFtdcInvestorPositionField', pRspInfo: 'CThostFtdcRspInfoField', nRequestID: 'int', bIsLast: 'bool') -> "void": log.info("OnRspQryInvestorPosition: " + api_struct_serialize(pInvestorPosition)) if bIsLast: pQryInstrument = api.CThostFtdcQryInstrumentField() pQryInstrument.ProductID = 'rb' self.tapi.ReqQryInstrument(pQryInstrument, 0) ## ///请求查询合约 log.info("send ReqQryInstrument: " + api_struct_serialize(pQryInstrument)) def OnRspQryInstrument(self, pInstrument: 'CThostFtdcInstrumentField', pRspInfo: 'CThostFtdcRspInfoField', nRequestID: 'int', bIsLast: 'bool') -> "void": # 过滤期货合约 if pInstrument.ProductClass == api.THOST_FTDC_PC_Futures: self.subIDs.append(pInstrument.InstrumentID) if bIsLast: log.info("OnRspQryInstrument isLast! size:" + str(len(self.subIDs))) log.debug(self.subIDs) 新增查询分类合约的接口(v6.5.1版本)1.上述demo中,只查询rb品种相关的合约,此外还可以按照以下四个类别进行过滤,都不填的话查询所有合约(包括期权合约但没有组合以及非交易的合约) 为了方便对结构体字段、值进行分析,实现了一个api_struct_serialize函数,将ctp-api中的结构体及值以冒号逗号的形式进行输出。 交易认证登录成功了,一些基础数据也查询到了,此外还有合约保证金率查询接口和合约手续费率查询接口,这也是比较慢的两个接口。 后面会分享一些实盘基础数据查询与存储的方法,总的思路就是盘前可以慢慢查,盘中避免查;盘中服务如果重启,则使用本来存储的数据,避免API线程的频繁占用,影响交易报单回推数据的接收。 下节会用代码实现报单操作,以及收到报单回推数据的字段分析,结合柜台系统的架构,详细拆解报单状态的流转,为后续的仓位管理做铺垫。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |