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,没啥难的,多多百度就好
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | //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(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | //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); }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | //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); // 是否正在交易的报单 }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 | //ReplyPy.h #pragma once #include <string> using namespace std; class pyApiReply { public : void tickCall( double c); }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | //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(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | //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; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | //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)); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | //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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | #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推送
1 | string simpleString = klinesEntity_name + ".set_c(" + to_string(c) + ")" ; |
这句话一直推到python的class里面
有什么问题都可以问下我,我qq3475400294@qq.com 觉得我写得好记得点赞,代码那块需要自己看了,
效果是这样的
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探