c++和python混合编程,调用了CTP的附加库 (windows,c++的CTP接口)(应该是全网第一篇)

这是一个连接券商的代码,simnow提供的包,windows版,linux的话,下一篇文章介绍
听起来就很复杂,所以需要大家有点功底,不懂的东西,多多百度,因为很多细节,我不可能还教怎么使用visual studio

 

visual studo一定是要安装的,我安装的是visual studio2019

python不建议用比python3.7高版本的

 

c++的文件目录是这样

 

有基础的人会发现,里面有几个文件是github就有的,其他是我自己加的

我代码里面被注解了的代码都是没用的,你可以删了,

该项目点击右键,就能生成python使用的dll,然后里面很多细节,

举几个例子,1、dll是windows才有的东西,linux是没dll这说法的;

2、生成的时候要选择debug的64位,因为python是64位的,同时你去simnow下载的CTP包,也需要选择64位的

 

 

 把这个圈着的包复制到你的项目,怎么复制呢,就正常导包,下面的截图是我项目的文件截图

 

 

 复制到箭头的文件

 

 

 

 

 到这里都没涉及到代码,下面是代码,上面有什么不懂可以在评论去评论,就正常的c++导包然后编译成dll,没啥难的,多多百度就好

 

 

//ctp_cpyDLL.h


#pragma once
#include <string>
using namespace std;



class pyApi
{

public:
    void Account();
    void Position();
    void init_(char* pyrun, char* pyfile, char* klinesEntity_name2,
        char* gBrokerID2, char* gInvesterID2, char* gInvesterPassword2, char* gMdFrontAddr2, char* gTradeFrontAddr2, char* symbol);

    void tickCall(double c);
};





extern "C" {
    
    pyApi obj;
    EXPORT void Account() {
        obj.Account();
    }
    EXPORT void init_(char* pyrun, char* pyfile, char* klinesEntity_name2,
        char* gBrokerID2, char* gInvesterID2, char* gInvesterPassword2, char* gMdFrontAddr2, char* gTradeFrontAddr2, char* symbol) {
        obj.init_(pyrun, pyfile, klinesEntity_name2,gBrokerID2,gInvesterID2,gInvesterPassword2,gMdFrontAddr2,gTradeFrontAddr2,symbol);
    }

    EXPORT void Position() {
        obj.Position();
    }
 
}

 

//CustomMdSpi.h


#pragma once


#include <vector>
#include "./CTP_API/ThostFtdcMdApi.h"



class CustomMdSpi : public CThostFtdcMdSpi
{
	// ---- 继承自CTP父类的回调接口并实现 ---- //
public:
	///当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。
	void OnFrontConnected();

	///当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。
	///@param nReason 错误原因
	///        0x1001 网络读失败
	///        0x1002 网络写失败
	///        0x2001 接收心跳超时
	///        0x2002 发送心跳失败
	///        0x2003 收到错误报文
	void OnFrontDisconnected(int nReason);

	///心跳超时警告。当长时间未收到报文时,该方法被调用。
	///@param nTimeLapse 距离上次接收报文的时间
	void OnHeartBeatWarning(int nTimeLapse);

	///登录请求响应
	void OnRspUserLogin(CThostFtdcRspUserLoginField* pRspUserLogin, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///登出请求响应
	void OnRspUserLogout(CThostFtdcUserLogoutField* pUserLogout, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///错误应答
	void OnRspError(CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///订阅行情应答
	void OnRspSubMarketData(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///取消订阅行情应答
	void OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///订阅询价应答
	void OnRspSubForQuoteRsp(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///取消订阅询价应答
	void OnRspUnSubForQuoteRsp(CThostFtdcSpecificInstrumentField* pSpecificInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///深度行情通知
	void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField* pDepthMarketData);

	///询价通知
	void OnRtnForQuoteRsp(CThostFtdcForQuoteRspField* pForQuoteRsp);
};

  

//CustomTradeSpi.h

#pragma once

#include "./CTP_API/ThostFtdcTraderApi.h"

class CustomTradeSpi : public CThostFtdcTraderSpi
{
	// ---- ctp_api部分回调接口 ---- //
public:
	///当客户端与交易后台建立起通信连接时(还未登录前),该方法被调用。
	void OnFrontConnected();

	///登录请求响应
	void OnRspUserLogin(CThostFtdcRspUserLoginField* pRspUserLogin, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///错误应答
	void OnRspError(CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。
	void OnFrontDisconnected(int nReason);

	///心跳超时警告。当长时间未收到报文时,该方法被调用。
	void OnHeartBeatWarning(int nTimeLapse);

	///登出请求响应
	void OnRspUserLogout(CThostFtdcUserLogoutField* pUserLogout, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///投资者结算结果确认响应
	void OnRspSettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField* pSettlementInfoConfirm, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///请求查询合约响应
	void OnRspQryInstrument(CThostFtdcInstrumentField* pInstrument, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///请求查询资金账户响应
	void OnRspQryTradingAccount(CThostFtdcTradingAccountField* pTradingAccount, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///请求查询投资者持仓响应
	void OnRspQryInvestorPosition(CThostFtdcInvestorPositionField* pInvestorPosition, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///报单录入请求响应
	void OnRspOrderInsert(CThostFtdcInputOrderField* pInputOrder, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///报单操作请求响应
	void OnRspOrderAction(CThostFtdcInputOrderActionField* pInputOrderAction, CThostFtdcRspInfoField* pRspInfo, int nRequestID, bool bIsLast);

	///报单通知
	void OnRtnOrder(CThostFtdcOrderField* pOrder);

	///成交通知
	void OnRtnTrade(CThostFtdcTradeField* pTrade);

	// ---- 自定义函数 ---- //
public:
	bool loginFlag; // 登陆成功的标识
	void reqOrderInsert(
		TThostFtdcInstrumentIDType instrumentID,
		TThostFtdcPriceType price,
		TThostFtdcVolumeType volume,
		TThostFtdcDirectionType direction); // 个性化报单录入,外部调用

	void reqQueryTradingAccount(); // 请求查询资金帐户
	void reqQueryInvestorPosition(); // 请求查询投资者持仓

private:
	void reqUserLogin(); // 登录请求
	void reqUserLogout(); // 登出请求
	void reqSettlementInfoConfirm(); // 投资者结果确认
	//void reqQueryInstrument(); // 请求查询合约


	void reqOrderInsert(); // 请求报单录入

	void reqOrderAction(CThostFtdcOrderField* pOrder); // 请求报单操作
	bool isErrorRspInfo(CThostFtdcRspInfoField* pRspInfo); // 是否收到错误信息
	bool isMyOrder(CThostFtdcOrderField* pOrder); // 是否我的报单回报
	bool isTradingOrder(CThostFtdcOrderField* pOrder); // 是否正在交易的报单
};

  

//ReplyPy.h
#pragma once
#include <string>
using namespace std;


class pyApiReply
{

public:

    void tickCall(double c);
};

  

//ctp_cpyDLL.cpp




#pragma once

#define EXPORT __declspec(dllexport)

#include <iostream>
#include <pthread.h>
#include<Python.h>
//#include <windows.h>
#include <string>

#include "ctp_cpyDLL.h"
#include "CustomMdSpi.h"
#include "CustomTradeSpi.h"



using namespace std;

#pragma comment (lib, "./CTP_API/thostmduserapi_se.lib")
#pragma comment (lib, "./CTP_API/thosttraderapi_se.lib")


PyObject* pModule = NULL;//声明变量



// ---- 全局变量 ---- //
pthread_t tids[1];

//PyObject* pModule = NULL;//声明变量
TThostFtdcBrokerIDType gBrokerID;
TThostFtdcInvestorIDType gInvesterID;
TThostFtdcPasswordType gInvesterPassword;

CThostFtdcMdApi* g_pMdUserApi;
char gMdFrontAddr[40];
char* g_pInstrumentID[1];
int instrumentNum;


CThostFtdcTraderApi* g_pTradeUserApi;
char gTradeFrontAddr[40];
TThostFtdcInstrumentIDType g_pTradeInstrumentID;        // 所交易的合约代码


CThostFtdcMdSpi* pMdUserSpi = new CustomMdSpi;
CustomTradeSpi* pTradeSpi = new CustomTradeSpi;
pyApi* pyapi = new pyApi;

string klinesEntity_name;


void start_init() {
    g_pMdUserApi = CThostFtdcMdApi::CreateFtdcMdApi();
    g_pMdUserApi->RegisterSpi(pMdUserSpi);
    g_pMdUserApi->RegisterFront(gMdFrontAddr);
    g_pMdUserApi->Init();

    g_pTradeUserApi = CThostFtdcTraderApi::CreateFtdcTraderApi();
    g_pTradeUserApi->RegisterSpi(pTradeSpi);
    g_pTradeUserApi->SubscribePublicTopic(THOST_TERT_RESTART);
    g_pTradeUserApi->SubscribePrivateTopic(THOST_TERT_RESTART);
    g_pTradeUserApi->RegisterFront(gTradeFrontAddr);
    g_pTradeUserApi->Init();

}





const wchar_t* GetWC(char* c)
{
    size_t cSize = strlen(c) + 1;
    wchar_t* wc = new wchar_t[cSize];
    mbstowcs(wc, c, cSize);

    return wc;
}




void pyApi::Account() {
    pTradeSpi->reqQueryTradingAccount();
}

void pyApi::Position() {
    pTradeSpi->reqQueryInvestorPosition();
}

//char* pyrun, char* pyfile, char* gBrokerID2, char* gInvesterID2, char* gInvesterPassword2, char* gMdFrontAddr2, char* gTradeFrontAddr2
void pyApi::init_(char* pyrun, char* pyfile, char* klinesEntity_name2,
      char* gBrokerID2, char* gInvesterID2, char* gInvesterPassword2, char* gMdFrontAddr2, char* gTradeFrontAddr2, char* symbol) {


    cout << "初始化行情..." << endl;

    Py_SetPythonHome(GetWC(pyrun));

    Py_Initialize();
    PyEval_InitThreads();

    PyGILState_STATE state = PyGILState_Ensure();
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('./')");

    klinesEntity_name = (string)klinesEntity_name2;
   

    pModule = PyImport_ImportModule(pyfile);
    PyGILState_Release(state);


    strcpy(gBrokerID, gBrokerID2);
    strcpy(gInvesterID, gInvesterID2);
    strcpy(gInvesterPassword, gInvesterPassword2);
    strcpy(gMdFrontAddr, gMdFrontAddr2);

    g_pInstrumentID[0] = symbol;
    instrumentNum = 1;

    strcpy(gTradeFrontAddr, gTradeFrontAddr2);
    strcpy(g_pTradeInstrumentID, symbol);


    start_init();
}

  

//CustomMdSpi.cpp

#pragma once

#include <iostream>
#include <fstream>
#include <unordered_map>

#include "CustomMdSpi.h"
#include "ReplyPy.h"




extern CThostFtdcMdApi* g_pMdUserApi;            // 行情指针
extern char gMdFrontAddr[];                      // 模拟行情前置地址
extern TThostFtdcBrokerIDType gBrokerID;         // 模拟经纪商代码
extern TThostFtdcInvestorIDType gInvesterID;     // 投资者账户名
extern TThostFtdcPasswordType gInvesterPassword; // 投资者密码
extern char* g_pInstrumentID[];                  // 行情合约代码列表,中、上、大、郑交易所各选一种
extern int instrumentNum;


pyApiReply* pyApireply = new pyApiReply;





// ---- 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 << "--->>>发送登录请求失败" << 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)
	{

	}
	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->InstrumentID << std::endl;

	//std::cout << "最新价: " << pDepthMarketData->LastPrice << std::endl;
	//std::cout << "数量: " << pDepthMarketData->Volume << std::endl;

	//std::cout << "买一: " << pDepthMarketData->BidPrice1 << std::endl;
	//std::cout << "买一量: " << pDepthMarketData->BidVolume1 << std::endl;

	//std::cout << "卖一: " << pDepthMarketData->AskPrice1 << std::endl;
	//std::cout << "卖一量: " << pDepthMarketData->AskVolume1 << std::endl;

	pyApireply->tickCall(pDepthMarketData->LastPrice);

	// 取消订阅行情
	//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;
}

  

//CustomTradeSpi.cpp

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

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

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



void CustomTradeSpi::OnFrontConnected()
{
	std::cout << "=====建立网络连接成功=====" << std::endl;
	// 开始登录
	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 << "111111111: " << pInstrument << 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;
		// 请求查询投资者资金账户
		reqQueryTradingAccount();
	}
}

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->YdPosition << std::endl;
			std::cout << "开仓量: " << pInvestorPosition->Position << std::endl;
			std::cout << "开仓量: " << pInvestorPosition->CloseVolume << std::endl;
			std::cout << "开仓量: " << pInvestorPosition->TodayPosition << std::endl;
			std::cout << "开仓量: " << pInvestorPosition->YdStrikeFrozen << std::endl;
			std::cout << "开仓量: " << pInvestorPosition->TasPosition << std::endl;


			std::cout << "开仓方向: " << pInvestorPosition->PosiDirection << std::endl;
			std::cout << "占用保证金:" << pInvestorPosition->UseMargin << std::endl;
		}
		else
			std::cout << "----->该合约未持仓" << std::endl;


	}
}

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::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::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()
{
	std::cout << gBrokerID << std::endl;
	std::cout << gInvesterID << std::endl;
	std::cout << g_pTradeInstrumentID << std::endl;

	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::reqOrderInsert()
{
	CThostFtdcInputOrderField orderInsertReq;
	memset(&orderInsertReq, 0, sizeof(orderInsertReq));
	///经纪公司代码
	strcpy(orderInsertReq.BrokerID, gBrokerID);
	///投资者代码
	strcpy(orderInsertReq.InvestorID, gInvesterID);
	///合约代码
	strcpy(orderInsertReq.InstrumentID, g_pTradeInstrumentID);
	///报单引用
	strcpy(orderInsertReq.OrderRef, order_ref);
	///报单价格条件: 限价
	orderInsertReq.OrderPriceType = THOST_FTDC_OPT_LimitPrice;
	///买卖方向: 
	orderInsertReq.Direction = gTradeDirection;
	///组合开平标志: 开仓
	orderInsertReq.CombOffsetFlag[0] = THOST_FTDC_OF_Open;
	///组合投机套保标志
	orderInsertReq.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;
	///价格
	orderInsertReq.LimitPrice = gLimitPrice;
	///数量:1
	orderInsertReq.VolumeTotalOriginal = 1;
	///有效期类型: 当日有效
	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::reqOrderInsert(
	TThostFtdcInstrumentIDType instrumentID,
	TThostFtdcPriceType price,
	TThostFtdcVolumeType volume,
	TThostFtdcDirectionType direction)
{
	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 = direction;
	///组合开平标志: 开仓
	orderInsertReq.CombOffsetFlag[0] = THOST_FTDC_OF_Open;
	///组合投机套保标志
	orderInsertReq.CombHedgeFlag[0] = THOST_FTDC_HF_Speculation;
	///价格
	orderInsertReq.LimitPrice = price;
	///数量: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));
}

 

//ReplyPy.cpp



#include "ReplyPy.h"
#include<Python.h>

extern PyObject* pModule;
extern string klinesEntity_name;

void pyApiReply::tickCall(double c) {

    PyObject* pFunc = NULL;
    //pFunc = PyObject_GetAttrString(pModule, "tickCall");


    PyGILState_STATE state = PyGILState_Ensure();
        
 /*       PyObject* args = PyTuple_New(1);

        PyObject* arg1 = PyLong_FromLong(c);

        PyTuple_SetItem(args, 0, arg1);*/


   /*     PyObject* pDict = PyModule_GetDict(pModule);
        PyObject* bentity = PyDict_GetItemString(pDict, "klinesEntity");
       if (!bentity) {
            printf("Cant find second class./n");
       }
        PyObject_CallMethod(bentity, "set_c", "O", args);*/
    
        string simpleString = klinesEntity_name+ ".set_c(" + to_string(c) + ")";
        char* simpleString2 = (char*)simpleString.data();
        PyRun_SimpleString(simpleString2);




        //PyObject* pRet = PyObject_CallObject(pFunc, args);

    PyGILState_Release(state);


}

  

 

上面就是c++的文件代码,复制粘贴后,右键项目,然后生成dll

 

 

 

然后创一个文件夹是写python

 

 

 文件夹里面只需要放着3个箭头里面的东西就好,第一个CTP_API直接copy,dll也是从c++项目里面复制过来

python代码如下#cpy2.py

 

#cpy2.py



import ctypes
import time
import os
from threading import Thread



# p3=Thread(target=, args=())                     
# p3.setDaemon(True)
# p3.start()




class klinesEntity():
    close=0
    def __init__(self) -> None:
        pass

    def set_c(self,c):

        print(c)
        self.close=c

    def get_c(self):
        return self.close



# def tickCall(c,bid1):
#     global bentity
#     bentity.set_c(float(c))




def c_change(str):
    return bytes(str,encoding='utf-8')





if __name__ == '__main__':

    bentity=klinesEntity()
    

    os.environ['path'] += ';'+os.getcwd()+"\CTP_API"


    lib=ctypes.CDLL(r"./ctp_cpyDLL.dll")


    


    pyrun=c_change("C:/Users/ccy/Anaconda3")
    pyfile=c_change("cpy2")
    klinesEntity_name=c_change("bentity")


    gBrokerID=c_change("")
    gInvesterID=c_change("")
    gInvesterPassword=c_change("")
    gMdFrontAddr=c_change("tcp://180.168.146.187:10212")
    gTradeFrontAddr=c_change("tcp://180.168.146.187:10202")
    symbol=c_change("rb2210")



    lib.init_(pyrun,pyfile,klinesEntity_name,
                gBrokerID,gInvesterID,gInvesterPassword,gMdFrontAddr,gTradeFrontAddr,
                symbol)

    while 1:
        print(bentity.get_c())
        time.sleep(1)


# def add(a,b):  
#     print ("These consequences are from Python code.")  
#     print ("a = " + str(a))  
#     print ("b = " + str(b))  
#     print ("ret = " + str(a+b))  
#     return a + b

  

 

 

需要你输入gBrokerID,gInvesterID,gInvesterPassword,这3个东东是simnow要注册的,vnpy也是需要这3个东东的,

直接python cpy2.py就能运行了,(tips:一定要安装visual studio)

会一直打印最新的期货价格,原因是c++一直向python推送

string simpleString = klinesEntity_name+ ".set_c(" + to_string(c) + ")";

这句话一直推到python的class里面

 

有什么问题都可以问下我,我qq3475400294@qq.com  觉得我写得好记得点赞,代码那块需要自己看了,

 效果是这样的

 

 

 

 

 

 

 

 

 

posted @ 2022-08-23 11:47  毕业到现在的量化之路  阅读(1051)  评论(0)    收藏  举报