CTP接口开发案例(内附源码)

CTP接口开发(内附源码)

提示:在看本博客之前建议先阅读上期所官方的开发文档(SimNow官网中去下载CTP接口文件),然后在SimNow官网注册模拟账号。

提示:股票CTP接口和期货CTP接口类似。若要换经纪商,则只需要将main.cpp文件中的模拟经纪商代码等修改成对应经纪商提供的即可。模拟盘和实盘的转换也只需要替换头文件和链接库文件即可。

上期所官方的开发文档下载地址:
链接: http://www.sfit.com.cn/5_1_DocumentDown.htm .

或百度网盘下载Api接口开发文档:
链接: Api开发文档
提取码:pv2f

ctp接口文件(v6.6.1版本):
链接: https://pan.baidu.com/s/1b3B3OnyqYOyjYHT30-Guhg.
提取码:aoje



前言

量化交易起源于上世纪七十年代,之后迅速发展和普及,尤其是在期货交易市场,程序化逐渐成为主流,有数据显示,国外成熟市场期货程序化交易占总交易量的70%-80%,而国内则刚刚起步,手工交易中交易者的情绪波动等弊端都会导致亏损。随着人工智能和数据分析的发展,越来越多的人开始使用程序化交易。

一、CTP是什么?

CTP是上海期货推出的一套程序调用的交易接口。

二、使用步骤

1.包含的头文件即连接库

在这里插入图片描述
在这里插入图片描述

2.在vs2019中导入链接库

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述根据上述三步的配置即可将链接库导入到项目中。

3.行情接口

在登录行情服务器时,不需要账号和密码,也可以通过CTP接口获取行情。
CThostFtdcMdSpi --> 是行情接口文件

行情接口代码如下:

#include <iostream>
#include <fstream>
#include <unordered_map>
#include "CustomMdSpi.h"

// ---- 全局参数声明 ---- //
//如果函数的声明中带有关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它作用
extern CThostFtdcMdApi* g_pMdUserApi;            // 行情指针
extern char gMdFrontAddr[];                      // 模拟行情前置地址
extern TThostFtdcBrokerIDType gBrokerID;         // 模拟经纪商代码
extern TThostFtdcInvestorIDType gInvesterID;     // 投资者账户名
extern TThostFtdcPasswordType gInvesterPassword; // 投资者密码
extern char* g_pInstrumentID[];                  // 行情合约代码列表,中、上、大、郑交易所各选一种
extern int instrumentNum;                        // 行情合约订阅数量


// ---- ctp_api回调函数 ---- //
// 连接成功应答
void CustomMdSpi::OnFrontConnected()
{
	std::cout << "=====建立网络连接成功=====" << std::endl;
	// 开始登录
	CThostFtdcReqUserLoginField loginReq;
	memset(&loginReq, 0, sizeof(loginReq));
	strcpy(loginReq.BrokerID, gBrokerID);
	strcpy(loginReq.UserID, gInvesterID);
	strcpy(loginReq.Password, gInvesterPassword);
	static int requestID = 0; // 请求编号
	int rt = g_pMdUserApi->ReqUserLogin(&loginReq, ++requestID);
	if (!rt)
		std::cout << "--->>>行情--发送登录请求成功" << std::endl;
	else
		std::cerr << "--->>>行情--发送登录请求失败,错误码:"<< rt << std::endl;
}

// 断开连接通知
void CustomMdSpi::OnFrontDisconnected(int nReason)
{
	std::cerr << "=====网络连接断开=====" << std::endl;
	std::cerr << "错误码: " << nReason << std::endl;
}

// 心跳超时警告
void CustomMdSpi::OnHeartBeatWarning(int nTimeLapse)
{
	std::cerr << "=====网络心跳超时=====" << std::endl;
	std::cerr << "距上次连接时间: " << nTimeLapse << std::endl;
}

// 登录应答
void CustomMdSpi::OnRspUserLogin(CThostFtdcRspUserLoginField* pRspUserLogin, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
	if (!bResult)
	{
		std::cout << "=====账户登录成功=====" << std::endl;
		std::cout << "交易日: " << pRspUserLogin->TradingDay << std::endl;
		std::cout << "登录时间: " << pRspUserLogin->LoginTime << std::endl;
		std::cout << "经纪商: " << pRspUserLogin->BrokerID << std::endl;
		std::cout << "帐户名: " << pRspUserLogin->UserID << std::endl;

		// 开始订阅行情
		int rt = g_pMdUserApi->SubscribeMarketData(g_pInstrumentID, instrumentNum);
		if (!rt)
			std::cout << ">>>>>>发送订阅行情请求成功" << std::endl;
		else
			std::cerr << "--->>>发送订阅行情请求失败" << std::endl;

	
	}
	else
		std::cerr << "返回错误--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << std::endl;
}

// 登出应答
void CustomMdSpi::OnRspUserLogout(CThostFtdcUserLogoutField* pUserLogout, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
	if (!bResult)
	{
		std::cout << "=====账户登出成功=====" << std::endl;
		std::cout << "经纪商: " << pUserLogout->BrokerID << std::endl;
		std::cout << "帐户名: " << pUserLogout->UserID << std::endl;
	}
	else
		std::cerr << "返回错误--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << std::endl;
}

// 错误通知
void CustomMdSpi::OnRspError(CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
	if (bResult)
		std::cerr << "返回错误--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << std::endl;
}

// 订阅行情应答
void CustomMdSpi::OnRspSubMarketData(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
	if (!bResult)
	{
		std::cout << "=====订阅行情成功=====" << std::endl;
		std::cout << "合约代码: " << pSpecificInstrument->InstrumentID << std::endl;

		// 如果需要存入文件或者数据库,在这里创建表头,不同的合约单独存储
		char filePath[100] = { '\0' };
		sprintf(filePath, ".//SqlData//%s_market_data.csv", pSpecificInstrument->InstrumentID);
		std::ofstream outFile;
		outFile.open(filePath, std::ios::out); // 新开文件
		outFile << "合约代码" << ","
			<< "更新时间" << ","
			<< "最新价" << ","
			<< "成交量" << ","
			<< "买价一" << ","
			<< "买量一" << ","
			<< "卖价一" << ","
			<< "卖量一" << ","
			<< "持仓量" << ","
			<< "换手率"
			<< std::endl;
		outFile.close();
	}
	else
		std::cerr << "返回错误--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << std::endl;
}

// 取消订阅行情应答
void CustomMdSpi::OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo,
	int nRequestID,
	bool bIsLast)
{
	bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
	if (!bResult)
	{
		std::cout << "=====取消订阅行情成功=====" << std::endl;
		std::cout << "合约代码: " << pSpecificInstrument->InstrumentID << std::endl;
	}
	else
		std::cerr << "返回错误--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << std::endl;
}

// 订阅询价应答
void CustomMdSpi::OnRspSubForQuoteRsp(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
	if (!bResult)
	{
		std::cout << "=====订阅询价成功=====" << std::endl;
		std::cout << "合约代码: " << pSpecificInstrument->InstrumentID << std::endl;
	}
	else
		std::cerr << "返回错误--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << std::endl;
}

// 取消订阅询价应答
void CustomMdSpi::OnRspUnSubForQuoteRsp(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
	if (!bResult)
	{
		std::cout << "=====取消订阅询价成功=====" << std::endl;
		std::cout << "合约代码: " << pSpecificInstrument->InstrumentID << std::endl;
	}
	else
		std::cerr << "返回错误--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << std::endl;
}

// 行情详情通知
void CustomMdSpi::OnRtnDepthMarketData(CThostFtdcDepthMarketDataField* pDepthMarketData)
{
	// 打印行情,字段较多,截取部分
	std::cout << "=====获得深度行情=====" << std::endl;
	std::cout << "交易日: " << pDepthMarketData->TradingDay << std::endl;
	std::cout << "交易所代码: " << pDepthMarketData->ExchangeID << std::endl;
	std::cout << "合约代码: " << pDepthMarketData->InstrumentID << std::endl;
	std::cout << "合约在交易所的代码: " << pDepthMarketData->ExchangeInstID << std::endl;
	std::cout << "最新价: " << pDepthMarketData->LastPrice << std::endl;
	std::cout << "数量: " << pDepthMarketData->Volume << std::endl;

	// 将行情写入到csv文件中
	// 如果只获取某一个合约行情,可以逐tick地存入文件或数据库
	//char filePath[100] = { '\0' };
	//sprintf(filePath, "%s_market_data.csv", pDepthMarketData->InstrumentID);
	//std::ofstream outFile;
	//outFile.open(filePath, std::ios::app); // 文件追加写入 
	//outFile << pDepthMarketData->InstrumentID << ","
	//	<< pDepthMarketData->UpdateTime << "." << pDepthMarketData->UpdateMillisec << ","
	//	<< pDepthMarketData->LastPrice << ","
	//	<< pDepthMarketData->Volume << ","
	//	<< pDepthMarketData->BidPrice1 << ","
	//	<< pDepthMarketData->BidVolume1 << ","
	//	<< pDepthMarketData->AskPrice1 << ","
	//	<< pDepthMarketData->AskVolume1 << ","
	//	<< pDepthMarketData->OpenInterest << ","
	//	<< pDepthMarketData->Turnover << std::endl;
	//outFile.close();

	// 计算实时k线
	


	// 取消订阅行情
	//int rt = g_pMdUserApi->UnSubscribeMarketData(g_pInstrumentID, instrumentNum);
	//if (!rt)
	//	std::cout << ">>>>>>发送取消订阅行情请求成功" << std::endl;
	//else
	//	std::cerr << "--->>>发送取消订阅行情请求失败" << std::endl;
}

// 询价详情通知
void CustomMdSpi::OnRtnForQuoteRsp(CThostFtdcForQuoteRspField* pForQuoteRsp)
{
	// 部分询价结果
	std::cout << "=====获得询价结果=====" << std::endl;
	std::cout << "交易日: " << pForQuoteRsp->TradingDay << std::endl;
	std::cout << "交易所代码: " << pForQuoteRsp->ExchangeID << std::endl;
	std::cout << "合约代码: " << pForQuoteRsp->InstrumentID << std::endl;
	std::cout << "询价编号: " << pForQuoteRsp->ForQuoteSysID << std::endl;
}

4.交易接口

示例代码如下:

#include <iostream>
#include <windows.h>
#include <time.h>
#include <thread>
#include <chrono>
#include "CustomTradeSpi.h"
#include "ThostFtdcUserApiDataType.h"

// ---- 全局参数声明 ---- //
extern TThostFtdcBrokerIDType gBrokerID;                      // 模拟经纪商代码
extern TThostFtdcInvestorIDType gInvesterID;                  // 投资者账户名
extern TThostFtdcPasswordType gInvesterPassword;              // 投资者密码
extern CThostFtdcTraderApi* g_pTradeUserApi;                  // 交易指针
extern char gTradeFrontAddr[];                                // 模拟交易前置地址
extern TThostFtdcInstrumentIDType g_pTradeInstrumentID;       // 所交易的合约代码

extern TThostFtdcPriceType gLimitPrice;                       // 交易价格

extern TThostFtdcAppIDType	AppID;							  // AppID
extern TThostFtdcAuthCodeType AuthCode;						  // 授权码


// 会话参数
TThostFtdcFrontIDType	trade_front_id;		//前置编号
TThostFtdcSessionIDType	session_id;		    //会话编号
TThostFtdcOrderRefType	order_ref;			//报单引用

void CustomTradeSpi::OnFrontConnected()
{
	std::cout << "====网络连接成功===" << std::endl;

	// 登录前客户端认证
	reqAuthenticate();
}

void CustomTradeSpi::OnRspAuthenticate(CThostFtdcRspAuthenticateField* pRspAuthenticateField, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	if (!isErrorRspInfo(pRspInfo))
	{
		// 登录
		reqUserLogin();
	}
}

void CustomTradeSpi::OnRspUserLogin(CThostFtdcRspUserLoginField* pRspUserLogin, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	if (!isErrorRspInfo(pRspInfo)) {
		std::cout << "=====交易账户登录成功====" << std::endl;
		loginFlag = true;
		std::cout << "交易日:" << pRspUserLogin->TradingDay << std::endl;
		std::cout << "登录时间:" << pRspUserLogin->LoginTime << std::endl;
		std::cout << "经纪商:" << pRspUserLogin->BrokerID << std::endl;
		std::cout << "账户名:" << pRspUserLogin->UserID << std::endl;

		//保存会话参数
		trade_front_id = pRspUserLogin->FrontID;		 // 前置编号
		session_id = pRspUserLogin->SessionID;			 // 会话编号
		strcpy(order_ref, pRspUserLogin->MaxOrderRef);   // 最大保单引用

		// 投资者结算结果确认
		reqSettlementInfoConfirm();

	}
}


void CustomTradeSpi::OnRspError(CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	isErrorRspInfo(pRspInfo);
}

void CustomTradeSpi::OnFrontDisconnected(int nReason)
{
	std::cerr << "=====网络连接断开=====" << std::endl;
	std::cerr << "错误码: " << nReason << std::endl;
}

void CustomTradeSpi::OnHeartBeatWarning(int nTimeLapse)
{
	std::cerr << "=====网络心跳超时=====" << std::endl;
	std::cerr << "距上次连接时间: " << nTimeLapse << std::endl;
}

void CustomTradeSpi::OnRspUserLogout(
	CThostFtdcUserLogoutField* pUserLogout,
	CThostFtdcRspInfoField* pRspInfo,
	int nRequestID,
	bool bIsLast)
{
	if (!isErrorRspInfo(pRspInfo))
	{
		loginFlag = false; // 登出就不能再交易了 
		std::cout << "=====账户登出成功=====" << std::endl;
		std::cout << "经纪商: " << pUserLogout->BrokerID << std::endl;
		std::cout << "帐户名: " << pUserLogout->UserID << std::endl;
	}
}

void CustomTradeSpi::OnRspSettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField* pSettlementInfoConfirm, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	if (!isErrorRspInfo(pRspInfo))
	{
		std::cout << "=====投资者结算结果确认成功=====" << std::endl;
		std::cout << "确认日期: " << pSettlementInfoConfirm->ConfirmDate << std::endl;
		std::cout << "确认时间: " << pSettlementInfoConfirm->ConfirmTime << std::endl;
		// 请求查询合约
		reqQueryInstrument();
	}
}

void CustomTradeSpi::OnRspQryInstrument(CThostFtdcInstrumentField* pInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID,bool bIsLast)
{
	if (!isErrorRspInfo(pRspInfo))
	{
		std::cout << "=====查询合约结果成功=====" << std::endl;
		std::cout << "交易所代码: " << pInstrument->ExchangeID << std::endl;
		std::cout << "合约代码: " << pInstrument->InstrumentID << std::endl;
		std::cout << "合约在交易所的代码: " << pInstrument->ExchangeInstID << std::endl;
		std::cout << "执行价: " << pInstrument->StrikePrice << std::endl;
		std::cout << "到期日: " << pInstrument->EndDelivDate << std::endl;
		std::cout << "当前交易状态: " << pInstrument->IsTrading << std::endl;
		// 请求查询投资者资金账户(CTP为就绪,后续实盘测测)
		reqQueryTradingAccount();

		//buy_open(g_pTradeInstrumentID, gLimitPrice, 1);

		//sell_open(g_pTradeInstrumentID, gLimitPrice, 1);

		//buy_close(g_pTradeInstrumentID, gLimitPrice, 1);

		//sell_close(g_pTradeInstrumentID, gLimitPrice, 1);
	}
}

void CustomTradeSpi::OnRspQryTradingAccount(CThostFtdcTradingAccountField* pTradingAccount, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	if (!isErrorRspInfo(pRspInfo))
	{
		std::cout << "=====查询投资者资金账户成功=====" << std::endl;
		std::cout << "投资者账号: " << pTradingAccount->AccountID << std::endl;
		std::cout << "可用资金: " << pTradingAccount->Available << std::endl;
		std::cout << "可取资金: " << pTradingAccount->WithdrawQuota << std::endl;
		std::cout << "当前保证金: " << pTradingAccount->CurrMargin << std::endl;
		std::cout << "平仓盈亏: " << pTradingAccount->CloseProfit << std::endl;

		// 请求查询投资者持仓
		reqQueryInvestorPosition();
	}
}

void CustomTradeSpi::OnRspQryInvestorPosition(CThostFtdcInvestorPositionField* pInvestorPosition, CThostFtdcRspInfoField* pRspInfo, int nRequestID,bool bIsLast)
{
	if (!isErrorRspInfo(pRspInfo))
	{
		std::cout << "=====查询投资者持仓成功=====" << std::endl;
		if (pInvestorPosition)
		{
			std::cout << "合约代码: " << pInvestorPosition->InstrumentID << std::endl;
			std::cout << "开仓价格: " << pInvestorPosition->OpenAmount << std::endl;
			std::cout << "开仓量: " << pInvestorPosition->OpenVolume << std::endl;
			std::cout << "开仓方向: " << pInvestorPosition->PosiDirection << std::endl;
			std::cout << "占用保证金:" << pInvestorPosition->UseMargin << std::endl;
		}
		else
			std::cout << "----->该合约未持仓" << std::endl;

		// 报单录入请求(这里是一部接口,此处是按顺序执行)
		/*if (loginFlag)
			reqOrderInsert();*/
			//if (loginFlag)
			//	buy_open(); // 自定义一笔交易

			// 策略交易
		std::cout << "=====开始进入策略交易=====" << std::endl;

		//while (loginFlag) {
		//	StrategyCheckAndTrade(g_pTradeInstrumentID, this);  // 调用策略
		//}
			
	}
}

void CustomTradeSpi::OnRspOrderInsert(CThostFtdcInputOrderField* pInputOrder, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	if (!isErrorRspInfo(pRspInfo))
	{
		std::cout << "=====报单录入成功=====" << std::endl;
		std::cout << "合约代码: " << pInputOrder->InstrumentID << std::endl;
		std::cout << "价格: " << pInputOrder->LimitPrice << std::endl;
		std::cout << "数量: " << pInputOrder->VolumeTotalOriginal << std::endl;
		std::cout << "开仓方向: " << pInputOrder->Direction << std::endl;
	}
}

void CustomTradeSpi::OnRspOrderAction(CThostFtdcInputOrderActionField* pInputOrderAction, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast)
{
	if (!isErrorRspInfo(pRspInfo))
	{
		std::cout << "=====报单操作成功=====" << std::endl;
		std::cout << "合约代码: " << pInputOrderAction->InstrumentID << std::endl;
		std::cout << "操作标志: " << pInputOrderAction->ActionFlag;
	}
}

void CustomTradeSpi::OnRtnOrder(CThostFtdcOrderField* pOrder)
{
	char str[10];
	sprintf(str, "%d", pOrder->OrderSubmitStatus);
	int orderState = atoi(str) - 48;	//报单状态0=已经提交,3=已经接受

	std::cout << "=====收到报单应答=====" << std::endl;

	if (isMyOrder(pOrder))
	{
		if (isTradingOrder(pOrder))
		{
			std::cout << "--->>> 等待成交中!" << std::endl;
			//reqOrderAction(pOrder); // 这里可以撤单
			//reqUserLogout(); // 登出测试
		}
		else if (pOrder->OrderStatus == THOST_FTDC_OST_Canceled)
			std::cout << "--->>> 撤单成功!" << std::endl;
	}
}

void CustomTradeSpi::OnRtnTrade(CThostFtdcTradeField* pTrade)
{
	std::cout << "=====报单成功成交=====" << std::endl;
	std::cout << "成交时间: " << pTrade->TradeTime << std::endl;
	std::cout << "合约代码: " << pTrade->InstrumentID << std::endl;
	std::cout << "成交价格: " << pTrade->Price << std::endl;
	std::cout << "成交量: " << pTrade->Volume << std::endl;
	std::cout << "开平仓方向: " << pTrade->Direction << std::endl;
}

bool CustomTradeSpi::isErrorRspInfo(CThostFtdcRspInfoField* pRspInfo)
{
	bool bResult = pRspInfo && (pRspInfo->ErrorID != 0);
	if (bResult)
		std::cerr << "返回错误--->>> ErrorID=" << pRspInfo->ErrorID << ", ErrorMsg=" << pRspInfo->ErrorMsg << std::endl;
	return bResult;
}

// 客户端认证请求
void CustomTradeSpi::reqAuthenticate()
{
	CThostFtdcReqAuthenticateField req;
	memset(&req, 0, sizeof(req));
	strcpy(req.BrokerID, gBrokerID);
	strcpy(req.AppID, AppID);
	strcpy(req.AuthCode, AuthCode);
	strcpy(req.UserID, gInvesterID);
	static int requestID = 0;
	int iResult = g_pTradeUserApi->ReqAuthenticate(&req, requestID);
	std::cerr << "---> 发送客户端认证:" << ((iResult == 0) ? "成功" : "失败") << std::endl;
}

// 登录
void CustomTradeSpi::reqUserLogin()
{
	CThostFtdcReqUserLoginField loginReq;
	memset(&loginReq, 0, sizeof(loginReq));
	strcpy(loginReq.BrokerID, gBrokerID);
	strcpy(loginReq.UserID, gInvesterID);
	strcpy(loginReq.Password, gInvesterPassword);
	static int requestID = 0; // 请求编号
	int rt = g_pTradeUserApi->ReqUserLogin(&loginReq, requestID);
	if (!rt)
		std::cout << ">>>>>>交易--发送登录请求成功" << std::endl;
	else
		std::cerr << "--->>>交易--发送登录请求失败" << std::endl;
}

// 登出
void CustomTradeSpi::reqUserLogout()
{
	CThostFtdcUserLogoutField logoutReq;
	memset(&logoutReq, 0, sizeof(logoutReq));
	strcpy(logoutReq.BrokerID, gBrokerID);
	strcpy(logoutReq.UserID, gInvesterID);
	static int requestID = 0; // 请求编号
	int rt = g_pTradeUserApi->ReqUserLogout(&logoutReq, requestID);
	if (!rt)
		std::cout << ">>>>>>交易--发送登出请求成功" << std::endl;
	else
		std::cerr << "--->>>交易--发送登出请求失败" << std::endl;
}

// 投资者结算结果确认
void CustomTradeSpi::reqSettlementInfoConfirm()
{
	CThostFtdcSettlementInfoConfirmField settlementConfirmReq;
	memset(&settlementConfirmReq, 0, sizeof(settlementConfirmReq));
	strcpy(settlementConfirmReq.BrokerID, gBrokerID);
	strcpy(settlementConfirmReq.InvestorID, gInvesterID);
	static int requestID = 0; // 请求编号
	int rt = g_pTradeUserApi->ReqSettlementInfoConfirm(&settlementConfirmReq, requestID);
	if (!rt)
	{
		std::cout << ">>>>>>发送投资者结算结果确认请求成功" << std::endl;
	}
	else
		std::cerr << "--->>>发送投资者结算结果确认请求失败" << std::endl;
}

// 请求查询合约
void CustomTradeSpi::reqQueryInstrument()
{
	CThostFtdcQryInstrumentField instrumentReq;
	memset(&instrumentReq, 0, sizeof(instrumentReq));
	strcpy(instrumentReq.InstrumentID, g_pTradeInstrumentID);
	static int requestID = 0; // 请求编号
	int rt = g_pTradeUserApi->ReqQryInstrument(&instrumentReq, requestID);
	if (!rt)
		std::cout << ">>>>>>发送合约查询请求成功" << std::endl;
	else
		std::cerr << "--->>>发送合约查询请求失败" << std::endl;
}

// 请求查询资金帐户
void CustomTradeSpi::reqQueryTradingAccount()
{
	CThostFtdcQryTradingAccountField tradingAccountReq;
	memset(&tradingAccountReq, 0, sizeof(tradingAccountReq));
	strcpy(tradingAccountReq.BrokerID, gBrokerID);
	strcpy(tradingAccountReq.InvestorID, gInvesterID);
	static int requestID = 0; // 请求编号
	std::this_thread::sleep_for(std::chrono::milliseconds(700)); // 有时候需要停顿一会才能查询成功
	int rt = g_pTradeUserApi->ReqQryTradingAccount(&tradingAccountReq, requestID);
	if (!rt)
		std::cout << ">>>>>>发送投资者资金账户查询请求成功" << std::endl;
	else
		std::cerr << "--->>>发送投资者资金账户查询请求失败" << std::endl;
}

void CustomTradeSpi::reqQueryInvestorPosition()
{
	CThostFtdcQryInvestorPositionField postionReq;
	memset(&postionReq, 0, sizeof(postionReq));
	strcpy(postionReq.BrokerID, gBrokerID);
	strcpy(postionReq.InvestorID, gInvesterID);
	strcpy(postionReq.InstrumentID, g_pTradeInstrumentID);
	static int requestID = 0; // 请求编号
	std::this_thread::sleep_for(std::chrono::milliseconds(700)); // 有时候需要停顿一会才能查询成功
	int rt = g_pTradeUserApi->ReqQryInvestorPosition(&postionReq, requestID);
	if (!rt)
		std::cout << ">>>>>>发送投资者持仓查询请求成功" << std::endl;
	else
		std::cerr << "--->>>发送投资者持仓查询请求失败" << std::endl;
}

// 买开仓
void CustomTradeSpi::buy_open(TThostFtdcInstrumentIDType instrumentID, TThostFtdcPriceType NewPrice, TThostFtdcVolumeType volume)
{
	CThostFtdcInputOrderField orderInsertReq;
	memset(&orderInsertReq, 0, sizeof(orderInsertReq));
	///经纪公司代码
	strcpy(orderInsertReq.BrokerID, gBrokerID);
	///投资者代码
	strcpy(orderInsertReq.InvestorID, gInvesterID);
	///合约代码
	strcpy(orderInsertReq.InstrumentID, instrumentID);
	///报单引用
	strcpy(orderInsertReq.OrderRef, order_ref);
	///报单价格条件: 限价
	orderInsertReq.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
	///买卖方向: 
	orderInsertReq.Direction = THOST_FTDC_D_Buy;
	///组合开平标志: 开仓、平仓等
	orderInsertReq.CombOffsetFlag[0] = THOST_FTDC_OF_Open;
	///组合投机套保标志
	orderInsertReq.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;
	///价格
	orderInsertReq.LimitPrice = NewPrice;
	///数量:1
	orderInsertReq.VolumeTotalOriginal = volume;
	///有效期类型: 当日有效
	orderInsertReq.TimeCondition = THOST_FTDC_TC_GFD;
	///成交量类型: 任何数量
	orderInsertReq.VolumeCondition = THOST_FTDC_VC_AV;
	///最小成交量: 1
	orderInsertReq.MinVolume = 1;
	///触发条件: 立即
	orderInsertReq.ContingentCondition = THOST_FTDC_CC_Immediately;
	///强平原因: 非强平
	orderInsertReq.ForceCloseReason = THOST_FTDC_FCC_NotForceClose;
	///自动挂起标志: 否
	orderInsertReq.IsAutoSuspend = 0;
	///用户强评标志: 否
	orderInsertReq.UserForceClose = 0;

	static int requestID = 0; // 请求编号
	int rt = g_pTradeUserApi->ReqOrderInsert(&orderInsertReq, ++requestID);
	if (!rt)
		std::cout << ">>>>>>发送买开仓报单录入请求成功" << std::endl;
	else
		std::cerr << "--->>>发送买开仓报单录入请求失败" << std::endl;
}

// 买平仓
void CustomTradeSpi::buy_close(TThostFtdcInstrumentIDType instrumentID, TThostFtdcPriceType NewPrice, TThostFtdcVolumeType volume, TThostFtdcTimeConditionType CombOffsetFlag)
{
	CThostFtdcInputOrderField orderInsertReq;
	memset(&orderInsertReq, 0, sizeof(orderInsertReq));
	///经纪公司代码
	strcpy(orderInsertReq.BrokerID, gBrokerID);
	///投资者代码
	strcpy(orderInsertReq.InvestorID, gInvesterID);
	///合约代码
	strcpy(orderInsertReq.InstrumentID, instrumentID);
	///报单引用
	strcpy(orderInsertReq.OrderRef, order_ref);
	///报单价格条件: 限价
	orderInsertReq.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
	///买卖方向: 
	orderInsertReq.Direction = THOST_FTDC_D_Buy;
	///组合开平标志: 开仓、平仓等
	orderInsertReq.CombOffsetFlag[0] = CombOffsetFlag;
	///组合投机套保标志
	orderInsertReq.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;
	///价格
	orderInsertReq.LimitPrice = NewPrice;
	///数量:1
	orderInsertReq.VolumeTotalOriginal = volume;
	///有效期类型: 当日有效
	orderInsertReq.TimeCondition = THOST_FTDC_TC_GFD;
	///成交量类型: 任何数量
	orderInsertReq.VolumeCondition = THOST_FTDC_VC_AV;
	///最小成交量: 1
	orderInsertReq.MinVolume = 1;
	///触发条件: 立即
	orderInsertReq.ContingentCondition = THOST_FTDC_CC_Immediately;
	///强平原因: 非强平
	orderInsertReq.ForceCloseReason = THOST_FTDC_FCC_NotForceClose;
	///自动挂起标志: 否
	orderInsertReq.IsAutoSuspend = 0;
	///用户强评标志: 否
	orderInsertReq.UserForceClose = 0;

	static int requestID = 0; // 请求编号
	int rt = g_pTradeUserApi->ReqOrderInsert(&orderInsertReq, ++requestID);
	if (!rt)
		std::cout << ">>>>>>发送买平仓报单录入请求成功" << std::endl;
	else
		std::cerr << "--->>>发送买平仓报单录入请求失败" << std::endl;
}

// 卖开仓
void CustomTradeSpi::sell_open(TThostFtdcInstrumentIDType instrumentID, TThostFtdcPriceType NewPrice, TThostFtdcVolumeType volume)
{
	CThostFtdcInputOrderField orderInsertReq;
	memset(&orderInsertReq, 0, sizeof(orderInsertReq));
	///经纪公司代码
	strcpy(orderInsertReq.BrokerID, gBrokerID);
	///投资者代码
	strcpy(orderInsertReq.InvestorID, gInvesterID);
	///合约代码
	strcpy(orderInsertReq.InstrumentID, instrumentID);
	///报单引用
	strcpy(orderInsertReq.OrderRef, order_ref);
	///报单价格条件: 限价
	orderInsertReq.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
	///买卖方向: 
	orderInsertReq.Direction = THOST_FTDC_D_Sell;
	///组合开平标志: 开仓、平仓等
	orderInsertReq.CombOffsetFlag[0] = THOST_FTDC_OF_Open;
	///组合投机套保标志
	orderInsertReq.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;
	///价格
	orderInsertReq.LimitPrice = NewPrice;
	///数量:1
	orderInsertReq.VolumeTotalOriginal = volume;
	///有效期类型: 当日有效
	orderInsertReq.TimeCondition = THOST_FTDC_TC_GFD;
	///成交量类型: 任何数量
	orderInsertReq.VolumeCondition = THOST_FTDC_VC_AV;
	///最小成交量: 1
	orderInsertReq.MinVolume = 1;
	///触发条件: 立即
	orderInsertReq.ContingentCondition = THOST_FTDC_CC_Immediately;
	///强平原因: 非强平
	orderInsertReq.ForceCloseReason = THOST_FTDC_FCC_NotForceClose;
	///自动挂起标志: 否
	orderInsertReq.IsAutoSuspend = 0;
	///用户强评标志: 否
	orderInsertReq.UserForceClose = 0;

	static int requestID = 0; // 请求编号
	int rt = g_pTradeUserApi->ReqOrderInsert(&orderInsertReq, ++requestID);
	if (!rt)
		std::cout << ">>>>>>发送卖开仓报单录入请求成功" << std::endl;
	else
		std::cerr << "--->>>发送卖开仓报单录入请求失败" << std::endl;
}

// 卖平仓
void CustomTradeSpi::sell_close(TThostFtdcInstrumentIDType instrumentID, TThostFtdcPriceType NewPrice, TThostFtdcVolumeType volume, TThostFtdcTimeConditionType CombOffsetFlag)
{
	CThostFtdcInputOrderField orderInsertReq;
	memset(&orderInsertReq, 0, sizeof(orderInsertReq));
	///经纪公司代码
	strcpy(orderInsertReq.BrokerID, gBrokerID);
	///投资者代码
	strcpy(orderInsertReq.InvestorID, gInvesterID);
	///合约代码
	strcpy(orderInsertReq.InstrumentID, instrumentID);
	///报单引用
	strcpy(orderInsertReq.OrderRef, order_ref);
	///报单价格条件: 限价
	orderInsertReq.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
	///买卖方向: 
	orderInsertReq.Direction = THOST_FTDC_D_Sell;
	///组合开平标志: 开仓、平仓等
	orderInsertReq.CombOffsetFlag[0] = CombOffsetFlag;
	///组合投机套保标志
	orderInsertReq.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;
	///价格
	orderInsertReq.LimitPrice = NewPrice;
	///数量:1
	orderInsertReq.VolumeTotalOriginal = volume;
	///有效期类型: 当日有效
	orderInsertReq.TimeCondition = THOST_FTDC_TC_GFD;
	///成交量类型: 任何数量
	orderInsertReq.VolumeCondition = THOST_FTDC_VC_AV;
	///最小成交量: 1
	orderInsertReq.MinVolume = 1;
	///触发条件: 立即
	orderInsertReq.ContingentCondition = THOST_FTDC_CC_Immediately;
	///强平原因: 非强平
	orderInsertReq.ForceCloseReason = THOST_FTDC_FCC_NotForceClose;
	///自动挂起标志: 否
	orderInsertReq.IsAutoSuspend = 0;
	///用户强评标志: 否
	orderInsertReq.UserForceClose = 0;

	static int requestID = 0; // 请求编号
	int rt = g_pTradeUserApi->ReqOrderInsert(&orderInsertReq, ++requestID);
	if (!rt)
		std::cout << ">>>>>>发送卖平仓报单录入请求成功" << std::endl;
	else
		std::cerr << "--->>>发送卖平仓报单录入请求失败" << std::endl;
}

// 请求报单操作
void CustomTradeSpi::reqOrderAction(CThostFtdcOrderField* pOrder)
{
	static bool orderActionSentFlag = false; // 是否发送了报单
	if (orderActionSentFlag)
		return;

	CThostFtdcInputOrderActionField orderActionReq;
	memset(&orderActionReq, 0, sizeof(orderActionReq));
	///经纪公司代码
	strcpy(orderActionReq.BrokerID, pOrder->BrokerID);
	///投资者代码
	strcpy(orderActionReq.InvestorID, pOrder->InvestorID);
	///报单操作引用
	//	TThostFtdcOrderActionRefType	OrderActionRef;
	///报单引用
	strcpy(orderActionReq.OrderRef, pOrder->OrderRef);
	///请求编号
	//	TThostFtdcRequestIDType	RequestID;
	///前置编号
	orderActionReq.FrontID = trade_front_id;
	///会话编号
	orderActionReq.SessionID = session_id;
	///交易所代码
	//	TThostFtdcExchangeIDType	ExchangeID;
	///报单编号
	//	TThostFtdcOrderSysIDType	OrderSysID;
	///操作标志
	orderActionReq.ActionFlag = THOST_FTDC_AF_Delete;
	///价格
	//	TThostFtdcPriceType	LimitPrice;
	///数量变化
	//	TThostFtdcVolumeType	VolumeChange;
	///用户代码
	//	TThostFtdcUserIDType	UserID;
	///合约代码
	strcpy(orderActionReq.InstrumentID, pOrder->InstrumentID);
	static int requestID = 0; // 请求编号
	int rt = g_pTradeUserApi->ReqOrderAction(&orderActionReq, ++requestID);
	if (!rt)
		std::cout << ">>>>>>发送报单操作请求成功" << std::endl;
	else
		std::cerr << "--->>>发送报单操作请求失败" << std::endl;
	orderActionSentFlag = true;
}

bool CustomTradeSpi::isMyOrder(CThostFtdcOrderField* pOrder)
{
	return ((pOrder->FrontID == trade_front_id) &&
		(pOrder->SessionID == session_id) &&
		(strcmp(pOrder->OrderRef, order_ref) == 0));
}

bool CustomTradeSpi::isTradingOrder(CThostFtdcOrderField* pOrder)
{
	return ((pOrder->OrderStatus != THOST_FTDC_OST_PartTradedNotQueueing) &&
		(pOrder->OrderStatus != THOST_FTDC_OST_Canceled) &&
		(pOrder->OrderStatus != THOST_FTDC_OST_AllTraded));
}

4.main函数

main函数代码如下:

#include <iostream>
#include <stdio.h>
#include <string>
#include <unordered_map>
#include "CustomMdSpi.h"
#include "CustomTradeSpi.h"
#include "CreateFiel.h"

using namespace std;

//链接库(导入链接库的第二种方法)
//#pragma comment (lib, "thostmduserapi_se.lib")
//#pragma comment (lib, "thosttraderapi_se.lib")


// ---- 全局变量(公共参数) ---- //
// SimNow(模拟)
TThostFtdcBrokerIDType gBrokerID = "9999";								   // 模拟经纪商代码
TThostFtdcInvestorIDType gInvesterID = "******";                           // 投资者账户名
TThostFtdcPasswordType gInvesterPassword = "**********";                   // 投资者密码
TThostFtdcAppIDType	AppID = "simnow_client_test";			               // AppID
TThostFtdcAuthCodeType	AuthCode = "0000000000000000";                     // 授权码

// 行情参数
CThostFtdcMdApi* g_pMdUserApi = nullptr;                             // 行情指针
char gMdFrontAddr[] = "tcp://180.168.146.187:10131";               // 模拟行情前置地址--全天站点
//char gMdFrontAddr[] = "tcp://180.168.146.187:10211";               // 模拟行情前置地址--电信
//char gMdFrontAddr[] = "tcp://180.168.146.187:10212";               // 模拟行情前置地址--电信1
//char gMdFrontAddr[] = "tcp://180.168.146.187:10213";               // 模拟行情前置地址--移动
char* g_pInstrumentID[] = { "p2209" };							     // 行情合约代码列表,中、上、大、郑交易所各选一种   期权:"IO2105-C-5000"
char* a1 = new char[10];
int instrumentNum = 1;                                               // 行情合约订阅数量


// 交易参数
CThostFtdcTraderApi* g_pTradeUserApi = nullptr;						 // 交易指针
char gTradeFrontAddr[] = "tcp://180.168.146.187:10130";            // 模拟交易前置地址--全天站点
//char gTradeFrontAddr[] = "tcp://180.168.146.187:10201";            // 模拟交易前置地址--电信
//char gTradeFrontAddr[] = "tcp://180.168.146.187:10202";            // 模拟交易前置地址--电信1
//char gTradeFrontAddr[] = "tcp://180.168.146.187:10203";            // 模拟交易前置地址--移动

TThostFtdcInstrumentIDType g_pTradeInstrumentID = "p2209";           // 所交易的合约代码
TThostFtdcPriceType gLimitPrice = 11064;                             // 交易价格

int main()
{
	// 若文件夹不存在,则创建所需文件夹
	createFile();

	// 初始化行情线程
	cout << "初始化行情..." << endl;
	char* mdFlowPath = ".//MarketData/";                                    // 存放行情接口在本地生成的流文件的文件路径(.con)
	g_pMdUserApi = CThostFtdcMdApi::CreateFtdcMdApi(mdFlowPath, true);      // 创建行情实例
	CThostFtdcMdSpi* pMdUserSpi = new CustomMdSpi;							// 创建行情回调实例
	g_pMdUserApi->RegisterSpi(pMdUserSpi);									// 注册事件类
	g_pMdUserApi->RegisterFront(gMdFrontAddr);								// 设置行情前置地址
	g_pMdUserApi->Init();													// 连接运行

	// 初始化交易线程
	cout << "初始化交易..." << endl;
	char* tdFlowPath = ".//TradingData/";                                    // 存放交易接口在本地生成的流文件的文件路径(.con)
	g_pTradeUserApi = CThostFtdcTraderApi::CreateFtdcTraderApi(tdFlowPath);  // 创建交易实例
	//CThostFtdcTraderSpi *pTradeSpi = new CustomTradeSpi;
	CustomTradeSpi* pTradeSpi = new CustomTradeSpi;							 // 创建交易回调实例
	g_pTradeUserApi->RegisterSpi(pTradeSpi);								 // 注册事件类
	g_pTradeUserApi->RegisterFront(gTradeFrontAddr);						 // 设置交易前置地址
	g_pTradeUserApi->SubscribePublicTopic(THOST_TERT_RESTART);				 // 订阅公共流
	g_pTradeUserApi->SubscribePrivateTopic(THOST_TERT_RESTART);				 // 订阅私有流
	g_pTradeUserApi->Init();												 // 连接运行


	// 等到线程退出
	g_pMdUserApi->Join();
	delete pMdUserSpi;
	g_pMdUserApi->Release();

	g_pTradeUserApi->Join();
	delete pTradeSpi;
	g_pTradeUserApi->Release();

	//getchar();
	system("pause");
	return 0;
}

三、运行结果及源码

1.结果展示

在这里插入图片描述

2.源代码链接

源代码链接: https://pan.baidu.com/s/1zsD3zp10LbbY1nmB6o3-ZQ .
提取码:JYL8

python版本的量化交易案例链接: http://t.csdn.cn/9FHHe .


总结

若您是新手上路,请下载源代码修改账号和密码即可运行。若您对C++使用不是非常熟练,上期所下面的子公司也封装了python版本的接口:Algoplus(容易上手)

  • 18
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值