CTP

您所在的位置:网站首页 交易类型代码 CTP

CTP

2024-07-09 19:39| 来源: 网络整理| 查看: 265

CTP-API开发系列之六:交易登录及查询流程 前情回顾全局配置参数交易初始化流程7步初始化交易api订阅私有流注意事项订阅公共流注意事项 交易认证登录流程OnFrontConnectedOnRspAuthenticate 交易数据查询流程新增查询分类合约的接口(v6.5.1版本) 日志截图下节预告

今天开始分享程序代码,主要以python语言为主。关于CTP-API的开发,前面进行了一些铺垫,不了解的朋友可以先看一下之前的文章,欢迎大家继续关注并订阅。

前情回顾

CTP-API开发系列之一:各版本更新说明(持续更新) CTP-API开发系列之二:问题汇总(持续更新) CTP-API开发系列之三:柜台系统简介 CTP-API开发系列之四:接口对接准备 CTP-API开发系列之五:SimNow环境介绍

全局配置参数

在这里插入图片描述 配置字段说明见之前的文章:CTP-API开发系列之五:SimNow环境介绍

交易初始化流程 def init_tradeapi(): "初始化交易api" tradeapi = api.CThostFtdcTraderApi_CreateFtdcTraderApi("logs//trade_con//") log.info("1.CreateFtdcTraderApi:" + tradeapi.GetApiVersion()) tradespi = CTradeSpi(tradeapi) log.info("2.RegisterFront:" + TradeFrontAddr) tradeapi.RegisterFront(TradeFrontAddr) log.info("3.RegisterSpi") tradeapi.RegisterSpi(tradespi) log.info("4.SubscribePrivateTopic") tradeapi.SubscribePrivateTopic(api.THOST_TERT_QUICK) log.info("5.SubscribePublicTopic") tradeapi.SubscribePublicTopic(api.THOST_TERT_NONE) log.info("6.Init") tradeapi.Init() log.info("7.Join") tradeapi.Join() 7步初始化交易api

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中我采用的是“取消订阅”。 在这里插入图片描述 4.随着大量期权合约的上市,上期技术也发流量飙升的问题,并在v6.5.1版本新增了“取消订阅”的方式。当时还引发了生产故障,很多客户终端加载合约过慢导致无法打开。 在这里插入图片描述

交易认证登录流程 def OnFrontConnected(self) -> "void": log.info("OnFrontConnected tradefront") authfield = api.CThostFtdcReqAuthenticateField() authfield.BrokerID = BROKERID authfield.UserID = USERID authfield.AppID = AppID authfield.AuthCode = AuthCode self.tapi.ReqAuthenticate(authfield, 0) log.info("send ReqAuthenticate: " + api_struct_serialize(authfield)) def OnRspAuthenticate(self, pRspAuthenticateField: 'CThostFtdcRspAuthenticateField', pRspInfo: 'CThostFtdcRspInfoField', nRequestID: 'int', bIsLast: 'bool') -> "void": log.info('OnRspAuthenticate: ' + api_struct_serialize(pRspAuthenticateField)) if not pRspInfo.ErrorID: loginfield = api.CThostFtdcReqUserLoginField() loginfield.BrokerID = BROKERID loginfield.UserID = USERID loginfield.Password = PASSWORD loginfield.UserProductInfo = "ctp_quant" self.tapi.ReqUserLogin(loginfield, 0) log.info("send ReqUserLogin: " + api_struct_serialize(loginfield)) OnFrontConnected

前面提到过,在与柜台系统连接建立成功后会回调该函数,然后进行认证,调用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品种相关的合约,此外还可以按照以下四个类别进行过滤,都不填的话查询所有合约(包括期权合约但没有组合以及非交易的合约) 在这里插入图片描述 2.CTP合约信息可分为可交易合约和非交易合约,非交易合约数据量占比较大。新增查询分类合约接口可依据查询请求域交易类型TradingType字段查询指定合约信息。

///请求查询分类合约: virtual int ReqQryClassifiedInstrument(CThostFtdcQryClassifiedInstrumentField *pQryClassifiedInstrument, int nRequestID) = 0; ///请求查询分类合约响应: virtual void OnRspQryClassifiedInstrument(CThostFtdcInstrumentField *pInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) ///查询分类合约 struct CThostFtdcQryClassifiedInstrumentField { ///合约代码 TThostFtdcInstrumentIDType InstrumentID; ///交易所代码 TThostFtdcExchangeIDType ExchangeID; ///合约在交易所的代码 TThostFtdcExchangeInstIDType ExchangeInstID; ///产品代码 TThostFtdcInstrumentIDType ProductID; ///合约交易状态 TThostFtdcTradingTypeType TradingType; ///合约分类类型 TThostFtdcClassTypeType ClassType; }; /// 其中合约类型TradingType的枚举值为: ///所有状态 #define TD_ALL '0' ///交易 #define TD_TRADE '1' ///非交易 #define TD_UNTRADE '2' /// 分类类型ClassType的枚举值为: ///所有合约 #define INS_ALL '0' ///期货、即期、期转现、Tas、金属指数合约 #define INS_FUTURE '1' ///期货期权、现货期权合约 #define INS_OPTION '2' ///组合合约 #define INS_COMB '3' //对应产品类型字段Productclass 为组合类型 日志截图

为了方便对结构体字段、值进行分析,实现了一个api_struct_serialize函数,将ctp-api中的结构体及值以冒号逗号的形式进行输出。

在这里插入图片描述

下节预告

交易认证登录成功了,一些基础数据也查询到了,此外还有合约保证金率查询接口和合约手续费率查询接口,这也是比较慢的两个接口。

后面会分享一些实盘基础数据查询与存储的方法,总的思路就是盘前可以慢慢查,盘中避免查;盘中服务如果重启,则使用本来存储的数据,避免API线程的频繁占用,影响交易报单回推数据的接收。

下节会用代码实现报单操作,以及收到报单回推数据的字段分析,结合柜台系统的架构,详细拆解报单状态的流转,为后续的仓位管理做铺垫。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3