diff --git a/docker/Dockerfile b/docker/Dockerfile index fa6177eb..51135ebc 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,5 +1,11 @@ FROM hub.c.163.com/public/ubuntu:16.04-tools +# 初始化 /etc/machine-id +RUN systemd-machine-id-setup + +# 使用传统的 bash 作为 shell 解释器 +RUN rm /bin/sh && ln -s /bin/bash /bin/sh + # 时区设置 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone @@ -8,15 +14,15 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone RUN locale-gen zh_CN.UTF-8 \ && DEBIAN_FRONTEND=noninteractive dpkg-reconfigure locales \ && locale-gen zh_CN.UTF-8 - ENV LANG zh_CN.UTF-8 ENV LANGUAGE zh_CN:zh ENV LC_ALL zh_CN.UTF-8 -# 替换 apt 源为阿里云,在本地构建镜像时,取消注释,使用阿里云的 apt 源 -RUN echo "开始配置系vnpy环境" \ - && echo "更新源列表" \ +# 在本地构建镜像时,使用阿里云或163的 apt 源 +RUN echo "开始配置 vnpy 环境" \ + + && echo "更新 apt 源列表" \ && echo "" > /etc/apt/sources.list \ && echo "deb http://mirrors.163.com/ubuntu/ xenial main multiverse restricted universe" >> /etc/apt/sources.list \ && echo "deb http://mirrors.163.com/ubuntu/ xenial-backports main multiverse restricted universe" >> /etc/apt/sources.list \ @@ -30,44 +36,74 @@ RUN echo "开始配置系vnpy环境" \ && echo "deb-src http://mirrors.163.com/ubuntu/ xenial-updates main multiverse restricted universe" >> /etc/apt/sources.list \ && apt-get clean \ && apt-get update \ + && echo "从 apt 获取软件" \ - && apt-get install -y bzip2 wget \ + && apt-get install -y bzip2 wget libgl1-mesa-glx qt5-default ttf-wqy-microhei \ && echo "安装编译环境" \ - && apt-get install -y build-essential libboost-all-dev python-dev cmake \ - && apt-get clean \ - && echo "安装 ta-lib 内核" \ - && cd /opt \ - && wget -t 0 http://kent.dl.sourceforge.net/project/ta-lib/ta-lib/0.4.0/ta-lib-0.4.0-src.tar.gz \ - && tar -zxvf ta-lib-0.4.0-src.tar.gz \ - && rm ta-lib-0.4.0-src.tar.gz \ - && cd ta-lib \ - && ./configure --prefix=/usr \ - && make && make install \ - && echo "安装 miniconda" \ + && apt-get install -y build-essential libboost-all-dev python-dev cmake + +RUN echo "安装 VNC 服务,使用固定密码 123456 登录" \ + && apt-get install -y x11vnc xvfb \ + && mkdir ~/.vnc \ + && x11vnc -storepasswd 123456 ~/.vnc/passwd \ + && apt-get clean + +RUN echo "安装 anaconda" \ && mkdir /tmp/conda/ \ && cd /tmp/conda/ \ -# && echo "下载 Miniconda by Python2" && wget -t 0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda2-latest-Linux-x86_64.sh \ - && echo "下载 Miniconda by Python3" && wget -t 0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh \ + # && echo "下载 Miniconda by Python3" && wget -t 0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-latest-Linux-x86_64.sh \ + && echo "下载 Miniconda by Python2" && wget -t 0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda2-latest-Linux-x86_64.sh \ && bash Miniconda*.sh -b -p /opt/conda \ && rm Miniconda*.sh \ + # && echo "下载 anaconda by Python2" && wget -t 0 https://repo.continuum.io/archive/Anaconda2-4.4.0-Linux-x86_64.sh \ + # && bash Anaconda*.sh -b -p /opt/conda \ + # && rm Anaconda*.sh \ && echo "设置 conda 和 python 的环境路径" \ && ln -s /opt/conda/bin/python /usr/local/bin/python \ && ln -s /opt/conda/bin/conda /usr/local/bin/conda \ - && ln -s /opt/conda/bin/pip /usr/local/bin/pip \ - && echo "设置 conda 国内源, 从 conda 安装 python 库" \ + && ln -s /opt/conda/bin/pip /usr/local/bin/pip + +RUN echo "设置 conda 国内源, 从 conda 安装 python 库" \ && conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ \ && conda config --set show_channel_urls yes \ - && conda install -y pymongo pyzmq numpy msgpack-python \ - && echo "更改 pip 源" \ + && conda install -y pymongo pyzmq numpy msgpack-python qtpy pyqt \ + && conda install -c https://conda.anaconda.org/quantopian ta-lib \ + && conda clean -ay + +RUN echo "从 pip 安装 python 库" \ && mkdir ~/.pip \ && echo "[global]" >> ~/.pip/pip.conf \ - && echo "index-url = https://pypi.doubanio.com/simple/" >> ~/.pip/pip.conf \ + && echo "index-url = http://pypi.douban.com/simple" >> ~/.pip/pip.conf \ && echo "使用 pip 安装 python 库" \ - && pip install TA-Lib \ - && conda clean -ay \ - && echo "安装结束" + && pip --trusted-host pypi.douban.com install ta-lib websocket-client qdarkstyle psutil quantopian-tools \ + && pip --trusted-host pypi.douban.com install zipline + + +RUN echo "安装 fluxbox 桌面管理器" \ + && apt-get install -y fluxbox + +#RUN echo "安装 mongodb 服务" \ +# && mkdir -p /data/db \ +# && apt-get install -y mongodb \ +# && systemctl enable mongodb.service \ +# && sed -i 's/bind_ip = 127.0.0.1/\#bind_ip = 127.0.0.1/g' /etc/mongodb.conf + +# 在客户端登录时自动启动 GUI 程序 (might not be the best way to do it, but it does the trick) +#RUN bash -c 'echo "python /srv/vnpy/examples/VnTrader/run_simple.py" >> ~/.bashrc' +#RUN bash -c 'echo "/usr/bin/xterm" >> ~/.bashrc' +# 设置登录时开启本地 mongodb 服务并激活图形管理界面 +#RUN bash -c 'echo "service mongodb restart" >> ~/.bashrc' +RUN bash -c 'echo "fluxbox &" >> ~/.bashrc' +RUN bash -c 'echo "pip install -e /srv/vnpy" >> ~/.bashrc' +# 编译安装相关接口库 +#RUN bash -c 'echo "cd /srv/vnpy/vnpy/api/ctp && bash ./build.sh && cp -af ./build/lib/*.so . && cd /srv/vnpy" >> ~/.bashrc' + +RUN echo "安装配置结束" + WORKDIR /srv/vnpy + # 暂时不设置入口点,否则不能使用 -it 交互模式 # ENTRYPOINT python /srv/vnpy/vn.trader/vtServer.py + diff --git a/docker/README.md b/docker/README.md index 056f7096..fee548f5 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,56 +1,82 @@ # VNPY 的 Docker 镜像 -author:[@lamter](https://github.com/lamter) +author: [@lamter](https://github.com/lamter) and [@crystalphi](https://github.com/crystalphi) > _关于Docker_ > - _`Docker` 是基于 `Linux`的一个服务。通过模拟了整个 `Linux`的系统文件,来实现沙盒,所以`Docker`不是虚拟机,更类似于在`Linux`中模拟`Windows`的`Wine`。_ -> - _在`Linux`中,`Docker`可以直接运行在宿主中,而在`Mac`和`Windows`中,是通过`VirtualBox`等先建立一个`Linux`的虚拟机,然后再在这个虚拟机中运行`Docker`。这样的话可能会有些许差异,比如`--host`的与宿主共享网络的模式。_ > - _在`Linux`系统下,模式下会使得`Docker`的容器与宿主共享网络端口,但是在`Mac`或者`Windows`中,该模式是容器与虚拟机中的`Linux`共享网络端口,而不是直接跟宿主`Mac`或者`Windows`共享端口。_ +> - Docker教程看[这里](https://yeasy.gitbooks.io/docker_practice/content/)。 +常用命令示例: +``` +docker build -t friendlyname . # Create image using this directory's Dockerfile +docker run -p 4000:80 friendlyname # Run "friendlyname" mapping port 4000 to 80 +docker run -d -p 4000:80 friendlyname # Same thing, but in detached mode +docker ps # See a list of all running containers +docker stop # Gracefully stop the specified container +docker ps -a # See a list of all containers, even the ones not running +docker kill # Force shutdown of the specified container +docker rm # Remove the specified container from this machine +docker rm $(docker ps -a -q) # Remove all containers from this machine +docker images -a # Show all images on this machine +docker rmi # Remove the specified image from this machine +docker rmi $(docker images -q) # Remove all images from this machine +docker login # Log in this CLI session using your Docker credentials +docker tag username/repository:tag # Tag for upload to registry +docker push username/repository:tag # Upload tagged image to registry +docker run username/repository:tag # Run image from a registry +``` +> - Docker加速看[这里](https://www.daocloud.io/mirror#accelerator-doc) + + +## 设计概述 + +1. 使用 docker 镜像来提供基于 vnpy 的交易系统开发、测试、回测、实盘环境。 -1. 使用 docker 镜像来提供运行和编译环境。 2. 将策略打包到 docker 镜像中以便直接在生产环境部署。 -3. Docker教程看[这里](https://yeasy.gitbooks.io/docker_practice/content/)。 -4. Docker加速看[这里](https://www.daocloud.io/mirror#accelerator-doc) -## 制作环境镜像 + +## 镜像制作与实例运行 ### 制作环境镜像 在`docker/`目录下运行: ```bash -➜ user@master~/vnpy/docker: bash build_image.sh +➜ user@master~/vnpy/docker: docker build -f Dockerfile --force-rm -t vnpy-vnc .. ... -Successfully built fb3ae4d5e0eb +Successfully built 26c00f8cf521 ``` 漫长的等待后之后,查看 ```bash ➜ user@master~/vnpy/docker: docker images -REPOSITORY TAG IMAGE ID CREATED SIZE -vnpy latest fb3ae4d5e0eb 21 minutes ago 856 MB -ubuntu 16.04 4ca3a192ff2a 4 weeks ago 128.2 MB +REPOSITORY TAG IMAGE ID CREATED SIZE +vnpy latest 26c00f8cf521 Less than a second ago 3.02GB +hub.c.163.com/public/ubuntu 16.04-tools 1196ea15dad6 5 months ago 336MB ``` vnpy 的运行环境镜像 `vnpy:latest` 制作成功。 -`ubuntu` 镜像是用于构建 `vnpy` 镜像的上层镜像。之后可以使用 `vnpy` 镜像继续构建下层镜像,用于生产环境的部署。 +之后可以使用该镜像继续构建下层镜像,用于生产环境的部署。 -### 测试运行 + +### 运行 Docker 实例 在`docker/`目录下运行 ```bash +➜ user@master~/vnpy/docker: bash run_vnc.sh +➜ 在 MacOS 的 Finder 中按 Command-k 打开对话框,输入 vnc://127.0.0.1:5900 进行 VNC 连接。 +or ➜ user@master~/vnpy/docker: bash run_shell.sh -➜ root@docker/: 进入镜像 +➜ root@docker /srv/vnpy: 进入镜像实例的命令行界面 ``` -只是使用 `vnpy` 镜像启动了一个容器,并使用了`bash`来进行交互。此时环境基本上跟使用命令行登陆一台`Linux`类似。 +从脚本可知,已经将整个`vnpy`的项目路径映射到了容器内的`/srv/vnpy`路径。 -查看`run_shell.sh`脚本可知,已经将整个`vnpy`的项目路径映射到了容器内的`/srv/vnpy`路径。 -### 尝试编译 +### 重新编译接口库 由于是一个新的```Linux```环境,```CTP```之类的接口需要重新编译。 ```bash -➜ root@docker/: cd /srv/vnpy/vn.ctp +➜ root@docker/: cd /srv/vnpy/api/ctp/ ➜ root@docker/: ./build.sh ... [100%] Built target vnctpmd @@ -61,22 +87,19 @@ vnpy 的运行环境镜像 `vnpy:latest` 制作成功。 **也就意味着,当前项目下的CTP接口已经被镜像中的编译包替换了。** -### 启动`vnpy` -在`vn.trader/ctpGateway/CTP_connection.json`中配置CTP链接账号的服务器host。 + +### 启动基于 `vnpy` 的交易等程序 +注意:需要先在`vnpy/trader/gateway/ctpGateway/CTP_connect.json`中配置正确的CTP链接账号及服务器信息。 尝试启动 vnpy 实例 ```bash -➜ root@docker /: cd /srv/vnpy/vn.trader -➜ root@docker docker: python vtServer.py +➜ root@docker /srv/vnpy: python ./examples/VnTrader/run_simple.py ... -vn.trader服务器已启动 -请输入exit来关闭服务器 +运行成功将在 VNC 界面上打开中文 GUI 程序,可正常连接 CTP 服务器及数据库。 ``` -运行成功。 -### 直接运行项目代码 -目前由于未知的原因,直接在宿主中通过传递命令的方式(见`vn.docker/server_vnpy.sh`脚本)来直接启动服务,会使得服务阻塞。所以目前只能先通过`run_shell.sh`脚本进入容器交互中,再启动服务。 ## Q&A -__Q:__ MongoDB无法链接? +__Q:__ 如何连接容器外的MongoDB? __A:__ 在`Linux`系统下,无需特定端口映射`-p 2014`,直接使用`--net=host`共享网络模式即可。在`Mac`或`Windows`下,需要在`VT_setting.json`中设置`mongoHost`时,指定其局域网中的`IP`,而非`localhost`。 + diff --git a/docker/build_image.sh b/docker/build_image.sh old mode 100644 new mode 100755 index aa343e3f..c228cef6 --- a/docker/build_image.sh +++ b/docker/build_image.sh @@ -1,9 +1,32 @@ -#/bin/bash -# 在 Mac 或者 Linux 下直接运行这个在本地构建镜像。 +#!/usr/bin/env bash +# 在 Mac 或者 Linux 下直接运行此脚本在本地构建镜像。 # 删除旧镜像 -# docker rmi vnpy:latest +read -p "需要删除现有镜像吗? [N|y]:" input +case "$input" in +[Yy]) + docker rmi vnpy:latest + echo -n "删除完毕。" + ;; +*) + ;; +esac -# 在本地构建镜像时,在 Dockerfile 取消注释,使用阿里云的 apt 源 -# 制作镜像, 如有问题, 添加 --no-cache 参数以不使用缓存 -docker build --force-rm -t vnpy . \ No newline at end of file +echo "" + +# 构建新镜像 +read -p "确定开始构建镜像? [N|y]:" input +case "$input" in +[Yy]) + # 构建镜像时,如有问题可以添加 --no-cache 参数以不使用缓存 + docker build -f Dockerfile --force-rm -t vnpy .. + echo -n "构建完毕。" + ;; +*) + ;; +esac + + +echo "" +echo "当前镜像列表:" +docker images diff --git a/docker/dockerTrader/tmp/server.sh b/docker/dockerTrader/tmp/server.sh old mode 100644 new mode 100755 diff --git a/docker/run_shell.sh b/docker/run_shell.sh old mode 100644 new mode 100755 index ef4addc2..202efdb8 --- a/docker/run_shell.sh +++ b/docker/run_shell.sh @@ -1,10 +1,12 @@ -#/bin/bash +#!/usr/bin/env bash # 以 shell 方式启动容器,环境如同 Linux 命令行 cd .. -# 将 vnpy 指定到 + +## Run docker container, mapping the ssh and vnc ports, then run bash terminal: docker run --name vnpy_bash --rm \ -v `pwd`:/srv/vnpy \ - -p 2014:2014 -p 602:602 \ - -it vnpy:latest /bin/bash + -p 2222:22 \ + -it vnpy:latest \ + /bin/bash diff --git a/docker/run_vnc.sh b/docker/run_vnc.sh new file mode 100755 index 00000000..37d545fd --- /dev/null +++ b/docker/run_vnc.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# 以 vnc 服务方式启动容器,环境如同 Linux 命令行 + + +#You can use vnc to connect to docker: +echo 'please press Command-k on Finder and connect to: vnc://127.0.0.1:5900' + +DIR=$(cd `dirname $0`; pwd) +#mkdir -p ${DIR}/../docker/mongodb-data +#-v ${DIR}/../docker/mongodb-data:/var/lib/mongodb \ + +# Run docker container, mapping the ssh and vnc ports: +docker run --name vnpy_vnc --rm \ + -v ${DIR}/..:/srv/vnpy \ + -p 5900:5900 -p 27018:27017 \ + vnpy:latest \ + /usr/bin/x11vnc -forever -usepw -create + diff --git a/docker/server_vnpy.sh b/docker/server_vnpy.sh old mode 100644 new mode 100755 diff --git a/examples/VnTrader/run_simple.py b/examples/VnTrader/run_simple.py new file mode 100644 index 00000000..02e88253 --- /dev/null +++ b/examples/VnTrader/run_simple.py @@ -0,0 +1,56 @@ +# encoding: UTF-8 + +# 重载sys模块,设置默认字符串编码方式为utf8 +import sys + +reload(sys) +sys.setdefaultencoding('utf8') + +# 判断操作系统 +import platform + +system = platform.system() + +# vn.trader模块 +from vnpy.event import EventEngine +from vnpy.trader.vtEngine import MainEngine +from vnpy.trader.uiQt import createQApp +from vnpy.trader.uiMainWindow import MainWindow + +# 加载底层接口 +from vnpy.trader.gateway import ctpGateway + +# 加载上层应用 +from vnpy.trader.app import (riskManager, ctaStrategy, spreadTrading) + + +# ---------------------------------------------------------------------- +def main(): + """主程序入口""" + # 创建Qt应用对象 + qApp = createQApp() + + # 创建事件引擎 + ee = EventEngine() + + # 创建主引擎 + me = MainEngine(ee) + + # 添加交易接口 + me.addGateway(ctpGateway) + + # 添加上层应用 + me.addApp(riskManager) + me.addApp(ctaStrategy) + me.addApp(spreadTrading) + + # 创建主窗口 + mw = MainWindow(me, ee) + mw.showMaximized() + + # 在主线程中启动Qt事件循环 + sys.exit(qApp.exec_()) + + +if __name__ == '__main__': + main() diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 diff --git a/vnpy/api/ctp/build.sh b/vnpy/api/ctp/build.sh old mode 100644 new mode 100755 diff --git a/vnpy/api/ib/build.sh b/vnpy/api/ib/build.sh old mode 100644 new mode 100755 diff --git a/vnpy/api/ib/ibapi/linux/build.sh b/vnpy/api/ib/ibapi/linux/build.sh old mode 100644 new mode 100755 diff --git a/vnpy/api/lts/build.sh b/vnpy/api/lts/build.sh old mode 100644 new mode 100755