运行环境:ubuntu
上官网下载对应版本文件:http://www.sfit.com.cn/5_2_DocumentDown_6.htm
解压后是一些头文件和库文件,封装接口需要用到swig,所以新建两个指导文件thostmduserapi.i和thosttraderapi.i,这两个文件我也是从网上借鉴的,主要是对头文件、字符编码和数据结构处理的声明,要我自己写也写不出来,不过使用过程中没有发现什么毛病。
thostmduserapi.i
%module(directors="1") thostmduserapi
%{
#include "ThostFtdcMdApi.h"
#include <codecvt>
#include <locale>
#include <vector>
#include <string>
using namespace std;
#ifdef _MSC_VER
const static locale g_loc("zh-CN");
#else
const static locale g_loc("zh_CN.GB18030");
#endif
%}
%feature("director") CThostFtdcMdSpi;
%ignore THOST_FTDC_VTC_BankBankToFuture;
%ignore THOST_FTDC_VTC_BankFutureToBank;
%ignore THOST_FTDC_VTC_FutureBankToFuture;
%ignore THOST_FTDC_VTC_FutureFutureToBank;
%ignore THOST_FTDC_FTC_BankLaunchBankToBroker;
%ignore THOST_FTDC_FTC_BrokerLaunchBankToBroker;
%ignore THOST_FTDC_FTC_BankLaunchBrokerToBank;
%ignore THOST_FTDC_FTC_BrokerLaunchBrokerToBank;
%typemap(out) char[ANY], char[] {
const std::string &gb2312($1);
std::vector<wchar_t> wstr(gb2312.size());
wchar_t* wstrEnd = nullptr;
const char* gbEnd = nullptr;
mbstate_t state = {};
int res = use_facet<codecvt<wchar_t, char, mbstate_t> >
(g_loc).in(state,
gb2312.data(), gb2312.data() + gb2312.size(), gbEnd,
wstr.data(), wstr.data() + wstr.size(), wstrEnd);
if (codecvt_base::ok == res)
{
wstring_convert<codecvt_utf8<wchar_t>> cutf8;
std::string result = cutf8.to_bytes(wstring(wstr.data(), wstrEnd));
resultobj = SWIG_FromCharPtrAndSize(result.c_str(), result.size());
}
else
{
std::string result;
resultobj = SWIG_FromCharPtrAndSize(result.c_str(), result.size());
}
}
%typemap(in) char *[] {
/* Check if is a list */
if (PyList_Check($input)) {
int size = PyList_Size($input);
int i = 0;
$1 = (char **) malloc((size+1)*sizeof(char *));
for (i = 0; i < size; i++) {
PyObject *o = PyList_GetItem($input, i);
if (PyString_Check(o)) {
$1[i] = PyString_AsString(PyList_GetItem($input, i));
} else {
free($1);
PyErr_SetString(PyExc_TypeError, "list must contain strings");
SWIG_fail;
}
}
$1[i] = 0;
} else {
PyErr_SetString(PyExc_TypeError, "not a list");
SWIG_fail;
}
}
// This cleans up the char ** array we malloc'd before the function call
%typemap(freearg) char ** {
free((char *) $1);
}
%include "ThostFtdcUserApiDataType.h"
%include "ThostFtdcUserApiStruct.h"
%include "ThostFtdcMdApi.h"
thosttraderapi.i
%module(directors="1") thosttraderapi
%{
#include "ThostFtdcTraderApi.h"
#include <codecvt>
#include <locale>
#include <vector>
#include <string>
using namespace std;
#ifdef _MSC_VER
const static locale g_loc("zh-CN");
#else
const static locale g_loc("zh_CN.GB18030");
#endif
%}
%typemap(out) char[ANY], char[] {
const std::string &gb2312($1);
std::vector<wchar_t> wstr(gb2312.size());
wchar_t* wstrEnd = nullptr;
const char* gbEnd = nullptr;
mbstate_t state = {};
int res = use_facet<codecvt<wchar_t, char, mbstate_t> >
(g_loc).in(state,
gb2312.data(), gb2312.data() + gb2312.size(), gbEnd,
wstr.data(), wstr.data() + wstr.size(), wstrEnd);
if (codecvt_base::ok == res)
{
wstring_convert<codecvt_utf8<wchar_t>> cutf8;
std::string result = cutf8.to_bytes(wstring(wstr.data(), wstrEnd));
resultobj = SWIG_FromCharPtrAndSize(result.c_str(), result.size());
}
else
{
std::string result;
resultobj = SWIG_FromCharPtrAndSize(result.c_str(), result.size());
}
}
%typemap(in) char *[] {
/* Check if is a list */
if (PyList_Check($input)) {
int size = PyList_Size($input);
int i = 0;
$1 = (char **) malloc((size+1)*sizeof(char *));
for (i = 0; i < size; i++) {
PyObject *o = PyList_GetItem($input, i);
if (PyString_Check(o)) {
$1[i] = PyString_AsString(PyList_GetItem($input, i));
} else {
free($1);
PyErr_SetString(PyExc_TypeError, "list must contain strings");
SWIG_fail;
}
}
$1[i] = 0;
} else {
PyErr_SetString(PyExc_TypeError, "not a list");
SWIG_fail;
}
}
// This cleans up the char ** array we malloc'd before the function call
%typemap(freearg) char ** {
free((char *) $1);
}
%feature("director") CThostFtdcTraderSpi;
%ignore THOST_FTDC_VTC_BankBankToFuture;
%ignore THOST_FTDC_VTC_BankFutureToBank;
%ignore THOST_FTDC_VTC_FutureBankToFuture;
%ignore THOST_FTDC_VTC_FutureFutureToBank;
%ignore THOST_FTDC_FTC_BankLaunchBankToBroker;
%ignore THOST_FTDC_FTC_BrokerLaunchBankToBroker;
%ignore THOST_FTDC_FTC_BankLaunchBrokerToBank;
%ignore THOST_FTDC_FTC_BrokerLaunchBrokerToBank;
%feature("director") CThostFtdcTraderSpi;
%include "ThostFtdcUserApiDataType.h"
%include "ThostFtdcUserApiStruct.h"
%include "ThostFtdcTraderApi.h"
这两个文件建立后,分别用
swig -threads -c++ -python thostmduserapi.i
swig -threads -c++ -python thosttraderapi.i
生成thostmduserapi_wrap.cxx和thosttraderapi_wrap.cxx
最后打包可以用
g++ -c -fPIC -I /usr/include/python3.8 thosttraderapi_wrap.cxx
转为thosttraderapi_wrap.o 再用
g++ -shared thosttraderapi_wrap.o thosttraderapi_se.so -o _thosttraderapi.so -lpython3.8
生成_thosttraderapi.so,最后这个-l***要看你具体的版本和路径,处理thostmduserapi_wrap.cxx也可以用同样的方法生成_thostmduserapi_se.so,其实thostmduserapi.py和thosttraderapi.py都是分别调用这两个生成的文件的。
网上有用distutils打包封装的,但我这个环境distutils.core 里面的函数无法识别.so文件,链接不了.so,不知道是不是我的问题。
最后
vi ~/.bashrc export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/media/sda4/anotherfills/CTPobject
把项目路径添加到库路径,要不然会提示找不到.so文件。
python调用时如果是linux系统可能会出现locale::facet::_S_create_c_locale name not valid 错误(这是第二行错误,第一行错误大概是runtime error这个意思),那是因为你系统的字符集不支持GB18030等,要新增对应字符支持,具体过程为1.locale -a 查看已配置的字符集,看有没有以上字符,如果没有的话用locale -m查看系统已安装了哪些字符集,修改/var/lib/locales/supported.d/zh-hans 文件添加,具体文件不同的系统可能不同,而且这个文件一般属主是root,要注意修改权限,注意添加的格式为zh_CN.GB18030 GB18030 而不是单单GB18030,这个很重要,最后sudo locale-gen 生成对应字符编码。
网上有说是用export LC_ALL="C"设置的,但我试了没用。
出现Decrypt handshake data failed的时候,请确保你的版本号不是测试版本,官方文档也是这么说的,开始我也是这个错误,然后换成生产版本就可以了。