当然不知道这个输出的结果是个什么意思,要仔细研究也要花上不少的精力。内心里还是很想弄明白程序的整个操作过程,但此时天色已经很晚了,脑袋昏昏的,看那些文字材料不知道要看到什么时候。看到《综合交易平台交易API特别说明》后面有一段代码挺不错的,很想将代码的实现过程弄清楚。可能硬着头皮看,不知道什么时候能看完。于是我打算一边打代码,一边揣摩每段代码的含义。花了差不多一个小时的时间,我敲完了代码,并对代码要实现的东西进行了一些总结。
现将代码贴出如下:
// tradeapitest.cpp
// 一个简单的例子, 介绍CThostFtdcTraderApi和CThostFtdcTraderSpi接口的使用
//本例将演示一个报单录入操作的过程
//CThostFtdcTraderApi :
Api对象
//CThostFtdcTraderSpi : 事件处理对象
#include
<stdio.h>
#include <windows.h>
#include
".ThostTraderApiThostFtdcTraderApi.h"
//保单录入操作是否完成的标志
//Create a manual reset event with no
signal
HANDLE g_hEvent =
CreateEvent(NULL,true,false,NULL);
//会员代码
TThostFtdcBrokerIDType g_chBrokerID;
//交易用户代码
TThostFtdcUserIDType g_chUserID;
class CSimpleHandler : public
CThostFtdcTraderSpi
{
public:
//构造函数,需要一个有效的指向CThostFtdcMduserApi实例的指针
CSimpleHandler(CThostFtdcTraderApi *pUserApi) :
m_pUserApi(pUserApi){}
~CSimpleHandler(){}
//当客户端与交易托管系统建立起通信连接,客户端需要进行登录
virtual void OnFrontConnected()
{
CThostFtdcReqUserLoginField
reqUserLogin;
//get BrokerID
printf("BrokerID: ");
scanf("%s",
&g_chBrokerID);
strcpy(reqUserLogin.BrokerID,g_chBrokerID);
//get userid
printf("userid: ");
scanf("%s",&g_chUserID);
strcpy(reqUserLogin.UserID,g_chUserID);
//get password
printf("password:");
scanf("%s",
&reqUserLogin.Password);
//发出登录请求
m_pUserApi->ReqUserLogin(&reqUserLogin,0);
}
virtual void
OnFrontDisconnected(int nReason)
{
//当发生这个情况后,API会自动重新连接,客户端可不做处理
printf("OnFrontDisconnected.n");
}
//当客户端发出登录请求之后,该方法会被调用,通知客户端登录是否成功
virtual void
OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin,
CThostFtdcRspInfoField *pRspInfo,int nRequestID, bool
bIsLast)
{
printf("OnRspUserLogin:n");
printf("ErrorCode=[%d],
ErrorMsg=[%s]n",pRspInfo->ErrorID,
pRspInfo->ErrorMsg);
printf("RequestID=[%d],Chain=[%d]n",nRequestID,bIsLast);
if(pRspInfo->ErrorID
!= 0){
//登录失败,客户端需要进行错误处理
printf("Failed
to login, errorcode = %d errormsg= %s requestid = %d chain = %d",
pRspInfo->ErrorID,
pRspInfo->ErrorMsg, nRequestID, bIsLast);
exit(-1);
}
//登录成功,发出保单录入请求
CThostFtdcInputOrderField
ord;
memset(&ord, 0,
sizeof(ord));
//经纪公司代码
strcpy(ord.BrokerID,
g_chBrokerID);
//投资者代码
strcpy(ord.InvestorID,
"12345");
//合约代码
strcpy(ord.InstrumentID,"cn0601");
//报单引用
strcpy(ord.OrderRef,"000000000001");
//用户代码
strcpy(ord.UserID,
g_chUserID);
//报单价格条件
ord.OrderPriceType =
THOST_FTDC_OPT_LimitPrice;
//买卖方向
ord.Direction =
THOST_FTDC_D_Buy;
//组合开平标志
strcpy(ord.CombOffsetFlag,"0");
//组合投机套保标志
strcpy(ord.CombHedgeFlag,"1");
//价格
ord.LimitPrice = 50000;
//数量
ord.VolumeTotalOriginal =
10;
//有效期类型
ord.TimeCondition =
THOST_FTDC_TC_GFD;
//GTD日期
strcpy(ord.GTDDate,"");
//成交量类型
ord.VolumeCondition =
THOST_FTDC_VC_AV;
//最小成交量
ord.MinVolume = 0;
//触发条件
ord.ContingentCondition =
THOST_FTDC_CC_Immediately;
//止损价
ord.StopPrice = 0;
//强平原因
ord.ForceCloseReason =
THOST_FTDC_FCC_NotForceClose;
//自动挂起标志
ord.IsAutoSuspend
=0;
m_pUserApi->ReqOrderInsert(&ord,1);
}
//保单录入应答
virtual void
OnRspOrderInsert(CThostFtdcInputOrderField *pInputOrder,
CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool
bIsLast)
{
//输出保单录入结果
printf("ErrorCode=[%d],ErrorMsg=[%s]n",pRspInfo->ErrorID,
pRspInfo->ErrorMsg);
//通知保单录入完成
SetEvent(g_hEvent);
}
//保单回报
virtual void OnRtnOrder(CThostFtdcOrderField
*pOrder)
{
printf("OnRtnOrder:n");
printf("OrderSysID=[%s]n",
pOrder->OrderSysID);
}
//针对用户请求的出错通知
virtual void OnRspError(CThostFtdcRspInfoField
*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);
//客户端需要进行错误处理
{
//客户端的错误处理
}
}
private:
//指向CThostFtdcMduserApi实例的指针
CThostFtdcTraderApi
*m_pUserApi;
};
int main()
{
//产生一个CThostFtdcTraderApi实例
CThostFtdcTraderApi *pUserApi =
CThostFtdcTraderApi::CreateFtdcTraderApi();
//产生一个事件处理的实例
CSimpleHandler
sh(pUserApi);
//相当于将sh依附于pUserApi
//注册一个事件处理的实例
pUserApi->RegisterSpi(&sh);
//pUserApi发生的一切事件都会调用sh中的处理函数
//订阅私有流
// TERT_RESTART:
从本交易日开始重传
// TERT_RESUME:
从上次收到的续传
// TERT_QUICK:
只传送登录后私有流的内容
pUserApi->SubscribePrivateTopic(THOST_TERT_RESUME);
//订阅公共流
// TERT_RESTART:从本交易日开始重传
// TERT_RESUME:
从上次收到的续传
// TERT_QUICK:
只传送登录后公共流的内容
pUserApi->SubscribePublicTopic(THOST_TERT_RESUME);
//设置交易托管系统服务的地址,可以注册多个地址备用
pUserApi->RegisterFront("tcp://172.16.0.31:57205");
//使客户端开始与后台服务器建立连接
pUserApi->Init();
//客户端等待报单操作完成
WaitForSingleObject(g_hEvent,INFINITE);
//释放API实例
pUserApi->Release();
return
0;
}
整个函数的重点在于新建立的CSimpleHandler是如何实现CThostFtdcTraderSpi的各个虚函数的,正是这种个性话的操作才让程序化控制交易流程得以实现.
这些虚函数和回调函数很像,有点像是模拟窗口程序的特点。
另外main函数实现了这样一个流程:创建Api对象(pUserApi)->
注册事件处理对象 (sh) -> 订阅共有流(SubscribePublicTopic) ->
订阅私有流(SubscribePrivateTopic) ->
注册前置机(RegisterFront) ->
初始化Api(Init)。至于初始化过程后面的内容,以后再慢慢研究了^_^
通过对CSimpleHandler的观察,不难得出交易系统处理报单大致是这样一个流程:
另外从网上流传的一个交易开发流程的实例里面可以看出CThostFtdcTraderSpi应该不止这样六个虚函数,从网上收集了一下,至少有这些虚函数需要去实现:
1. OnFrontConnected
: 当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。
2. OnRspUserLogin : 登录请求响应,
当连接成功之后会调用这个函数
3. OnRspSettlementInfoConfirm: 投资者结算结果确认响应
4. OnRspQryInstrument: 请求查询合约响应
5. OnRspQryTradingAccount: 请求查询资金账户响应
6. OnRspQryInvestorPosition:
请求查询投资者持仓响应
7. OnRspOrderInsert
: 报单录入请求响应,
可以在OnRspUserLogin后面就下单,当然什么时候下单都可以,看程序怎么调了。程序员可以自行安排下单的时间和顺序。
8. OnRspOrderAction
: 报单操作请求响应
9. OnRspError : 错误应答
10. OnFrontDisconnected
: 当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。
11. OnHeartBeatWarning
: 心跳超时警告。当长时间未收到报文时,该方法被调用。
12. OnRtnOrder
: 报单通知,也叫报单回报。 应该是交易所回传过来的报单信息
13. OnRtnTrade : 成交通知
今天就写到这里了,已经晚上4:30了,回去睡觉觉了!
|