跳到主要内容

开发前的准备

API开发者在开发过程中可以在量投quantfair环境中进行开发测试,QDP模拟环境的行情提供实盘行情,目前包括国内上期所、中金所、大商所、郑商所、广期所、能源交易中心和上金所。

测试帐号需要发送申请邮件到qdp@quantdo.com.cn,具体申请步骤见投资者测试申请

API开发者在测试环境完成测试后转向实盘交易时,在期货公司或黄金综合类会员开户完成后,会取得诸如BrokerID、UserID、用户密码、交易前置地址和行情前置地址等交易相关信息,进行实盘交易。

开发流程

API接口初始化

以下步骤描述的是创建和初始化行情接口或交易接口的过程,通过以下步骤开启交易接口或行情接口的工作线程。在初始化阶段,程序必须完成如下步骤(具体代码请参考开发实例):

  1. 创建一个Api实例,这里的API实例是指接口中提供的CQdpFtdcTraderApi:: CreateFtdcTraderApi;
  1. 创建SPI实例,这里的SPI实例是指开发者创建的自己的类,该类已经继承了接口中的SPI 接口类(CQdpFtdcTraderSpi);
  1. 向Api实例注册(CQdpFtdcTraderApi::RegisterSpi)Spi实例;
  1. 订阅私有流SubscribePrivateTopic。 用于接收私有数据,如委托回报、成交回报。默认模式是从上次断开连接处继续收取交易所发布数据(Resume模式,对应的数据字典是QDP_TERT_RESUME)开发者还可以指定全部重新获取(对应的数据字典是QDP_TERT_RESTART),或从登陆后获取(对应的数据字典是QDP_TERT_QUICK)。如不订阅私有流,API将收不到客户的委托回报和成交回报等信息;
  1. 订阅公共流SubscribePublicTopic。 用于接收公有数据,如合约的交易状态。默认模式是从上次断开连接处继续收取QDP发布数据(对应的数据字典是QDP_TERT_RESUME),开发者还可以指定全部重新获取(对应的数据字典是QDP_TERT_RESTART),或从登陆后获取(对应的数据字典是QDP_TERT_QUICK)。如不订阅公共流,API将收不到合约的交易状态等信息;
  1. 向 API实例注册前置地址RegisterFront。 交易接口需要注册交易前置地址。相关地址在实盘交易时向期货公司或黄金综合类会员咨询;
  1. API实例调用Init方法,启动API线程。 关闭API线程需要调用Release方法,调用的线程不能在API线程内部;
  1. 等待API线程退出,调用Join接口。

在初始化阶段,程序只能调用订阅接口;在OnFrontConnected方法调用后必须调用ReqUserLogin向QDP服务端发起登录请求,请求成功后才可以任意调用交易接口中的请求方法,如ReqOrderInsert等,同时按照需要响应回调接口中的应答方法。在登录成功之前不能进行任何别的请求。

其他注意事项:
  1. API请求的输入参数不能为NULL。
  1. 20210329版本后,需要在登录成功后分别私有流和公有流请求ReqReady。
  1. 如果QDP服务端是需要认证的,则在登录前需要调用ReqAuthenticate向QDP发起登录认证请求,收到认证成功的Rsp后再进行登录请求。

连接和重连

API线程启动后会自动连接对应的交易前置,连接成功后会回调对应的SPI实例的OnFrontConnected方法,一般在这个回调方法中做请求登录操作,不做其它的操作;

如果一直没有回调这个方法,请检查API注册的前置地址是否正确,QDP柜台是否已经启动。

连接建立后QDP交易核心会分配一个SessionID给该连接,该SessionID在登录成功的应答里获取(用户本地报单号撤单时需要用到SessionID)。API线程会不断的通过这个连接和QDP交易核心发送心跳报文,这个心跳发送间隔默认为10秒,可以通过SetHeartbeatTimeout方法设置超时时间(必须在Init方法调用之前设置);

连接建立后必须尽快发起登录操作,也只能做登录操作,长时间不登录会被QDP交易核心断开连接。

连接断开时API线程会回调OnFrontDisconnected方法,该方法的参数nReason指明了连接断开的原因,一般都是网络连接断开或心跳超时导致的,心跳超时导致的端口需要客户自己检查API程序在回调时做了一些耗时的操作阻塞了API线程接收心跳报文,另外一个可以增加超时时间;

连接断开后API自己会定时重连QDP前置。重连成功后的SessionID与原来的SessionID是不同的。

认证

认证请求必须在连接已经建立的情况下发起,并且在登录之前。

QDP客户的穿透式监管,主要分为两种模式:直连(QDP的大部分客户)和中继

直连模式的流程如下:

  1. 期货公司会在QDP后台根据客户提供的信息(经销商编码+交易终端+AppID/RelayAppID),生成对应的新的AppID和AuthCode,并且提供给客户;
  1. 客户通过ReqAuthenticate接口将AppID和AuthCode发给QDP;
  1. QDP的Spi会通过OnRspAuthenticate返回验证结果;
  1. 在验证成功之后,再进行登录,否则登录会报错(错误码为168,错误信息为“登录之前必须先进行APPID验证”)。

中继模式的流程如下:

使用中继模式接入qdp的系统,在直连模式流程的基础上,在每一个客户接入中继系统后,都需要调用api接口ReqSubmitUserSystemInfo上报客户端采集信息

  1. 需要利用qdpdatacollectapi中的QDGetLocalSystemInfo接口,采集对应的信息,参见信息采集API使用demo开发实例
  1. 再调用ReqSubmitUserSystemInfo接口上报客户端采集信息。

:如果是使用libqdpdatacollectapi.so,linux目前采用lshw命令采集硬盘序列号信息,请确保环境有该命令,否则登录返回错误码为6(采集硬盘序列号失败)。

认证请求

int ReqAuthenticate(CQdpFtdcAuthenticateField *pAuthenticate, int nRequestID);

用户登录认证请求信息CQdpFtdcAuthenticateField说明,详见ReqAuthenticate方法开发接口

注意:认证请求信息需向期货公司获取。

认证应答

void OnRspAuthenticate(CQdpFtdcRtnAuthenticateField *pRtnAuthenticate, CQdpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

用户登录认证应答信息CQdpFtdcRtnAuthenticateField说明,详见OnRspAuthenticate方法开发接口

登录

登录请求必须在连接已经建立的情况下发起(如果QDP服务端是需要认证的,则需要在认证成功后发起)。QDP支持同一个账号的多点登录。同时登录的账号能收到该账号的所有报单,包括该账号在其它连接下发起的报单请求。

登录请求

int ReqUserLogin (CQdpFtdcReqUserLoginField *pReqUserLogin, int nRequestID);

用户登录请求信息CQdpFtdcReqUserLoginField说明,详见ReqUserLogin方法开发接口

登录应答

void OnRspUserLogin(CQdpFtdcRspUserLoginField *pRspUserLogin, CQdpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);

用户登录应答信息CQdpFtdcRspUserLoginField说明,详见OnRspUserLogin方法开发接口

获取投资者代码

API开发者可通过接口查询获取投资者代码,QDP报单时需要填写InvestorID,即投资者代码。

用户投资者查询请求

int ReqQryUserInvestor(CQdpFtdcQryUserInvestorField *pQryUserInvestor, int nRequestID)

用户投资者查询请求信息CQdpFtdcQryUserInvestorField说明,详见ReqQryUserInvestor方法开发接口

用户投资者查询应答

void OnRspQryUserInvestor(CQdpFtdcRspUserInvestorField *pUserInvestor, CQdpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)

用户投资者应答信息CQdpFtdcRspUserInvestorField说明,详见OnRspQryUserInvestor方法开发接口

获取投资者资金信息

QDP的初始资金信息是从对应的主席系统导入的资金信息,比如期货公司都是结算后从CTP主席导入客户的资金信息,客户实际的资金额度应以主席柜台为准。

用户投资者资金信息查询请求

int ReqQryInvestorAccount(CQdpFtdcQryInvestorAccountField *pQryInvestorAccount, int nRequestID)

用户投资者资金查询请求信息CQdpFtdcQryInvestorAccountField说明,详见ReqQryInvestorAccount方法开发接口

用户投资者资金信息查询应答

void OnRspQryInvestorAccount(CQdpFtdcRspInvestorAccountField *pRspInvestorAccount, CQdpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)

用户投资者资金应答信息CQdpFtdcRspInvestorAccountField说明,详见OnRspQryInvestorAccount方法开发接口

获取投资者持仓信息

QDP的初始持仓信息是从交易所查询得到的。如果盘中交易时客户在主席做了开平仓操作,那么次席QDP系统的持仓信息和主席系统的持仓信息会不匹配,因为在主席上做的报单成交流水都不会推送到次席QDP上来。

Position表示客户当前的持仓量;TodayPosition表示客户当前的今持仓量;Position-TodayPosition表示客户当前的昨仓数量;YdPosition不是客户的当前昨仓数量,它表示客户期初的昨持仓数量,它是个不变值。

目前上期所和能源交易中心提供平今和平昨指令,其它交易所只提供平仓指令。中金所和上金所平仓时优先平今,大商所和郑商所平仓时优先平昨。

用户投资者持仓查询请求

int ReqQryInvestorPosition (CQdpFtdcQryInvestorPositionField *pQryUserInvestorPosition, int nRequestID)

用户投资者持仓查询请求信息CQdpFtdcQryInvestorPositionField说明,详见ReqQryInvestorPosition方法开发接口

用户投资者持仓查询应答

void OnRspQryUserInvestor(CQdpFtdcRspUserInvestorField *pUserInvestor, CQdpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)

用户投资者应答信息CQdpFtdcRspUserInvestorField说明,详见OnRspQryInvestorPosition方法开发接口

委托和成交

报单请求

int ReqOrderInsert(CQdpFtdcInputOrderField *pInputOrder, int nRequestID)

用户报单请求信息CQdpFtdcInputOrderField说明,详见ReqOrderInsert 方法开发接口

撤单请求

int ReqOrderAction(CQdpFtdcOrderActionField *pOrderAction, int nRequestID);

用户撤单请求信息CQdpFtdcOrderActionField说明,详见ReqOrderAction 方法开发接口

QDP撤单有2种撤单方式,一个以ExchangeID和OrderSysID进行撤单,另一个以UserID、UserOrderLocalID、FrontID、SessionID;两者都填以第一种方式为准

委托通知

void OnRtnOrder(CQdpFtdcOrderField *pOrder);

委托回报CQdpFtdcOrderField说明,详见OnRtnOrder 方法开发接口

成交通知

void OnRtnTrade(CQdpFtdcTradeField *pTrade);

成交信息CQdpFtdcTradeField说明,详见OnRtnTrade 方法开发接口