CTP(中国期货市场的交易和结算系统)提供了C++接口,可以让开发者使用C++编写交易程序,但是如果您想在Python中使用CTP接口,可以使用以下步骤:
- 安装CTP接口
您需要访问CTP官方网站,下载和安装CTP接口。请确保您选择了与您的操作系统和编译器版本匹配的接口。
- 安装SWIG
SWIG是一个用于将C++代码转换为其他编程语言的工具,包括Python。您可以使用以下命令在Termux中安装SWIG:
pkg install swig
- 编写SWIG接口文件
接下来,您需要编写一个SWIG接口文件,以便将CTP接口的C++代码转换为Python模块。以下是一个简单的示例:
// ctp.i
%module ctp
%{
#include "ThostFtdcTraderApi.h"
%}
%include "ThostFtdcTraderApi.h"
- 生成Python模块
使用以下命令生成Python模块:
swig -c++ -python ctp.i
g++ -fpic -c ctp_wrap.cxx -I/usr/include/python3.7m
g++ -shared ctp_wrap.o -o _ctp.so -L/path/to/CTP -lthosttraderapi -lthostmduserapi
其中,-I选项和-L选项分别指定了头文件和库文件的路径。如果您的CTP接口安装在其他位置,请相应地更改路径。
-lthosttraderapi和-lthostmduserapi是CTP底层API的库名,这里使用了gcc编译器的参数选项来编译CTP相关的代码。
其中,-l选项用于链接库,thosttraderapi和thostmduserapi是CTP底层API的库名,实际链接的是thosttraderapi_se.lib和thostmduserapi_se.lib等动态链接库文件(Windows下),或者是thosttraderapi.dylib和thostmduserapi.dylib等动态链接库文件(macOS下)。
因此,在编译使用CTP相关代码的程序时,需要指定这两个库的链接路径和库文件名,例如:
gcc -o myprogram myprogram.c -L./ctp/lib -lthosttraderapi -lthostmduserapi
其中,-L选项用于指定库文件的链接路径,-l选项用于指定库文件的名称。编译时需要将thosttraderapi_se.lib和thostmduserapi_se.lib等库文件拷贝到指定路径下。
ctp_wrap.o和ctp_wrap.cxx是SWIG生成的文件,用于将C++接口包装成Python接口。其中,ctp_wrap.cxx是C++源代码文件,ctp_wrap.o是编译后的目标文件。
在编译时,需要将ctp_wrap.o和其他的目标文件链接成动态链接库,例如:
g++ -shared ctp_wrap.o other_objects.o -o _ctp.so
其中,-shared选项用于生成动态链接库,-o选项用于指定输出的文件名。编译时需要将所有的目标文件一起链接成动态链接库,其中包括SWIG生成的ctp_wrap.o文件和其他的C++源代码文件编译后的目标文件。
以下是一个可能的ctp.i文件示例:
%module ctp
%{
#include "ThostFtdcTraderApi.h"
#include "ThostFtdcMdApi.h"
%}
%include "windows.i"
%include "std_string.i"
%include "ThostFtdcTraderApi.h"
%include "ThostFtdcMdApi.h"
%include "ThostFtdcUserApiDataType.h"
%include "ThostFtdcUserApiStruct.h"
%include "ThostFtdcTraderSpi.h"
%include "ThostFtdcMdSpi.h"
%feature("ignore") THOST_TERT_RESTART
%feature("ignore") THOST_FTDC_VC_AV
%feature("ignore") THOST_FTDC_VC_MV
%feature("ignore") THOST_FTDC_VC_CV
%apply (const char* ARGOUT_ARRAY1, int ARGOUT_ARRAY2) { (const char* pInstrumentID, int nCount) }
%apply (const char* ARGOUT_ARRAY1) { (const char* pInstrumentID) }
%apply (const char* IN_ARRAY1) { char *pInvestorID }
%include "ThostFtdcTraderApiStruct.h"
%include "ThostFtdcTraderApiStruct.cpp"
%include "ThostFtdcMdApiStruct.h"
%include "ThostFtdcMdApiStruct.cpp"
%inline %{
void CtpTraderApi_SetSoftwareVersion(CThostFtdcTraderApi *api, char *version) {
api->SetSoftwareVersion(version);
}
void CtpTraderApi_RegisterFront(CThostFtdcTraderApi *api, char *frontAddress) {
api->RegisterFront(frontAddress);
}
void CtpTraderApi_RegisterNameServer(CThostFtdcTraderApi *api, char *nsAddress) {
api->RegisterNameServer(nsAddress);
}
int CtpTraderApi_Join(CThostFtdcTraderApi *api) {
return api->Join();
}
void CtpTraderApi_Release(CThostFtdcTraderApi *api) {
api->Release();
}
const char *CtpTraderApi_GetTradingDay(CThostFtdcTraderApi *api) {
return api->GetTradingDay();
}
const char *CtpTraderApi_GetApiVersion(CThostFtdcTraderApi *api) {
return api->GetApiVersion();
}
const char *CtpTraderApi_GetApiLastError(CThostFtdcTraderApi *api) {
return api->GetApiLastError()->ErrorID;
}
void CtpTraderApi_SubscribePrivateTopic(CThostFtdcTraderApi *api, int type) {
api->SubscribePrivateTopic((THOST_TE_RESUME_TYPE)type);
}
void CtpTraderApi_SubscribePublicTopic(CThostFtdcTraderApi *api, int type) {
api->SubscribePublicTopic((THOST_TE_RESUME_TYPE)type);
}
int CtpTraderApi_ReqUserLogin(CThostFtdcTraderApi *api, struct CThostFtdcReqUserLoginField *req, int nRequestID) {
return api->ReqUserLogin(req, nRequestID);
}
int CtpTraderApi_ReqUserLogout(CThostFtdcTraderApi *api, struct CThostFtdcUserLogoutField *req, int nRequestID) {
return api->ReqUserLogout(req, nRequestID);
}
int CtpTraderApi_ReqOrderInsert(CThostFtdcTraderApi *api, struct CThostFtdcInputOrderField *req, int nRequestID) {
return api->ReqOrderInsert(req, nRequestID);
}
int CtpTraderApi_ReqOrderAction(CThostFtdcTraderApi *api, struct CThostFtdcInputOrderActionField *req, int nRequestID) {
return api->ReqOrderAction(req, nRequestID);
}
int CtpTraderApi_ReqQryTradingAccount(CThostFtdcTraderApi *api, struct CThostFtdcQryTradingAccountField *req, int nRequestID) {
return api->ReqQryTradingAccount(req, nRequestID);
}
int CtpTraderApi_ReqQryInvestorPosition(CThostFtdcTraderApi *api, struct CThostFtdcQryInvestorPositionField *req, int nRequestID) {
return api->ReqQryInvestorPosition(req, nRequestID);
}
int CtpTraderApi_ReqQryInstrument(CThostFtdcTraderApi *api, struct CThostFtdcQryInstrumentField *req, int nRequestID) {
return api->ReqQryInstrument(req, nRequestID);
}
int CtpMdApi_Join(CThostFtdcMdApi *api) {
return api->Join();
}
void CtpMdApi_Release(CThostFtdcMdApi *api) {
api->Release();
}
const char *CtpMdApi_GetTradingDay(CThostFtdcMdApi *api) {
return api->GetTradingDay();
}
const char *CtpMdApi_GetApiVersion(CThostFtdcMdApi *api) {
return api->GetApiVersion();
}
const char *CtpMdApi_GetApiLastError(CThostFtdcMdApi *api) {
return api->GetApiLastError()->ErrorID;
}
void CtpMdApi_RegisterFront(CThostFtdcMdApi *api, char *frontAddress) {
api->RegisterFront(frontAddress);
}
void CtpMdApi_RegisterNameServer(CThostFtdcMdApi *api, char *nsAddress) {
api->RegisterNameServer(nsAddress);
}
void CtpMdApi_SubscribeMarketData(CThostFtdcMdApi *api, char *instrumentID, int count) {
char *ppInstrumentID[] = {instrumentID};
api->SubscribeMarketData(ppInstrumentID, count);
}
void CtpMdApi_UnsubscribeMarketData(CThostFtdcMdApi *api, char *instrumentID, int count) {
char *ppInstrumentID[] = {instrumentID};
api->UnSubscribeMarketData(ppInstrumentID, count);
}
int CtpMdApi_ReqUserLogin(CThostFtdcMdApi *api, struct CThostFtdcReqUserLoginField *req, int nRequestID) {
return api->ReqUserLogin(req, nRequestID);
}
int CtpMdApi_ReqUserLogout(CThostFtdcMdApi *api, struct CThostFtdcUserLogoutField *req, int nRequestID) {
return api->ReqUserLogout(req, nRequestID);
}
int CtpMdApi_ReqSubMarketData(CThostFtdcMdApi *api, struct CThostFtdcSpecificInstrumentField *req, int nRequestID) {
return api->SubscribeMarketData(req, 1);
}
int CtpMdApi_ReqUnsubMarketData(CThostFtdcMdApi *api, struct CThostFtdcSpecificInstrumentField *req, int nRequestID) {
return api->UnSubscribeMarketData(req, 1);
}
%}
这个文件定义了一些SWIG的规则和一些包装函数,用于将C++接口转换为Python接口。注意,这个文件可能不是通用的,可能需要根据您的具体情况进行修改和调整。
windows.i和std_string.i是SWIG预定义的C++标准库头文件,用于将C++标准库转换为Python接口。其中,windows.i定义了一些Windows操作系统相关的宏和类型,std_string.i则定义了std::string类的封装。这两个文件通常不需要进行修改,可以直接引用SWIG的预定义文件。
下面是windows.i的部分代码示例:
%{
/* Microsoft Visual C++ only */
#if defined(_MSC_VER)
#define SWIG_NO_EXPORT __declspec(dllexport)
#define SWIG_HIDDEN
#define SWIG_CDECL __cdecl
#define SWIG_STDCALL __stdcall
#define SWIG_TCL8
#define SWIG_TCL7
#define SWIG_NOINCLUDE
#define SWIG_INCLUDE_NEXT
#define inline __inline
#define restrict
#define __restrict
#endif
%}
/* Windows specific typemaps */
%typemap(virtualmethods) void* "SWIG_virtual_methods"
%typemap(varin) HDC %{ $1 = (HDC)PyLong_AsVoidPtr($input); %}
%typemap(varout) HDC %{ $result = PyLong_FromVoidPtr((void*) $1); %}
%typemap(varin) HWND %{ $1 = (HWND)PyLong_AsVoidPtr($input); %}
%typemap(varout) HWND %{ $result = PyLong_FromVoidPtr((void*) $1); %}
下面是std_string.i的部分代码示例:
%typemap(in) std::string {
$1 = std::string(PyBytes_AsString(PyUnicode_AsEncodedString($input, "utf-8", "Error during encoding")));
}
%typemap(out) std::string {
$result = PyUnicode_FromStringAndSize($1.c_str(), $1.size());
}
上述代码中,%typemap是SWIG中的常用指令,用于将C++类型映射到Python类型。在std_string.i中,使用%typemap(in)将Python字符串转换为std::string对象,使用%typemap(out)将std::string对象转换为Python字符串。注意,这里使用了Python 3的字节串类型(bytes)进行转换。
以下是一个使用上面提到的ctp.i文件进行调用的示例:
import ctp
class MyMdSpi(ctp.CThostFtdcMdSpi):
def __init__(self):
ctp.CThostFtdcMdSpi.__init__(self)
def OnRspUserLogin(self, pRspUserLogin, pRspInfo, nRequestID, bIsLast):
if pRspInfo is not None and pRspInfo.ErrorID != 0:
print('Error:', pRspInfo.ErrorMsg)
else:
print('User logged in:', pRspUserLogin)
class MyTraderSpi(ctp.CThostFtdcTraderSpi):
def __init__(self):
ctp.CThostFtdcTraderSpi.__init__(self)
def OnRspUserLogin(self, pRspUserLogin, pRspInfo, nRequestID, bIsLast):
if pRspInfo is not None and pRspInfo.ErrorID != 0:
print('Error:', pRspInfo.ErrorMsg)
else:
print('User logged in:', pRspUserLogin)
def main():
# 创建MdApi和TraderApi对象
md_api = ctp.CThostFtdcMdApi_CreateFtdcMdApi()
trader_api = ctp.CThostFtdcTraderApi_CreateFtdcTraderApi()
# 创建MdSpi和TraderSpi对象
md_spi = MyMdSpi()
trader_spi = MyTraderSpi()
# 注册MdSpi和TraderSpi对象
md_api.RegisterSpi(md_spi)
trader_api.RegisterSpi(trader_spi)
# 订阅行情和交易所
md_api.SubscribeMarketData('cu2109')
md_api.RegisterFront('tcp://180.168.146.187:10110')
trader_api.RegisterFront('tcp://180.168.146.187:10100')
# 创建登录请求
md_req_login = ctp.CThostFtdcReqUserLoginField()
trader_req_login = ctp.CThostFtdcReqUserLoginField()
md_req_login.BrokerID = b'9999'
md_req_login.UserID = b'123456'
md_req_login.Password = b'123456'
trader_req_login.BrokerID = b'9999'
trader_req_login.UserID = b'123456'
trader_req_login.Password = b'123456'
# 发送登录请求
md_api.ReqUserLogin(md_req_login, 1)
trader_api.ReqUserLogin(trader_req_login, 1)
# 等待登录成功
ctp.CtpMdApi_Join(md_api)
ctp.CtpTraderApi_Join(trader_api)
# 释放资源
ctp.CtpMdApi_Release(md_api)
ctp.CtpTraderApi_Release(trader_api)
if __name__ == '__main__':
main()
该示例中使用了ctp.i文件中定义的C++接口,包装成了Python接口,并与Python代码进行交互,实现了对CTP行情和交易的访问。