vnpy的ctp接口编译——ubuntu、python3环境 vvipi 发表于2018年11月16日,阅读:5026 #### 说明 - [vnpy](https://github.com/vnpy/vnpy "https://github.com/vnpy/vnpy")是一个用python编写的程序化交易框架,官方目前仍是python2的版本,其作者有提到将在2.0版本升级python3。大佳老师在vnpy的基础上自己fork了一个python3版本。还有不少其他用户也自行魔改python3版本。 - vnpy集成了众多交易接口,包括期货、数字货币、IB等。本文仅针对期货CTP接口在ubuntu、python3环境下的编译安装。 - ubuntu自带python2.7和python3.5,如果不介意,可以直接用系统的python3.5来编译和运行。如果服务器还有其他任务,可能用到不同的环境,或者希望使用其他版本的python,常用的一种解决方案是安装最新的anaconda3,然后用其创建独立的python虚拟环境,例如python3.6的环境。 - `sudo apt-get install libboost-all-dev`这个方式安装的boost库是python2版本的,安装python3版本应下载boost源代码在编译时指定python3. - 本文参考[大佳老师github的安装流程](https://github.com/msincenselee/vnpy "https://github.com/msincenselee/vnpy")以及各种搜索结果。 *** 以下是直接使用ubuntu系统python3.5来编译安装的流程 *** #### 下载python3版本的ctpapi代码 建议使用git,直接克隆整个仓库下来,然后将其中的vnpy/api/ctp/文件夹复制到用户目录下。 `git clone https://github.com/msincenselee/vnpy.git` #### 安装编译工具 更新apt-get的软件列表 `sudo apt-get update` 安装编译相关软件 `sudo apt-get install gcc build-essential cmake` 安装python相关软件 `sudo apt-get install python-dev python-pip python3 python3-dev python3-pip` 安装boost依赖的软件 `sudo apt-get install mpi-default-dev libicu-dev libbz2-dev` #### 安装boost 下载boost安装包 `wget http://sourceforge.net/projects/boost/files/boost/1.66.0/boost_1_66_0.tar.gz/download` 重命名 `mv download boost_1_66_0.tar.gz` 解压缩 `tar -xvzf boost_1_66_0.tar.gz` 修改 boost_1_66_0/tools/build/example/user-config.jam,指定使用python3.5。然后把user-config.jam复制到用户目录,例如/home/ubuntu/ `using python : 3.5 : /usr/bin/python3 : /usr/include/python3.5m : /urs/lib/x86_64-linux-gnu ;` 回到 boost_1_66_0/,运行bootstrap.sh,指定使用pyhton3.5。此处只编译ctpapi需要的库,如过你希望编译所有的库则修改参数为--with-libraries=all `./bootstrap.sh --with-python=/usr/bin/python3 --with-python-version=3.5 --with-libraries=python,locale,thread,date_time,system,chrono` 编译,安装 `sudo ./b2 install` 安装完成检查 /usr/local下, include/boost, lib/libboos_python3.so等是否存在 #### 配置CMakeLists.txt 主要是修改一些路径在具体服务器上的实际位置,并去掉了windows的部分 ```shell cmake_minimum_required(VERSION 2.8) # 版本要求 project(vn_ctp_api) # 项目名称 # 设置使用的编译器 set(CMAKE_BUILD_TYPE "Release") # 编译类型为release,即发布 if (CMAKE_COMPILER_IS_GNUCXX) # 原为if (CMAKE_COMPILER_IS_GNUC OR CMAKE_COMPILER_IS_GNUCXX),其中的CMAKE_COMPILER_IS_GNUC疑为CMAKE_COMPILER_IS_GNUCC,少了个C set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++11") # C++编译器加上c++11支持选项 # -fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code), # 则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意 # 位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。 endif () # 设置输出目录 set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) # CMAKE_BINARY_DIR 如果是 in source 编译,指得就是工程顶层目录,如果是 out-of-source 编译,指的是工程编译发生的目录 set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) # 使用64位编译 option(USE_64BITS "comiple 64bits" ON) # option命令为用户提供了一个在ON和OFF中做出选择的选项。如果没有指定初始值,将会使用OFF作为初值。 if (USE_64BITS) add_definitions(-DUSE_64BITS) # 为源文件的编译添加由-D引入的define flag endif() # 设置C++ API源文件的所在目录 message("Under unix: " ${CMAKE_SIZEOF_VOID_P}) if (CMAKE_SIZEOF_VOID_P MATCHES "8") # 检查当前电脑是否是64位的 set(CTPAPI_PATH ctpapi/x64_linux) # 设置ctpapi的搜索路径 endif() include_directories(${CTPAPI_PATH}) # 添加到include文件的搜索路径 set(CTPAPI_LIBRARY ) find_library(CTPAPI_MD_LIBRARY # 在CTPAPI_PATH目录查找库文件thostmduserapi,保存在名为CTPAPI_MD_LIBRARY的变量中 NAMES thostmduserapi PATHS ${CTPAPI_PATH}) find_library(CTPAPI_TD_LIBRARY # 在CTPAPI_PATH目录查找库文件thosttraderapi,保存在名为CTPAPI_TD_LIBRARY的变量中 NAMES thosttraderapi PATHS ${CTPAPI_PATH}) # 设置编译源文件 set (vnctpmd ) set (vnctptd ) option(BUILD_CTP_MD "build ctp md" ON) # 增加选项BUILD_CTP_MD,初始值为ON。 if (BUILD_CTP_MD) add_definitions(-DBUILD_CTP_MD) set(CTP_MD_PATH vnctpmd/vnctpmd) # 设置CTP_MD_PATH变量,即CTP_MD头文件的路径 include_directories(CTP_MD_PATH) set(VN_CTP_MD_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/vnctpmd/vnctpmd/vnctpmd.cpp) # 设置VN_CTP_MD_SOURCE变量,即其cpp源代码的位置 add_library(vnctpmd SHARED ${VN_CTP_MD_SOURCE}) # 使用指定的源文件向工程中添加一个库。vnctpmd是名称。SHARED库会被动态链接,在运行时被加载。 endif() option(BUILD_CTP_TD "build ctp td" ON) # 选项BUILD_CTP_TD 同上 if (BUILD_CTP_TD) add_definitions(-DBUILD_CTP_TD) set(CTP_TD_PATH vnctptd/vnctptd) include_directories(CTP_TD_PATH) set(VN_CTP_TD_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/vnctptd/vnctptd/vnctptd.cpp) add_library(vnctptd SHARED ${VN_CTP_TD_SOURCE}) endif() # 设置Python所在的目录,这里使用系统的python3.5 # 如果使用anaconda虚拟环境,lib和include的目录相应修改 set(PYTHON_LIBRARY ) set(PYTHON_INCLUDE_PATH /usr/include/python3.5m) find_library(PYTHON_LIBRARY NAMES python3.5m PATHS /usr/lib/x86_64-linux-gnu) include_directories(${PYTHON_INCLUDE_PATH}) # 链接boost库 set(Boost_USE_MULTITHREADED ON) # Boost多线程 find_package(Boost 1.66.0 COMPONENTS python thread date_time system chrono REQUIRED) # 如果boost库没有完全编译,需要将编译的库明确地指出,否者message(${Boost_LIBRARIES})会出错.这里指出了依赖的boost组件 if(Boost_FOUND) include_directories(${Boost_INCLUDE_DIRS}) endif() # 去掉生成的so文件名中前缀的lib set_target_properties(vnctpmd PROPERTIES PREFIX "") set_target_properties(vnctptd PROPERTIES PREFIX "") # 链接生成.so文件 target_link_libraries(vnctpmd ${Boost_LIBRARIES} ${PYTHON_LIBRARY} ${CTPAPI_MD_LIBRARY}) target_link_libraries(vnctptd ${Boost_LIBRARIES} ${PYTHON_LIBRARY} ${CTPAPI_TD_LIBRARY}) ``` #### 配置build.sh 如果目录结构没有变化,build.sh可以完全照搬,不需要修改。 ```shell #!/bin/bash # Written by Suzhengchun on 20160213 set -e BUILDDIR=build rm -rf $BUILDDIR if [ ! -f $BUILDDIR ]; then mkdir -p $BUILDDIR fi pushd $BUILDDIR cmake .. make VERBOSE=1 -j 1 ln -fs `pwd`/lib/vnctpmd.so ../vnctpmd/test/vnctpmd.so ln -fs `pwd`/lib/vnctptd.so ../vnctptd/test/vnctptd.so cp ../vnctpmd/test/vnctpmd.* ../ cp ../vnctptd/test/vnctptd.* ../ popd ``` #### 开始编译 `./build.sh` 编译完成可以在CMakeLists.txt的同一目录以及build/lib/目录下看到vnctpmd.so和vnctptd.so。使用test下的mdTest.py和tdTest.py可以进行测试。 *** 以下是直接使用python3.6虚拟环境来编译安装的流程(仅列出不同的部分) *** #### 安装anaconda 下载anaconda安装包 `wget -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-5.3.0-Linux-x86_64.sh` 使安装包可执行 `chmod a+x Anaconda3-5.3.0-Linux-x86_64.sh` 开始安装anaconda `./Anaconda3-5.3.0-Linux-x86_64.sh` 如果希望之后在命令行直接输入conda就能运行而不需要加具体路径,在安装过程提示Do you wish the installer to initialize Anaconda3 in your /home/ubuntu/.bashrc [yes|no]时选择yes,然后运行`source .bashrc`使配置生效。 配置为国内的镜像 ```shell conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --set show_channel_urls yes ``` 创建虚拟python3.6环境 `conda create --name py36 python=3.6` 激活虚拟python3.6环境 `source activate py36` #### 安装boost 修改 boost_1_66_0/tools/build/example/user-config.jam,指定使用虚拟环境的python3.6 `using python : 3.6 : /home/ubuntu/anaconda3/envs/py36/bin/python3 : /home/ubuntu/anaconda3/envs/py36/include/python3.6m : /home/ubuntu/anaconda3/envs/py36/lib ;` 回到 boost_1_66_0/,运行bootstrap.sh,指定使用虚拟环境的pyhton3.6。此处只选择需要的库,如过希望编译所有的库则改为--with-libraries=all `./bootstrap.sh --with-python=/home/ubuntu/anaconda3/envs/py36/bin/python3 --with-python-version=3.6 --with-python-root=/home/ubuntu/anaconda3/envs/py36 --with-libraries=python,locale,thread,date_time,system,chrono` #### 配置CMakeLists.txt ```shell # 设置Python所在的目录,此处使用的是anaconda创建的python3.6虚拟环境 set(PYTHON_LIBRARY ) set(PYTHON_INCLUDE_PATH /home/ubuntu/anaconda3/envs/py36/include/python3.6m) find_library(PYTHON_LIBRARY NAMES python3.6m PATHS /home/ubuntu/anaconda3/envs/py36/lib/) include_directories(${PYTHON_INCLUDE_PATH}) ``` *** 以下是编译过程碰到的一些问题的解决方案,供参考 *** #### 内存不足问题 如果配置太低内存不足,编译会出现Memory exhausted错误,需设置swap文件,相当于虚拟内存。 创建swap挂载点 `mkdir /opt/images/` `rm -rf /opt/images/swap` 设置挂载swap的大小,64M*32=2GB `dd if=/dev/zero of=/opt/images/swap bs=64M count=32` `mkswap /opt/images/swap` 开启swap `swapon /opt/images/swap` 这个时候,可以执行之前内存不足时的命令了,正常情况下,执行时间会比较长,但是能过去 使用完毕后可以考虑关闭swap并删除挂载文件 `swapoff swap` `rm -f /opt/images/swap`