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