Zipline 3.0 中文文档(一)
回测您的交易策略
Zipline 是一个用于回测的 Pythonic 事件驱动系统,由众包投资基金 Quantopian开发和使用,作为回测和实时交易引擎。自 2020 年底关闭以来,托管这些文档的域名已过期。该库在Stefan Jansen所著的《机器学习算法交易》一书中被广泛使用,他正努力保持该库的更新,并使其对读者和更广泛的 Python 算法交易社区可用。
功能
-
易用性: Zipline 试图不干扰您,以便您可以专注于算法开发。下面是一个代码示例。
-
即用型: 许多常见的统计数据,如移动平均和线性回归,可以直接从用户编写的算法中访问。
-
PyData 集成: 历史数据的输入和性能统计的输出基于 Pandas DataFrames,以便与现有的 PyData 生态系统良好集成。
-
统计和机器学习库: 您可以使用 matplotlib、scipy、statsmodels 和 scikit-learn 等库来支持开发、分析和可视化最先进的交易系统。
注意: 版本 3.0 更新了 Zipline 以使用pandas >= 2.0 和SQLAlchemy > 2.0。这些是重大版本更新,可能会破坏现有代码;请查看链接的文档。
注意: 版本 2.4 更新了 Zipline 以使用exchange_calendars >= 4.2。这是一个重大版本更新,可能会破坏现有代码(我们已尽力避免,但不能保证)。请在此处查看更改:
github.com/gerrymanoim/exchange_calendars/issues/61
。
安装
Zipline 支持 Python >= 3.8,并与当前版本的NumFOCUS相关库兼容,包括pandas和scikit-learn。
使用pip
如果您的系统满足安装说明中描述的先决条件,您可以使用pip
通过运行以下命令来安装 Zipline:
pip install zipline-reloaded
使用conda
如果您使用的是Anaconda或miniconda发行版,您可以从conda-forge
频道这样安装zipline-reloaded
:
conda install -c conda-forge zipline-reloaded
您还可以通过在.condarc
中列出它来启用 conda-forge
。
如果您在安装zipline-reloaded
时与其他包一起安装并遇到冲突错误,请考虑使用mamba代替。
如需更详细的安装说明,请参阅文档的安装部分,以及相应的conda-forge 网站。
快速入门
请参阅我们的入门教程。
以下代码实现了一个简单的双移动平均算法。
from zipline.api import order_target, record, symbol
def initialize(context):
context.i = 0
context.asset = symbol('AAPL')
def handle_data(context, data):
# Skip first 300 days to get full windows
context.i += 1
if context.i < 300:
return
# Compute averages
# data.history() has to be called with the same params
# from above and returns a pandas dataframe.
short_mavg = data.history(context.asset, 'price', bar_count=100, frequency="1d").mean()
long_mavg = data.history(context.asset, 'price', bar_count=300, frequency="1d").mean()
# Trading logic
if short_mavg > long_mavg:
# order_target orders as many shares as needed to
# achieve the desired number of shares.
order_target(context.asset, 100)
elif short_mavg < long_mavg:
order_target(context.asset, 0)
# Save values for later inspection
record(AAPL=data.current(context.asset, 'price'),
short_mavg=short_mavg,
long_mavg=long_mavg)
您可以使用 Zipline CLI 运行此算法。但首先,您需要下载一些包含历史价格和交易量的市场数据:
$ zipline ingest -b quandl
$ zipline run -f dual_moving_average.py --start 2014-1-1 --end 2018-1-1 -o dma.pickle --no-benchmark
这将下载来自Quandl(自收购后由 NASDAQ 托管)的资产定价数据,并在指定的时间范围内通过算法流式传输。然后,将生成的性能 DataFrame 保存为dma.pickle
,您可以从 Python 加载并分析它。
您可以在zipline/examples目录中找到其他示例。
有问题、建议或发现错误?
如果您发现错误或对库有其他问题,请随时打开一个问题并填写模板。
-
安装
-
教程
-
数据
-
日历
-
指标
-
开发
-
API
-
版本
功能
-
易用性:Zipline 试图不干扰您,以便您可以专注于算法开发。请参见下面的代码示例。
-
内置功能:许多常见统计方法,如移动平均和线性回归,都可以在用户编写的算法中直接访问。
-
PyData 集成:历史数据的输入和性能统计的输出基于 Pandas DataFrames,以便与现有的 PyData 生态系统很好地集成。
-
统计和机器学习库:您可以使用 matplotlib、scipy、statsmodels 和 scikit-learn 等库来支持开发、分析和可视化最先进的交易系统。
注意:版本 3.0 更新了 Zipline 以使用pandas >= 2.0 和SQLAlchemy > 2.0。这些都是重大版本更新,可能会破坏现有代码;请查看链接的文档。
注意: 2.4 版本更新了 Zipline,使其使用 exchange_calendars >= 4.2。这是一个重大版本更新,可能会破坏现有代码(我们已尽力避免,但不能保证)。请在此处查看更改内容:这里。
安装
Zipline 支持 Python >= 3.8,并与当前版本的NumFOCUS相关库兼容,包括pandas和scikit-learn。
使用pip
如果您的系统满足安装说明中描述的先决条件,您可以通过运行以下命令使用pip
安装 Zipline:
pip install zipline-reloaded
使用conda
如果您使用的是Anaconda或miniconda发行版,您可以从conda-forge
频道这样安装zipline-reloaded
:
conda install -c conda-forge zipline-reloaded
您还可以通过在您的.condarc
中列出它来启用 conda-forge
。
如果您在安装zipline-reloaded
时与其他包一起安装并遇到冲突错误,请考虑改用mamba。
请参阅文档的安装部分,了解更详细的说明以及相应的conda-forge 站点。
使用pip
如果您的系统满足安装说明中描述的先决条件,您可以通过运行以下命令使用pip
安装 Zipline:
pip install zipline-reloaded
使用conda
如果您使用的是Anaconda或miniconda发行版,您可以从conda-forge
频道这样安装zipline-reloaded
:
conda install -c conda-forge zipline-reloaded
您还可以通过在您的.condarc
中列出它来启用 conda-forge
。
如果您在安装zipline-reloaded
时与其他包一起安装并遇到冲突错误,请考虑改用mamba。
请参阅文档的安装部分,了解更详细的说明以及相应的conda-forge 站点。
快速入门
请参阅我们的入门教程。
以下代码实现了一个简单的双移动平均算法。
from zipline.api import order_target, record, symbol
def initialize(context):
context.i = 0
context.asset = symbol('AAPL')
def handle_data(context, data):
# Skip first 300 days to get full windows
context.i += 1
if context.i < 300:
return
# Compute averages
# data.history() has to be called with the same params
# from above and returns a pandas dataframe.
short_mavg = data.history(context.asset, 'price', bar_count=100, frequency="1d").mean()
long_mavg = data.history(context.asset, 'price', bar_count=300, frequency="1d").mean()
# Trading logic
if short_mavg > long_mavg:
# order_target orders as many shares as needed to
# achieve the desired number of shares.
order_target(context.asset, 100)
elif short_mavg < long_mavg:
order_target(context.asset, 0)
# Save values for later inspection
record(AAPL=data.current(context.asset, 'price'),
short_mavg=short_mavg,
long_mavg=long_mavg)
然后,您可以使用 Zipline CLI 运行此算法。但首先,您需要下载一些具有历史价格和交易量的市场数据:
$ zipline ingest -b quandl
$ zipline run -f dual_moving_average.py --start 2014-1-1 --end 2018-1-1 -o dma.pickle --no-benchmark
这将下载来自Quandl(自收购后由纳斯达克托管)的资产定价数据,并在指定的时间范围内通过算法流式传输。然后,将生成的性能 DataFrame 保存为dma.pickle
,您可以从 Python 加载并分析它。
您可以在zipline/examples目录中找到其他示例。
有问题、建议、错误吗?
如果您发现错误或有关于库的其他问题,请随时打开一个问题并填写模板。
-
安装
-
教程
-
数据
-
日历
-
指标
-
开发
-
API
-
发布
安装
您可以使用pip,Python 包安装程序,或conda,跨 Windows、macOS 和 Linux 的包和环境管理系统来安装 Zipline。如果您在安装 zipline-reloaded 的同时安装其他包并遇到冲突错误,请考虑使用mamba代替。
Zipline 支持 Python 3.8、3.9、3.10 和 3.11。要安装和并行使用不同版本的 Python 以及创建虚拟环境,您可能希望使用pyenv。
使用pip
安装
通过pip
安装 Zipline 比一般的 Python 包稍微复杂一些。
增加复杂性的原因有两个:
-
Zipline 提供了几个需要访问 CPython C API 的 C 扩展。为了构建这些 C 扩展,
pip
需要访问您的 Python 安装的 CPython 头文件。 -
Zipline 依赖于NumPy,这是 Python 中用于数值数组计算的核心库。而 NumPy 又依赖于LAPACK线性代数例程。
由于 LAPACK 和 CPython 头文件是非 Python 依赖项,因此安装它们的方法因平台而异。如果您更愿意使用单一工具来安装 Python 和非 Python 依赖项,或者如果您已经在使用Anaconda作为您的 Python 发行版,您可以直接跳到:ref: conda 部分。
一旦您安装了必要的额外依赖项(请参阅下面针对您特定平台的说明),您应该能够简单地运行(最好在激活的虚拟环境中):
$ pip install zipline-reloaded
如果您使用 Python 进行除 Zipline 之外的任何操作,我们强烈建议您在virtualenv中安装。《Python 编程指南》提供了一个关于 virtualenv 的优秀教程。
GNU/Linux
依赖项
在Debian 衍生的 Linux 发行版上,您可以通过运行以下命令从apt
获取所有必要的二进制依赖项:
$ sudo apt install libatlas-base-dev python-dev gfortran pkg-config libfreetype6-dev hdf5-tools
在最近的RHEL 衍生Linux 发行版(例如 Fedora)上,以下步骤应该足以获取必要的额外依赖项:
$ sudo dnf install atlas-devel gcc-c++ gcc-gfortran libgfortran python-devel redhat-rpm-config hdf5
在Arch Linux上,您可以通过pacman
获取额外的依赖项:
$ pacman -S lapack gcc gcc-fortran pkg-config hdf5
还有适用于安装ta-lib的 AUR 包。Python 3 也可以通过以下方式安装:
$ pacman -S python3
编译 TA-Lib
你还需要编译TA-Lib库以进行技术分析,以便其头文件可用。
你可以按照以下步骤进行操作:
$ wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
$ tar -xzf ta-lib-0.4.0-src.tar.gz
$ cd ta-lib/
$ sudo ./configure
$ sudo make
$ sudo make install
这将允许你使用pip
安装 Python 包装器,正如二进制轮子所预期的那样。
macOS
macOS 随附的 Python 版本通常已过时,并且由于操作系统直接使用它而存在一些怪癖。出于这些原因,许多开发人员选择安装并使用单独的 Python 安装。
Python 搭车指南提供了关于在 macOS 上安装 Python的优秀指南,该指南解释了如何使用Homebrew管理器安装 Python。或者,你也可以使用pyenv。
假设你已经使用brew
安装了 Python,那么你可能还需要以下包:
$ brew install freetype pkg-config gcc openssl hdf5 ta-lib
Windows
对于 Windows,安装 Zipline 最简单且最支持的方法是使用conda
。
使用conda
安装
另一种安装 Zipline 的方法是通过conda
包管理器,它是Anaconda发行版的一部分。或者,你可以使用相关但更轻量级的Miniconda或Miniforge安装程序。
使用 Conda 而不是pip
的主要优点是,conda
原生理解像numpy
和scipy
这样的包的复杂二进制依赖关系。这意味着conda
可以安装 Zipline 及其依赖项,而不需要使用第二个工具来获取 Zipline 的非 Python 依赖项。
有关如何安装conda
的说明,请参阅Conda 安装文档。
一旦设置了conda
,你就可以从conda-forge
频道安装 Zipline。
请参阅此处了解最新的安装详细信息。
管理conda
环境
建议在隔离的conda
环境中安装 Zipline。在conda
环境中安装 Zipline 不会干扰你的默认 Python 部署或 site-packages,这将防止与你的全局库发生任何可能的冲突。有关conda
环境的更多信息,请参阅Conda 用户指南。
假设已经设置了conda
,你可以创建一个conda
环境:
$ conda create -n env_zipline python=3.10
现在你已经设置了一个名为env_zipline
的隔离环境,这是一个类似沙盒的结构,用于安装 Zipline。然后你应该使用以下命令激活 conda 环境:
$ conda activate env_zipline
你可以通过运行以下命令来安装 Zipline:
(env_zipline) $ conda install -c ml4t zipline-reloaded
要停用conda
环境:
(env_zipline) $ conda deactivate
注意
conda activate
和 conda deactivate
仅适用于 conda 4.6 及更高版本。对于 conda 4.6 之前的版本,请运行:
- Windows:
activate
或deactivate
- Linux 和 macOS:
source activate
或source deactivate
使用 pip
安装
通过 pip
安装 Zipline 比一般的 Python 包稍微复杂一些。
增加复杂性的原因有两个:
-
Zipline 提供了多个需要访问 CPython C API 的 C 扩展。为了构建这些 C 扩展,
pip
需要访问您 Python 安装的 CPython 头文件。 -
Zipline 依赖于 NumPy,这是 Python 中用于数值数组计算的核心库。NumPy 反过来又依赖于 LAPACK 线性代数例程。
由于 LAPACK 和 CPython 头文件是非 Python 依赖项,因此安装它们的方法因平台而异。如果您更愿意使用单个工具来安装 Python 和非 Python 依赖项,或者如果您已经在使用 Anaconda 作为您的 Python 发行版,则可以跳至 :ref: conda 部分。
一旦您安装了必要的额外依赖项(请参阅下面的特定平台),您应该能够简单地运行(最好在激活的虚拟环境中):
$ pip install zipline-reloaded
如果您使用 Python 进行除 Zipline 之外的任何操作,我们强烈建议您在 virtualenv 中安装。《Python 漫游者指南》提供了一个关于 virtualenv 的优秀教程。
GNU/Linux
依赖项
在 Debian 派生的 Linux 发行版上,您可以通过运行以下命令从 apt
获取所有必要的二进制依赖项:
$ sudo apt install libatlas-base-dev python-dev gfortran pkg-config libfreetype6-dev hdf5-tools
在最近的 RHEL 派生的 Linux 发行版(例如 Fedora)上,以下内容应该足以获取必要的额外依赖项:
$ sudo dnf install atlas-devel gcc-c++ gcc-gfortran libgfortran python-devel redhat-rpm-config hdf5
在 Arch Linux 上,您可以通过 pacman
获取额外的依赖项:
$ pacman -S lapack gcc gcc-fortran pkg-config hdf5
也有 AUR 包可用于安装 ta-lib。Python 3 也可以通过以下方式安装:
$ pacman -S python3
编译 TA-Lib
您还需要编译 TA-Lib 库以进行技术分析,以便其头文件可用。
您可以按照以下步骤操作:
$ wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
$ tar -xzf ta-lib-0.4.0-src.tar.gz
$ cd ta-lib/
$ sudo ./configure
$ sudo make
$ sudo make install
这将允许您按照二进制轮子的预期使用 pip
安装 Python 包装器。
macOS
macOS 随附的 Python 版本通常已过时,并且由于操作系统直接使用它而存在一些特殊情况。出于这些原因,许多开发者选择安装并使用单独的 Python 安装。
Python 漫游指南提供了在 macOS 上安装 Python的优秀指南,解释了如何使用Homebrew管理器安装 Python。或者,您可以使用pyenv。
假设您已经使用brew
安装了 Python,您可能还需要以下包:
$ brew install freetype pkg-config gcc openssl hdf5 ta-lib
Windows
对于 Windows,安装 Zipline 最简单且最支持的方法是使用conda
。
GNU/Linux
依赖项
在Debian 衍生的 Linux 发行版上,您可以通过运行以下命令从apt
获取所有必要的二进制依赖项:
$ sudo apt install libatlas-base-dev python-dev gfortran pkg-config libfreetype6-dev hdf5-tools
在最近的RHEL 衍生的 Linux 发行版(例如 Fedora)上,以下步骤应该足以获取必要的额外依赖项:
$ sudo dnf install atlas-devel gcc-c++ gcc-gfortran libgfortran python-devel redhat-rpm-config hdf5
在Arch Linux上,您可以通过pacman
获取额外的依赖项:
$ pacman -S lapack gcc gcc-fortran pkg-config hdf5
也有 AUR 包可用于安装ta-lib。Python 3 也可以通过以下方式安装:
$ pacman -S python3
编译 TA-Lib
您还需要编译TA-Lib技术分析库,以便其头文件可用。
您可以按照以下步骤操作:
$ wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
$ tar -xzf ta-lib-0.4.0-src.tar.gz
$ cd ta-lib/
$ sudo ./configure
$ sudo make
$ sudo make install
这将允许您按照二进制轮子的预期使用pip
安装 Python 包装器。
依赖项
在Debian 衍生的 Linux 发行版上,您可以通过运行以下命令从apt
获取所有必要的二进制依赖项:
$ sudo apt install libatlas-base-dev python-dev gfortran pkg-config libfreetype6-dev hdf5-tools
在最近的RHEL 衍生的 Linux 发行版(例如 Fedora)上,以下步骤应该足以获取必要的额外依赖项:
$ sudo dnf install atlas-devel gcc-c++ gcc-gfortran libgfortran python-devel redhat-rpm-config hdf5
在Arch Linux上,您可以通过pacman
获取额外的依赖项:
$ pacman -S lapack gcc gcc-fortran pkg-config hdf5
也有 AUR 包可用于安装ta-lib。Python 3 也可以通过以下方式安装:
$ pacman -S python3
编译 TA-Lib
您还需要编译TA-Lib技术分析库,以便其头文件可用。
您可以按照以下步骤操作:
$ wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
$ tar -xzf ta-lib-0.4.0-src.tar.gz
$ cd ta-lib/
$ sudo ./configure
$ sudo make
$ sudo make install
这将允许您按照二进制轮子的预期使用pip
安装 Python 包装器。
macOS
macOS 随附的 Python 版本通常已过时,并且由于操作系统直接使用它而存在一些怪癖。出于这些原因,许多开发人员选择安装并使用单独的 Python 安装。
Python 漫游指南提供了在 macOS 上安装 Python的优秀指南,解释了如何使用Homebrew管理器安装 Python。或者,您可以使用pyenv。
假设您已使用brew
安装了 Python,您可能还需要以下包:
$ brew install freetype pkg-config gcc openssl hdf5 ta-lib
Windows
对于 Windows,安装 Zipline 最简单且最支持的方法是使用conda
。
使用conda
安装
另一种安装 Zipline 的方法是通过conda
包管理器,该管理器包含在Anaconda发行版中。或者,您可以使用相关但更轻量级的Miniconda或Miniforge安装程序。
使用 Conda 而非pip
的主要优势在于,conda
原生理解numpy
和scipy
等包的复杂二进制依赖关系。这意味着conda
可以安装 Zipline 及其依赖项,而无需使用第二个工具来获取 Zipline 的非 Python 依赖项。
有关如何安装conda
的说明,请参阅Conda 安装文档。
一旦设置了conda
,您就可以从conda-forge
频道安装 Zipline。
有关最新安装详细信息,请参见此处。
管理conda
环境
建议在隔离的conda
环境中安装 Zipline。在conda
环境中安装 Zipline 不会干扰您的默认 Python 部署或 site-packages,这将防止与您的全局库发生任何可能的冲突。有关conda
环境的更多信息,请参阅Conda 用户指南。
假设已经设置了conda
,您可以创建一个conda
环境:
$ conda create -n env_zipline python=3.10
现在,您已经设置了一个名为env_zipline
的隔离环境,这是一个类似沙箱的结构,用于安装 Zipline。然后,您应该通过使用以下命令来激活 conda 环境:
$ conda activate env_zipline
您可以通过运行以下命令来安装 Zipline:
(env_zipline) $ conda install -c ml4t zipline-reloaded
要停用conda
环境:
(env_zipline) $ conda deactivate
注意
conda activate
和 conda deactivate
仅适用于 conda 4.6 及更高版本。对于 conda 4.6 之前的版本,请运行:
- Windows:
activate
或deactivate
- Linux 和 macOS:
source activate
或source deactivate
### 管理conda
环境
建议在隔离的conda
环境中安装 Zipline。在conda
环境中安装 Zipline 不会干扰您的默认 Python 部署或 site-packages,这将防止与您的全局库发生任何可能的冲突。有关conda
环境的更多信息,请参阅Conda 用户指南。
假设已经设置了conda
,您可以创建一个conda
环境:
$ conda create -n env_zipline python=3.10
现在,您已经设置了一个名为env_zipline
的隔离环境,这是一个类似沙箱的结构,用于安装 Zipline。然后,您应该通过使用以下命令来激活 conda 环境:
$ conda activate env_zipline
您可以通过运行以下命令来安装 Zipline:
(env_zipline) $ conda install -c ml4t zipline-reloaded
要停用 conda
环境:
(env_zipline) $ conda deactivate
注意
conda activate
和 conda deactivate
仅适用于 conda 4.6 及更高版本。对于 conda 4.6 之前的版本,请运行:
- Windows:
activate
或deactivate
- Linux 和 macOS:
source activate
或source deactivate
教程
Zipline 是一个用 Python 编写的 开源 算法交易模拟器。
一些好处包括:
-
真实:滑点、交易成本、订单延迟。
-
基于流:逐个处理每个事件,避免前瞻性偏差。
-
包含电池:常见的转换(移动平均线)以及常见的风险计算(夏普比率)可以在执行回测时高效计算。
本教程假设您已正确安装 Zipline,如果您尚未完成,请参阅 安装 说明。
如何构建算法
每个 Zipline 算法都由您必须定义的两个函数组成:
-
initialize(context)
-
handle_data(context, data)
在算法开始之前,Zipline 调用 initialize()
函数并传入一个 context
变量。context
是一个持久的命名空间,用于存储您需要从一个算法迭代到下一个迭代访问的变量。
算法初始化后,Zipline 为每个事件调用 handle_data()
函数一次。在每次调用时,它传递相同的 context
变量和一个名为 data
的事件帧,其中包含当前交易栏的开盘、最高、最低和收盘(OHLC)价格以及您投资组合中每只股票的成交量。
一个简单的例子
让我们来看一个来自 zipline/examples 目录的非常简单的算法,buyapple.py
。每个周期,即一个交易日,它订购 10 股苹果股票并记录价格。
from zipline.examples import buyapple
from zipline.api import order, record, symbol
def initialize(context):
pass
def handle_data(context, data):
order(symbol('AAPL'), 10)
record(AAPL=data.current(symbol('AAPL'), 'price'))
如您所见,我们首先必须导入一些我们想要使用的函数。所有在您的算法中常用的函数都可以在 zipline.api
中找到。这里我们使用 order()
,它接受两个参数:一个证券对象和一个指定您想要订购多少股票的数字(如果是负数,order()
将卖出/做空股票)。在这种情况下,我们希望在每次迭代中订购 10 股苹果股票。
最后,record()
函数允许您在每次迭代时保存变量的值。您向其提供变量的名称以及变量本身:varname=var
。算法运行完成后,您将能够访问您使用 record()
跟踪的每个变量值,并使用您提供的名称(我们将在下面进一步看到)。您还可以看到我们如何访问 AAPL 股票在 data
事件帧中的当前价格数据。
如何运行算法
现在,要在金融数据上测试此算法,Zipline 提供了三种接口:1. 通过 zipline
命令的命令行,2. 通过 zipline
魔法在 Jupyter Notebook
中,3. 通过 run_algorithm()
执行你的算法,就像任何 Python 脚本一样,例如在你的 IDE 中。
在我们运行任何算法之前,我们需要一些数据。
数据摄取
如果你还没有摄取数据,那么运行:
$ zipline ingest -b <bundle>
其中 <bundle>
是你要摄取的 bundle 的名称。目前你可以使用默认的 quandl 来处理 Quandl WIKI 价格数据。有关如何获取其他新数据的更多详细信息,请查看 数据摄取 部分。
命令行界面
安装 Zipline 后,你应该能够从命令行执行以下操作(例如在 Windows 上的 cmd.exe
,在 OSX 上的终端应用程序,或在 Linux 上的 bash shell):
$ zipline run --help
Usage: zipline run [OPTIONS]
Run a backtest for the given algorithm.
Options:
-f, --algofile FILENAME The file that contains the algorithm to run.
-t, --algotext TEXT The algorithm script to run.
-D, --define TEXT Define a name to be bound in the namespace
before executing the algotext. For example
'-Dname=value'. The value may be any python
expression. These are evaluated in order so
they may refer to previously defined names.
--data-frequency [daily|minute]
The data frequency of the simulation.
[default: daily]
--capital-base FLOAT The starting capital for the simulation.
[default: 10000000.0]
-b, --bundle BUNDLE-NAME The data bundle to use for the simulation.
[default: quandl]
--bundle-timestamp TIMESTAMP The date to lookup data on or before.
[default: <current-time>]
-s, --start DATE The start date of the simulation.
-e, --end DATE The end date of the simulation.
-o, --output FILENAME The location to write the perf data. If this
is '-' the perf will be written to stdout.
[default: -]
--trading-calendar TRADING-CALENDAR
The calendar you want to use e.g. LSE. NYSE
is the default.
--print-algo / --no-print-algo Print the algorithm to stdout.
--benchmark-file The csv file that contains the benchmark
returns (date, returns columns)
--benchmark-symbol The instrument's symbol to be used as
a benchmark.
(should exist in the ingested bundle)
--benchmark-sid The sid of the instrument to be used as a
benchmark.
(should exist in the ingested bundle)
--no-benchmark This flag is used to set the benchmark to
zero. Alpha, beta and benchmark metrics
are not calculated
--help Show this message and exit.
如你所见,有一些标志指定了算法的位置(-f
),以及指定使用哪些数据的参数,默认为 quandl
。
对于运行算法的日期范围(--start
和 --end
)也存在一些争议。要使用基准测试,你需要在前面列出的基准选项中选择一个。你始终可以使用不使用基准的选项(--no-benchmark
),在这种情况下,将零回报作为基准(此时不计算 alpha、beta 和基准指标)。
最后,你会想要保存算法的性能指标,以便你可以分析它的表现。这是通过 --output
标志完成的,它将导致它将性能 DataFrame
写入 pickle Python 文件格式。请注意,你还可以定义一个配置文件,其中包含这些参数,然后你可以方便地将其传递给 -c
选项,这样你就不必每次都提供命令行参数了(请参见示例目录中的 .conf 文件)。
因此,要执行上述算法并将结果保存到 buyapple_out.pickle
,我们按如下方式调用 zipline run
:
zipline run -f ../zipline/examples/buyapple.py --start 2016-1-1 --end 2018-1-1 -o buyapple_out.pickle --no-benchmark
AAPL
[2018-01-03 04:30:51.843465] INFO: Performance: Simulated 503 trading days out of 503.
[2018-01-03 04:30:51.843598] INFO: Performance: first open: 2016-01-04 14:31:00+00:00
[2018-01-03 04:30:51.843672] INFO: Performance: last close: 2017-12-29 21:00:00+00:00
run
首先调用 initialize()
函数,然后逐日流式传输历史股票价格通过 handle_data()
。在每次调用 handle_data()
后,我们指示 zipline
订购 10 股 AAPL。在调用 order()
函数后,zipline
将订购的股票和数量输入订单簿。在 handle_data()
函数完成后,zipline
查找任何未完成的订单并尝试填充它们。如果该股票的交易量足够大,订单将在添加佣金并应用滑点模型后执行,该模型模拟了你的订单对股票价格的影响,因此你的算法将被收取比股票价格 * 10 更多的费用。(注意,你也可以更改 zipline
使用的佣金和滑点模型,请参见。
让我们快速查看一下性能DataFrame
。为此,我们在 IPython Notebook 中使用pandas
并打印前 10 行。请注意,zipline
大量使用pandas
,尤其是在数据输入和输出方面,因此值得花时间学习它。
import pandas as pd
perf = pd.read_pickle('buyapple_out.pickle') # read in perf DataFrame
perf.head()
AAPL | algo_volatility | algorithm_period_return | alpha | benchmark_period_return | benchmark_volatility | beta | capital_used | ending_cash | ending_exposure | ending_value | excess_return | gross_leverage | long_exposure | long_value | longs_count | max_drawdown | max_leverage | net_leverage | orders | period_close | period_label | period_open | pnl | portfolio_value | positions | returns | sharpe | short_exposure | short_value | shorts_count | sortino | starting_cash | starting_exposure | starting_value | trading_days | transactions | treasury_period_return | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2016-01-04 21:00:00+00:00 | 105.35 | NaN | 0.000000e+00 | NaN | -0.013983 | NaN | NaN | 0.0 | 10000000.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0 | 0.000000e+00 | 0.0 | 0.000000 | [{'dt': 2016-01-04 21:00:00+00:00, 'reason': N... | 2016-01-04 21:00:00+00:00 | 2016-01 | 2016-01-04 14:31:00+00:00 | 0.0 | 10000000.0 | [] | 0.000000e+00 | NaN | 0 | 0 | 0 | NaN | 10000000.0 | 0.0 | 0.0 | 1 | [] | 0.0 |
2016-01-05 21:00:00+00:00 | 102.71 | 0.000001 | -1.000000e-07 | -0.000022 | -0.012312 | 0.175994 | -0.000006 | -1028.1 | 9998971.9 | 1027.1 | 1027.1 | 0.0 | 0.000103 | 1027.1 | 1027.1 | 1 | -1.000000e-07 | 0.0 | 0.000103 | [{'dt': 2016-01-05 21:00:00+00:00, 'reason': N... | 2016-01-05 21:00:00+00:00 | 2016-01 | 2016-01-05 14:31:00+00:00 | -1.0 | 9999999.0 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | -1.000000e-07 | -11.224972 | 0 | 0 | 0 | -11.224972 | 10000000.0 | 0.0 | 0.0 | 2 | [{'order_id': '4011063b5c094e82a5391527044098b... | 0.0 |
2016-01-06 21:00:00+00:00 | 100.70 | 0.000019 | -2.210000e-06 | -0.000073 | -0.024771 | 0.137853 | 0.000054 | -1008.0 | 9997963.9 | 2014.0 | 2014.0 | 0.0 | 0.000201 | 2014.0 | 2014.0 | 1 | -2.210000e-06 | 0.0 | 0.000201 | [{'dt': 2016-01-06 21:00:00+00:00, 'reason': N... | 2016-01-06 21:00:00+00:00 | 2016-01 | 2016-01-06 14:31:00+00:00 | -21.1 | 9999977.9 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | -2.110000e-06 | -9.823839 | 0 | 0 | 0 | -9.588756 | 9998971.9 | 1027.1 | 1027.1 | 3 | [{'order_id': '3bf9fe20cc46468d99f741474226c03... | 0.0 |
2016-01-07 21:00:00+00:00 | 96.45 | 0.000064 | -1.081000e-05 | 0.000243 | -0.048168 | 0.167868 | 0.000300 | -965.5 | 9996998.4 | 2893.5 | 2893.5 | 0.0 | 0.000289 | 2893.5 | 2893.5 | 1 | -1.081000e-05 | 0.0 | 0.000289 | [{'dt': 2016-01-07 21:00:00+00:00, 'reason': N... | 2016-01-07 21:00:00+00:00 | 2016-01 | 2016-01-07 14:31:00+00:00 | -86.0 | 9999891.9 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | -8.600019e-06 | -10.592737 | 0 | 0 | 0 | -9.688947 | 9997963.9 | 2014.0 | 2014.0 | 4 | [{'order_id': '6af6aed9fbb44a6bba17e802051b94d... | 0.0 |
2016-01-08 21:00:00+00:00 | 96.96 | 0.000063 | -9.380000e-06 | 0.000466 | -0.058601 | 0.145654 | 0.000311 | -970.6 | 9996027.8 | 3878.4 | 3878.4 | 0.0 | 0.000388 | 3878.4 | 3878.4 | 1 | -1.081000e-05 | 0.0 | 0.000388 | [{'dt': 2016-01-08 21:00:00+00:00, 'reason': N... | 2016-01-08 21:00:00+00:00 | 2016-01 | 2016-01-08 14:31:00+00:00 | 14.3 | 9999906.2 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | 1.430015e-06 | -7.511729 | 0 | 0 | 0 | -7.519659 | 9996998.4 | 2893.5 | 2893.5 | 5 | {'order_id': '18f64975732449a18fca06e9c69bf5c... | 0.0 |
如你所见,每个交易日都有一行,从 2016 年的第一个工作日开始。在列中,你可以找到有关你的算法状态的各种信息。第一列AAPL
是由前面提到的record()
函数放置在那里的,它允许我们绘制苹果的价格。例如,我们现在可以很容易地检查我们的投资组合价值如何随时间变化,与 AAPL 股票价格相比。
%pylab inline
figsize(12, 12)
import matplotlib.pyplot as plt
ax1 = plt.subplot(211)
perf.portfolio_value.plot(ax=ax1)
ax1.set_ylabel('Portfolio Value')
ax2 = plt.subplot(212, sharex=ax1)
perf.AAPL.plot(ax=ax2)
ax2.set_ylabel('AAPL Stock Price')
Populating the interactive namespace from numpy and matplotlib
<matplotlib.text.Text at 0x10c48c198>
![_images/tutorial_11_2.png
如你所见,我们的算法表现,通过portfolio_value
评估,与 AAPL 股票价格紧密匹配。这并不奇怪,因为我们的算法只要有机会就会买入 AAPL。
Jupyter Notebook
Jupyter Notebook是一个非常强大的基于浏览器的 Python 解释器界面(本教程就是在其中编写的)。由于它是许多量化研究人员非常流行的界面,Zipline 提供了一种简单的方法,可以在不要求你使用 CLI 的情况下在 Notebook 内运行你的算法。
要使用它,你需要在一个单元格中编写你的算法,并让 Zipline 知道它应该运行这个算法。这是通过%%zipline
IPython 魔术命令完成的,该命令在你从 IPython Notebook 中import zipline
后可用。这个魔术命令接受与上述命令行界面相同的参数。因此,要使用相同的参数运行上述算法,我们只需在导入zipline
后执行以下单元格来注册魔术命令。
%load_ext zipline
%%zipline --start 2016-1-1 --end 2018-1-1
from zipline.api import symbol, order, record
def initialize(context):
pass
def handle_data(context, data):
order(symbol('AAPL'), 10)
record(AAPL=data.current(symbol('AAPL'), "price")
注意,我们不需要像上面那样指定输入文件,因为魔术将使用单元格的内容并在那里查找您的算法函数。此外,我们没有定义输出文件,而是使用-o
指定了一个变量名,该变量名将在名称空间中创建,并包含我们在上面查看的性能DataFrame
。
_.head()
AAPL | algo_volatility | algorithm_period_return | alpha | benchmark_period_return | benchmark_volatility | beta | capital_used | ending_cash | ending_exposure | ending_value | excess_return | gross_leverage | long_exposure | long_value | longs_count | max_drawdown | max_leverage | net_leverage | orders | period_close | period_label | period_open | pnl | portfolio_value | positions | returns | sharpe | short_exposure | short_value | shorts_count | sortino | starting_cash | starting_exposure | starting_value | trading_days | transactions | treasury_period_return | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2016-01-04 21:00:00+00:00 | 105.35 | NaN | 0.000000e+00 | NaN | -0.013983 | NaN | NaN | 0.00 | 10000000.00 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0 | 0.000000e+00 | 0.0 | 0.000000 | [{'created': 2016-01-04 21:00:00+00:00, 'reaso... | 2016-01-04 21:00:00+00:00 | 2016-01 | 2016-01-04 14:31:00+00:00 | 0.00 | 10000000.00 | [] | 0.000000e+00 | NaN | 0 | 0 | 0 | NaN | 10000000.00 | 0.0 | 0.0 | 1 | [] | 0.0 |
2016-01-05 21:00:00+00:00 | 102.71 | 1.122497e-08 | -1.000000e-09 | -2.247510e-07 | -0.012312 | 0.175994 | -6.378047e-08 | -1027.11 | 9998972.89 | 1027.1 | 1027.1 | 0.0 | 0.000103 | 1027.1 | 1027.1 | 1 | -9.999999e-10 | 0.0 | 0.000103 | {'created': 2016-01-04 21:00:00+00:00, 'reaso... | 2016-01-05 21:00:00+00:00 | 2016-01 | 2016-01-05 14:31:00+00:00 | -0.01 | 9999999.99 | [{'amount': 10, 'cost_basis': 102.711000000000... | -1.000000e-09 | -11.224972 | 0 | 0 | 0 | -11.224972 | 10000000.00 | 0.0 | 0.0 | 2 | [{'dt': 2016-01-05 21:00:00+00:00, 'order_id':... | 0.0 |
2016-01-06 21:00:00+00:00 | 100.70 | 1.842654e-05 | -2.012000e-06 | -4.883861e-05 | -0.024771 | 0.137853 | 5.744807e-05 | -1007.01 | 9997965.88 | 2014.0 | 2014.0 | 0.0 | 0.000201 | 2014.0 | 2014.0 | 1 | -2.012000e-06 | 0.0 | 0.000201 | [{'created': 2016-01-05 21:00:00+00:00, 'reaso... | 2016-01-06 21:00:00+00:00 | 2016-01 | 2016-01-06 14:31:00+00:00 | -20.11 | 9999979.88 | [{'amount': 20, 'cost_basis': 101.706000000000... | -2.011000e-06 | -9.171989 | 0 | 0 | 0 | -9.169708 | 9998972.89 | 1027.1 | 1027.1 | 3 | [{'dt': 2016-01-06 21:00:00+00:00, 'order_id':... | 0.0 |
2016-01-07 21:00:00+00:00 | 96.45 | 6.394658e-05 | -1.051300e-05 | 2.633450e-04 | -0.048168 | 0.167868 | 3.005102e-04 | -964.51 | 9997001.37 | 2893.5 | 2893.5 | 0.0 | 0.000289 | 2893.5 | 2893.5 | 1 | -1.051300e-05 | 0.0 | 0.000289 | [{'created': 2016-01-06 21:00:00+00:00, 'reaso... | 2016-01-07 21:00:00+00:00 | 2016-01 | 2016-01-07 14:31:00+00:00 | -85.01 | 9999894.87 | [{'amount': 30, 'cost_basis': 99.9543333333335... | -8.501017e-06 | -10.357397 | 0 | 0 | 0 | -9.552189 | 9997965.88 | 2014.0 | 2014.0 | 4 | [{'dt': 2016-01-07 21:00:00+00:00, 'order_id':... | 0.0 |
2016-01-08 21:00:00+00:00 | 96.96 | 6.275294e-05 | -8.984000e-06 | 4.879306e-04 | -0.058601 | 0.145654 | 3.118401e-04 | -969.61 | 9996031.76 | 3878.4 | 3878.4 | 0.0 | 0.000388 | 3878.4 | 3878.4 | 1 | -1.051300e-05 | 0.0 | 0.000388 | [{'created': 2016-01-07 21:00:00+00:00, 'reaso... | 2016-01-08 21:00:00+00:00 | 2016-01 | 2016-01-08 14:31:00+00:00 | 15.29 | 9999910.16 | [{'amount': 40, 'cost_basis': 99.2060000000002... | 1.529016e-06 | -7.215497 | 0 | 0 | 0 | -7.301134 | 9997001.37 | 2893.5 | 2893.5 | 5 | [{'dt': 2016-01-08 21:00:00+00:00, 'order_id':... | 0.0 |
IDE 通过[run_algorithm()
要在您喜欢的 IDE 中执行类似于 Python 脚本的算法,请使用run_algorithm()
(参见 API 参考)。
要调整上述buyapple.py
示例(参见同一目录中的buyapple_ide.py
),只需添加以下内容:
from zipline import run_algorithm
import pandas as pd
import pandas_datareader.data as web
def initialize(context):
...
def handle_data(context, data):
...
start = pd.Timestamp('2014')
end = pd.Timestamp('2018')
sp500 = web.DataReader('SP500', 'fred', start, end).SP500
benchmark_returns = sp500.pct_change()
result = run_algorithm(start=start.tz_localize('UTC'),
end=end.tz_localize('UTC'),
initialize=initialize,
handle_data=handle_data,
capital_base=100000,
benchmark_returns=benchmark_returns,
bundle='quandl',
data_frequency='daily')
我们将关键算法参数传递给run_algorithm()
,包括我们从联邦储备经济数据服务(过去 10 年可用)下载的 S&P 500 的一些基准数据。
返回的result
值包含与前一个示例相同的DataFrame
。您可以对DataFrame
应用您喜欢的逻辑,而不是将analyze()
函数定义为算法的一部分。
如何使用历史价格:双移动平均线交叉示例
双移动平均线(DMA)是一种经典的动量策略。它可能不再被任何严肃的交易者使用,但仍然非常有教育意义。基本思想是我们计算两个滚动或移动平均线(mavg)——一个具有较长窗口,旨在捕捉长期趋势,另一个具有较短窗口,旨在捕捉短期趋势。一旦短期 mavg 从下方穿过长期 mavg,我们就假设股票价格具有上升趋势,并买入股票。如果短期 mavg 从上方穿过,我们退出头寸,因为我们假设股票会进一步下跌。
由于我们需要访问先前的价格来实施此策略,因此我们需要一个新概念:历史
data.history()
是一个方便的函数,它为您保留了一个数据滚动窗口。第一个参数是您想要收集的条形图数量,第二个参数是单位('1d'
或'1m'
,但请注意,您需要有分钟级别的数据才能使用1m
)。有关history()
功能的更详细描述,请参阅 API 参考。让我们来看一个策略,这将使这一点变得清晰:
%%zipline --start 2014-1-1 --end 2018-1-1 -o dma.pickle
from zipline.api import order_target, record, symbol
import matplotlib.pyplot as plt
def initialize(context):
context.i = 0
context.asset = symbol('AAPL')
def handle_data(context, data):
# Skip first 300 days to get full windows
context.i += 1
if context.i < 300:
return
# Compute averages
# data.history() has to be called with the same params
# from above and returns a pandas dataframe.
short_mavg = data.history(context.asset, 'price', bar_count=100, frequency="1d").mean()
long_mavg = data.history(context.asset, 'price', bar_count=300, frequency="1d").mean()
# Trading logic
if short_mavg > long_mavg:
# order_target orders as many shares as needed to
# achieve the desired number of shares.
order_target(context.asset, 100)
elif short_mavg < long_mavg:
order_target(context.asset, 0)
# Save values for later inspection
record(AAPL=data.current(context.asset, 'price'),
short_mavg=short_mavg,
long_mavg=long_mavg)
def analyze(context, perf):
fig = plt.figure()
ax1 = fig.add_subplot(211)
perf.portfolio_value.plot(ax=ax1)
ax1.set_ylabel('portfolio value in $')
ax2 = fig.add_subplot(212)
perf['AAPL'].plot(ax=ax2)
perf[['short_mavg', 'long_mavg']].plot(ax=ax2)
perf_trans = perf.loc[[t != [] for t in perf.transactions]]
buys = perf_trans.loc[[t[0]['amount'] > 0 for t in perf_trans.transactions]]
sells = perf_trans.loc[
[t[0]['amount'] < 0 for t in perf_trans.transactions]]
ax2.plot(buys.index, perf.short_mavg.loc[buys.index],
'^', markersize=10, color='m')
ax2.plot(sells.index, perf.short_mavg.loc[sells.index],
'v', markersize=10, color='k')
ax2.set_ylabel('price in $')
plt.legend(loc=0)
plt.show()
在这里,我们明确地定义了一个analyze()
函数,该函数会在回测完成后自动被调用。
尽管可能不那么直接明显,但history()
(双关语)的强大功能不容小觑,因为大多数算法都会以某种形式利用过去的市场发展。您可以轻松设计一个策略,使用scikit-learn训练一个分类器,该分类器试图根据过去的价格预测未来的市场走势,(注意,大多数scikit-learn
函数需要numpy.ndarray
而不是pandas.DataFrame
,因此您可以通过.to_numpy()
简单地传递DataFrame
的底层ndarray
)。
我们还使用了上面的order_target()
函数。像这样的其他函数可以使订单管理和投资组合再平衡变得更加容易。有关更多详细信息,请参阅 API 参考。
结论
我们希望本教程能为您提供一些关于zipline
架构、API 和功能的初步了解。下一步,可以查看一些示例。
欢迎在我们的邮件列表上提问,在我们的GitHub 问题跟踪器上报问题,或参与进来。
如何构建算法
每个 Zipline 算法都由您必须定义的两个函数组成:
-
initialize(context)
-
handle_data(context, data)
在算法开始之前,Zipline 会调用initialize()
函数并传递一个context
变量。context
是一个持久的命名空间,用于存储您需要从一个算法迭代访问到下一个算法的变量。
算法初始化后,Zipline 会为每个事件调用一次handle_data()
函数。每次调用时,它都会传递相同的context
变量和一个名为data
的事件框架,其中包含当前交易时段的开盘、最高、最低和收盘(OHLC)价格以及您投资组合中每只股票的成交量。
一个简单的例子
让我们来看一个非常简单的算法,来自zipline/examples目录,buyapple.py
。每个周期,即交易日,它都会订购 10 股苹果股票并记录价格。
from zipline.examples import buyapple
from zipline.api import order, record, symbol
def initialize(context):
pass
def handle_data(context, data):
order(symbol('AAPL'), 10)
record(AAPL=data.current(symbol('AAPL'), 'price'))
如您所见,我们首先需要导入一些我们想要使用的函数。所有在您的算法中常用的函数都可以在zipline.api
中找到。这里我们使用的是order()
,它接受两个参数:一个证券对象和一个指定您想要订购多少股票的数字(如果是负数,order()
将卖出/做空股票)。在这种情况下,我们希望在每次迭代中订购 10 股苹果股票。
最后,record()
函数允许您在每次迭代中保存变量的值。您向它提供变量的名称以及变量本身:varname=var
。算法运行完成后,您将能够访问您使用record()
跟踪的每个变量值,并使用您提供的名称(我们将在下面进一步看到)。您还可以看到我们如何访问data
事件帧中 AAPL 股票的当前价格数据。
一个简单的例子
让我们来看一下zipline/examples目录中的一个非常简单的算法,buyapple.py
。每个周期,即交易日,它都会下单购买 10 股苹果股票并记录价格。
from zipline.examples import buyapple
from zipline.api import order, record, symbol
def initialize(context):
pass
def handle_data(context, data):
order(symbol('AAPL'), 10)
record(AAPL=data.current(symbol('AAPL'), 'price'))
如您所见,我们首先需要导入一些我们想要使用的函数。所有在您的算法中常用的函数都可以在zipline.api
中找到。这里我们使用的是order()
,它接受两个参数:一个证券对象和一个指定您想要订购多少股票的数字(如果是负数,order()
将卖出/做空股票)。在这种情况下,我们希望在每次迭代中订购 10 股苹果股票。
最后,record()
函数允许您在每次迭代中保存变量的值。您向它提供变量的名称以及变量本身:varname=var
。算法运行完成后,您将能够访问您使用record()
跟踪的每个变量值,并使用您提供的名称(我们将在下面进一步看到)。您还可以看到我们如何访问data
事件帧中 AAPL 股票的当前价格数据。
如何运行算法
现在要在金融数据上测试这个算法,Zipline 提供了三个接口:1. 通过zipline
命令的命令行,2. 通过zipline
魔法的Jupyter Notebook
,以及 3. run_algorithm()
来像任何 Python 脚本一样执行您的算法,例如在您的 IDE 中。
在我们能够运行任何算法之前,我们需要一些数据。
数据摄取
如果您还没有摄取数据,请运行:
$ zipline ingest -b <bundle>
其中<bundle>
是要摄取的 bundle 的名称。您现在可以使用默认的 quandl 来处理Quandl WIKI 价格数据。有关如何获取其他新数据的更多详细信息,请查看摄取数据部分。
命令行界面
安装 Zipline 后,您应该能够从命令行执行以下操作(例如在 Windows 上的cmd.exe
,在 OSX 上的 Terminal 应用程序,或在 Linux 上的 bash shell):
$ zipline run --help
Usage: zipline run [OPTIONS]
Run a backtest for the given algorithm.
Options:
-f, --algofile FILENAME The file that contains the algorithm to run.
-t, --algotext TEXT The algorithm script to run.
-D, --define TEXT Define a name to be bound in the namespace
before executing the algotext. For example
'-Dname=value'. The value may be any python
expression. These are evaluated in order so
they may refer to previously defined names.
--data-frequency [daily|minute]
The data frequency of the simulation.
[default: daily]
--capital-base FLOAT The starting capital for the simulation.
[default: 10000000.0]
-b, --bundle BUNDLE-NAME The data bundle to use for the simulation.
[default: quandl]
--bundle-timestamp TIMESTAMP The date to lookup data on or before.
[default: <current-time>]
-s, --start DATE The start date of the simulation.
-e, --end DATE The end date of the simulation.
-o, --output FILENAME The location to write the perf data. If this
is '-' the perf will be written to stdout.
[default: -]
--trading-calendar TRADING-CALENDAR
The calendar you want to use e.g. LSE. NYSE
is the default.
--print-algo / --no-print-algo Print the algorithm to stdout.
--benchmark-file The csv file that contains the benchmark
returns (date, returns columns)
--benchmark-symbol The instrument's symbol to be used as
a benchmark.
(should exist in the ingested bundle)
--benchmark-sid The sid of the instrument to be used as a
benchmark.
(should exist in the ingested bundle)
--no-benchmark This flag is used to set the benchmark to
zero. Alpha, beta and benchmark metrics
are not calculated
--help Show this message and exit.
如您所见,有几个标志指定了算法的位置(-f
)以及指定使用哪些数据的参数,默认为quandl
。
还有用于指定算法运行时间范围的参数(--start
和--end
)。要使用基准,您需要选择列出的基准选项之一。您始终可以使用使用零回报作为基准的选项(--no-benchmark
)(在这种情况下,不计算 alpha,beta 和基准指标)。
最后,您将希望保存算法的性能指标,以便您可以分析其表现。这是通过--output
标志完成的,这将导致它以 pickle Python 文件格式编写性能DataFrame
。请注意,您还可以使用这些参数定义一个配置文件,然后方便地将其传递给-c
选项,这样您就不必一直提供命令行参数(请参见示例目录中的.conf 文件)。
因此,要执行上述算法并将结果保存到buyapple_out.pickle
,我们按如下方式调用zipline run
:
zipline run -f ../zipline/examples/buyapple.py --start 2016-1-1 --end 2018-1-1 -o buyapple_out.pickle --no-benchmark
AAPL
[2018-01-03 04:30:51.843465] INFO: Performance: Simulated 503 trading days out of 503.
[2018-01-03 04:30:51.843598] INFO: Performance: first open: 2016-01-04 14:31:00+00:00
[2018-01-03 04:30:51.843672] INFO: Performance: last close: 2017-12-29 21:00:00+00:00
run
首先调用initialize()
函数,然后通过handle_data()
逐日流式传输历史股票价格。在每次调用handle_data()
之后,我们指示zipline
订购 10 股 AAPL。在调用order()
函数之后,zipline
将订购的股票和数量输入订单簿。在handle_data()
函数完成后,zipline
查找任何未完成的订单并尝试填充它们。如果该股票的交易量足够高,订单将在添加佣金并应用滑点模型后执行,该模型模拟了您的订单对股票价格的影响,因此您的算法将被收取的费用不仅仅是股票价格* 10。(请注意,您也可以更改zipline
使用的佣金和滑点模型,请参见。
让我们快速浏览一下性能DataFrame
。为此,我们在 IPython Notebook 中使用pandas
并打印前 10 行。请注意,zipline
大量使用pandas
,特别是在数据输入和输出方面,因此值得花时间学习它。
import pandas as pd
perf = pd.read_pickle('buyapple_out.pickle') # read in perf DataFrame
perf.head()
AAPL | algo_volatility | algorithm_period_return | alpha | benchmark_period_return | benchmark_volatility | beta | capital_used | ending_cash | ending_exposure | ending_value | excess_return | gross_leverage | long_exposure | long_value | longs_count | max_drawdown | max_leverage | net_leverage | orders | period_close | period_label | period_open | pnl | portfolio_value | positions | returns | sharpe | short_exposure | short_value | shorts_count | sortino | starting_cash | starting_exposure | starting_value | trading_days | transactions | treasury_period_return | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2016-01-04 21:00:00+00:00 | 105.35 | NaN | 0.000000e+00 | NaN | -0.013983 | NaN | NaN | 0.0 | 10000000.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0 | 0.000000e+00 | 0.0 | 0.000000 | [{'dt': 2016-01-04 21:00:00+00:00, 'reason': N... | 2016-01-04 21:00:00+00:00 | 2016-01 | 2016-01-04 14:31:00+00:00 | 0.0 | 10000000.0 | [] | 0.000000e+00 | NaN | 0 | 0 | 0 | NaN | 10000000.0 | 0.0 | 0.0 | 1 | [] | 0.0 |
2016-01-05 21:00:00+00:00 | 102.71 | 0.000001 | -1.000000e-07 | -0.000022 | -0.012312 | 0.175994 | -0.000006 | -1028.1 | 9998971.9 | 1027.1 | 1027.1 | 0.0 | 0.000103 | 1027.1 | 1027.1 | 1 | -1.000000e-07 | 0.0 | 0.000103 | [{'dt': 2016-01-05 21:00:00+00:00, 'reason': N... | 2016-01-05 21:00:00+00:00 | 2016-01 | 2016-01-05 14:31:00+00:00 | -1.0 | 9999999.0 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | -1.000000e-07 | -11.224972 | 0 | 0 | 0 | -11.224972 | 10000000.0 | 0.0 | 0.0 | 2 | [{'order_id': '4011063b5c094e82a5391527044098b... | 0.0 |
2016-01-06 21:00:00+00:00 | 100.70 | 0.000019 | -2.210000e-06 | -0.000073 | -0.024771 | 0.137853 | 0.000054 | -1008.0 | 9997963.9 | 2014.0 | 2014.0 | 0.0 | 0.000201 | 2014.0 | 2014.0 | 1 | -2.210000e-06 | 0.0 | 0.000201 | [{'dt': 2016-01-06 21:00:00+00:00, 'reason': N... | 2016-01-06 21:00:00+00:00 | 2016-01 | 2016-01-06 14:31:00+00:00 | -21.1 | 9999977.9 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | -2.110000e-06 | -9.823839 | 0 | 0 | 0 | -9.588756 | 9998971.9 | 1027.1 | 1027.1 | 3 | [{'order_id': '3bf9fe20cc46468d99f741474226c03... | 0.0 |
2016-01-07 21:00:00+00:00 | 96.45 | 0.000064 | -1.081000e-05 | 0.000243 | -0.048168 | 0.167868 | 0.000300 | -965.5 | 9996998.4 | 2893.5 | 2893.5 | 0.0 | 0.000289 | 2893.5 | 2893.5 | 1 | -1.081000e-05 | 0.0 | 0.000289 | [{'dt': 2016-01-07 21:00:00+00:00, 'reason': N... | 2016-01-07 21:00:00+00:00 | 2016-01 | 2016-01-07 14:31:00+00:00 | -86.0 | 9999891.9 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | -8.600019e-06 | -10.592737 | 0 | 0 | 0 | -9.688947 | 9997963.9 | 2014.0 | 2014.0 | 4 | [{'order_id': '6af6aed9fbb44a6bba17e802051b94d... | 0.0 |
2016-01-08 21:00:00+00:00 | 96.96 | 0.000063 | -9.380000e-06 | 0.000466 | -0.058601 | 0.145654 | 0.000311 | -970.6 | 9996027.8 | 3878.4 | 3878.4 | 0.0 | 0.000388 | 3878.4 | 3878.4 | 1 | -1.081000e-05 | 0.0 | 0.000388 | [{'dt': 2016-01-08 21:00:00+00:00, 'reason': N... | 2016-01-08 21:00:00+00:00 | 2016-01 | 2016-01-08 14:31:00+00:00 | 14.3 | 9999906.2 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | 1.430015e-06 | -7.511729 | 0 | 0 | 0 | -7.519659 | 9996998.4 | 2893.5 | 2893.5 | 5 | {'order_id': '18f64975732449a18fca06e9c69bf5c... | 0.0 |
正如您所见,每行代表一个交易日,从 2016 年的第一个工作日开始。在列中,您可以找到有关您的算法状态的各种信息。第一列AAPL
是由前面提到的record()
函数放置在那里的,它允许我们绘制苹果的价格。例如,我们现在可以很容易地检查我们的投资组合价值随时间的变化与 AAPL 股票价格相比。
%pylab inline
figsize(12, 12)
import matplotlib.pyplot as plt
ax1 = plt.subplot(211)
perf.portfolio_value.plot(ax=ax1)
ax1.set_ylabel('Portfolio Value')
ax2 = plt.subplot(212, sharex=ax1)
perf.AAPL.plot(ax=ax2)
ax2.set_ylabel('AAPL Stock Price')
Populating the interactive namespace from numpy and matplotlib
<matplotlib.text.Text at 0x10c48c198>
![_images/tutorial_11_2.png
正如您所见,我们的算法性能通过portfolio_value
评估,与 AAPL 股票价格紧密匹配。这并不令人惊讶,因为我们的算法只要有机会就会买入 AAPL。
Jupyter Notebook
Jupyter Notebook是一个非常强大的基于浏览器的 Python 解释器界面(本教程就是在其中编写的)。由于它是许多定量研究人员非常流行的界面,Zipline 提供了一种简单的方法,可以在不要求您使用 CLI 的情况下在 Notebook 中运行您的算法。
要使用它,您必须在单元格中编写您的算法,并让 Zipline 知道它应该运行此算法。这是通过%%zipline
IPython 魔法命令完成的,该命令在您从 IPython Notebook 中import zipline
后可用。此魔法接受与上面描述的命令行界面相同的参数。因此,要使用相同的参数运行上面的算法,我们只需在导入zipline
以注册魔法后执行以下单元格。
%load_ext zipline
%%zipline --start 2016-1-1 --end 2018-1-1
from zipline.api import symbol, order, record
def initialize(context):
pass
def handle_data(context, data):
order(symbol('AAPL'), 10)
record(AAPL=data.current(symbol('AAPL'), "price")
请注意,我们不需要像上面那样指定输入文件,因为魔法将使用单元格的内容并在那里查找您的算法函数。此外,我们没有定义输出文件,而是使用-o
指定了一个变量名,该变量名将在名称空间中创建,并包含我们上面查看的性能DataFrame
。
_.head()
AAPL | algo_volatility | algorithm_period_return | alpha | benchmark_period_return | benchmark_volatility | beta | capital_used | ending_cash | ending_exposure | ending_value | excess_return | gross_leverage | long_exposure | long_value | longs_count | max_drawdown | max_leverage | net_leverage | orders | period_close | period_label | period_open | pnl | portfolio_value | positions | returns | sharpe | short_exposure | short_value | shorts_count | sortino | starting_cash | starting_exposure | starting_value | trading_days | transactions | treasury_period_return | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2016-01-04 21:00:00+00:00 | 105.35 | NaN | 0.000000e+00 | NaN | -0.013983 | NaN | NaN | 0.00 | 10000000.00 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0 | 0.000000e+00 | 0.0 | 0.000000 | [{'created': 2016-01-04 21:00:00+00:00, 'reaso... | 2016-01-04 21:00:00+00:00 | 2016-01 | 2016-01-04 14:31:00+00:00 | 0.00 | 10000000.00 | [] | 0.000000e+00 | NaN | 0 | 0 | 0 | NaN | 10000000.00 | 0.0 | 0.0 | 1 | [] | 0.0 |
2016-01-05 21:00:00+00:00 | 102.71 | 1.122497e-08 | -1.000000e-09 | -2.247510e-07 | -0.012312 | 0.175994 | -6.378047e-08 | -1027.11 | 9998972.89 | 1027.1 | 1027.1 | 0.0 | 0.000103 | 1027.1 | 1027.1 | 1 | -9.999999e-10 | 0.0 | 0.000103 | {'created': 2016-01-04 21:00:00+00:00, 'reaso... | 2016-01-05 21:00:00+00:00 | 2016-01 | 2016-01-05 14:31:00+00:00 | -0.01 | 9999999.99 | [{'amount': 10, 'cost_basis': 102.711000000000... | -1.000000e-09 | -11.224972 | 0 | 0 | 0 | -11.224972 | 10000000.00 | 0.0 | 0.0 | 2 | [{'dt': 2016-01-05 21:00:00+00:00, 'order_id':... | 0.0 |
2016-01-06 21:00:00+00:00 | 100.70 | 1.842654e-05 | -2.012000e-06 | -4.883861e-05 | -0.024771 | 0.137853 | 5.744807e-05 | -1007.01 | 9997965.88 | 2014.0 | 2014.0 | 0.0 | 0.000201 | 2014.0 | 2014.0 | 1 | -2.012000e-06 | 0.0 | 0.000201 | [{'created': 2016-01-05 21:00:00+00:00, 'reaso... | 2016-01-06 21:00:00+00:00 | 2016-01 | 2016-01-06 14:31:00+00:00 | -20.11 | 9999979.88 | [{'amount': 20, 'cost_basis': 101.706000000000... | -2.011000e-06 | -9.171989 | 0 | 0 | 0 | -9.169708 | 9998972.89 | 1027.1 | 1027.1 | 3 | [{'dt': 2016-01-06 21:00:00+00:00, 'order_id':... | 0.0 |
2016-01-07 21:00:00+00:00 | 96.45 | 6.394658e-05 | -1.051300e-05 | 2.633450e-04 | -0.048168 | 0.167868 | 3.005102e-04 | -964.51 | 9997001.37 | 2893.5 | 2893.5 | 0.0 | 0.000289 | 2893.5 | 2893.5 | 1 | -1.051300e-05 | 0.0 | 0.000289 | [{'created': 2016-01-06 21:00:00+00:00, 'reaso... | 2016-01-07 21:00:00+00:00 | 2016-01 | 2016-01-07 14:31:00+00:00 | -85.01 | 9999894.87 | [{'amount': 30, 'cost_basis': 99.9543333333335... | -8.501017e-06 | -10.357397 | 0 | 0 | 0 | -9.552189 | 9997965.88 | 2014.0 | 2014.0 | 4 | [{'dt': 2016-01-07 21:00:00+00:00, 'order_id':... | 0.0 |
2016-01-08 21:00:00+00:00 | 96.96 | 6.275294e-05 | -8.984000e-06 | 4.879306e-04 | -0.058601 | 0.145654 | 3.118401e-04 | -969.61 | 9996031.76 | 3878.4 | 3878.4 | 0.0 | 0.000388 | 3878.4 | 3878.4 | 1 | -1.051300e-05 | 0.0 | 0.000388 | [{'created': 2016-01-07 21:00:00+00:00, 'reaso... | 2016-01-08 21:00:00+00:00 | 2016-01 | 2016-01-08 14:31:00+00:00 | 15.29 | 9999910.16 | [{'amount': 40, 'cost_basis': 99.2060000000002... | 1.529016e-06 | -7.215497 | 0 | 0 | 0 | -7.301134 | 9997001.37 | 2893.5 | 2893.5 | 5 | [{'dt': 2016-01-08 21:00:00+00:00, 'order_id':... | 0.0 |
IDE 通过[run_algorithm()
要在您喜欢的 IDE 中像 Python 脚本一样执行算法,请使用run_algorithm()
(参见 API 参考)。
要根据上述的buyapple.py
示例进行调整(参见同一目录中的buyapple_ide.py
),只需添加以下内容:
from zipline import run_algorithm
import pandas as pd
import pandas_datareader.data as web
def initialize(context):
...
def handle_data(context, data):
...
start = pd.Timestamp('2014')
end = pd.Timestamp('2018')
sp500 = web.DataReader('SP500', 'fred', start, end).SP500
benchmark_returns = sp500.pct_change()
result = run_algorithm(start=start.tz_localize('UTC'),
end=end.tz_localize('UTC'),
initialize=initialize,
handle_data=handle_data,
capital_base=100000,
benchmark_returns=benchmark_returns,
bundle='quandl',
data_frequency='daily')
我们将关键算法参数传递给run_algorithm()
,包括我们从联邦储备经济数据服务下载的 S&P 500 的一些基准数据(过去 10 年内的数据)。
result
返回值包含与前一个示例相同的DataFrame
。您可以对DataFrame
应用您喜欢的逻辑,而不是将analyze()
函数定义为算法的一部分。
数据摄取
如果您尚未摄取数据,请运行:
$ zipline ingest -b <bundle>
其中<bundle>
是将要摄取的 bundle 的名称。您现在可以使用默认的 quandl 来处理Quandl WIKI 价格数据。有关如何获取其他新数据的更多详细信息,请查看数据摄取部分。
命令行界面
安装 Zipline 后,您应该能够从命令行执行以下操作(例如,在 Windows 上的cmd.exe
,在 OSX 上的 Terminal 应用程序,或在 Linux 上的 bash shell):
$ zipline run --help
Usage: zipline run [OPTIONS]
Run a backtest for the given algorithm.
Options:
-f, --algofile FILENAME The file that contains the algorithm to run.
-t, --algotext TEXT The algorithm script to run.
-D, --define TEXT Define a name to be bound in the namespace
before executing the algotext. For example
'-Dname=value'. The value may be any python
expression. These are evaluated in order so
they may refer to previously defined names.
--data-frequency [daily|minute]
The data frequency of the simulation.
[default: daily]
--capital-base FLOAT The starting capital for the simulation.
[default: 10000000.0]
-b, --bundle BUNDLE-NAME The data bundle to use for the simulation.
[default: quandl]
--bundle-timestamp TIMESTAMP The date to lookup data on or before.
[default: <current-time>]
-s, --start DATE The start date of the simulation.
-e, --end DATE The end date of the simulation.
-o, --output FILENAME The location to write the perf data. If this
is '-' the perf will be written to stdout.
[default: -]
--trading-calendar TRADING-CALENDAR
The calendar you want to use e.g. LSE. NYSE
is the default.
--print-algo / --no-print-algo Print the algorithm to stdout.
--benchmark-file The csv file that contains the benchmark
returns (date, returns columns)
--benchmark-symbol The instrument's symbol to be used as
a benchmark.
(should exist in the ingested bundle)
--benchmark-sid The sid of the instrument to be used as a
benchmark.
(should exist in the ingested bundle)
--no-benchmark This flag is used to set the benchmark to
zero. Alpha, beta and benchmark metrics
are not calculated
--help Show this message and exit.
如您所见,有几个标志指定了算法的位置(-f
)以及指定使用哪些数据的参数,默认为quandl
。
还有用于指定算法运行时间范围的参数(--start
和--end
)。要使用基准,您需要选择前面列出的基准选项之一。您始终可以使用将零回报作为基准的选项(--no-benchmark
)(在这种情况下,不计算 alpha、beta 和基准指标)。
最后,您会希望保存算法的性能指标,以便分析其表现。这是通过--output
标志完成的,它将导致它以 pickle Python 文件格式编写性能DataFrame
。请注意,您还可以使用这些参数定义一个配置文件,然后方便地将其传递给-c
选项,这样您就不必每次都提供命令行参数(请参阅示例目录中的.conf 文件)。
因此,要执行上述算法并将结果保存到buyapple_out.pickle
,我们按如下方式调用zipline run
:
zipline run -f ../zipline/examples/buyapple.py --start 2016-1-1 --end 2018-1-1 -o buyapple_out.pickle --no-benchmark
AAPL
[2018-01-03 04:30:51.843465] INFO: Performance: Simulated 503 trading days out of 503.
[2018-01-03 04:30:51.843598] INFO: Performance: first open: 2016-01-04 14:31:00+00:00
[2018-01-03 04:30:51.843672] INFO: Performance: last close: 2017-12-29 21:00:00+00:00
run
首先调用initialize()
函数,然后通过handle_data()
逐日流式传输历史股票价格。在每次调用handle_data()
之后,我们指示zipline
订购 10 股 AAPL。在调用order()
函数之后,zipline
将订购的股票和数量输入订单簿。在handle_data()
函数完成后,zipline
查找任何未完成的订单并尝试填充它们。如果该股票的交易量足够大,订单在添加佣金并应用滑点模型(该模型模拟您的订单对股票价格的影响)后执行,因此您的算法将被收取的费用不仅仅是股票价格 * 10。(请注意,您也可以更改zipline
使用的佣金和滑点模型,请参阅。
让我们快速查看一下DataFrame
的表现。为此,我们在 IPython Notebook 中使用pandas
并打印前 10 行。请注意,zipline
大量使用pandas
,尤其是在数据输入和输出方面,因此值得花时间学习它。
import pandas as pd
perf = pd.read_pickle('buyapple_out.pickle') # read in perf DataFrame
perf.head()
AAPL | algo_volatility | algorithm_period_return | alpha | benchmark_period_return | benchmark_volatility | beta | capital_used | ending_cash | ending_exposure | ending_value | excess_return | gross_leverage | long_exposure | long_value | longs_count | max_drawdown | max_leverage | net_leverage | orders | period_close | period_label | period_open | pnl | portfolio_value | positions | returns | sharpe | short_exposure | short_value | shorts_count | sortino | starting_cash | starting_exposure | starting_value | trading_days | transactions | treasury_period_return | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2016-01-04 21:00:00+00:00 | 105.35 | NaN | 0.000000e+00 | NaN | -0.013983 | NaN | NaN | 0.0 | 10000000.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0 | 0.000000e+00 | 0.0 | 0.000000 | [{'dt': 2016-01-04 21:00:00+00:00, 'reason': N... | 2016-01-04 21:00:00+00:00 | 2016-01 | 2016-01-04 14:31:00+00:00 | 0.0 | 10000000.0 | [] | 0.000000e+00 | NaN | 0 | 0 | 0 | NaN | 10000000.0 | 0.0 | 0.0 | 1 | [] | 0.0 |
2016-01-05 21:00:00+00:00 | 102.71 | 0.000001 | -1.000000e-07 | -0.000022 | -0.012312 | 0.175994 | -0.000006 | -1028.1 | 9998971.9 | 1027.1 | 1027.1 | 0.0 | 0.000103 | 1027.1 | 1027.1 | 1 | -1.000000e-07 | 0.0 | 0.000103 | [{'dt': 2016-01-05 21:00:00+00:00, 'reason': N... | 2016-01-05 21:00:00+00:00 | 2016-01 | 2016-01-05 14:31:00+00:00 | -1.0 | 9999999.0 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | -1.000000e-07 | -11.224972 | 0 | 0 | 0 | -11.224972 | 10000000.0 | 0.0 | 0.0 | 2 | [{'order_id': '4011063b5c094e82a5391527044098b... | 0.0 |
2016-01-06 21:00:00+00:00 | 100.70 | 0.000019 | -2.210000e-06 | -0.000073 | -0.024771 | 0.137853 | 0.000054 | -1008.0 | 9997963.9 | 2014.0 | 2014.0 | 0.0 | 0.000201 | 2014.0 | 2014.0 | 1 | -2.210000e-06 | 0.0 | 0.000201 | [{'dt': 2016-01-06 21:00:00+00:00, 'reason': N... | 2016-01-06 21:00:00+00:00 | 2016-01 | 2016-01-06 14:31:00+00:00 | -21.1 | 9999977.9 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | -2.110000e-06 | -9.823839 | 0 | 0 | 0 | -9.588756 | 9998971.9 | 1027.1 | 1027.1 | 3 | [{'order_id': '3bf9fe20cc46468d99f741474226c03... | 0.0 |
2016-01-07 21:00:00+00:00 | 96.45 | 0.000064 | -1.081000e-05 | 0.000243 | -0.048168 | 0.167868 | 0.000300 | -965.5 | 9996998.4 | 2893.5 | 2893.5 | 0.0 | 0.000289 | 2893.5 | 2893.5 | 1 | -1.081000e-05 | 0.0 | 0.000289 | [{'dt': 2016-01-07 21:00:00+00:00, 'reason': N... | 2016-01-07 21:00:00+00:00 | 2016-01 | 2016-01-07 14:31:00+00:00 | -86.0 | 9999891.9 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | -8.600019e-06 | -10.592737 | 0 | 0 | 0 | -9.688947 | 9997963.9 | 2014.0 | 2014.0 | 4 | [{'order_id': '6af6aed9fbb44a6bba17e802051b94d... | 0.0 |
2016-01-08 21:00:00+00:00 | 96.96 | 0.000063 | -9.380000e-06 | 0.000466 | -0.058601 | 0.145654 | 0.000311 | -970.6 | 9996027.8 | 3878.4 | 3878.4 | 0.0 | 0.000388 | 3878.4 | 3878.4 | 1 | -1.081000e-05 | 0.0 | 0.000388 | [{'dt': 2016-01-08 21:00:00+00:00, 'reason': N... | 2016-01-08 21:00:00+00:00 | 2016-01 | 2016-01-08 14:31:00+00:00 | 14.3 | 9999906.2 | [{'sid': Equity(8 [AAPL]), 'last_sale_price': ... | 1.430015e-06 | -7.511729 | 0 | 0 | 0 | -7.519659 | 9996998.4 | 2893.5 | 2893.5 | 5 | {'order_id': '18f64975732449a18fca06e9c69bf5c... | 0.0 |
如您所见,每行代表一个交易日,从 2016 年的第一个工作日开始。在列中,您可以找到有关算法状态的各种信息。最左边的列AAPL
是由前面提到的record()
函数放置的,它允许我们绘制苹果的价格。例如,我们现在可以很容易地检查我们的投资组合价值随时间的变化与 AAPL 股票价格相比如何。
%pylab inline
figsize(12, 12)
import matplotlib.pyplot as plt
ax1 = plt.subplot(211)
perf.portfolio_value.plot(ax=ax1)
ax1.set_ylabel('Portfolio Value')
ax2 = plt.subplot(212, sharex=ax1)
perf.AAPL.plot(ax=ax2)
ax2.set_ylabel('AAPL Stock Price')
Populating the interactive namespace from numpy and matplotlib
<matplotlib.text.Text at 0x10c48c198>
![_images/tutorial_11_2.png
如您所见,我们的算法性能通过portfolio_value
评估,与 AAPL 股票价格紧密匹配。这并不令人惊讶,因为我们的算法只要有机会就会购买 AAPL。
Jupyter Notebook
Jupyter Notebook是一个非常强大的基于浏览器的 Python 解释器界面(本教程就是在其中编写的)。由于它是许多定量研究人员非常流行的界面,Zipline 提供了一种简单的方法,可以在不要求你使用 CLI 的情况下在 Notebook 内部运行你的算法。
要使用它,你需要在一个单元格中编写你的算法,并让 Zipline 知道它应该运行这个算法。这是通过%%zipline
IPython 魔术命令完成的,该命令在你从 IPython Notebook 中import zipline
之后可用。这个魔术接受与上面描述的命令行界面相同的参数。因此,要使用相同的参数运行上面的算法,我们只需要在导入zipline
以注册魔术之后执行以下单元格。
%load_ext zipline
%%zipline --start 2016-1-1 --end 2018-1-1
from zipline.api import symbol, order, record
def initialize(context):
pass
def handle_data(context, data):
order(symbol('AAPL'), 10)
record(AAPL=data.current(symbol('AAPL'), "price")
请注意,我们不需要像上面那样指定输入文件,因为魔术将使用单元格的内容并在那里查找你的算法函数。此外,我们不是定义输出文件,而是使用-o
指定一个变量名,该变量名将在名称空间中创建,并包含我们在上面查看的性能DataFrame
。
_.head()
AAPL | algo_volatility | algorithm_period_return | alpha | benchmark_period_return | benchmark_volatility | beta | capital_used | ending_cash | ending_exposure | ending_value | excess_return | gross_leverage | long_exposure | long_value | longs_count | max_drawdown | max_leverage | net_leverage | orders | period_close | period_label | period_open | pnl | portfolio_value | positions | returns | sharpe | short_exposure | short_value | shorts_count | sortino | starting_cash | starting_exposure | starting_value | trading_days | transactions | treasury_period_return | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2016-01-04 21:00:00+00:00 | 105.35 | NaN | 0.000000e+00 | NaN | -0.013983 | NaN | NaN | 0.00 | 10000000.00 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0 | 0.000000e+00 | 0.0 | 0.000000 | [{'created': 2016-01-04 21:00:00+00:00, 'reaso... | 2016-01-04 21:00:00+00:00 | 2016-01 | 2016-01-04 14:31:00+00:00 | 0.00 | 10000000.00 | [] | 0.000000e+00 | NaN | 0 | 0 | 0 | NaN | 10000000.00 | 0.0 | 0.0 | 1 | [] | 0.0 |
2016-01-05 21:00:00+00:00 | 102.71 | 1.122497e-08 | -1.000000e-09 | -2.247510e-07 | -0.012312 | 0.175994 | -6.378047e-08 | -1027.11 | 9998972.89 | 1027.1 | 1027.1 | 0.0 | 0.000103 | 1027.1 | 1027.1 | 1 | -9.999999e-10 | 0.0 | 0.000103 | {'created': 2016-01-04 21:00:00+00:00, 'reaso... | 2016-01-05 21:00:00+00:00 | 2016-01 | 2016-01-05 14:31:00+00:00 | -0.01 | 9999999.99 | [{'amount': 10, 'cost_basis': 102.711000000000... | -1.000000e-09 | -11.224972 | 0 | 0 | 0 | -11.224972 | 10000000.00 | 0.0 | 0.0 | 2 | [{'dt': 2016-01-05 21:00:00+00:00, 'order_id':... | 0.0 |
2016-01-06 21:00:00+00:00 | 100.70 | 1.842654e-05 | -2.012000e-06 | -4.883861e-05 | -0.024771 | 0.137853 | 5.744807e-05 | -1007.01 | 9997965.88 | 2014.0 | 2014.0 | 0.0 | 0.000201 | 2014.0 | 2014.0 | 1 | -2.012000e-06 | 0.0 | 0.000201 | [{'created': 2016-01-05 21:00:00+00:00, 'reaso... | 2016-01-06 21:00:00+00:00 | 2016-01 | 2016-01-06 14:31:00+00:00 | -20.11 | 9999979.88 | [{'amount': 20, 'cost_basis': 101.706000000000... | -2.011000e-06 | -9.171989 | 0 | 0 | 0 | -9.169708 | 9998972.89 | 1027.1 | 1027.1 | 3 | [{'dt': 2016-01-06 21:00:00+00:00, 'order_id':... | 0.0 |
2016-01-07 21:00:00+00:00 | 96.45 | 6.394658e-05 | -1.051300e-05 | 2.633450e-04 | -0.048168 | 0.167868 | 3.005102e-04 | -964.51 | 9997001.37 | 2893.5 | 2893.5 | 0.0 | 0.000289 | 2893.5 | 2893.5 | 1 | -1.051300e-05 | 0.0 | 0.000289 | [{'created': 2016-01-06 21:00:00+00:00, 'reaso... | 2016-01-07 21:00:00+00:00 | 2016-01 | 2016-01-07 14:31:00+00:00 | -85.01 | 9999894.87 | [{'amount': 30, 'cost_basis': 99.9543333333335... | -8.501017e-06 | -10.357397 | 0 | 0 | 0 | -9.552189 | 9997965.88 | 2014.0 | 2014.0 | 4 | [{'dt': 2016-01-07 21:00:00+00:00, 'order_id':... | 0.0 |
2016-01-08 21:00:00+00:00 | 96.96 | 6.275294e-05 | -8.984000e-06 | 4.879306e-04 | -0.058601 | 0.145654 | 3.118401e-04 | -969.61 | 9996031.76 | 3878.4 | 3878.4 | 0.0 | 0.000388 | 3878.4 | 3878.4 | 1 | -1.051300e-05 | 0.0 | 0.000388 | [{'created': 2016-01-07 21:00:00+00:00, 'reaso... | 2016-01-08 21:00:00+00:00 | 2016-01 | 2016-01-08 14:31:00+00:00 | 15.29 | 9999910.16 | [{'amount': 40, 'cost_basis': 99.2060000000002... | 1.529016e-06 | -7.215497 | 0 | 0 | 0 | -7.301134 | 9997001.37 | 2893.5 | 2893.5 | 5 | [{'dt': 2016-01-08 21:00:00+00:00, 'order_id':... | 0.0 |
IDE 通过 [run_algorithm()
要在您喜欢的 IDE 中像执行 Python 脚本一样执行算法,请使用 run_algorithm()
(参见 API 参考)。
要调整上述buyapple.py
示例(参见同一目录中的buyapple_ide.py
),只需添加以下内容:
from zipline import run_algorithm
import pandas as pd
import pandas_datareader.data as web
def initialize(context):
...
def handle_data(context, data):
...
start = pd.Timestamp('2014')
end = pd.Timestamp('2018')
sp500 = web.DataReader('SP500', 'fred', start, end).SP500
benchmark_returns = sp500.pct_change()
result = run_algorithm(start=start.tz_localize('UTC'),
end=end.tz_localize('UTC'),
initialize=initialize,
handle_data=handle_data,
capital_base=100000,
benchmark_returns=benchmark_returns,
bundle='quandl',
data_frequency='daily')
我们将关键算法参数传递给 run_algorithm()
,包括我们从联邦储备经济数据服务下载的 S&P 500 的一些基准数据(过去 10 年可用)。
返回值result
包含与前一个示例相同的DataFrame
。您可以对这个DataFrame
应用您喜欢的逻辑,而不是在算法中定义一个analyze()
函数。
如何使用历史价格:双移动平均线交叉示例
双移动平均线(DMA)是一种经典的动量策略。虽然现在可能没有哪个严肃的交易者会使用它,但它仍然非常有教育意义。基本思想是我们计算两个滚动或移动平均线(mavg)——一个较长窗口的平均线,用于捕捉长期趋势,另一个较短窗口的平均线,用于捕捉短期趋势。一旦短期 mavg 从下方穿过长期 mavg,我们就认为股价具有上升动量,并买入股票。如果短期 mavg 从上方穿过,我们就退出仓位,因为我们认为股价会进一步下跌。
由于我们需要访问先前的价格来实现这个策略,我们需要一个新的概念:历史。
data.history()
是一个便捷函数,它为您保留了一个数据滚动窗口。第一个参数是您想要收集的条形图数量,第二个参数是单位('1d'
或'1m'
,但请注意,使用1m
需要有分钟级别的数据)。如需更详细地了解history()
的功能,请参阅 API 参考。让我们来看一下这个策略,它应该能让你更清楚:
%%zipline --start 2014-1-1 --end 2018-1-1 -o dma.pickle
from zipline.api import order_target, record, symbol
import matplotlib.pyplot as plt
def initialize(context):
context.i = 0
context.asset = symbol('AAPL')
def handle_data(context, data):
# Skip first 300 days to get full windows
context.i += 1
if context.i < 300:
return
# Compute averages
# data.history() has to be called with the same params
# from above and returns a pandas dataframe.
short_mavg = data.history(context.asset, 'price', bar_count=100, frequency="1d").mean()
long_mavg = data.history(context.asset, 'price', bar_count=300, frequency="1d").mean()
# Trading logic
if short_mavg > long_mavg:
# order_target orders as many shares as needed to
# achieve the desired number of shares.
order_target(context.asset, 100)
elif short_mavg < long_mavg:
order_target(context.asset, 0)
# Save values for later inspection
record(AAPL=data.current(context.asset, 'price'),
short_mavg=short_mavg,
long_mavg=long_mavg)
def analyze(context, perf):
fig = plt.figure()
ax1 = fig.add_subplot(211)
perf.portfolio_value.plot(ax=ax1)
ax1.set_ylabel('portfolio value in $')
ax2 = fig.add_subplot(212)
perf['AAPL'].plot(ax=ax2)
perf[['short_mavg', 'long_mavg']].plot(ax=ax2)
perf_trans = perf.loc[[t != [] for t in perf.transactions]]
buys = perf_trans.loc[[t[0]['amount'] > 0 for t in perf_trans.transactions]]
sells = perf_trans.loc[
[t[0]['amount'] < 0 for t in perf_trans.transactions]]
ax2.plot(buys.index, perf.short_mavg.loc[buys.index],
'^', markersize=10, color='m')
ax2.plot(sells.index, perf.short_mavg.loc[sells.index],
'v', markersize=10, color='k')
ax2.set_ylabel('price in $')
plt.legend(loc=0)
plt.show()
在这里,我们明确地定义了一个analyze()
函数,该函数在回测完成后会自动调用。
尽管这可能不是直接显而易见的,但history()
(双关语)的力量不容小觑,因为大多数算法都会以某种形式利用先前的市场发展。你可以轻松地设计一个策略,使用scikit-learn训练一个分类器,试图根据过去的价格预测未来的市场走势,(注意,大多数scikit-learn
函数需要numpy.ndarray
而不是pandas.DataFrame
,所以你可以简单地通过.to_numpy()
传递DataFrame
的底层ndarray
)。
我们还使用了上面的order_target()
函数。这类函数可以使订单管理和投资组合再平衡变得更加容易。更多详情请参阅 API 参考。
结论
我们希望本教程能为您提供一些关于zipline
架构、API 和功能的初步了解。下一步,可以查看一些示例。
如有疑问,请随时在我们的邮件列表上提问,在我们的GitHub 问题跟踪器上报告问题,或参与进来。
结论
我们希望本教程能为您提供一些关于zipline
架构、API 和功能的初步了解。下一步,可以查看一些示例。
欢迎在我们的邮件列表上提问,在我们的GitHub 问题跟踪器上报问题,或参与进来。
Data
数据包是一组定价数据、调整数据和资产数据库的集合。数据包使我们能够预加载运行回测所需的所有数据,并将数据存储起来以备将来使用。
发现可用的数据包
Zipline 自带一个默认数据包,并允许注册新的数据包。要查看哪些数据包可能可用,我们可以运行 bundles
命令,例如:
$ zipline bundles
my-custom-bundle 2016-05-05 20:35:19.809398
my-custom-bundle 2016-05-05 20:34:53.654082
my-custom-bundle 2016-05-05 20:34:48.401767
quandl 2016-05-05 20:06:40.894956
这里的输出显示有 3 个数据包可用:
-
my-custom-bundle
(用户添加) -
quandl
(由 Zipline 提供,默认数据包)
名称旁边的日期和时间显示了该数据包数据导入的时间。我们已经为 my-custom-bundle
运行了三次不同的导入。我们从未为 quandl
数据包导入任何数据,因此它只显示 <no ingestions>
。
注意:Quantopian 曾经提供了一个重新打包的 quandl
数据包版本,名为 quantopian-quandl
,截至 2021 年 4 月仍然可用。虽然它导入速度更快,但它没有该库后来要求的国别代码,而当前的 Zipline 版本为 quandl
数据包插入了这些代码。如果你想使用 quantopian-quandl
,请使用这个解决方案手动更新数据库。 ## 数据导入
使用数据包的第一步是导入数据。导入过程将调用一些自定义数据包命令,然后将数据写入 Zipline 可以找到的标准位置。默认情况下,导入的数据将写入的位置是 $ZIPLINE_ROOT/data/<bundle>
,默认情况下 ZIPLINE_ROOT=~/.zipline
。导入步骤可能需要一些时间,因为它可能涉及下载和处理大量数据。要导入数据包,请运行:
$ zipline ingest [-b <bundle>]
其中 <bundle>
是要导入的数据包的名称,默认为 quandl
。
Old Data
ingest
命令使用时,它会将新数据写入 $ZIPLINE_ROOT/data/<bundle>
的子目录,该子目录以当前日期命名。这使得查看旧数据或甚至使用旧副本运行回测成为可能。使用旧的导入数据运行回测使得稍后重现回测结果变得更加容易。
默认情况下保存所有数据的缺点是,即使您不想使用这些数据,数据目录也可能变得非常大。如前所述,我们可以使用 bundles 命令 列出所有导入。为了解决旧数据泄露的问题,还有一个命令:clean
,它将根据某些时间约束清除数据包。
例如:
# clean everything older than <date>
$ zipline clean [-b <bundle>] --before <date>
# clean everything newer than <date>
$ zipline clean [-b <bundle>] --after <date>
# keep everything in the range of [before, after] and delete the rest
$ zipline clean [-b <bundle>] --before <date> --after <after>
# clean all but the last <int> runs
$ zipline clean [-b <bundle>] --keep-last <int>
使用数据包运行回测
现在数据已经导入,我们可以使用它来运行回测,使用 run
命令。可以使用 --bundle
选项指定要使用的数据包,例如:
$ zipline run --bundle <bundle> --algofile algo.py ...
我们还可以使用--bundle-timestamp
选项指定查找捆绑数据所用的日期。设置--bundle-timestamp
将导致run
使用小于或等于bundle-timestamp
的最新的捆绑数据摄取。这就是我们如何使用旧数据进行回测。bundle-timestamp
使用小于或等于的关系,因此我们可以指定运行旧回测的日期,并获取该日期对我们可用的相同数据。bundle-timestamp
默认设置为当前日期,以使用最新的数据。
默认数据捆绑包
Quandl WIKI 捆绑包
默认情况下,Zipline 附带了quandl
数据捆绑包,该捆绑包使用 Quandl 的WIKI 数据集。Quandl 数据捆绑包包括每日定价数据、拆分、现金股息和资产元数据。要摄取quandl
数据捆绑包,请运行以下任一命令:
$ zipline ingest -b quandl
$ zipline ingest
任一命令下载和处理数据应该只需要几分钟。
注意
Quandl 在 2018 年初停止了这个数据集的更新,不再更新。尽管如此,它仍然是一个有用的起点,可以在不设置自己的数据集的情况下尝试 Zipline。## 编写新的捆绑包
数据捆绑包的存在是为了方便使用不同的数据源与 Zipline。要添加新的捆绑包,必须实现一个ingest
函数。
ingest
函数负责将数据加载到内存中,并将其传递给一组由 Zipline 提供的写入器对象,以将数据转换为 Zipline 的内部格式。ingest
函数可以通过从远程位置(如quandl
捆绑包)下载数据或仅加载机器上已有的文件来工作。该函数提供了将数据写入正确位置的写入器。如果摄取部分失败,捆绑包将不会处于不完整状态。
ingest
函数的签名应为:
ingest(environ,
asset_db_writer,
minute_bar_writer,
daily_bar_writer,
adjustment_writer,
calendar,
start_session,
end_session,
cache,
show_progress,
output_dir)
environ
environ
是一个映射,表示要使用的环境变量。这是传递任何摄取所需的定制参数的地方,例如:quandl
捆绑包使用环境传递 API 密钥和下载重试尝试次数。
asset_db_writer
asset_db_writer
是AssetDBWriter
的一个实例。这是资产元数据的写入器,提供资产生命周期和符号到资产 ID(sid)的映射。这可能还包括资产名称、交易所和其他一些列。要写入数据,请使用各种元数据的数据框调用write()
。有关数据格式的更多信息,请参阅 write 的文档。
minute_bar_writer
分钟条形写入器
是 BcolzMinuteBarWriter
的一个实例。该写入器用于将数据转换为 Zipline 的内部 bcolz 格式,以便稍后由 BcolzMinuteBarReader
读取。如果提供分钟数据,用户应该使用 (sid, 数据框) 元组的可迭代对象调用 write()
。show_progress
参数也应该传递给此方法。如果数据源不提供分钟级数据,则无需调用写入方法。向 write()
传递一个空的迭代器也是可接受的,以表明没有分钟数据。
注意
传递给 write()
的数据可以是惰性迭代器或生成器,以避免一次性将所有分钟数据加载到内存中。只要日期严格递增,给定的 sid 也可以在数据中出现多次。
日条形写入器
日条形写入器
是 BcolzDailyBarWriter
的一个实例。该写入器用于将数据转换为 Zipline 的内部 bcolz 格式,以便稍后由 BcolzDailyBarReader
读取。如果提供日数据,用户应该使用可迭代对象的 (sid, 数据框) 元组调用 write()
。show_progress
参数也应该传递给此方法。如果数据源不提供日数据,则无需调用写入方法。向 write()
传递一个空的可迭代对象也是可接受的,以表明没有日数据。如果没有提供日数据但提供了分钟数据,则会进行日汇总以满足日历史请求。
注意
与 分钟条形写入器
类似,传递给 write()
的数据可以是惰性可迭代对象或生成器,以避免一次性将所有数据加载到内存中。与 分钟条形写入器
不同的是,sid 在数据可迭代对象中只能出现一次。
调整写入器
调整写入器
是 SQLiteAdjustmentWriter
的一个实例。该写入器用于存储拆分、合并、股息和股票股息。数据应以数据框的形式提供,并传递给 write()
。这些字段都是可选的,但写入器可以接受您拥有的尽可能多的数据。
日历
日历
是 zipline.utils.calendars.TradingCalendar
的一个实例。提供日历是为了帮助一些捆绑包生成所需日期的查询。
开始会话
开始会话
是一个 pandas.Timestamp
对象,指示捆绑包应该加载数据的第一天。
结束会话
结束会话
是一个pandas.Timestamp
对象,表示包应加载数据的最后一天。
缓存
缓存
是dataframe_cache
的一个实例。这个对象是一个从字符串到数据框的映射。这个对象是在摄取过程中崩溃时提供的。其想法是,摄取函数应该检查缓存中是否存在原始数据,如果不存在,则应该获取它,然后将其存储在缓存中。然后它可以解析并写入数据。只有在成功加载后,缓存才会被清除,这可以防止摄取函数在解析中出现错误时需要重新下载所有数据。如果获取数据非常快,例如如果它来自另一个本地文件,则不需要使用此缓存。
显示进度
显示进度
是一个布尔值,表示用户希望接收关于摄取函数获取和写入数据的进度的反馈。例如,显示已下载的文件数量占所需总量的百分比,或者显示数据转换的进度。实现循环中显示进度
的一个有用工具是maybe_show_progress
。这个参数应该总是被转发到minute_bar_writer.write
和daily_bar_writer.write
。
输出目录
输出目录
是一个字符串,表示所有数据将被写入的文件路径。输出目录
将是$ZIPLINE_ROOT
的某个子目录,并将包含当前摄取的开始时间。如果由于某些原因您的摄取函数可以不使用写入器而直接产生输出,则可以直接将资源移动到这里。例如,quantopian:quandl
包使用这个直接将包解压到输出目录
。
从.csv 文件摄取数据
Zipline 提供了一个名为csvdir
的包,允许用户从.csv
文件中摄取数据。文件格式应为 OHLCV 格式,包含日期、股息和拆分。下面提供了一个示例。在zipline/tests/resources/csvdir_samples
中还有其他用于测试目的的示例。
date,open,high,low,close,volume,dividend,split
2012-01-03,58.485714,58.92857,58.42857,58.747143,75555200,0.0,1.0
2012-01-04,58.57143,59.240002,58.468571,59.062859,65005500,0.0,1.0
2012-01-05,59.278572,59.792858,58.952858,59.718571,67817400,0.0,1.0
2012-01-06,59.967144,60.392857,59.888573,60.342857,79573200,0.0,1.0
2012-01-09,60.785713,61.107143,60.192856,60.247143,98506100,0.0,1.0
2012-01-10,60.844284,60.857143,60.214287,60.462856,64549100,0.0,1.0
2012-01-11,60.382858,60.407143,59.901428,60.364285,53771200,0.0,1.0
一旦您的数据格式正确,您可以编辑~/.zipline/extension.py
文件中的extension.py
文件,并导入 csvdir 包和pandas
。
import pandas as pd
from zipline.data.bundles import register
from zipline.data.bundles.csvdir import csvdir_equities
然后,我们希望指定我们的包数据的开始和结束会话:
start_session = pd.Timestamp('2016-1-1', tz='utc')
end_session = pd.Timestamp('2018-1-1', tz='utc')
然后我们可以注册()
我们的包,并传递我们的.csv
文件所在的目录位置:
register(
'custom-csvdir-bundle',
csvdir_equities(
['daily'],
'/path/to/your/csvs',
),
calendar_name='NYSE', # US equities
start_session=start_session,
end_session=end_session
)
最后,我们可以运行以下命令来摄取我们的数据:
$ zipline ingest -b custom-csvdir-bundle
Loading custom pricing data: [############------------------------] 33% | FAKE: sid 0
Loading custom pricing data: [########################------------] 66% | FAKE1: sid 1
Loading custom pricing data: [####################################] 100% | FAKE2: sid 2
Loading custom pricing data: [####################################] 100%
Merging daily equity files: [####################################]
# optionally, we can pass the location of our csvs via the command line
$ CSVDIR=/path/to/your/csvs zipline ingest -b custom-csvdir-bundle
如果你想使用不在 NYSE 日历或现有 Zipline 日历中的股票,你可以查看Trading Calendar Tutorial
来构建一个自定义交易日历,然后你可以将名称传递给register()
。
实用示例
请参阅Algoseek的分钟数据和日本股票的每日频率示例,来自书籍机器学习交易。
发现可用的捆绑包
Zipline 自带一个默认捆绑包,以及注册新捆绑包的能力。要查看哪些捆绑包可能可用,我们可以运行bundles
命令,例如:
$ zipline bundles
my-custom-bundle 2016-05-05 20:35:19.809398
my-custom-bundle 2016-05-05 20:34:53.654082
my-custom-bundle 2016-05-05 20:34:48.401767
quandl 2016-05-05 20:06:40.894956
这里的输出显示有 3 个可用的捆绑包:
-
my-custom-bundle
(由用户添加) -
quandl
(由 Zipline 提供,默认捆绑包)
名称旁边的日期和时间显示了该捆绑包数据被摄取的时间。我们为my-custom-bundle
进行了三次不同的数据摄取。我们从未为quandl
捆绑包摄取过任何数据,因此它只显示<no ingestions>
。
注意:Quantopian 曾经提供了一个重新打包的quandl
捆绑包版本,名为quantopian-quandl
,截至 2021 年 4 月仍然可用。虽然它摄取速度更快,但它没有库后来要求的国别代码,而当前的 Zipline 版本为quandl
捆绑包插入了国别代码。如果你想使用quantopian-quandl
,请使用这个解决方法手动更新数据库。
摄取数据
使用数据捆绑包的第一步是摄取数据。摄取过程将调用一些自定义捆绑包命令,然后将数据写入 Zipline 可以找到的标准位置。默认情况下,摄取的数据将被写入的位置是$ZIPLINE_ROOT/data/<bundle>
,默认情况下ZIPLINE_ROOT=~/.zipline
。摄取步骤可能需要一些时间,因为它可能涉及下载和处理大量数据。要摄取捆绑包,请运行:
$ zipline ingest [-b <bundle>]
其中<bundle>
是要摄取的捆绑包的名称,默认为quandl
。
旧数据
当使用ingest
命令时,它会将新数据写入到以当前日期命名的$ZIPLINE_ROOT/data/<bundle>
的子目录中。这使得查看旧数据或甚至使用旧副本运行回测成为可能。使用旧的数据摄取运行回测使得稍后更容易重现回测结果。
默认情况下保存所有数据的缺点是,即使您不想使用数据,数据目录也可能变得很大。如前所述,我们可以使用 bundles 命令 列出所有导入。为了解决旧数据泄露的问题,还有另一个命令:clean
,它将根据某些时间约束清除数据包。
例如:
# clean everything older than <date>
$ zipline clean [-b <bundle>] --before <date>
# clean everything newer than <date>
$ zipline clean [-b <bundle>] --after <date>
# keep everything in the range of [before, after] and delete the rest
$ zipline clean [-b <bundle>] --before <date> --after <after>
# clean all but the last <int> runs
$ zipline clean [-b <bundle>] --keep-last <int>
使用数据包运行回测
现在数据已经导入,我们可以使用它来运行回测,使用 run
命令。可以使用 --bundle
选项指定要使用的数据包,例如:
$ zipline run --bundle <bundle> --algofile algo.py ...
我们还可以使用 --bundle-timestamp
选项指定要查找数据包数据的日期。设置 --bundle-timestamp
将导致 run
使用不大于或等于 bundle-timestamp
的最新数据包导入。这就是我们如何使用旧数据运行回测。bundle-timestamp
使用小于或等于的关系,因此我们可以指定运行旧回测的日期,并获取该日期对我们可用的相同数据。bundle-timestamp
默认为当前日期,以使用最新数据。
默认数据包
Quandl WIKI 数据包
默认情况下,Zipline 附带了使用 Quandl 的 WIKI 数据集 的 quandl
数据包。Quandl 数据包包括每日价格数据、拆分、现金股息和资产元数据。要导入 quandl
数据包,请运行以下任一命令:
$ zipline ingest -b quandl
$ zipline ingest
任一命令下载和处理数据的时间应该只需几分钟。
注意
Quandl 已于 2018 年初停止更新此数据集。尽管如此,它仍然是一个有用的起点,可以在不设置自己的数据集的情况下尝试 Zipline。### Quandl WIKI 数据包
默认情况下,Zipline 附带了使用 Quandl 的 WIKI 数据集 的 quandl
数据包。Quandl 数据包包括每日价格数据、拆分、现金股息和资产元数据。要导入 quandl
数据包,请运行以下任一命令:
$ zipline ingest -b quandl
$ zipline ingest
任一命令下载和处理数据的时间应该只需几分钟。
注意
Quandl 已于 2018 年初停止更新此数据集。尽管如此,它仍然是一个有用的起点,可以在不设置自己的数据集的情况下尝试 Zipline。
编写新的数据包
数据包的存在是为了方便使用不同的数据源与 Zipline。要添加新的数据包,必须实现一个 ingest
函数。
ingest
函数负责将数据加载到内存中,并将其传递给 Zipline 提供的一组写入器对象,以将数据转换为 Zipline 的内部格式。ingest 函数可以通过下载远程位置的数据来工作,例如 quandl
包,或者只是加载已经在机器上的文件。函数会提供写入器,将数据写入正确的位置。如果部分 ingestion 失败,包将不会处于不完整状态。
ingest 函数的签名应该是:
ingest(environ,
asset_db_writer,
minute_bar_writer,
daily_bar_writer,
adjustment_writer,
calendar,
start_session,
end_session,
cache,
show_progress,
output_dir)
environ
environ
是一个映射,表示要使用的环境变量。这是传递任何自定义参数的地方,例如:quandl
包使用环境变量传递 API 密钥和下载重试次数。
asset_db_writer
asset_db_writer
是 AssetDBWriter
的一个实例。它是用于资产元数据的写入器,提供资产生命周期和符号到资产 ID(sid)的映射。它还可能包含资产名称、交易所和其他一些列。要写入数据,请调用 write()
方法,并传入各个元数据的数据框。关于数据格式的更多信息,请参阅 write 的文档。
minute_bar_writer
minute_bar_writer
是 BcolzMinuteBarWriter
的一个实例。这个写入器用于将数据转换为 Zipline 内部 bcolz 格式,以便稍后由 BcolzMinuteBarReader
读取。如果提供了分钟数据,用户应该调用 write()
方法,并传入一个 (sid, dataframe) 元组的迭代器。show_progress
参数也应该传递给这个方法。如果数据源不提供分钟级数据,则无需调用 write 方法。向 write()
传递一个空迭代器也是可接受的,以表示没有分钟级数据。
注意
write()
方法接收的数据可以是惰性迭代器或生成器,以避免一次性将所有分钟数据加载到内存中。只要日期严格递增,一个给定的 sid 也可以在数据中出现多次。
daily_bar_writer
daily_bar_writer
是 BcolzDailyBarWriter
的一个实例。该写入器用于将数据转换为 Zipline 的内部 bcolz 格式,以便稍后由 BcolzDailyBarReader
读取。如果提供了每日数据,用户应该使用可迭代对象的 (sid, dataframe) 元组调用 write()
。show_progress
参数也应该转发给此方法。如果数据源不提供每日数据,则无需调用 write 方法。向 write()
传递一个空的可迭代对象以表示没有每日数据也是可接受的。如果没有提供每日数据但提供了分钟数据,则会进行每日汇总以服务每日历史请求。
Note
与 minute_bar_writer
类似,传递给 write()
的数据可以是惰性可迭代对象或生成器,以避免一次性将所有数据加载到内存中。与 minute_bar_writer
不同的是,sid 在数据可迭代对象中只能出现一次。
adjustment_writer
adjustment_writer
是 SQLiteAdjustmentWriter
的一个实例。该写入器用于存储拆分、合并、股息和股票股息。数据应以数据框的形式提供,并传递给 write()
。这些字段都是可选的,但写入器可以接受您拥有的尽可能多的数据。
calendar
calendar
是 zipline.utils.calendars.TradingCalendar
的一个实例。提供日历是为了帮助某些捆绑包生成所需日期的查询。
start_session
start_session
是一个 pandas.Timestamp
对象,表示该捆绑包应该加载数据的第一天。
end_session
end_session
是一个 pandas.Timestamp
对象,表示该捆绑包应该加载数据的最后一天。
cache
cache
是 dataframe_cache
的一个实例。这个对象是一个字符串到数据框的映射。如果摄取过程中发生崩溃,这个对象会被提供。其想法是,摄取函数应该检查缓存中是否存在原始数据,如果不存在,则应该获取它并将其存储在缓存中。然后它可以解析并写入数据。只有在成功加载后,缓存才会被清除,这可以防止摄取函数在解析中出现错误时需要重新下载所有数据。如果获取数据非常快,例如如果它来自另一个本地文件,则不需要使用此缓存。
show_progress
show_progress
是一个布尔值,表示用户希望接收关于摄取函数在获取和写入数据方面的进度反馈。例如,显示已下载的文件数量占所需总数的百分比,或者数据转换的进度。实现 show_progress
的一个有用工具是 maybe_show_progress
。这个参数应该始终传递给 minute_bar_writer.write
和 daily_bar_writer.write
。
output_dir
output_dir
是一个字符串,表示所有数据将被写入的文件路径。output_dir
将是 $ZIPLINE_ROOT
的某个子目录,并包含当前摄取开始的时间。如果您的摄取函数可以直接生成输出而不需要写入器,则可以直接将资源移动到这里。例如,quantopian:quandl
包使用这个直接将包解压到 output_dir
。
environ
environ
是一个映射,代表要使用的环境变量。这是传递任何摄取所需的定制参数的地方,例如:quandl
包使用环境变量传递 API 密钥和下载重试次数。
asset_db_writer
asset_db_writer
是 AssetDBWriter
的一个实例。它是用于资产元数据的写入器,提供资产生命周期和符号到资产 ID(sid)的映射。它还可能包含资产名称、交易所和其他一些列。要写入数据,请调用 write()
方法,并传入各个元数据的数据框。关于数据格式的更多信息,请参阅 write 的文档。
minute_bar_writer
minute_bar_writer
是BcolzMinuteBarWriter
的一个实例。该写入器用于将数据转换为 Zipline 的内部 bcolz 格式,以便稍后由BcolzMinuteBarReader
读取。如果提供了分钟数据,用户应该使用可迭代的(sid, dataframe)元组调用write()
。show_progress
参数也应该传递给此方法。如果数据源不提供分钟级数据,则无需调用 write 方法。向write()
传递一个空迭代器也是可接受的,以表明没有分钟数据。
注意
传递给write()
的数据可以是惰性迭代器或生成器,以避免一次性将所有分钟数据加载到内存中。只要日期严格递增,一个给定的 sid 也可以在数据中出现多次。
daily_bar_writer
daily_bar_writer
是BcolzDailyBarWriter
的一个实例。该写入器用于将数据转换为 Zipline 的内部 bcolz 格式,以便稍后由BcolzDailyBarReader
读取。如果提供了每日数据,用户应该使用可迭代的(sid, dataframe)元组调用write()
。show_progress
参数也应该传递给此方法。如果数据源不提供每日数据,则无需调用 write 方法。向write()
传递一个空迭代器也是可接受的,以表明没有每日数据。如果没有提供每日数据但提供了分钟数据,则会进行每日汇总以服务每日历史请求。
注意
与minute_bar_writer
类似,传递给write()
的数据可以是惰性迭代器或生成器,以避免一次性将所有数据加载到内存中。与minute_bar_writer
不同的是,一个 sid 只能在数据迭代器中出现一次。
adjustment_writer
adjustment_writer
是SQLiteAdjustmentWriter
的一个实例。该写入器用于存储拆分、合并、股息和股票股息。数据应以数据框的形式提供,并传递给write()
。这些字段中的每一个都是可选的,但写入器可以接受您拥有的尽可能多的数据。
calendar
calendar
是zipline.utils.calendars.TradingCalendar
的一个实例。日历提供给一些捆绑包,以帮助生成所需日期的查询。
start_session
start_session
是一个pandas.Timestamp
对象,指示捆绑包应该加载数据的第一天。
end_session
end_session
是一个 pandas.Timestamp
对象,表示包应该加载数据的最后一天。
cache
cache
是 dataframe_cache
的一个实例。这个对象是一个从字符串到数据框的映射。如果摄取过程中途崩溃,这个对象会被提供。其想法是,摄取函数应该检查缓存中是否存在原始数据,如果不存在,则应该获取它,然后将其存储在缓存中。然后它可以解析并写入数据。只有在成功加载后,缓存才会被清除,这可以防止摄取函数在解析中出现错误时需要重新下载所有数据。如果获取数据非常快,例如如果数据来自另一个本地文件,则不需要使用此缓存。
show_progress
show_progress
是一个布尔值,表示用户希望接收关于摄取函数获取和写入数据进度的反馈。例如,显示已下载的文件数量占所需总数的比例,或者摄取函数在进行某些数据转换时的进度。实现 show_progress
循环的一个有用工具是 maybe_show_progress
。这个参数应该始终传递给 minute_bar_writer.write
和 daily_bar_writer.write
。
output_dir
output_dir
是一个字符串,表示所有数据将被写入的文件路径。output_dir
将是 $ZIPLINE_ROOT
的某个子目录,并且将包含当前摄取开始的时间。如果由于某种原因,您的摄取函数可以不通过写入器产生自己的输出,那么可以直接将资源移动到这里。例如,quantopian:quandl
包使用这个功能直接将包解压到 output_dir
中。
从 .csv 文件中摄取数据
Zipline 提供了一个名为 csvdir
的包,允许用户从 .csv
文件中摄取数据。文件格式应为 OHLCV 格式,包含日期、股息和拆分。下面提供了一个示例。在 zipline/tests/resources/csvdir_samples
中还有其他用于测试目的的示例。
date,open,high,low,close,volume,dividend,split
2012-01-03,58.485714,58.92857,58.42857,58.747143,75555200,0.0,1.0
2012-01-04,58.57143,59.240002,58.468571,59.062859,65005500,0.0,1.0
2012-01-05,59.278572,59.792858,58.952858,59.718571,67817400,0.0,1.0
2012-01-06,59.967144,60.392857,59.888573,60.342857,79573200,0.0,1.0
2012-01-09,60.785713,61.107143,60.192856,60.247143,98506100,0.0,1.0
2012-01-10,60.844284,60.857143,60.214287,60.462856,64549100,0.0,1.0
2012-01-11,60.382858,60.407143,59.901428,60.364285,53771200,0.0,1.0
一旦您的数据格式正确,您可以编辑 ~/.zipline/extension.py
文件中的 extension.py
文件,并导入 csvdir 包以及 pandas
。
import pandas as pd
from zipline.data.bundles import register
from zipline.data.bundles.csvdir import csvdir_equities
然后,我们想要指定我们的包数据的开始和结束会话:
start_session = pd.Timestamp('2016-1-1', tz='utc')
end_session = pd.Timestamp('2018-1-1', tz='utc')
然后我们可以 register()
我们的包,并传递我们的 .csv
文件所在的目录位置:
register(
'custom-csvdir-bundle',
csvdir_equities(
['daily'],
'/path/to/your/csvs',
),
calendar_name='NYSE', # US equities
start_session=start_session,
end_session=end_session
)
最后,我们可以运行以下命令来摄取我们的数据:
$ zipline ingest -b custom-csvdir-bundle
Loading custom pricing data: [############------------------------] 33% | FAKE: sid 0
Loading custom pricing data: [########################------------] 66% | FAKE1: sid 1
Loading custom pricing data: [####################################] 100% | FAKE2: sid 2
Loading custom pricing data: [####################################] 100%
Merging daily equity files: [####################################]
# optionally, we can pass the location of our csvs via the command line
$ CSVDIR=/path/to/your/csvs zipline ingest -b custom-csvdir-bundle
如果你想使用不在纽约证券交易所日历或现有 Zipline 日历中的股票,你可以查看Trading Calendar Tutorial
来构建一个自定义交易日历,然后将其名称传递给register()
。
实用示例
查看书籍机器学习在交易中的应用中的示例,包括Algoseek的分钟数据和日本股票的日频数据。
标签:中文,01,Zipline,0.0,00,zipline,文档,--,2016 From: https://www.cnblogs.com/apachecn/p/18189003