二代行情接口
◇ 1.使用前须知
二代行情mdAPI跟6.3.15api包里的mdAPI有所不同,区别如下:
接口方面:二代行情mdAPI多一个ReqQryMulticastInstrument接口。
使用范围:二代行情mdAPI只有连接
支持交易所组播行情的mdfront
才能获得完整功能,即可以使用ReqQryMulticastInstrument查询组播合约;连接其他行情前置则不能使用该函数。兼容性:兼容非看穿式监管行情前置,包括mdfront和行情front;暂时不兼容看穿式监管行情前置front_se!
本文档的接口函数说明部分仅列出新增接口,其他接口参照CThostFtdcMdApi和CThostFtdcMdSpi部分
◇ 2.说明
目前交易所不允许投资者直接连接交易所报盘网去接收组播行情,如果期货公司将行情转发出来给投资者使用,投资者便能享受到快速的组播行情。但是因为转发的只有增量行情,而只有增量部分的是无法得到完整的行情的,所以投资者可以订阅一路CTP行情,作为快照用。有了快照和增量,便能拼出一份完整的行情。如图所示:
以下方法仅做参考:
1、订阅CTP行情。
可以连接mdfront组件接收行情,因为CTP端的行情是完整的行情,而非增量,所以可以作为基准快照,在后续拼装完整行情的时候使用。
2、订阅期货公司的转发行情。
具有解码能力的投资者,可以订阅该行情,并参考交易所二代行情协议规范做相应解码。解码后会得到增量行情,但是这里要注意,这个增量行情还不能直接拿来用,因为该行情里没有InstrumentID,只有合约编号InstrumentNo,而CTP mdfront的行情里是InstrumentID,两者无法关联。为了解决这个问题,新的mdapi增加了ReqQryMulticastInstrument接口,该接口会返回InstrumentID和InstrumentNo的对应关系,有了这个函数便可以拼出完整的行情。注意,仅新的组播mdfront支持该函数,普通行情front和老mdfront不支持该函数!完整行情拼装方法如下:
a) 盘前接入
开盘后,CTP推送每tick快照行情,转发行情则推送每tick增量行情。投资者程序判断同一合约两边的UpdateTime和UpdateMillisec。如果一致,则将mdfront的这笔tick快照行情作为该合约的基准快照,后续的增量行情都在此基础上做拼装,得到笔笔完整行情。
b) 盘中接入
盘中,如果客户接入,则方法同上述a,投资者程序实时判断两边的UpdateTime和UpdateMillisec,直到遇到一致,则作为基准快照。
c) 盘中丢行情
交易所的组播行情带行情序号,如果行情序号不连续了,说明行情丢包了。此时应该停止行情组装工作,重新寻找最新的行情快照,方法同a。
◇ 3.代码示例
// mduserhandle.h
#include "ThostFtdcMdApi.h"
#include <stdio.h>
#include <Windows.h>
TThostFtdcInstrumentIDType g_chInstrumentID;
class CMduserHandler : public CThostFtdcMdSpi
{
private:
CThostFtdcMdApi *m_mdApi;
public:
void connect()
{
//创建并初始化API
m_mdApi = CThostFtdcMdApi::CreateFtdcMdApi("", true, true);
m_mdApi->RegisterSpi(this);
m_mdApi->RegisterFront("tcp://218.28.130.102:41413");
m_mdApi->Init();
}
//登陆
void login()
{
CThostFtdcReqUserLoginField t = {0};
while (m_mdApi->ReqUserLogin(&t, 1)!=0) Sleep(1000);
}
//请求查询组播合约
void ReqQryMulticastInstrument()
{
CThostFtdcQryMulticastInstrumentField a = { 0 };
a.TopicID = 1001;
strcpy_s(a.InstrumentID, "cu1905");
while (m_mdApi->ReqQryMulticastInstrument(&a, 1)!=0) Sleep(1000);
}
void OnRspQryMulticastInstrument(CThostFtdcMulticastInstrumentField *pMulticastInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
if (pMulticastInstrument)
{
strcpy_s(g_chInstrumentID,pMulticastInstrument->InstrumentID);
}
}
// 订阅行情
void subscribe()
{
char **ppInstrument=new char * [50];
ppInstrumentID[0] = g_chInstrumentID;
while (m_mdApi->SubscribeMarketData(ppInstrument, 1)!=0) Sleep(1000);
}
//接收行情
void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData)
{
printf("OnRtnDepthMarketData\n");
}
};
// main.cpp
#include "mduserhandle.h"
int main(int argc, char* argv[])
{
CMduserHandler *mduser = new CMduserHandler;
mduser->connect();
mduser->login();
mduser->ReqQryMulticastInstrument();
mduser->subscribe();
Sleep(INFINITE);
}