量化交易期货ctp使用说明(企业版,穿透式监管)(值得收藏)

量化交易期货ctp使用说明(企业版,穿透式监管)(值得收藏),第1张

1.代码说明

本文章中的期货class="superseo">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 ReqPlaceOrder(const string& szOrderRef, const string &szStockCode, const char &cAction, const double dPrice, const int iQuantity);
	//撤单
	TdResponse 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 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 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 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 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 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 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 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 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 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 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 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 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 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 &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(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> InstrumentDatas;
		TradeData::GetInstruments(InstrumentDatas);
		if (0 == InstrumentDatas.size())
		{
			LError("database Instrument is empty");
			return;
		}

		vector  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 &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(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);
	}


}


 


 


 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/925507.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存