1.代码说明
本文章中的期货ctp代码来自分布式高频量化交易系统
联系作者,获取源码:高频量化交易系统的学习交流群 - 简书 (jianshu.com)
2.期货ctp介绍,
2.1 期货账户
要连接期货交易所交易,需要开设自己的账户,实现期货交易、银期转账、保证金等功能,由于小白一般不会用实盘资金交易,所以此处推荐用上期所提供的simnow虚拟交易平台申请一个虚拟账户。simnow地址:www.simnow.com.cn
2.2账户信息
1.BrokerID
简称期商编码,是指该期货公司在CTP系统上的编码,为四位数。例如海通期货是8000。
2.TradeFront, MarketFront
TradeFront是指CTP系统的交易前置IP地址,客户用来连接下单撤单等;MarketFront是指行情前置IP地址,用来订阅收取行情。
3.InvestorID(UserID,InvestUnitID)
投资者代码,是指该客户在CTP系统上的唯一ID,在期货公司开户后由期货公司分配得到。UserID是操作员代码,InvestUnitID是投资单元代码,普通投资者遇到要填这两个值的,直接填InvestorID即可。
4.Password
开户时设置的密码。需要注意的是开户完首次登录CTP系统需要修改密码,在期货公司官网上下载快期客户端登录,点修改密码就可以。
5.AppID
客户终端软件代码。
6.AuthCode
客户终端软件认证码。
2.3测试环境
simnow数据前置地址:
(1)交易时段的地址,如09:00-15:00和21:00-02:30,使用第一套地址,这些数据是真实的行情数据,只是时间上比真实的行情会有延迟30秒左右(SIMNOW从交易所接收后转发出来的)。
(2)非交易时段地址,这时的数据是历史行情的播放,比如昨天的数据之类的,可以用来做程序调试。
2.4 期货ctp的api文件
ThostFtdcTraderApi.h:C++头文件,包含交易相关的指令,如报单。
ThostFtdcMdApi.h:C++头文件,包含获取行情相关的指令。
ThostFtdcUserApiStruct.h:包含了所有用到的数据结构。
ThostFtdcUserApiDataType.h:包含了所有用到的数据类型。
CTP的所有接口都分为Spi和Api两种,分别对应C++中的类:XXXXSpi和XXXXApi。下面说的Api和Spi指的都是这两种东西。
我们主动对服务器发出的请求都是通过Api进行
而服务器的所有响应消息,都得用Spi,通过重写虚函数的形式接收
所有Api都有自己的创建(实例化)方法:XXXXApi::CreateXXXXApi,不应使用new
Spi没有自己的实例化方法,可以按自己喜欢的方式实例化。但是Spi必须注册到Api中才会有用。
Spi和Api一般是配套的
3.交易api
大家按照下面的流程登录期货ctp,查询数据,发送委托报单
3.1建立继承CThostFtdcTraderSpi的类TdAdapterCtp
class TdAdapterCtp : public CThostFtdcTraderSpi
{
public:
TdAdapterCtp();
virtual ~TdAdapterCtp();
public:
void Connect(CtpConfig &config);
void LogOut();
bool IsLogin() const;
public:
//查询资金
int ReqQueryBalance();
//查询委托
int ReqQueryOrder();
//查询成交
int ReqQueryTrade();
//查询持仓
int ReqQueryPosition();
//查询合约
int ReqQryInstrument();
///请求查询合约保证金率
int ReqQryInstrumentMarginRate(string szInstrumentId);
///请求查询合约手续费率
int ReqQryInstrumentCommissionRate(string szInstrumentId);
///请求查询报单手续费
int ReqQryInstrumentOrderCommRate(string szInstrumentId);
//请求查询经纪公司交易参数
int ReqQryBrokerTradingParams();
//请求查询结算信息确认
int ReqQrySettlementInfoConfirm();
///请求查询投资者结算结果
int ReqQrySettlementInfo();
///投资者结算结果确认
int ReqSettlementInfoConfirm();
//请求查询行情
int ReqQryDepthMarketData(string szInstrumentId = "", string szExchangeId = "");
//委托
TdResponse<string> ReqPlaceOrder(const string& szOrderRef, const string &szStockCode, const char &cAction, const double dPrice, const int iQuantity);
//撤单
TdResponse<string> ReqCancelOrder(int iFrontID, int iSessionID, const string& szOrderRef, const string& szInstrumentID);
private:
virtual void OnFrontConnected();
virtual void OnFrontDisConnected(int nReason);
///客户端认证响应
virtual void OnRspAuthenticate(CThostFtdcRspAuthenticateField *pRspAuthenticateField, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///用户口令更新请求响应
virtual void OnRspUserPasswordUpdate(CThostFtdcUserPasswordUpdateField *pUserPasswordUpdate, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
//登录响应
virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
//退出响应
virtual void OnRspUserLogout(CThostFtdcUserLogoutField *pUserLogout, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
//查询资金响应
virtual void OnRspQryTradingAccount(CThostFtdcTradingAccountField *pTradingAccount, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
//查询委托响应
virtual void OnRspQryOrder(CThostFtdcOrderField *pOrder, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
//查询成交响应
virtual void OnRspQryTrade(CThostFtdcTradeField *pTrade, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
//查询持仓响应
virtual void OnRspQryInvestorPosition(CThostFtdcInvestorPositionField *pInvestorPosition, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///请求查询合约响应
virtual void OnRspQryInstrument(CThostFtdcInstrumentField *pInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///请求查询合约保证金率响应
virtual void OnRspQryInstrumentMarginRate(CThostFtdcInstrumentMarginRateField *pInstrumentMarginRate, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///请求查询合约手续费率响应
virtual void OnRspQryInstrumentCommissionRate(CThostFtdcInstrumentCommissionRateField *pInstrumentCommissionRate, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///请求查询报单手续费响应
virtual void OnRspQryInstrumentOrderCommRate(CThostFtdcInstrumentOrderCommRateField *pInstrumentOrderCommRate, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///请求查询经纪公司交易参数响应
virtual void OnRspQryBrokerTradingParams(CThostFtdcBrokerTradingParamsField *pBrokerTradingParams, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///请求查询结算信息确认响应
virtual void OnRspQrySettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField *pSettlementInfoConfirm, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///请求查询投资者结算结果响应
virtual void OnRspQrySettlementInfo(CThostFtdcSettlementInfoField *pSettlementInfo, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///投资者结算结果确认响应
virtual void OnRspSettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField *pSettlementInfoConfirm, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///请求查询行情响应
virtual void OnRspQryDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
private:
//委托回报
virtual void OnRtnOrder(CThostFtdcOrderField *pOrder);
//成交回报
virtual void OnRtnTrade(CThostFtdcTradeField *pTrade);
///报单录入请求响应
virtual void OnRspOrderInsert(CThostFtdcInputOrderField *pInputOrder, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///报单操作请求响应
virtual void OnRspOrderAction(CThostFtdcInputOrderActionField *pInputOrderAction, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///错误应答
virtual void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
///报单录入错误回报
virtual void OnErrRtnOrderInsert(CThostFtdcInputOrderField *pInputOrder, CThostFtdcRspInfoField *pRspInfo);
///报单操作错误回报
virtual void OnErrRtnOrderAction(CThostFtdcOrderActionField *pOrderAction, CThostFtdcRspInfoField *pRspInfo);
private:
BalanceT ConvertBalance(const CThostFtdcTradingAccountField *pAccount);
OrderT ConvertOrder(const CThostFtdcOrderField *pOrder);
TradeT ConvertTrade(const CThostFtdcTradeField *pTrade);
PositionT ConvertPosition(const CThostFtdcInvestorPositionField *pPos);
int GetRequestId();
private:
CThostFtdcTraderApi *m_pTraderApi;
CtpConfig m_Config;
int m_iRequestId;
bool m_IsLogin;
mutex m_RequestIdMtx; //锁 m_iRequestId
};
3.2登录
3.2.1?? ?连接到期货CTP
读取配置文件中的期货ctp的ip和端口,存储到CtpConfig中 调用Connect函数连接期货ctp
void TdAdapterCtp::Connect(CtpConfig &config)
{
m_Config = config;
m_pTraderApi = CThostFtdcTraderApi::CreateFtdcTraderApi();
if (!m_pTraderApi)
{
LError("ctp create traderapi failed");
return;
}
m_pTraderApi->RegisterSpi(this);
string szTmpFrontAddr = "tcp://" + m_Config.szTradeIp + ':' + to_string(m_Config.iTradePort);
printf("Trade FrontAddress=%s\n", szTmpFrontAddr.c_str());
char szFrontAddr[100] = { 0 };
sprintf(szFrontAddr, "%s", szTmpFrontAddr.c_str());
m_pTraderApi->SubscribePublicTopic(THOST_TERT_QUICK);
m_pTraderApi->SubscribePrivateTopic(THOST_TERT_QUICK);
m_pTraderApi->RegisterFront(szFrontAddr);
m_pTraderApi->Init(); //调用Init,开始连接
}
3.2.2?? ?连接响应函数
如果连接成功,则调用客户端认证函数ReqAuthenticate
void TdAdapterCtp::OnFrontConnected()
{
printf("ctp OnFrontConnected\n");
LInfo("ctp OnFrontConnected");
CThostFtdcReqAuthenticateField ReqAuthenticateField;
memset(ReqAuthenticateField.BrokerID, 0, sizeof(ReqAuthenticateField.BrokerID));
memset(ReqAuthenticateField.UserID, 0, sizeof(ReqAuthenticateField.UserID));
memset(ReqAuthenticateField.AuthCode, 0, sizeof(ReqAuthenticateField.AuthCode));
memset(ReqAuthenticateField.AppID, 0, sizeof(ReqAuthenticateField.AppID));
sprintf(ReqAuthenticateField.BrokerID, "%s", m_Config.szBrokerId.c_str());
sprintf(ReqAuthenticateField.UserID, "%s", m_Config.szUserId.c_str());
sprintf(ReqAuthenticateField.AuthCode, "%s", m_Config.szAuthCode.c_str());
sprintf(ReqAuthenticateField.AppID, "%s", m_Config.szAppID.c_str());
int iRet = m_pTraderApi->ReqAuthenticate(&ReqAuthenticateField, GetRequestId());
if (iRet != 0)
{
LError("send ctp ReqAuthenticate Error ,iRet=[{0}]", iRet);
}
}
3.2.3?? ?客户端认证响应
客户端认证响应函数中调用ReqUserLogin登录函数。?
void TdAdapterCtp::OnRspAuthenticate(CThostFtdcRspAuthenticateField *pRspAuthenticateField, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
if (!pRspInfo || pRspInfo->ErrorID == 0)
{
printf("ctp OnRspAuthenticate OK\n");
LInfo("ctp OnRspAuthenticate OK");
CThostFtdcReqUserLoginField ReqUserLoginField;
memset(ReqUserLoginField.BrokerID, 0, sizeof(ReqUserLoginField.BrokerID));
memset(ReqUserLoginField.UserID, 0, sizeof(ReqUserLoginField.UserID));
memset(ReqUserLoginField.Password, 0, sizeof(ReqUserLoginField.Password));
sprintf(ReqUserLoginField.BrokerID, "%s", m_Config.szBrokerId.c_str());
sprintf(ReqUserLoginField.UserID, "%s", m_Config.szUserId.c_str());
sprintf(ReqUserLoginField.Password, "%s", m_Config.szPassword.c_str());
int iRet = m_pTraderApi->ReqUserLogin(&ReqUserLoginField, GetRequestId());
if (iRet != 0)
{
LError("ctp send ReqUserLogin fail ,iRet=[{0}]", iRet);
}
}
else
{
printf("ctp OnRspAuthenticate error, ErrorMsg=[%s]\n", pRspInfo->ErrorMsg);
LError("ctp OnRspAuthenticate ErrorID=[{0},ErrorMsg=[{1}]]", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
}
}
3.2.4?? ?登录响应函数
如果需要修改密码,可以看注释部分的代码
void TdAdapterCtp::OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
if (0 == pRspInfo->ErrorID)
{
printf("ctp TdAdapterCtp OnRspUserLogin success\n");
LInfo("ctp TdAdapterCtp OnRspUserLogin success");
m_IsLogin = true;
}
else
{
printf("ctp TdAdapterCtp OnRspUserLogin Error,error_msg=[%s]\n", pRspInfo->ErrorMsg);
LError("ctp TdAdapterCtp OnRspUserLogin Error, error_code=[{0}],error_msg=[{1}]", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
//首次登录需要修改登录密码
/*
CThostFtdcUserPasswordUpdateField UserPasswordUpdate;
memset(&UserPasswordUpdate, 0, sizeof(UserPasswordUpdate));
sprintf(UserPasswordUpdate.BrokerID, "%s", m_Config.szBrokerId.c_str());
sprintf(UserPasswordUpdate.UserID, "%s", m_Config.szUser.c_str());
sprintf(UserPasswordUpdate.OldPassword, "%s", m_Config.szPassword.c_str());
sprintf(UserPasswordUpdate.NewPassword, "%s", "simnow!!123456");
int iRet = m_pTraderApi->ReqUserPasswordUpdate(&UserPasswordUpdate, GetRequestId());
if (iRet != 0)
{
LError("ctp send ReqUserPasswordUpdate fail ,iRet=[{0}]", iRet);
}
*/
}
}
3.3?? ?查询
3.3.1?? ?查询资金请求?
int TdAdapterCtp::ReqQueryBalance()
{
LInfo("ctp ReqQueryBalance");
CThostFtdcQryTradingAccountField ReqParam;
memset(&ReqParam, 0, sizeof(ReqParam));
strcpy(ReqParam.BrokerID, m_Config.szBrokerId.c_str());
strcpy(ReqParam.InvestorID, m_Config.szUserId.c_str());
int iRequestId = GetRequestId();
int iRet = m_pTraderApi->ReqQryTradingAccount(&ReqParam, iRequestId);
if (iRet != 0)
{
LError("send ctp ReqQryTradingAccount Error,iRet=[{0}]", iRet);
return RET_SEND_JYS_FAIL;
}
return iRequestId;
}
3.3.2?? ?查询资金响应?
void TdAdapterCtp::OnRspQryTradingAccount(CThostFtdcTradingAccountField *pTradingAccount, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
if (!pRspInfo || 0 == pRspInfo->ErrorID)
{
LInfo("---- ctp OnRspQryTradingAccount success ----");
if (NULL == pTradingAccount)
{
LDebug("没有数据");
return;
}
LDebug("Available=[{0}]", pTradingAccount->Available);
LDebug("Balance=[{0}]", pTradingAccount->Balance);
LDebug("PreBalance=[{0}]", pTradingAccount->PreBalance);
LDebug("CurrMargin=[{0}]", pTradingAccount->CurrMargin);
LDebug("PreMargin=[{0}]", pTradingAccount->PreMargin);
LDebug("FrozenMargin=[{0}]", pTradingAccount->FrozenMargin);
LDebug("FrozenCash=[{0}]", pTradingAccount->FrozenCash);
LDebug("CloseProfit=[{0}]", pTradingAccount->CloseProfit);
LDebug("PositionProfit=[{0}]", pTradingAccount->PositionProfit);
BalanceT BalanceData = ConvertBalance(pTradingAccount);
TdResponse<BalanceT> TdResponseData;
TdResponseData.RspResult = BalanceData;
TdResponseData.iErrCode = 0;
TdResponseData.szMsg = "";
TdResponseData.iRequestId = nRequestID;
ExecuteEngine::GetInstance()->HandleQueryBalanceRsp(TdResponseData);
}
else
{
LError("ctp OnRspQryTradingAccount Error ,error_code=[{0}],error_msg=[{1}]", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
}
}
?3.3.3?? ?查询委托请求
int TdAdapterCtp::ReqQueryOrder()
{
LInfo("ctp ReqQueryOrder");
CThostFtdcQryOrderField ReqParam;
memset(&ReqParam, 0, sizeof(ReqParam));
strcpy(ReqParam.BrokerID, m_Config.szBrokerId.c_str());
strcpy(ReqParam.InvestorID, m_Config.szUserId.c_str());
// query all orders
int iRequestId = GetRequestId();
int iRet = m_pTraderApi->ReqQryOrder(&ReqParam, iRequestId);
if (iRet != 0)
{
LError("send ctp ReqQryOrder Error,iRet=[{0}]", iRet);
return RET_SEND_JYS_FAIL;
}
return iRequestId;
}
3.3.4?? ?查询委托响应?
void TdAdapterCtp::OnRspQryOrder(CThostFtdcOrderField *pOrder, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
if (!pRspInfo || 0 == pRspInfo->ErrorID)
{
LInfo("---- ctp OnRspQryOrder success ----");
if (NULL == pOrder)
{
LDebug("没有数据");
return;
}
LDebug("pOrder=[{0}]", pOrder->ExchangeID);
LDebug("InstrumentID=[{0}]", pOrder->InstrumentID);
LDebug("OrderRef=[{0}]", pOrder->OrderRef);
LDebug("Direction=[{0}]", pOrder->Direction);
LDebug("LimitPrice=[{0}]", pOrder->LimitPrice);
LDebug("VolumeTotalOriginal=[{0}]", pOrder->VolumeTotalOriginal);
LDebug("ForceCloseReason=[{0}]", pOrder->ForceCloseReason);
LDebug("OrderLocalID=[{0}]", pOrder->OrderLocalID);
LDebug("TradingDay=[{0}]", pOrder->TradingDay);
LDebug("OrderSysID=[{0}]", pOrder->OrderSysID);
LDebug("OrderSource=[{0}]", pOrder->OrderSource);
LDebug("OrderStatus=[{0}]", pOrder->OrderStatus);
LDebug("VolumeTraded=[{0}]", pOrder->VolumeTraded);
LDebug("VolumeTotal=[{0}]", pOrder->VolumeTotal);
LDebug("InsertDate=[{0}]", pOrder->InsertDate);
LDebug("InsertTime=[{0}]", pOrder->InsertTime);
OrderT OrderData = ConvertOrder(pOrder);
TdResponse<OrderT> TdResponseData;
TdResponseData.RspResult = OrderData;
TdResponseData.iErrCode = 0;
TdResponseData.szMsg = "";
TdResponseData.bIsLast = bIsLast;
TdResponseData.iRequestId = nRequestID;
ExecuteEngine::GetInstance()->HandleQueryOrderRsp(TdResponseData);
}
else
{
LError("ctp OnRspQryOrder Error,error_code=[{0}],error_msg=[{1}]", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
}
}
3.3.5?? ?查询成交请求?
int TdAdapterCtp::ReqQueryTrade()
{
LInfo("ctp ReqQueryTrade");
CThostFtdcQryTradeField ReqParam;
memset(&ReqParam, 0, sizeof(ReqParam));
strcpy(ReqParam.BrokerID, m_Config.szBrokerId.c_str());
strcpy(ReqParam.InvestorID, m_Config.szUserId.c_str());
// query all trades
int iRequestId = GetRequestId();
int iRet = m_pTraderApi->ReqQryTrade(&ReqParam, iRequestId);
if (iRet != 0)
{
LError("send ctp ReqQryTrade Error,iRet=[{0}]", iRet);
return RET_SEND_JYS_FAIL;
}
return iRequestId;
}
3.3.6?? ?查询成交响应?
void TdAdapterCtp::OnRspQryTrade(CThostFtdcTradeField *pTrade, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
if (!pRspInfo || 0 == pRspInfo->ErrorID)
{
LInfo("---- ctp OnRspQryTrade success ----");
if (NULL == pTrade)
{
LDebug("没有数据");
return;
}
LDebug("ExchangeID=[{0}]", pTrade->ExchangeID);
LDebug("InstrumentID=[{0}]", pTrade->InstrumentID);
LDebug("OrderRef=[{0}]", pTrade->OrderRef);
LDebug("TradeID=[{0}]", pTrade->TradeID);
LDebug("Direction=[{0}]", pTrade->Direction);
LDebug("OrderSysID=[{0}]", pTrade->OrderSysID);
LDebug("OffsetFlag=[{0}]", pTrade->OffsetFlag);
LDebug("Price=[{0}]", pTrade->Price);
LDebug("Volume=[{0}]", pTrade->Volume);
LDebug("TradeDate=[{0}]", pTrade->TradeDate);
LDebug("TradeTime=[{0}]", pTrade->TradeTime);
LDebug("OrderLocalID=[{0}]", pTrade->OrderLocalID);
TradeT TradeData = ConvertTrade(pTrade);
TdResponse<TradeT> TdResponseData;
TdResponseData.RspResult = TradeData;
TdResponseData.iErrCode = 0;
TdResponseData.szMsg = "";
TdResponseData.bIsLast = bIsLast;
TdResponseData.iRequestId = nRequestID;
ExecuteEngine::GetInstance()->HandleQueryTradeRsp(TdResponseData);
}
else
{
LError("ctp OnRspQryTrade Error ,error_code=[{0}],error_msg=[{1}]", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
}
}
3.3.7?? ?查询持仓请求?
int TdAdapterCtp::ReqQueryPosition()
{
LInfo("ctp ReqQueryPosition");
CThostFtdcQryInvestorPositionField ReqParam;
memset(&ReqParam, 0, sizeof(ReqParam));
strcpy(ReqParam.BrokerID, m_Config.szBrokerId.c_str());
strcpy(ReqParam.InvestorID, m_Config.szUserId.c_str());
// query all positions
int iRequestId = GetRequestId();
int iRet = m_pTraderApi->ReqQryInvestorPosition(&ReqParam, iRequestId);
if (iRet != 0)
{
LError("send ctp ReqQryInvestorPosition Error,iRet=[{0}]", iRet);
return RET_SEND_JYS_FAIL;
}
return iRequestId;
}
?3.3.8?? ?查询持仓响应
void TdAdapterCtp::OnRspQryInvestorPosition(CThostFtdcInvestorPositionField *pInvestorPosition, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
if (!pRspInfo || 0 == pRspInfo->ErrorID)
{
LInfo("---- ctp OnRspQryInvestorPosition success ----");
if (NULL == pInvestorPosition)
{
LDebug("没有数据");
return;
}
LDebug("ExchangeID=[{0}]", pInvestorPosition->ExchangeID);
LDebug("InstrumentID=[{0}]", pInvestorPosition->InstrumentID);
LDebug("PosiDirection=[{0}]", pInvestorPosition->PosiDirection);
LDebug("HedgeFlag=[{0}]", pInvestorPosition->HedgeFlag);
LDebug("PositionDate=[{0}]", pInvestorPosition->PositionDate);
LDebug("YdPosition=[{0}]", pInvestorPosition->YdPosition);
LDebug("Position=[{0}]", pInvestorPosition->Position);
LDebug("LongFrozen=[{0}]", pInvestorPosition->LongFrozen);
LDebug("ShortFrozen=[{0}]", pInvestorPosition->ShortFrozen);
LDebug("LongFrozenAmount=[{0}]", pInvestorPosition->LongFrozenAmount);
LDebug("ShortFrozenAmount=[{0}]", pInvestorPosition->ShortFrozenAmount);
LDebug("OpenVolume=[{0}]", pInvestorPosition->OpenVolume);
LDebug("CloseVolume=[{0}]", pInvestorPosition->CloseVolume);
LDebug("OpenAmount=[{0}]", pInvestorPosition->OpenAmount);
LDebug("CloseAmount=[{0}]", pInvestorPosition->CloseAmount);
LDebug("PositionCost=[{0}]", pInvestorPosition->PositionCost);
LDebug("PreMargin=[{0}]", pInvestorPosition->PreMargin);
LDebug("UseMargin=[{0}]", pInvestorPosition->UseMargin);
LDebug("FrozenMargin=[{0}]", pInvestorPosition->FrozenMargin);
LDebug("FrozenCash=[{0}]", pInvestorPosition->FrozenCash);
LDebug("FrozenCommission=[{0}]", pInvestorPosition->FrozenCommission);
LDebug("Commission=[{0}]", pInvestorPosition->Commission);
LDebug("CashIn=[{0}]", pInvestorPosition->CashIn);
LDebug("CloseProfit=[{0}]", pInvestorPosition->CloseProfit);
LDebug("PositionProfit=[{0}]", pInvestorPosition->PositionProfit);
LDebug("PreSettlementPrice=[{0}]", pInvestorPosition->PreSettlementPrice);
LDebug("SettlementPrice=[{0}]", pInvestorPosition->SettlementPrice);
LDebug("TradingDay=[{0}]", pInvestorPosition->TradingDay);
LDebug("SettlementID=[{0}]", pInvestorPosition->SettlementID);
LDebug("OpenCost=[{0}]", pInvestorPosition->OpenCost);
LDebug("ExchangeMargin=[{0}]", pInvestorPosition->ExchangeMargin);
LDebug("CloseProfitByDate=[{0}]", pInvestorPosition->CloseProfitByDate);
LDebug("CloseProfitByTrade=[{0}]", pInvestorPosition->CloseProfitByTrade);
LDebug("TodayPosition=[{0}]", pInvestorPosition->TodayPosition);
LDebug("MarginRateByMoney=[{0}]", pInvestorPosition->MarginRateByMoney);
LDebug("MarginRateByVolume=[{0}]", pInvestorPosition->MarginRateByVolume);
LDebug("StrikeFrozenAmount=[{0}]", pInvestorPosition->StrikeFrozenAmount);
LDebug("AbandonFrozen=[{0}]", pInvestorPosition->AbandonFrozen);
LDebug("YdStrikeFrozen=[{0}]", pInvestorPosition->YdStrikeFrozen);
LDebug("InvestUnitID=[{0}]", pInvestorPosition->InvestUnitID);
PositionT PositionData = ConvertPosition(pInvestorPosition);
TdResponse<PositionT> TdResponseData;
TdResponseData.RspResult = PositionData;
TdResponseData.iErrCode = 0;
TdResponseData.szMsg = "";
TdResponseData.bIsLast = bIsLast;
TdResponseData.iRequestId = nRequestID;
ExecuteEngine::GetInstance()->HandleQueryPositionRsp(TdResponseData);
}
else
{
LError("ctp OnRspQryInvestorPosition Error,error_code=[{0}],error_msg=[{1}]", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
}
}
3.3.9?? ?查询合约请求?
int TdAdapterCtp::ReqQryInstrument()
{
LInfo("ctp ReqQryInstrument");
CThostFtdcQryInstrumentField Req;
memset(&Req, 0, sizeof(Req));
int iRequestId = GetRequestId();
int iRet = m_pTraderApi->ReqQryInstrument(&Req, iRequestId);
if (iRet != 0)
{
LError("send ctp ReqQryTrade Error,iRet=[{0}]", iRet);
return RET_SEND_JYS_FAIL;
}
return iRequestId;
}
3.3.10?? ?查询合约响应?
void TdAdapterCtp::OnRspQryInstrument(CThostFtdcInstrumentField *pInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
if (!pRspInfo || 0 == pRspInfo->ErrorID)
{
LInfo("---- ctp OnRspQryInstrument success ----");
if (NULL == pInstrument)
{
LDebug("没有数据");
return;
}
/*
LDebug("InstrumentID=[{0}]", pInstrument->InstrumentID);
LDebug("ExchangeID=[{0}]", pInstrument->ExchangeID);
LDebug("InstrumentName=[{0}]", pInstrument->InstrumentName);
LDebug("ExchangeInstID=[{0}]", pInstrument->ExchangeInstID);
LDebug("ProductID=[{0}]", pInstrument->ProductID);
LDebug("ProductClass=[{0}]", pInstrument->ProductClass);
LDebug("DeliveryYear=[{0}]", pInstrument->DeliveryYear);
LDebug("DeliveryMonth=[{0}]", pInstrument->DeliveryMonth);
LDebug("IsTrading=[{0}]", pInstrument->IsTrading);
LDebug("PriceTick=[{0}]", pInstrument->PriceTick);
LDebug("StrikePrice=[{0}]", pInstrument->StrikePrice);
*/
InstrumentT InstrumentData;
InstrumentData.szExchangeId = pInstrument->ExchangeID;
InstrumentData.szInstrumentId = pInstrument->InstrumentID;
InstrumentData.szInstrumentName = pInstrument->InstrumentName;
InstrumentData.szProductId = pInstrument->ProductID;
InstrumentData.szProductClass = pInstrument->ProductClass;
InstrumentData.iDeliveryYear = pInstrument->DeliveryYear;
InstrumentData.iDeliveryMonth = pInstrument->DeliveryMonth;
InstrumentData.iMaxMarketOrderVolume = pInstrument->MaxMarketOrderVolume;
InstrumentData.iMinMarketOrderVolume = pInstrument->MinMarketOrderVolume;
InstrumentData.iMaxLimitOrderVolume = pInstrument->MaxLimitOrderVolume;
InstrumentData.iMinLimitOrderVolume = pInstrument->MinLimitOrderVolume;
InstrumentData.iVolumeMultiple = pInstrument->VolumeMultiple;
InstrumentData.dPriceTick = pInstrument->PriceTick;
InstrumentData.szExpireDate = pInstrument->ExpireDate;
InstrumentData.iIsTrading = pInstrument->IsTrading;
InstrumentData.szPositionType = pInstrument->PositionType;
InstrumentData.szPositionDateType = pInstrument->PositionDateType;
InstrumentData.dLongMarginRatio = pInstrument->LongMarginRatio;
InstrumentData.dShortMarginRatio = pInstrument->ShortMarginRatio;
InstrumentData.szMaxMarginSideAlgorithm = pInstrument->MaxMarginSideAlgorithm;
InstrumentData.dStrikePrice = pInstrument->StrikePrice;
InstrumentData.cOptionsType = pInstrument->OptionsType;
InstrumentData.dUnderlyingMultiple = pInstrument->UnderlyingMultiple;
TdResponse<InstrumentT> TdResponseData;
TdResponseData.RspResult = InstrumentData;
TdResponseData.iErrCode = 0;
TdResponseData.szMsg = "";
TdResponseData.bIsLast = bIsLast;
TdResponseData.iRequestId = nRequestID;
ExecuteEngine::GetInstance()->HandleQueryInstrumentRsp(TdResponseData);
}
else
{
LError("ctp OnRspQryInstrument Error,error_code=[{0}],error_msg=[{1}]", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
}
}
3.4?? ?委托报单和撤单
3.4.1?? ?委托报单请求?
TdResponse<string> TdAdapterCtp::ReqPlaceOrder(const string& szOrderRef, const string &szStockCode, const char &cAction, const double dPrice, const int iQuantity)
{
LInfo("ctp ReqPlaceOrder szOrderRef=[{0}],szStockCode=[{1}],cAction=[{2}],dPrice=[{3}],iQuantity=[{4}]", szOrderRef, szStockCode, cAction, dPrice, iQuantity);
CThostFtdcInputOrderField ReqParam;
memset(&ReqParam, 0, sizeof(ReqParam));
strcpy(ReqParam.BrokerID, m_Config.szBrokerId.c_str());
strcpy(ReqParam.InvestorID, m_Config.szUserId.c_str());
snprintf(ReqParam.OrderRef, sizeof(ReqParam.OrderRef), "%s", szOrderRef.c_str());
snprintf(ReqParam.InstrumentID, sizeof(ReqParam.InstrumentID), "%s", szStockCode.c_str());
ReqParam.LimitPrice = dPrice; // always use limit
ReqParam.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
ReqParam.TimeCondition = THOST_FTDC_TC_GFD;
if (cAction == ORDER_ACTION_BUY_OPEN)
{
ReqParam.Direction = THOST_FTDC_D_Buy;
ReqParam.CombOffsetFlag[0] = THOST_FTDC_OF_Open;
}
else if (cAction == ORDER_ACTION_SELL_OPEN)
{
ReqParam.Direction = THOST_FTDC_D_Sell;
ReqParam.CombOffsetFlag[0] = THOST_FTDC_OF_Open;
}
else if (cAction == ORDER_ACTION_BUY_CLOSE)
{
ReqParam.Direction = THOST_FTDC_D_Buy;
ReqParam.CombOffsetFlag[0] = THOST_FTDC_OF_Close;
}
else if (cAction == ORDER_ACTION_SELL_CLOSE)
{
ReqParam.Direction = THOST_FTDC_D_Sell;
ReqParam.CombOffsetFlag[0] = THOST_FTDC_OF_Close;
}
else
{
LError("unkown action to ctp");
}
// quantity
ReqParam.VolumeTotalOriginal = iQuantity;
// other options
ReqParam.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;
ReqParam.VolumeCondition = THOST_FTDC_VC_AV;
ReqParam.MinVolume = 1;
ReqParam.ContingentCondition = THOST_FTDC_CC_Immediately;
ReqParam.ForceCloseReason = THOST_FTDC_FCC_NotForceClose;
ReqParam.IsAutoSuspend = 0;
ReqParam.UserForceClose = 0;
int iRequestId = GetRequestId();
int iRet = m_pTraderApi->ReqOrderInsert(&ReqParam, iRequestId);
if (0 == iRet)
{
LInfo(" send ctp ReqPlaceOrder success");
TdResponse<string> TdResponseData;
TdResponseData.RspResult = szOrderRef;
TdResponseData.iErrCode = 0;
TdResponseData.szMsg = "OK";
TdResponseData.iRequestId = iRequestId;
return TdResponseData;
}
else
{
LError("send ctp ReqPlaceOrder Error,iRet=[{0}]", iRet);
TdResponse<string> TdResponseData;
TdResponseData.RspResult = szOrderRef;
TdResponseData.iErrCode = RET_SEND_JYS_FAIL;
TdResponseData.szMsg = "send ctp ReqOrderInsert Error";
TdResponseData.iRequestId = iRequestId;
return TdResponseData;
}
}
3.4.2?? ?撤单请求
TdResponse<string> TdAdapterCtp::ReqCancelOrder(int iFrontID, int iSessionID, const string& szOrderRef, const string& szInstrumentID)
{
LInfo("ctp ReqCancelOrder,iFrontID=[{0}],iSessionID=[{1}],szOrderRef=[{2}],szInstrumentID=[{3}]", iFrontID, iSessionID, szOrderRef, szInstrumentID);
CThostFtdcInputOrderActionField ReqParam;
memset(&ReqParam, 0, sizeof(ReqParam));
strcpy(ReqParam.BrokerID, m_Config.szBrokerId.c_str());
strcpy(ReqParam.InvestorID, m_Config.szUserId.c_str());
ReqParam.FrontID = iFrontID;
ReqParam.SessionID = iSessionID;
strcpy(ReqParam.OrderRef, szOrderRef.c_str());
strcpy(ReqParam.InstrumentID, szInstrumentID.c_str());
ReqParam.ActionFlag = THOST_FTDC_AF_Delete;
int iRequestId = GetRequestId();
int iRet = m_pTraderApi->ReqOrderAction(&ReqParam, iRequestId);
if (0 == iRet)
{
LInfo("send ctp ReqCancelOrder success");
TdResponse<string> TdResponseData;
TdResponseData.RspResult = szOrderRef;
TdResponseData.iErrCode = 0;
TdResponseData.szMsg = "Ok";
TdResponseData.iRequestId = iRequestId;
return TdResponseData;
}
else
{
LError("send ctp ReqCancelOrder Error,iRet=[{0}]", iRet);
TdResponse<string> TdResponseData;
TdResponseData.RspResult = szOrderRef;
TdResponseData.iErrCode = RET_SEND_JYS_FAIL;
TdResponseData.szMsg = "send ctp ReqOrderAction Error";
TdResponseData.iRequestId = iRequestId;
return TdResponseData;
}
}
3.4.3?? ?委托回报?
在委托报单后,会收到委托回报
void TdAdapterCtp::OnRtnOrder(CThostFtdcOrderField *pOrder)
{
LDebug("--------ctp OnRtnOrder-------------");
LDebug("pOrder->BrokerID=[{0}]", pOrder->BrokerID);
LDebug("pOrder->InvestorID=[{0}]", pOrder->InvestorID);
LDebug("pOrder->InstrumentID=[{0}]", pOrder->InstrumentID);
LDebug("pOrder->UserID=[{0}]", pOrder->UserID);
LDebug("pOrder->Direction=[{0}]", pOrder->Direction);
LDebug("pOrder->LimitPrice=[{0}]", pOrder->LimitPrice);
LDebug("pOrder->VolumeTotalOriginal=[{0}]", pOrder->VolumeTotalOriginal);
LDebug("pOrder->ClientID=[{0}]", pOrder->ClientID);
LDebug("pOrder->ExchangeID=[{0}]", pOrder->ExchangeID);
LDebug("pOrder->ExchangeInstID=[{0}]", pOrder->ExchangeInstID);
LDebug("pOrder->OrderLocalID=[{0}]", pOrder->OrderLocalID);
LDebug("pOrder->OrderRef=[{0}]", pOrder->OrderRef);
LDebug("pOrder->OrderSysID=[{0}]", pOrder->OrderSysID);
LDebug("pOrder->OrderStatus=[{0}]", pOrder->OrderStatus);
LDebug("pOrder->StatusMsg=[{0}]", pOrder->StatusMsg);
if (THOST_FTDC_OST_AllTraded == pOrder->OrderStatus)
{
LDebug("全部成交");
}
else if (THOST_FTDC_OST_PartTradedQueueing == pOrder->OrderStatus)
{
LDebug("部分成交还在队列中");
}
else if (THOST_FTDC_OST_PartTradedNotQueueing == pOrder->OrderStatus)
{
LDebug("部分成交不在队列中");
}
else if (THOST_FTDC_OST_NoTradeQueueing == pOrder->OrderStatus)
{
LDebug("未成交还在队列中");
}
else if (THOST_FTDC_OST_NoTradeNotQueueing == pOrder->OrderStatus)
{
LDebug("未成交不在队列中");
}
else if (THOST_FTDC_OST_Canceled == pOrder->OrderStatus)
{
LDebug("撤单");
}
else if (THOST_FTDC_OST_Unknown == pOrder->OrderStatus)
{
LDebug("未知");
}
else if (THOST_FTDC_OST_NotTouched == pOrder->OrderStatus)
{
LDebug("尚未触发");
}
else if (THOST_FTDC_OST_Touched == pOrder->OrderStatus)
{
LDebug("已触发");
}
LDebug("pOrder->OrderSubmitStatus=[{0}]", pOrder->OrderSubmitStatus);
if (THOST_FTDC_OSS_InsertSubmitted == pOrder->OrderSubmitStatus)
{
LDebug("已经提交");
}
else if (THOST_FTDC_OSS_CancelSubmitted == pOrder->OrderSubmitStatus)
{
LDebug("撤单已经提交");
}
else if (THOST_FTDC_OSS_ModifySubmitted == pOrder->OrderSubmitStatus)
{
LDebug("修改已经提交");
}
else if (THOST_FTDC_OSS_Accepted == pOrder->OrderSubmitStatus)
{
LDebug("已经接受");
}
else if (THOST_FTDC_OSS_InsertRejected == pOrder->OrderSubmitStatus)
{
LDebug("报单已经被拒绝");
}
else if (THOST_FTDC_OSS_CancelRejected == pOrder->OrderSubmitStatus)
{
LDebug("撤单已经被拒绝");
}
else if (THOST_FTDC_OSS_ModifyRejected == pOrder->OrderSubmitStatus)
{
LDebug("改单已经被拒绝");
}
LDebug("pOrder->VolumeTraded=[{0}]", pOrder->VolumeTraded);
LDebug("pOrder->VolumeTotal=[{0}]", pOrder->VolumeTotal);
LDebug("pOrder->AccountID=[{0}]", pOrder->AccountID);
LDebug("pOrder->RequestID=[{0}]", pOrder->RequestID);
OrderT OrderData = ConvertOrder(pOrder);
string szUserId = OrderData.szOrderRef.substr(0, VIR_ACCOUNT_LENGTH);
LDebug("szUserId=[{0}]", szUserId);
OrderData.szUserId = szUserId;
TdResponse<OrderT> TdResponseData;
TdResponseData.RspResult = OrderData;
TdResponseData.iErrCode = 0;
TdResponseData.szMsg = "";
TdResponseData.iRequestId = pOrder->RequestID;
ExecuteEngine::GetInstance()->HandleOrderNotify(TdResponseData);
}
3.4.4?? ?成交回报
如果委托报单成交,会有成交回报?
void TdAdapterCtp::OnRtnTrade(CThostFtdcTradeField *pTrade)
{
LDebug("-----------ctp OnRtnTrade------------");
LDebug("pTrade->BrokerID=[{0}]", pTrade->BrokerID);
LDebug("pTrade->InvestorID=[{0}]", pTrade->InvestorID);
LDebug("pTrade->InstrumentID=[{0}]", pTrade->InstrumentID);
LDebug("pTrade->OrderRef=[{0}]", pTrade->OrderRef);
LDebug("pTrade->UserID=[{0}]", pTrade->UserID);
LDebug("pTrade->ExchangeID=[{0}]", pTrade->ExchangeID);
LDebug("pTrade->Direction=[{0}]", pTrade->Direction);
LDebug("pTrade->OrderSysID=[{0}]", pTrade->OrderSysID);
LDebug("pTrade->ClientID=[{0}]", pTrade->ClientID);
LDebug("pTrade->ExchangeInstID=[{0}]", pTrade->ExchangeInstID);
LDebug("pTrade->OffsetFlag=[{0}]", pTrade->OffsetFlag);
LDebug("pTrade->TradeID=[{0}]", pTrade->TradeID);
LDebug("pTrade->Price=[{0}]", pTrade->Price);
LDebug("pTrade->Volume=[{0}]", pTrade->Volume);
LDebug("pTrade->OrderLocalID=[{0}]", pTrade->OrderLocalID);
TradeT TradeData = ConvertTrade(pTrade);
string szUserId = TradeData.szOrderRef.substr(0, VIR_ACCOUNT_LENGTH);
LDebug("szUserId=[{0}]", szUserId);
TradeData.szUserId = szUserId;
// notify trade
TdResponse<TradeT> TdResponseData;
TdResponseData.RspResult = TradeData;
TdResponseData.iErrCode = 0;
TdResponseData.szMsg = "";
TdResponseData.iRequestId = 0;
ExecuteEngine::GetInstance()->HandleTradeNotify(TdResponseData);
}
4?? ?行情api
大家按照下面的流程登录期货ctp,订阅行情,接收行情数据
4.1?? ?建立继承CThostFtdcMdSpi的类MdAdapterCtp
class MdAdapterCtp : public CThostFtdcMdSpi
{
public:
MdAdapterCtp();
virtual ~MdAdapterCtp();
public:
void Connect(CtpConfig &ConfigData);
void Logout();
void ReqSubscribeMarketdata(const vector<string> &vInstrumentId);
private:
int GetRequestId();
private:
CtpConfig m_CtpConfig;
CThostFtdcMdApi *m_pQuoteApi;
int m_iRequestId; // user custom req_id
mutex m_RequestIdMtx;
bool m_bIsLogin;
private:
// CTP callbacks
virtual void OnFrontConnected();
virtual void OnFrontDisconnected(int nReason);
virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
virtual void OnRspUserLogout(CThostFtdcUserLogoutField *pUserLogout, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
virtual void OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
virtual void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData);
};
4.2?? ?连接到期货ctp?
void MdAdapterCtp::Connect(CtpConfig &ConfigData)
{
m_CtpConfig = ConfigData;
m_pQuoteApi = CThostFtdcMdApi::CreateFtdcMdApi();
if (!m_pQuoteApi)
{
LError("ctp create quoteapi Error");
return;
}
m_pQuoteApi->RegisterSpi(this);
string szFrontAddr = "tcp://" + m_CtpConfig.szMarketIp + ':' + to_string(m_CtpConfig.iMarketPort);
std::cout << "Market FrontAddress=" << szFrontAddr << endl;
//const_cast转换符是用来移除变量的const或volatile限定符
m_pQuoteApi->RegisterFront(const_cast<char *>(szFrontAddr.c_str()));
m_pQuoteApi->Init();
}
4.3?? ?连接响应函数
在连接响应函数中调用ReqUserLogin登录函数?
void MdAdapterCtp::OnFrontConnected()
{
printf("ctp MdAdapterCtp OnFrontConnected\n");
LInfo("---- ctp MdAdapterCtp OnFrontConnected ----");
CThostFtdcReqUserLoginField ReqParam;
memset(&ReqParam, 0, sizeof(ReqParam));
strcpy(ReqParam.BrokerID, m_CtpConfig.szBrokerId.c_str());
strcpy(ReqParam.UserID, m_CtpConfig.szUserId.c_str());
strcpy(ReqParam.Password, m_CtpConfig.szPassword.c_str());
int iRet = m_pQuoteApi->ReqUserLogin(&ReqParam, GetRequestId());
if (iRet != 0)
{
LError("send ctp MdAdapterCtp ReqUserLogin Error,iRet=[{0}]", iRet);
}
else
{
LInfo("send ctp MdAdapterCtp ReqUserLogin OK");
}
}
4.4?? ?登录响应函数
获取合约数据,进行订阅行情
void MdAdapterCtp::OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
if (!pRspInfo || pRspInfo->ErrorID == 0)
{
printf("ctp MdAdapterCtp OnRspUserLogin success\n");
LInfo("ctp MdAdapterCtp OnRspUserLogin success");
m_bIsLogin = true;
//获取合约数据
vector<shared_ptr<InstrumentT>> InstrumentDatas;
TradeData::GetInstruments(InstrumentDatas);
if (0 == InstrumentDatas.size())
{
LError("database Instrument is empty");
return;
}
vector<string> vInstrumentId;
for (int i = 0; i < InstrumentDatas.size(); i++)
{
vInstrumentId.push_back(InstrumentDatas[i]->szInstrumentId);
}
//订阅
ReqSubscribeMarketdata(vInstrumentId);
}
else
{
std::cout << "ctp MdAdapterCtp OnRspUserLogin Error,error_msg=" << pRspInfo->ErrorMsg << endl;
LError("ctp MdAdapterCtp OnRspUserLogin Error, error_code=[{0}],error_msg=[{1}]", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
}
}
4.5?? ?订阅行情请求函数?
void MdAdapterCtp::ReqSubscribeMarketdata(const vector<string> &vInstrumentId)
{
LInfo("ctp ReqSubscribeMarketdata");
if (false == m_bIsLogin)
{
LError("MdAdapterCtp is not login");
}
const int iCount = vInstrumentId.size();
char **pInstrumentIdArray = new char*[iCount];
for (int i = 0; i < iCount; ++i)
{
pInstrumentIdArray[i] = const_cast<char *>(vInstrumentId[i].c_str());
//printf("[%d]=%s\n",i, pInstrumentIdArray[i]);
//LInfo("ReqSubscribeMarketdata i=[{0}],StockCode=[{1}]", i, pInstrumentIdArray[i]);
}
//必须输入合约代码才能订阅
int iRet = m_pQuoteApi->SubscribeMarketData(pInstrumentIdArray, iCount);
if (iRet != 0)
{
LError("send ctp SubscribeMarketData Error,iRet=[{0}]", iRet);
}
else
{
LInfo("send ctp SubscribeMarketData OK");
}
delete[] pInstrumentIdArray;
}
4.6?? ?订阅行情响应函数?
void MdAdapterCtp::OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
if (!pRspInfo || pRspInfo->ErrorID == 0)
{
//LInfo("ctp MdAdapterCtp OnRspSubMarketData success");
}
else
{
LError("ctp MdAdapterCtp OnRspSubMarketData Error, error_code=[{0}],error_msg=[{1}]", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
}
}
4.7?? ?接收行情数据函数?
void MdAdapterCtp::OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData)
{
printf("---------pDepthMarketData--%s------------------\n", pDepthMarketData->InstrumentID);
MemPoolMng*pMemPoolMng = MemPoolMng::GetInstance();
//发送到CMsgQueueServer
{
char*pData = pMemPoolMng->GetMaxMemBlock(sizeof(CThostFtdcDepthMarketDataField));
if (NULL == pData)
{
LError("pData is NULL!");
return;
}
CThostFtdcDepthMarketDataField*pMarketData = (CThostFtdcDepthMarketDataField*)pData;
memcpy(pMarketData, pDepthMarketData, sizeof(CThostFtdcDepthMarketDataField));
char*pMemBlock = pMemPoolMng->GetMaxMemBlock(sizeof(ServerMsg));
if (NULL == pMemBlock)
{
LError("pMemBlock is NULL!");
return;
}
ServerMsg*pServerMsg = (ServerMsg*)pMemBlock;
pServerMsg->iFunctionId = FUNC_MARKET_QUOTE;
pServerMsg->pBody = (char*)pMarketData;
pServerMsg->iBodyLen = sizeof(CThostFtdcDepthMarketDataField);
CMsgQueueServer::GetInstance()->PostMsg(pServerMsg);
}
//发送到CSaveData
{
char*pData = pMemPoolMng->GetMaxMemBlock(sizeof(CThostFtdcDepthMarketDataField));
if (NULL == pData)
{
LError("pData is NULL!");
return;
}
CThostFtdcDepthMarketDataField*pMarketData = (CThostFtdcDepthMarketDataField*)pData;
memcpy(pMarketData, pDepthMarketData, sizeof(CThostFtdcDepthMarketDataField));
char*pMemBlock = pMemPoolMng->GetMaxMemBlock(sizeof(ServerMsg));
if (NULL == pMemBlock)
{
LError("pMemBlock is NULL!");
return;
}
ServerMsg*pServerMsg = (ServerMsg*)pMemBlock;
pServerMsg->iFunctionId = FUNC_MARKET_QUOTE;
pServerMsg->pBody = (char*)pMarketData;
pServerMsg->iBodyLen = sizeof(CThostFtdcDepthMarketDataField);
CSaveData::GetInstance()->PostMsg(pServerMsg);
}
}
?
?
?
|