跳到主要内容

开发示例

普通Tcp方式接收行情Demo

// mddemo.cpp : 
//一个简单的例子,介绍QdFtdcMduserApi和QdFtdcMduserSpi接口的使用。

#include <stdio.h>
#include <string.h>
#include <float.h>
#include "QdFtdcMdApi.h"

class CSimpleHandler : public CQdFtdcMduserSpi
{
public:
// 构造函数,需要一个有效的指向CQdFtdcMduserApi实例的指针
CSimpleHandler(CQdFtdcMduserApi *pUserApi) : m_pUserApi(pUserApi) {}
~CSimpleHandler() {}

// 当客户端与行情发布服务器建立起通信连接,客户端需要进行登录
void OnFrontConnected()
{
printf("OnFrontConnected.\n")
CQdFtdcReqUserLoginField reqUserLogin;
memset(&reqUserLogin, 0, sizeof(CQdFtdcReqUserLoginField));
strcpy(reqUserLogin.BrokerID, "0001");
strcpy(reqUserLogin.UserID, "t002");
strcpy(reqUserLogin.Password, "111111");
m_pUserApi->ReqUserLogin(&reqUserLogin, 0);
}

// 当客户端与行情发布服务器通信连接断开时,该方法被调用
void OnFrontDisconnected(int nReason)
{
// 当发生这个情况后,API会自动重新连接,客户端可不做处理
printf("OnFrontDisconnected.\n");
}

// 当客户端发出登录请求之后,该方法会被调用,通知客户端登录是否成功
void OnRspUserLogin(CQdFtdcRspUserLoginField *pRspUserLogin, CQdFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
printf("OnRspUserLogin:\n");
if (NULL == pRspInfo)
{
return;
}
printf("ErrorCode=[%d], ErrorMsg=[%s]\n", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
printf("RequestID=[%d], Chain=[%d]\n", nRequestID, bIsLast);

if (pRspInfo->ErrorID != 0)
{
// 端登失败,客户端需进行错误处理
return;
}
char * contracts[3]={"","",""};
contracts[0]="IF1503";
contracts[1]="IF1504";
contracts[2]="IF1506";
m_pUserApi->SubMarketData(contracts, 3);

/*char * uncontracts[2]={"",""};
uncontracts[0]="IF1509";
uncontracts[1]="IH1503";
m_pUserApi->UnSubMarketData(uncontracts, 2);*/
}

// 深度行情通知,行情服务器会主动通知客户端
void OnRtnDepthMarketData(CQdFtdcDepthMarketDataField *pMarketData)
{
// 客户端按需处理返回的数据
printf("%s,%s,%d,",pMarketData->InstrumentID,pMarketData->UpdateTime,pMarketData->UpdateMillisec);
if (pMarketData->AskPrice1==DBL_MAX)
printf("%s,","");
else
printf("%f,",pMarketData->AskPrice1);
if (pMarketData->BidPrice1==DBL_MAX)
printf("%s \n","");
else
printf("%f \n",pMarketData->BidPrice1);
}

// 针对用户请求的出错通知
void OnRspError(CQdFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
printf("OnRspError:\n");
printf("ErrorCode=[%d], ErrorMsg=[%s]\n", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
printf("RequestID=[%d], Chain=[%d]\n", nRequestID, bIsLast);
}

///订阅合约的相关信息
void OnRspSubMarketData(CQdFtdcSpecificInstrumentField *pSpecificInstrument, CQdFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
printf("Sub 返回订阅合约:%s \n",pSpecificInstrument->InstrumentID);
}

///退订合约的相关信息
void OnRspUnSubMarketData(CQdFtdcSpecificInstrumentField *pSpecificInstrument, CQdFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
printf("UnSub 返回订阅合约:%s \n",pSpecificInstrument->InstrumentID);
}

private:
// 指向CQdFtdcMduserApi实例的指针
CQdFtdcMduserApi *m_pUserApi;
};

int main()
{
// 产生一个CQdFtdcMduserApi实例
CQdFtdcMduserApi *pUserApi = CQdFtdcMduserApi::CreateFtdcMduserApi();
// 产生一个事件处理的实例
CSimpleHandler sh(pUserApi);
// 注册一事件处理的实例
pUserApi->RegisterSpi(&sh);
// 注册需要的深度行情主题
/// TERT_RESTART:从本交易日开始重传
/// TERT_RESUME:从上次收到的续传
/// TERT_QUICK:先传送当前行情快照,再传送登录后市场行情的内容
//pUserApi-> SubscribeMarketDataTopic (110, Qd_TERT_RESTART);
// 设置行情发布服务器的地址
pUserApi->RegisterFront("tcp://192.168.1.100:7220");
// 使客户端开始与行情发布服务器建立连接
pUserApi->Init();
pUserApi->Join();
// 释放useapi实例
pUserApi->Release();
return 0;
}

上期能源或者大商所组播行情Demo

#include <stdio.h>
#include <string.h>
#include <float.h>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
#include "QdFtdcMdApi.h"

using namespace std;

char *g_mdFile = "marketdata.log";
char *g_apiMdFile = "apimarketdata.log";

void write_txt(std::string strMkData, char *fileName)
{
ofstream outfile;
outfile.open(fileName, ios::app);
outfile << strMkData << endl;
outfile.close();
}

template <typename T>
string MyTostring(T num)
{
stringstream ss;
string str;
ss << num;
ss >> str;
return str;
}

class CSimpleHandler : public CQdFtdcMduserSpi
{
public:
CSimpleHandler(CQdFtdcMduserApi *pUserApi) : m_pUserApi(pUserApi) {}

~CSimpleHandler() {}

// Udp行情接受
void UdpMarketData(CQdFtdcDepthMarketDataField *qmdata)
{
printf("UdpMarketData: InstrumentID %s,%s,%d\n", qmdata->InstrumentID, qmdata->UpdateTime, qmdata->UpdateMillisec);
};

// 当客户端与行情发布服务器建立起通信连接,客户端需要进行登录
void OnFrontConnected()
{
CQdFtdcReqUserLoginField reqUserLogin;
memset(&reqUserLogin, 0, sizeof(CQdFtdcReqUserLoginField));
strcpy(reqUserLogin.BrokerID, "0001");
strcpy(reqUserLogin.UserID, "t002");
strcpy(reqUserLogin.Password, "111111");
m_pUserApi->ReqUserLogin(&reqUserLogin, 0);
}

// 当客户端与行情发布服务器通信连接断开时,该方法被调用
void OnFrontDisconnected(int nReason)
{
// 当发生这个情况后,API会自动重新连接,客户端可不做处理
printf("OnFrontDisconnected.\n");
}

// 当客户端发出登录请求之后,该方法会被调用,通知客户端登录是否成功
void OnRspUserLogin(CQdFtdcRspUserLoginField *pRspUserLogin, CQdFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
printf("OnRspUserLogin:\n");
if (NULL == pRspInfo)
{
return;
}
printf("ErrorCode=[%d], ErrorMsg=[%s]\n", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
printf("RequestID=[%d], Chain=[%d]\n", nRequestID, bIsLast);

if (pRspInfo->ErrorID != 0)
{
// 端登失败,客户端需进行错误处理
return;
}
char *sContracts[2] = {0};
sContracts[0] = "pg2104";
sContracts[1] = "p2104";

// 注册需要的合约
m_pUserApi->SubMarketData(sContracts, 2);
// 取消不需要的合约
// m_pUserApi->UnSubMarketData(contracts,1);

CQdFtdcQryShfeMultiInfoField fld;
m_pUserApi->ReqQrySHFEMultiInfo(&fld,0);
}

// 深度行情通知,行情服务器会主动通知客户端
void OnRtnDepthMarketData(CQdFtdcDepthMarketDataField *pMarketData)
{
if (NULL == pMarketData)
{
printf("NULL == pMarketData\n");
return;
}
printf("InstrumentID %s--vm:%d------%d------%d------%d------%d------%d------%d------%d------%d------%d------%d------%d\n",
pMarketData->InstrumentID, pMarketData->Volume,
pMarketData->AskPrice1, pMarketData->AskVolume2, pMarketData->AskVolume3, pMarketData->AskVolume4, pMarketData->AskVolume5,
pMarketData->BidPrice1, pMarketData->BidVolume2, pMarketData->BidVolume3, pMarketData->BidVolume4, pMarketData->BidVolume5, pMarketData->PacketNo);

string strMarketData = "";
strMarketData += "ExchangeID=[" + string(pMarketData->ExchangeID) + "], InstrumentID=[" +
string(pMarketData->InstrumentID) + "], InstrumentStatus=[" + string(1, pMarketData->InstrumentStatus) +
"], LastPrice=[" + MyTostring(pMarketData->LastPrice) + "], AskPrice1=[" + MyTostring(pMarketData->AskPrice1) +
"], AskVolume1=[" + MyTostring(pMarketData->AskVolume1) + "], BidPrice1=[" + MyTostring(pMarketData->BidPrice1) +
"], BidVolume1=[" + MyTostring(pMarketData->BidVolume1) + "], AskPrice2=[" + MyTostring(pMarketData->AskPrice2) +
"], AskVolume2=[" + MyTostring(pMarketData->AskVolume2) + "], BidPrice2=[" + MyTostring(pMarketData->BidPrice2) +
"], BidVolume2=[" + MyTostring(pMarketData->BidVolume2) + "], AskPrice3=[" + MyTostring(pMarketData->AskPrice3) +
"], AskVolume3=[" + MyTostring(pMarketData->AskVolume3) + "], BidPrice3=[" + MyTostring(pMarketData->BidPrice3) +
"], BidVolume3=[" + MyTostring(pMarketData->BidVolume3) + "], AskPrice4=[" + MyTostring(pMarketData->AskPrice4) +
"], AskVolume4=[" + MyTostring(pMarketData->AskVolume4) + "], BidPrice4=[" + MyTostring(pMarketData->BidPrice4) +
"], BidVolume4=[" + MyTostring(pMarketData->BidVolume4) + "], AskPrice5=[" + MyTostring(pMarketData->AskPrice5) +
"], AskVolume5=[" + MyTostring(pMarketData->AskVolume5) + "], BidPrice5=[" + MyTostring(pMarketData->BidPrice5) +
"], BidVolume5=[" + MyTostring(pMarketData->BidVolume5) + "], UpdateTime=[" + MyTostring(pMarketData->UpdateTime) +
"], UpdateMillisec=[" + MyTostring(pMarketData->UpdateMillisec) + "], PacketNo=[" + MyTostring(pMarketData->PacketNo) + "]";
write_txt(strMarketData, g_mdFile);
}

// 针对用户请求的出错通知
void OnRspError(CQdFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
printf("OnRspError:\n");
printf("ErrorCode=[%d], ErrorMsg=[%s]\n", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
printf("RequestID=[%d], Chain=[%d]\n", nRequestID, bIsLast);
// 客户端需进行错误处理
}

/// 订阅合约的相关信息
void OnRspSubMarketData(CQdFtdcSpecificInstrumentField *pSpecificInstrument, CQdFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
printf("Sub 返回订阅合约:%s \n", pSpecificInstrument->InstrumentID);
}

/// 订阅合约的相关信息
void OnRspUnSubMarketData(CQdFtdcSpecificInstrumentField *pSpecificInstrument, CQdFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
printf("UnSub 返回订阅合约:%s \n",pSpecificInstrument->InstrumentID);
}

// 以下是组播行情回调函数
// 用户可继承此接口解析上期所组播原始报文-用户自己解析时候
void OnMutiData(char *data, int len)
{
printf("[qdp multicast md] multidata: %d\n", len);
}

/// 组播参数查询结束通知
void OnRtnShfeMultiLevel(CQdFtdcShfeMultiLevelField *pShfeMultiLevel)
{
printf("[qdp multicast md] Level: %d\n", pShfeMultiLevel->Level);
CQdFtdcQryMarketDataField reqFld;
reqFld.TopicID = 141;
m_pUserApi->ReqQryDepthMarketData(&reqFld, 0);
}

/// 组播参数通知
void OnRtnShfeMultiParameters(CQdFtdcShfeMultiParametersField *pShfeMultiParameters)
{
printf("[qdp multicast md] OnRtnShfeMultiParameters: %s, %d, %f, %f\n", pShfeMultiParameters->InstrumentID,
pShfeMultiParameters->InstrumentNo, pShfeMultiParameters->CodecPrice, pShfeMultiParameters->PriceTick);
}

void OnRspQryDepthMarketData(CQdFtdcDepthMarketDataField *pDepthMarketData, CQdFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
if (pDepthMarketData == NULL)
return;
printf("OnRspQryDepthMarketData InstrumentID=%s PacketNo = %d InstrumentNo = %d\n",
pDepthMarketData->InstrumentID, pDepthMarketData->PacketNo, pDepthMarketData->InstrumentNo);
};

// 解析后的上期组播数据,api内部解析只回调这个函数
void OnRtnShfeMultiMarketData(CQdFtdcDepthMarketDataField *pMarketData)
{
if (NULL == pMarketData)
{
printf("OnRtnShfeMultiMarketData: NULL == pMarketData\n");
return;
}
printf("OnRtnShfeMultiMarketData InstrumentID=%s,UpdateTime=%s,UpdateMillisec=%d,LastPrice=%.3f,Volume=%d,AskPrice1=%.3f,BidPrice1=%.3f,ExchangeID=%s,PacketNo=%d\n",
pMarketData->InstrumentID,
pMarketData->UpdateTime,
pMarketData->UpdateMillisec,
pMarketData->LastPrice,
pMarketData->Volume,
pMarketData->AskPrice1,
pMarketData->BidPrice1,
pMarketData->ExchangeID,
pMarketData->PacketNo);

string strMarketData = "";
strMarketData += "ExchangeID=[" + string(pMarketData->ExchangeID) + "], InstrumentID=[" +
string(pMarketData->InstrumentID) + "], InstrumentStatus=[" + string(1, pMarketData->InstrumentStatus) +
"], LastPrice=[" + MyTostring(pMarketData->LastPrice) + "], AskPrice1=[" + MyTostring(pMarketData->AskPrice1) +
"], AskVolume1=[" + MyTostring(pMarketData->AskVolume1) + "], BidPrice1=[" + MyTostring(pMarketData->BidPrice1) +
"], BidVolume1=[" + MyTostring(pMarketData->BidVolume1) + "], AskPrice2=[" + MyTostring(pMarketData->AskPrice2) +
"], AskVolume2=[" + MyTostring(pMarketData->AskVolume2) + "], BidPrice2=[" + MyTostring(pMarketData->BidPrice2) +
"], BidVolume2=[" + MyTostring(pMarketData->BidVolume2) + "], AskPrice3=[" + MyTostring(pMarketData->AskPrice3) +
"], AskVolume3=[" + MyTostring(pMarketData->AskVolume3) + "], BidPrice3=[" + MyTostring(pMarketData->BidPrice3) +
"], BidVolume3=[" + MyTostring(pMarketData->BidVolume3) + "], AskPrice4=[" + MyTostring(pMarketData->AskPrice4) +
"], AskVolume4=[" + MyTostring(pMarketData->AskVolume4) + "], BidPrice4=[" + MyTostring(pMarketData->BidPrice4) +
"], BidVolume4=[" + MyTostring(pMarketData->BidVolume4) + "], AskPrice5=[" + MyTostring(pMarketData->AskPrice5) +
"], AskVolume5=[" + MyTostring(pMarketData->AskVolume5) + "], BidPrice5=[" + MyTostring(pMarketData->BidPrice5) +
"], BidVolume5=[" + MyTostring(pMarketData->BidVolume5) + "], UpdateTime=[" + MyTostring(pMarketData->UpdateTime) +
"], UpdateMillisec=[" + MyTostring(pMarketData->UpdateMillisec) + "], PacketNo=[" + MyTostring(pMarketData->PacketNo) + "]";
write_txt(strMarketData, g_apiMdFile);
}

private:
// 指向CQdFtdcMduserApi实例的指针
CQdFtdcMduserApi *m_pUserApi;
};

int main()
{

CQdFtdcMduserApi *pUserApi = CQdFtdcMduserApi::CreateFtdcMduserApi();
// 产生一个事件处理的实例
CSimpleHandler *sh = new CSimpleHandler(pUserApi);
// 注册一事件处理的实例
pUserApi->RegisterSpi(sh);

// 1、传统的tcp api行情
//pUserApi->RegisterFront("tcp://192.168.101.123:30007");

//下面大商和上期通道只能启动一个
// 2、大商所组播行情
// 大商所组播地址(双通道)
//char DMultiAddr1[256] = "141,dcemulti://10.252.3.106@239.3.42.71:21000#192.168.48.71";
//char DMultiAddr2[256] = "141,dcemulti://10.252.3.106@239.3.42.71:21000#192.168.48.71";
//pUserApi->SetMultiCast(true);
//pUserApi->RegTopicMultiAddr(DMultiAddr1);
//pUserApi->RegTopicMultiAddr(DMultiAddr2);

/*// 3、上期主播行情
// char sFrontAaddr[256] = "tcp://1.1.1.1:30007";
//上期组播地址
char SMultiAddr[256] = "1000,multi://10.252.3.106@239.3.42.71:21000#192.168.48.71";
pUserApi->SetMultiCast(true);
pUserApi->SetUserFreedom(false);//这里由api解析
// pUserApi->SetUserFreedom(true);//这里由用户自己解析 (客户可以通过OnMutiData接口接收原始组播报文)
pUserApi->RegTopicMultiAddr(SMultiAddr);

// API初始化
pUserApi->Init();
pUserApi->Join();
pUserApi->Release();
return 0;
}