Appearance
XTP Pro交易XTrader-API使用示例说明
目录
1. 交易库介绍
该文档旨在帮助开发者快速使用极速交易平台XTP Pro版本的交易API,文中是XTrader-API接口调用示例。
1.1. 头文件
| 文件名 | 详情 |
|---|---|
xtpx_trader_api.h | 交易接口头文件,交易接口类。 |
xtpx_api_data_type.h | 定义兼容数据基本类型。 |
xtpx_api_struct_common.h | 定义业务公共数据结构。 |
xgw_x_api_fund_struct.h | 定义资金划拨相关结构体类型。 |
xoms_x_api_struct.h | 定义交易类相关数据结构。 |
xgw_x_api_query_struct.h | 定义交易类查询相关数据结构。 |
xtrade_x_api_data_type.h | 定义交易使用的数据基本类型。 |
1.2. 库文件
| 适用系统 | 文件名 |
|---|---|
| windows | xtpxtraderapi.dll xtpxtraderapi.lib |
| linux | libxtpxtraderapi.so |
1.3. 接口说明
- (1) 交易API提供了两个接口类:交易类TraderApi接口和交易回调类TraderSpi接口。
- (2) 报单和查询通知是通过异步方式提供。
- (3) 客户端应用程序可通过TraderApi发出报单和查询请求,通过继承TraderSpi并重写回调函数来响应后台服务,处理回报数据。
- (4) XTP Pro版本的库文件目前只支持64位的,注意创建64位的工程,并且设置64位的编译器来进行编译。
2. Quick Start
2.1. 创建Api实例
示例代码如下:
cpp
XTPX::API::TraderApi* m_pTraderApi = NULL;
int client_id = 1;//一个进程一个client id,可在[1, 24]区间内任选,并固定下来
std::string save_file_path = "./";//保存xtp api日志的路径,需要有可读写权限
XTP_LOG_LEVEL log_level = XTP_LOG_LEVEL_DEBUG;//xtp api日志的输出级别,建议调试时使用debug级别,正常运行时使用info级别
///创建TraderApi
m_pTraderApi = XTPX::API::TraderApi::CreateTraderApi(client_id, save_file_path.c_str(), log_level);
if (NULL == m_pTraderApi)
{
//创建API失败
}2.2. 初始化Api参数
(1)设定心跳超时时间 示例代码如下:
cpp
///设定与交易服务器交互的超时时间,单位为秒,默认是15s,调试时可以设定大点
uint32_t heat_beat_interval = 15;
m_pTraderApi->SetHeartBeatInterval(heat_beat_interval);(2)设定交易公共流首次登录时的传输方式 如果不设置,默认将采用 Quick 方式登录。
如果需要获取登录前的报单订单响应和成交回报信息,可以采用 Restart 方式登录。
如果不需要登录前的报单订单响应和成交回报信息,可以采用 Quick 方式登录。
示例代码如下:
cpp
//设定公共流传输方式
XTP_TE_RESUME_TYPE resume_type = XTP_TERT_QUICK;//第一次登陆所使用的公共流消息传送方式,用户可视自身需要在quick和restart中任选
m_pTraderApi->SubscribePublicTopic(resume_type);(3)设定软件开发代码 此软件开发代码,为客户申请XTP开户时,由运营人员提供。如果用户没有收到这个软件开发代码,或者使用已有的软件开发代码无法登录时,请联系运营人员。
示例代码如下:
cpp
//设定软件开发代码,由运营人员提供
char software_key[] = "xxxxxxxxxxxxx";
m_pTraderApi->SetSoftwareKey(software_key);(4)设定软件版本号 此软件版本号为用户自定义字段,设定规则是仅可使用如下字符0-9,a-z,A-Z 以及. 。
示例代码如下:
cpp
//设定软件版本号,用户自定义(仅可使用如下字符0-9,a-z,A-Z,.)
char version[] = "xxxxxxxxxxxxx";
m_pTraderApi->SetSoftwareVersion(version);2.3. 创建Spi类
如果想要获取交易数据,必须得有自己的回调响应类。下面仅以收到订单响应为例,创建了一个Spi回调响应类MyTraderSpi,具体步骤如下:
(1)继承XTPX::API::TraderSpi,创建自己的Spi类MyTraderSpi
以常用的接口回调函数为例。 trader_spi.h文件,交易回调类接口定义:
cpp
#include "xtpx_trader_api.h"
using namespace XTPX::API;
class MyTraderSpi : public TraderSpi
{
public:
MyTraderSpi();
~MyTraderSpi();
///交易服务器断线通知
void OnDisconnected(uint64_t session_id, int reason);
//当登录成功后,中途出现某个服务(资金划拨或者查询)服务状态改变时,该方法将被调用
void OnServerStatusNotification(uint64_t session_id, uint32_t server_type, bool status);
//报单初始状态通知
void OnOrderAck(XTPOrderInfo *order_info, uint64_t session_id);
///报单响应通知
void OnOrderEvent(XTPOrderInfo *order_info, XTPRI *error_info, uint64_t session_id);
///成交回报通知
void OnTradeEvent(XTPTradeReport *trade_info, uint64_t session_id);
///撤单失败通知
void OnCancelOrderError(XTPOrderCancelErrorInfo *cancel_info, XTPRI *error_info, uint64_t session_id);
///查询持仓回调响应
void OnQueryPosition(XTPQueryStkPositionRsp *position, XTPRI *error_info, int request_id, bool is_last, uint64_t session_id);
///查询资金回调响应
void OnQueryAsset(XTPQueryAssetRsp *trading_account, XTPRI *error_info, int request_id, bool is_last, uint64_t session_id);
//TODO:根据需要可继续重写其他回调函数
};(2)重写回调函数逻辑 根据需要重写对应的回调函数逻辑。
2.4. 创建Spi实例
示例代码如下:
cpp
//创建Spi实例
MyTraderSpi* m_pTraderSpi = new MyTraderSpi();2.5. 注册Spi
示例代码如下:
cpp
//注册Spi
m_pTraderApi->RegisterSpi(m_pTraderSpi);2.6. 登陆交易服务器
示例代码如下:
cpp
std::string trader_server_ip = "xxx.xxx.xxx.xxx";//交易服务器ip地址
int trader_server_port = xxx;//交易服务器端口port
std::string trader_username = "xxxxxxxx";//交易服务器的登陆账户名
std::string trader_password = "xxxxxx";//交易服务器的登陆密码
std::string local_ip = "192.168.2.111";//用户的本地ip,需要用户自行修改为网卡对应的ip
uint64_t session_id_ = 0;//用户登陆后对应的session_id
//登录交易服务器
session_id_ = m_pTraderApi->Login(trader_server_ip.c_str(), trader_server_port, trader_username.c_str(), trader_password.c_str(), XTP_PROTOCOL_TCP, local_ip.c_str());
if (0 == session_id_)
{
//登录失败,获取失败原因
XTPRI* error_info = m_pTraderApi->GetApiLastError();
std::cout << "Login to server error, " << error_info->error_id << " : " << error_info->error_msg << std::endl;
return 0;
}
// 登录成功
std::cout << "Login to server success." << std::endl;
//TODO: 用户逻辑,例如查询资金、持仓、报单等2.7. 查询用户资金
登陆成功后需要先查询用户资金,作为后续交易的依据。
(1) 调用查询资金接口 示例代码如下:
cpp
//查询用户资金
m_pTraderApi->QueryAsset(session_id_, 1);//request_id用户可自定义,此处以1为例,该接口不受查询服务是否可用影响(2) 重写查询资金回报接口逻辑 以输出查询结果为例,示例代码如下:
cpp
void MyTraderSpi::OnQueryAsset(XTPQueryAssetRsp *trading_account, XTPRI *error_info, int request_id, bool is_last, uint64_t session_id)
{
cout << "------------------- OnQueryTradingAccount-----------" << endl;
//TODO:处理查询资金逻辑,此处仅以屏幕输出为例
cout << "request_id:" << request_id << ",total_asset:" << trading_account->total_asset << ",security_asset:" << trading_account->security_asset;
cout << ",buying_power:" << trading_account->buying_power << ",fund_buy_amount:" << trading_account->fund_buy_amount;
cout << ",fund_buy_fee:" << trading_account->fund_buy_fee << ",fund_sell_amount:" << trading_account->fund_sell_amount << ",fund_sell_fee:" << trading_account->fund_sell_fee << endl;
}2.8. 查询用户持仓
登陆成功后需要查询用户持仓,作为后续交易的依据。 (1) 调用查询用户持仓接口 以查询所有持仓为例。
示例代码如下:
cpp
//查询沪深全市场主股卡持仓
m_pTraderApi->QueryAllPosition(NULL, session_id_, 2);//request_id用户可自定义,此处以2为例(2) 重写查询持仓回报接口逻辑 以输出查询结果为例,示例代码如下:
cpp
void MyTraderSpi::OnQueryPosition(XTPQueryStkPositionRsp * investor_position, XTPRI * error_info, int request_id, bool is_last, uint64_t session_id)
{
if (error_info && error_info->error_id !=0)
{
//查询出错
if (error_info->error_id == 11000350)
{
//账户里没有持仓
cout << "------------------- Position is empty.-----------" << endl;
}
else
{
//真正的出错
}
return;
}
//TODO:处理查询持仓回报逻辑,此处仅以屏幕输出为例
cout << "request_id:" << request_id << ",is_last:" << is_last << ",";
cout << "ticker:" << investor_position->ticker << ",ticker_name:" << investor_position->ticker_name;
cout << ",total_qty:" << investor_position->total_qty << ",sellable_qty:" << investor_position->sellable_qty << ",avg_price:" << investor_position->avg_price;
cout << ",unrealized_pnl:" << investor_position->unrealized_pnl << endl;
if (XTP_POSITION_SECURITY_PLACEMENT == investor_position->position_security_type)
{
//此时查询到的持仓为配股或者配债持仓,需要单独处理
}
if (is_last)
{
//TODO:为最后一条持仓回报,可以进行后续的处理逻辑
}
}2.9. 报单
在资金和持仓都查询成功后,可以根据需要进行报单。 示例代码如下:
cpp
//报单
//初始化报单结构体,以9.01的限价买入沪市"600000"1000股为例。
XTPOrderInsertInfo order;
memset(&order, 0, sizeof(XTPOrderInsertInfo));
order.market = XTP_MKT_SH_A;
std::string stdstr_ticker = "600000";
strncpy(order.ticker, stdstr_ticker.c_str(), XTP_TICKER_LEN);
order.business_type = XTP_BUSINESS_TYPE_CASH;
order.side = XTP_SIDE_BUY;
order.position_effect = XTP_POSITION_EFFECT_INIT;
order.price_type = XTP_PRICE_LIMIT;
order.price = 9.01;
order.quantity = 1000;
uint64_t ret = m_pTraderApi->InsertOrder(&order, session_id_);
if (ret == 0)
{
// 报单失败,获取失败原因
XTPRI* error_info = m_pTraderApi->GetApiLastError();
std::cout << "Insert order error, " << error_info->error_id << " : " << error_info->error_msg << std::endl;
}
else
{
// 报单成功返回的order_xtp_id,保证一个交易日内唯一
//TODO:其他逻辑,建议用户将报单在本地按照order_xtp_id保存,此时可以视报单状态为初始状态
}2.10. 订单初始状态响应
当用户成功报单后,会收到服务器推送的订单初始状态的响应消息,此时OnOrderAck()函数会被调用。该响应仅表明服务器收到了报单且没被OMS拒单。
用户可以重写订单响应里面的处理逻辑,下面以输出日志为例:
cpp
void MyTraderSpi::OnOrderAck(XTPOrderInfo *order_info, uint64_t session_id)
{
cout << "-------------------- OnOrderAck -------------------------" << endl;
//TODO:处理订单响应,此处仅以做屏幕输出为例,用户可以用自己的处理逻辑改写
cout << "xtp_id:" << order_info->order_xtp_id << ",client_id:" << order_info->order_client_id << ",status:" << order_info->order_status << ",cancel_xtp_id:" << order_info->order_cancel_xtp_id;
cout << ",order_submit_status:" << order_info->order_submit_status << ",ticker:" << order_info->ticker << ",market:" << order_info->market << ",price:" << order_info->price;
cout << ",quantity:" << order_info->quantity << ",price_type:" << order_info->price_type << ",side:" << (int)(order_info->side) << ",qty_traded:" << order_info->qty_traded << ",qty_left:" << order_info->qty_left;
cout << ",insert_time:" << order_info->insert_time << ",update_time:" << order_info->update_time << ",cancel_time:" << order_info->cancel_time << ",trade_amount:" << order_info->trade_amount;
cout << ",position_effect:" << (int)(order_info->position_effect) << ",business_type:" << order_info->business_type;
cout << ",order_local_id:" << order_info->order_local_id << ",order_type:" << order_info->order_type << endl;
}2.11. 处理订单响应
当用户成功报单后,会收到服务器推送的订单响应消息,此时OnOrderEvent()函数会被调用。
对于一笔订单来说,如果不发生拒单,OnOrderEvent()函数的第一条消息会是订单报送到交易所后的ack消息,第二条消息是订单完结状态的消息。
用户可以重写订单响应里面的处理逻辑,下面以输出日志为例:
cpp
void MyTraderSpi::OnOrderEvent(XTPOrderInfo *order_info, XTPRI *error_info, uint64_t session_id)
{
cout << "-------------------- OnOrderEvent -------------------------" << endl;
//TODO:处理订单响应,此处仅以做屏幕输出为例,用户可以用自己的处理逻辑改写
cout << "xtp_id:" << order_info->order_xtp_id << ",client_id:" << order_info->order_client_id << ",status:" << order_info->order_status << ",cancel_xtp_id:" << order_info->order_cancel_xtp_id;
cout << ",order_submit_status:" << order_info->order_submit_status << ",ticker:" << order_info->ticker << ",market:" << order_info->market << ",price:" << order_info->price;
cout << ",quantity:" << order_info->quantity << ",price_type:" << order_info->price_type << ",side:" << (int)(order_info->side) << ",qty_traded:" << order_info->qty_traded << ",qty_left:" << order_info->qty_left;
cout << ",insert_time:" << order_info->insert_time << ",update_time:" << order_info->update_time << ",cancel_time:" << order_info->cancel_time << ",trade_amount:" << order_info->trade_amount;
cout << ",position_effect:" << (int)(order_info->position_effect) << ",business_type:" << order_info->business_type;
cout << ",order_local_id:" << order_info->order_local_id << ",order_type:" << order_info->order_type << ",error_id:" << error_info->error_id << ",error_msg:" << error_info->error_msg << endl;
//TODO:根据报单响应情况来处理
switch (order_info->order_status)
{
case XTP_ORDER_STATUS_NOTRADEQUEUEING:
{
//订单确认状态,表示订单被交易所接受
break;
}
case XTP_ORDER_STATUS_ALLTRADED:
{
//订单全部成交状态,表示订单到达已完结状态
break;
}
case XTP_ORDER_STATUS_PARTTRADEDNOTQUEUEING:
{
//订单部分撤单状态,表示订单到达已完结状态
break;
}
case XTP_ORDER_STATUS_CANCELED:
{
//订单全部撤单状态,表示订单到达已完结状态
break;
}
case XTP_ORDER_STATUS_REJECTED:
{
//订单拒单状态,表示订单因有错误而被拒绝,此时可以关注拒单原因
if (error_info && (error_info->error_id > 0))
{
//TODO:说明有错误导致拒单,此处仅以屏幕输出错误信息为例,用户可以用自己的处理逻辑改写
cout << "error_id:" << error_info->error_id << ",error_msg:" << error_info->error_msg << endl;
}
break;
}
default:
break;
}
}2.12. 处理成交回报
当用户的报单发生成交的时候,会有对应的成交回报推送,此时OnTradeEvent函数会被调用。
用户可以重写成交回报里面的处理逻辑,下面以输出日志为例:
cpp
void MyTraderSpi::OnTradeEvent(XTPTradeReport *trade_info, uint64_t session_id)
{
cout << "-------------------- OnTradeEvent -------------------------" << endl;
//TODO:处理成交回报,此处仅以做屏幕输出为例,用户可以用自己的处理逻辑改写
cout << "xtp_id:" << trade_info->order_xtp_id << ",client_id:" << trade_info->order_client_id;
cout << ",ticker:" << trade_info->ticker << ",market:" << trade_info->market << ",price:" << trade_info->price;
cout << ",quantity:" << trade_info->quantity << ",side:" << (int)(trade_info->side) << ",trade_time:" << trade_info->trade_time << ",trade_amount:" << trade_info->trade_amount;
cout << ",position_effect:" << (int)(trade_info->position_effect) << ",business_type:" << trade_info->business_type;
cout << ",exec_id:" << trade_info->exec_id << ",report_index:" << trade_info->report_index << ",order_exch_id:" << trade_info->order_exch_id;
cout << ",trade_type:" << trade_info->trade_type << ",branch_pbu:" << trade_info->branch_pbu << endl;
//TODO:用户可以根据成交回报来更新本地的持仓
}2.13. 断线重连
重写回调函数,总体思路是调用重连成功后,重新更新session_id。示例代码如下:
cpp
void MyTraderSpi::OnDisconnected(uint64_t session_id, int reason)
{
//交易服务器断线后,此函数会被调用
//TODO:重新login,并在login成功后,更新session_id
cout << "Disconnect from Trader server. " << endl;
//断线后,重新连接
uint64_t temp_session_id_ = 0;
while (temp_session_id_ == 0)
{
temp_session_id_ = m_pTraderApi->Login(trader_server_ip.c_str(), trader_server_port, trader_username.c_str(), trader_password.c_str(), XTP_PROTOCOL_TCP, local_ip.c_str());
if (temp_session_id_ == 0)
{
// 登录失败,获取错误信息
XTPRI* error_info = m_pTraderApi->GetApiLastError();
std::cout << "login to server error, " << error_info->error_id << " : " << error_info->error_msg << std::endl;
//等待10s以后再次连接,可修改此等待时间,建议不要小于3s
#ifdef _WIN32
Sleep(10000);
#else
sleep(10);
#endif // _WIN32
}
} ;
//重新登录成功后更新session_id
cout << "login to server success. " << endl;
session_id_ = temp_session_id_;
}2.14. 服务状态改变时的通知
重写回调函数,当资金划拨服务或者查询服务不可用时,需等待服务恢复后才能使用。示例代码如下:
cpp
void MyTraderSpi::OnServerStatusNotification(uint64_t session_id, uint32_t server_type, bool status)
{
if (2 == server_type)//1表示资金划拨服务,2表示查询服务
{
query_server_status = status;//实时记录查询服务状态,用于判断是否可以做查询请求
}
}3. 交易时需注意的问题
- (1) 一个交易API实例支持不同的账户登陆,一个进程中仅允许创建交易API实例。
- (2) 订单响应OnOrderEvent里不会推送订单的部成状态,需要用户自己结合成交回报来判断订单的部成状态。
- (3) 在登陆的时候,仅支持Quick和Restart两种公共流消息传输模式,如果用户断线后,在不调用Logout()的情况下重连,将默认采用Resume模式连接。
- (4) InsertOrder()成功,如果没有被OMS拒单的话,会收到OnOrderAck()响应消息,表示订单的初始状态。
- (5) 订单号order_xtp_id的生成是在API本地生成,不涉及网络通讯。order_xtp_id将保证。
- (6) 交易API不支持过夜,请务必。
- (7) 交易服务器目前仅支持TCP连接。
- (8) 普通用户自行选择client_id时,仅支持之间的数值。
- (9) 交易服务器上有风控控制,请注意报单的频率和拒单数量。触发风控后,可能会被限制下单或强制断线。
- (10) 查询结果中,如果返回的错误信息中,此时不代表查询出错,仅仅代表没有找到满足查询条件的结果。
- (11) 资金划拨和查询资金划拨时,要注意资金划拨服务是否可用,用户登录成功默认服务是可用的,当遇到服务状态改变时,回调接口会被响应。其他查询操作同理,但有些查询操作不受查询服务是否可用影响,请关注查询接口上的注释说明。
- (12) 当OMS服务端未收到过从API端发送出去的某个订单,且未报送到交易所时,就会收到接口的响应回调,用户需关注下该接口回调过来的order_xtp_id。
4. 简单Demo示例代码
下面是一个简单的代码示例,演示了交易API通过TCP方式连接交易服务器并执行查询和报单的过程,包括:创建、初始化、登录交易、在登陆成功后查询资金、查询资金结果收到后查询持仓、收到查询持仓结果后进行报单、处理回报消息、断线重连。
main.cpp文件
cpp
#include "xtpx_trader_api.h"
#include <string>
#include <iostream>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif // _WIN32
#include "trade_spi.h"
XTPX::API::TraderApi* m_pTraderApi = NULL;//全局变量,程序共用一个api
std::string trader_server_ip = "xxx.xxx.xxx.xxx";//交易服务器ip地址,请自行修改
int trader_server_port = xxx;//交易服务器端口port,请自行修改
std::string trader_username = "xxxxxxxx";//交易服务器的登陆账户名,请自行修改
std::string trader_password = "xxxxxx";//交易服务器的登陆密码,请自行修改
std::string local_ip = "192.168.2.111";//用户的本地ip,需要用户自行修改为网卡对应的ip
uint64_t session_id_ = 0;//用户登陆后对应的session_id
bool query_server_status = true;//默认查询服务可用
int main()
{
int client_id = 1;//一个进程一个client id,可在[1, 24]区间内任选,并固定下来
std::string save_file_path = "./";//保存xtp api日志的路径,需要有可读写权限
XTP_LOG_LEVEL log_level = XTP_LOG_LEVEL_DEBUG;//xtp api日志的输出级别,建议调试时使用debug级别,正常运行时使用info以上级别
//初始化交易api
m_pTraderApi = XTPX::API::TraderApi::CreateTraderApi(client_id, save_file_path.c_str(), XTP_LOG_LEVEL_DEBUG);
if (NULL == m_pTraderApi)
{
//创建API失败
std::cout << "Failed to create trader api, please check the input parameters." << std::endl;
return 0;
}
///设定与交易服务器交互的超时时间,单位为秒,默认是15s,调试时可以设定大点
uint32_t heat_beat_interval = 15;
m_pTraderApi->SetHeartBeatInterval(heat_beat_interval);
//设定公共流传输方式
XTP_TE_RESUME_TYPE resume_type = XTP_TERT_QUICK;//第一次登陆所使用的公共流消息传送方式,用户可视自身需要在quick和restart中任选
m_pTraderApi->SubscribePublicTopic(resume_type);
//设定用户的开发代码,在XTP申请开户时,由xtp运营人员提供
char software_key[] = "xxxxxxxxxxxxx";
m_pTraderApi->SetSoftwareKey(software_key);
//设定软件版本号,用户自定义(仅可使用如下字符0-9,a-z,A-Z,.)
char version[] = "xxxxxxxxxxxxx";
m_pTraderApi->SetSoftwareVersion(version);
//创建Spi类实例
MyTraderSpi* m_pTraderSpi = new MyTraderSpi();
if (NULL == m_pTraderSpi)
{
std::cout << "Failed to create quote spi, please check the input parameters." << std::endl;
return 0;
}
//注册Spi
m_pTraderApi->RegisterSpi(m_pTraderSpi);
//登录交易服务器
session_id_ = m_pTraderApi->Login(trader_server_ip.c_str(), trader_server_port, trader_username.c_str(), trader_password.c_str(), XTP_PROTOCOL_TCP, local_ip.c_str());
if (0 == session_id_)
{
//登录失败,获取失败原因
XTPRI* error_info = m_pTraderApi->GetApiLastError();
std::cout << "Login to server error, " << error_info->error_id << " : " << error_info->error_msg << std::endl;
return 0;
}
// 登录成功
std::cout << "Login to server success." << std::endl;
//查询用户资金
int ret = m_pTraderApi->QueryAsset(session_id_, 1);//request_id用户可自定义,此处以1为例
if (ret != 0)
{
//查询资金请求发送失败,打印失败原因
XTPRI* error_info = m_pTraderApi->GetApiLastError();
std::cout << "Query asset send error, " << error_info->error_id << " : " << error_info->error_msg << std::endl;
}
//主线程循环,防止进程退出
while (true)
{
#ifdef _WIN32
Sleep(1000);
#else
sleep(1);
#endif // WIN32
}
return 0;
}MyTraderSpi类相关定义和实现文件。 trader_spi.h文件
cpp
#pragma once
#include "xtpx_trader_api.h"
#include <fstream>
using namespace XTPX::API;
class MyTraderSpi : public TraderSpi
{
public:
MyTraderSpi();
~MyTraderSpi();
///交易服务器断线通知
virtual void OnDisconnected(uint64_t session_id, int reason);
//当登录成功后,中途出现某个服务(资金划拨或者查询)服务状态改变时,该方法将被调用
virtual void OnServerStatusNotification(uint64_t session_id, uint32_t server_type, bool status);
//报单初始状态通知
virtual void OnOrderAck(XTPOrderInfo *order_info, uint64_t session_id);
///报单响应通知
virtual void OnOrderEvent(XTPOrderInfo *order_info, XTPRI *error_info, uint64_t session_id);
///成交回报通知
virtual void OnTradeEvent(XTPTradeReport *trade_info, uint64_t session_id);
///撤单失败通知
virtual void OnCancelOrderError(XTPOrderCancelErrorInfo *cancel_info, XTPRI *error_info, uint64_t session_id);
///查询持仓回调响应
virtual void OnQueryPosition(XTPQueryStkPositionRsp *investor_position, XTPRI *error_info, int request_id, bool is_last, uint64_t session_id);
///查询资金回调响应
virtual void OnQueryAsset(XTPQueryAssetRsp *trading_account, XTPRI *error_info, int request_id, bool is_last, uint64_t session_id);
//TODO:根据需要可继续重写其他回调函数
};trader_spi.cpp文件
cpp
#include "trade_spi.h"
#include <iostream>
#include <stdio.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include <windows.h>
#endif
using namespace std;
extern bool query_server_status;
extern XTPX::API::TraderApi* m_pTraderApi;//全局变量,程序共用的api
extern std::string trader_server_ip;//交易服务器ip地址
extern int trader_server_port;//交易服务器端口port
extern std::string trader_username;//交易服务器的登陆账户名
extern std::string trader_password;//交易服务器的登陆密码
extern std::string local_ip;//用户的本地ip,需要用户自行修改为网卡对应的ip
extern uint64_t session_id_;//用户登陆后对应的session_id
MyTraderSpi::MyTraderSpi()
{
}
MyTraderSpi::~MyTraderSpi()
{
}
void MyTraderSpi::OnDisconnected(uint64_t session_id, int reason)
{
//交易服务器断线后,此函数会被调用
//TODO:重新login,并在login成功后,更新session_id
cout << "Disconnect from Trader server. " << endl;
//断线后,重新连接
uint64_t temp_session_id_ = 0;
while (temp_session_id_ == 0)
{
temp_session_id_ = m_pTraderApi->Login(trader_server_ip.c_str(), trader_server_port, trader_username.c_str(), trader_password.c_str(), XTP_PROTOCOL_TCP, local_ip.c_str());
if (temp_session_id_ == 0)
{
// 登录失败,获取错误信息
XTPRI* error_info = m_pTraderApi->GetApiLastError();
std::cout << "login to server error, " << error_info->error_id << " : " << error_info->error_msg << std::endl;
//等待10s以后再次连接,可修改此等待时间,建议不要小于3s
#ifdef _WIN32
Sleep(10000);
#else
sleep(10);
#endif // _WIN32
}
} ;
//重新登录成功后更新session_id
cout << "login to server success. " << endl;
session_id_ = temp_session_id_;
}
void MyTraderSpi::OnServerStatusNotification(uint64_t session_id, uint32_t server_type, bool status)
{
if (2 == server_type)//1表示资金划拨服务,2表示查询服务
{
query_server_status = status;//实时记录查询服务状态,用于判断是否可以做查询请求
}
}
void MyTraderSpi::OnOrderAck(XTPOrderInfo *order_info, uint64_t session_id)
{
cout << "-------------------- OnOrderAck -------------------------" << endl;
//TODO:处理订单响应,此处仅以做屏幕输出为例,用户可以用自己的处理逻辑改写
cout << "xtp_id:" << order_info->order_xtp_id << ",client_id:" << order_info->order_client_id << ",status:" << order_info->order_status << ",cancel_xtp_id:" << order_info->order_cancel_xtp_id;
cout << ",order_submit_status:" << order_info->order_submit_status << ",ticker:" << order_info->ticker << ",market:" << order_info->market << ",price:" << order_info->price;
cout << ",quantity:" << order_info->quantity << ",price_type:" << order_info->price_type << ",side:" << (int)(order_info->side) << ",qty_traded:" << order_info->qty_traded << ",qty_left:" << order_info->qty_left;
cout << ",insert_time:" << order_info->insert_time << ",update_time:" << order_info->update_time << ",cancel_time:" << order_info->cancel_time << ",trade_amount:" << order_info->trade_amount;
cout << ",position_effect:" << (int)(order_info->position_effect) << ",business_type:" << order_info->business_type;
cout << ",order_local_id:" << order_info->order_local_id << ",order_type:" << order_info->order_type << endl;
}
void MyTraderSpi::OnOrderEvent(XTPOrderInfo *order_info, XTPRI *error_info, uint64_t session_id)
{
cout << "-------------------- OnOrderEvent -------------------------" << endl;
//TODO:处理订单响应,此处仅以做屏幕输出为例,用户可以用自己的处理逻辑改写
cout << "xtp_id:" << order_info->order_xtp_id << ",client_id:" << order_info->order_client_id << ",status:" << order_info->order_status << ",cancel_xtp_id:" << order_info->order_cancel_xtp_id;
cout << ",order_submit_status:" << order_info->order_submit_status << ",ticker:" << order_info->ticker << ",market:" << order_info->market << ",price:" << order_info->price;
cout << ",quantity:" << order_info->quantity << ",price_type:" << order_info->price_type << ",side:" << (int)(order_info->side) << ",qty_traded:" << order_info->qty_traded << ",qty_left:" << order_info->qty_left;
cout << ",insert_time:" << order_info->insert_time << ",update_time:" << order_info->update_time << ",cancel_time:" << order_info->cancel_time << ",trade_amount:" << order_info->trade_amount;
cout << ",position_effect:" << (int)(order_info->position_effect) << ",business_type:" << order_info->business_type;
cout << ",order_local_id:" << order_info->order_local_id << ",order_type:" << order_info->order_type << ",error_id:" << error_info->error_id << ",error_msg:" << error_info->error_msg << endl;
//TODO:根据报单响应情况来处理
switch (order_info->order_status)
{
case XTP_ORDER_STATUS_NOTRADEQUEUEING:
{
//订单确认状态,表示订单被交易所接受
break;
}
case XTP_ORDER_STATUS_ALLTRADED:
{
//订单全部成交状态,表示订单到达已完结状态
break;
}
case XTP_ORDER_STATUS_PARTTRADEDNOTQUEUEING:
{
//订单部分撤单状态,表示订单到达已完结状态
break;
}
case XTP_ORDER_STATUS_CANCELED:
{
//订单全部撤单状态,表示订单到达已完结状态
break;
}
case XTP_ORDER_STATUS_REJECTED:
{
//订单拒单状态,表示订单因有错误而被拒绝,此时可以关注拒单原因
if (error_info && (error_info->error_id > 0))
{
//TODO:说明有错误导致拒单,此处仅以屏幕输出错误信息为例,用户可以用自己的处理逻辑改写
cout << "error_id:" << error_info->error_id << ",error_msg:" << error_info->error_msg << endl;
}
break;
}
default:
break;
}
}
void MyTraderSpi::OnTradeEvent(XTPTradeReport *trade_info, uint64_t session_id)
{
cout << "-------------------- OnTradeEvent -------------------------" << endl;
//TODO:处理成交回报,此处仅以做屏幕输出为例,用户可以用自己的处理逻辑改写
cout << "xtp_id:" << trade_info->order_xtp_id << ",client_id:" << trade_info->order_client_id;
cout << ",ticker:" << trade_info->ticker << ",market:" << trade_info->market << ",price:" << trade_info->price;
cout << ",quantity:" << trade_info->quantity << ",side:" << (int)(trade_info->side) << ",trade_time:" << trade_info->trade_time << ",trade_amount:" << trade_info->trade_amount;
cout << ",position_effect:" << (int)(trade_info->position_effect) << ",business_type:" << trade_info->business_type;
cout << ",exec_id:" << trade_info->exec_id << ",report_index:" << trade_info->report_index << ",order_exch_id:" << trade_info->order_exch_id;
cout << ",trade_type:" << trade_info->trade_type << ",branch_pbu:" << trade_info->branch_pbu << endl;
//TODO:用户可以根据成交回报来更新本地的持仓
}
void MyTraderSpi::OnCancelOrderError(XTPOrderCancelErrorInfo *cancel_info, XTPRI *error_info, uint64_t session_id)
{
cout << "-----------------OnCancelOrderError---------------------" << endl;
cout << "cancel_order_xtp_id:" << cancel_info->order_xtp_id << ",order_xtp_id:" << cancel_info->orig_order_xtp_id << ",error_id:" << error_info->error_id << ",msg:" << error_info->error_msg << endl;
}
void MyTraderSpi::OnQueryPosition(XTPQueryStkPositionRsp * investor_position, XTPRI * error_info, int request_id, bool is_last, uint64_t session_id)
{
if (error_info && error_info->error_id !=0)
{
//查询出错
if (error_info->error_id == 11000350)
{
//账户里没有持仓
cout << "------------------- Position is empty.-----------" << endl;
}
else
{
//真正的出错
}
return;
}
//TODO:处理查询持仓回报逻辑,此处仅以屏幕输出为例
cout << "request_id:" << request_id << ",is_last:" << is_last << ",";
cout << "ticker:" << investor_position->ticker << ",ticker_name:" << investor_position->ticker_name;
cout << ",total_qty:" << investor_position->total_qty << ",sellable_qty:" << investor_position->sellable_qty << ",avg_price:" << investor_position->avg_price;
cout << ",unrealized_pnl:" << investor_position->unrealized_pnl << endl;
if (is_last)
{
//TODO:为最后一条持仓回报,可以进行后续的处理逻辑,此处以报单为例
//报单
//初始化报单结构体,以9.01的限价买入沪市"600000"1000股为例。
XTPOrderInsertInfo order;
memset(&order, 0, sizeof(XTPOrderInsertInfo));
order.market = XTP_MKT_SH_A;
std::string stdstr_ticker = "600000";
strncpy(order.ticker, stdstr_ticker.c_str(), XTP_TICKER_LEN);
order.business_type = XTP_BUSINESS_TYPE_CASH;
order.side = XTP_SIDE_BUY;
order.position_effect = XTP_POSITION_EFFECT_INIT;
order.price_type = XTP_PRICE_LIMIT;
order.price = 9.01;
order.quantity = 1000;
uint64_t ret = m_pTraderApi->InsertOrder(&order, session_id_);
if (ret == 0)
{
// 报单失败,获取失败原因
XTPRI* error_info = m_pTraderApi->GetApiLastError();
cout << "Insert order error, " << error_info->error_id << " : " << error_info->error_msg << endl;
}
else
{
// 报单成功会返回order_xtp_id,它保证一个交易日内唯一
//TODO:其他逻辑,建议用户将报单在本地按照order_xtp_id保存,此时可以视报单状态为初始状态
}
}
}
void MyTraderSpi::OnQueryAsset(XTPQueryAssetRsp * trading_account, XTPRI * error_info, int request_id, bool is_last, uint64_t session_id)
{
cout << "------------------- OnQueryTradingAccount-----------" << endl;
//TODO:处理查询资金逻辑,此处仅以屏幕输出并触发查询持仓为例
cout << "request_id:" << request_id << ",total_asset:" << trading_account->total_asset << ",security_asset:" << trading_account->security_asset;
cout << ",buying_power:" << trading_account->buying_power << ",fund_buy_amount:" << trading_account->fund_buy_amount;
cout << ",fund_buy_fee:" << trading_account->fund_buy_fee << ",fund_sell_amount:" << trading_account->fund_sell_amount << ",fund_sell_fee:" << trading_account->fund_sell_fee << endl;
//查询沪深全市场主股卡持仓
if(query_server_status)//查询服务可用
{
int ret = m_pTraderApi->QueryAllPosition(NULL, session_id_, 2);//request_id用户可自定义,此处以2为例
if (ret != 0)
{
//查询持仓请求发送失败,打印失败原因
XTPRI* error_info = m_pTraderApi->GetApiLastError();
cout << "Query position send error, " << error_info->error_id << " : " << error_info->error_msg << endl;
}
}
}