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 觉得我写得好记得点赞,代码那块需要自己看了,
效果是这样的

浙公网安备 33010602011771号